ns_gige.cc revision 1057
17119Sgblack@eecs.umich.edu/*
27119Sgblack@eecs.umich.edu * Copyright (c) 2004 The Regents of The University of Michigan
310037SARM gem5 Developers * All rights reserved.
47120Sgblack@eecs.umich.edu *
57120Sgblack@eecs.umich.edu * Redistribution and use in source and binary forms, with or without
67120Sgblack@eecs.umich.edu * modification, are permitted provided that the following conditions are
77120Sgblack@eecs.umich.edu * met: redistributions of source code must retain the above copyright
87120Sgblack@eecs.umich.edu * notice, this list of conditions and the following disclaimer;
97120Sgblack@eecs.umich.edu * redistributions in binary form must reproduce the above copyright
107120Sgblack@eecs.umich.edu * notice, this list of conditions and the following disclaimer in the
117120Sgblack@eecs.umich.edu * documentation and/or other materials provided with the distribution;
127120Sgblack@eecs.umich.edu * neither the name of the copyright holders nor the names of its
137120Sgblack@eecs.umich.edu * contributors may be used to endorse or promote products derived from
147120Sgblack@eecs.umich.edu * this software without specific prior written permission.
157119Sgblack@eecs.umich.edu *
167119Sgblack@eecs.umich.edu * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
177119Sgblack@eecs.umich.edu * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
187119Sgblack@eecs.umich.edu * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
197119Sgblack@eecs.umich.edu * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
207119Sgblack@eecs.umich.edu * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
217119Sgblack@eecs.umich.edu * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
227119Sgblack@eecs.umich.edu * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
237119Sgblack@eecs.umich.edu * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
247119Sgblack@eecs.umich.edu * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
257119Sgblack@eecs.umich.edu * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
267119Sgblack@eecs.umich.edu * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
277119Sgblack@eecs.umich.edu */
287119Sgblack@eecs.umich.edu
297119Sgblack@eecs.umich.edu/* @file
307119Sgblack@eecs.umich.edu * Device module for modelling the National Semiconductor
317119Sgblack@eecs.umich.edu * DP83820 ethernet controller.  Does not support priority queueing
327119Sgblack@eecs.umich.edu */
337119Sgblack@eecs.umich.edu#include <cstdio>
347119Sgblack@eecs.umich.edu#include <deque>
357119Sgblack@eecs.umich.edu#include <string>
367119Sgblack@eecs.umich.edu
377119Sgblack@eecs.umich.edu#include "base/inet.hh"
387119Sgblack@eecs.umich.edu#include "cpu/exec_context.hh"
397119Sgblack@eecs.umich.edu#include "cpu/intr_control.hh"
407119Sgblack@eecs.umich.edu#include "dev/dma.hh"
417119Sgblack@eecs.umich.edu#include "dev/etherlink.hh"
427119Sgblack@eecs.umich.edu#include "dev/ns_gige.hh"
437119Sgblack@eecs.umich.edu#include "dev/pciconfigall.hh"
447646Sgene.wu@arm.com#include "dev/tsunami_cchip.hh"
4510196SCurtis.Dunham@arm.com#include "mem/bus/bus.hh"
467646Sgene.wu@arm.com#include "mem/bus/dma_interface.hh"
477646Sgene.wu@arm.com#include "mem/bus/pio_interface.hh"
487646Sgene.wu@arm.com#include "mem/bus/pio_interface_impl.hh"
497646Sgene.wu@arm.com#include "mem/functional_mem/memory_control.hh"
507646Sgene.wu@arm.com#include "mem/functional_mem/physical_memory.hh"
517646Sgene.wu@arm.com#include "sim/builder.hh"
527646Sgene.wu@arm.com#include "sim/debug.hh"
537646Sgene.wu@arm.com#include "sim/host.hh"
5410196SCurtis.Dunham@arm.com#include "sim/sim_stats.hh"
557646Sgene.wu@arm.com#include "targetarch/vtophys.hh"
567646Sgene.wu@arm.com
577646Sgene.wu@arm.comconst char *NsRxStateStrings[] =
587646Sgene.wu@arm.com{
597646Sgene.wu@arm.com    "rxIdle",
607646Sgene.wu@arm.com    "rxDescRefr",
617646Sgene.wu@arm.com    "rxDescRead",
627646Sgene.wu@arm.com    "rxFifoBlock",
637646Sgene.wu@arm.com    "rxFragWrite",
6410196SCurtis.Dunham@arm.com    "rxDescWrite",
657646Sgene.wu@arm.com    "rxAdvance"
667646Sgene.wu@arm.com};
677646Sgene.wu@arm.com
687646Sgene.wu@arm.comconst char *NsTxStateStrings[] =
697646Sgene.wu@arm.com{
707646Sgene.wu@arm.com    "txIdle",
717646Sgene.wu@arm.com    "txDescRefr",
727646Sgene.wu@arm.com    "txDescRead",
737205Sgblack@eecs.umich.edu    "txFifoBlock",
7410196SCurtis.Dunham@arm.com    "txFragRead",
757205Sgblack@eecs.umich.edu    "txDescWrite",
767205Sgblack@eecs.umich.edu    "txAdvance"
777205Sgblack@eecs.umich.edu};
787205Sgblack@eecs.umich.edu
797205Sgblack@eecs.umich.educonst char *NsDmaState[] =
807205Sgblack@eecs.umich.edu{
817205Sgblack@eecs.umich.edu    "dmaIdle",
827205Sgblack@eecs.umich.edu    "dmaReading",
837205Sgblack@eecs.umich.edu    "dmaWriting",
847205Sgblack@eecs.umich.edu    "dmaReadWaiting",
857205Sgblack@eecs.umich.edu    "dmaWriteWaiting"
867205Sgblack@eecs.umich.edu};
877205Sgblack@eecs.umich.edu
887205Sgblack@eecs.umich.eduusing namespace std;
897205Sgblack@eecs.umich.edu
908442Sgblack@eecs.umich.edu// helper function declarations
918442Sgblack@eecs.umich.edu// These functions reverse Endianness so we can evaluate network data
927205Sgblack@eecs.umich.edu// correctly
937205Sgblack@eecs.umich.eduuint16_t reverseEnd16(uint16_t);
947205Sgblack@eecs.umich.eduuint32_t reverseEnd32(uint32_t);
957205Sgblack@eecs.umich.edu
967205Sgblack@eecs.umich.edu///////////////////////////////////////////////////////////////////////
977205Sgblack@eecs.umich.edu//
987205Sgblack@eecs.umich.edu// NSGigE PCI Device
997205Sgblack@eecs.umich.edu//
1007205Sgblack@eecs.umich.eduNSGigE::NSGigE(const std::string &name, IntrControl *i, Tick intr_delay,
1017597Sminkyu.jeong@arm.com               PhysicalMemory *pmem, Tick tx_delay, Tick rx_delay,
1027597Sminkyu.jeong@arm.com               MemoryController *mmu, HierParams *hier, Bus *header_bus,
1037205Sgblack@eecs.umich.edu               Bus *payload_bus, Tick pio_latency, bool dma_desc_free,
1047205Sgblack@eecs.umich.edu               bool dma_data_free, Tick dma_read_delay, Tick dma_write_delay,
1057205Sgblack@eecs.umich.edu               Tick dma_read_factor, Tick dma_write_factor, PciConfigAll *cf,
1067205Sgblack@eecs.umich.edu               PciConfigData *cd, Tsunami *t, uint32_t bus, uint32_t dev,
1077205Sgblack@eecs.umich.edu               uint32_t func, bool rx_filter, const int eaddr[6],
1087205Sgblack@eecs.umich.edu               uint32_t tx_fifo_size, uint32_t rx_fifo_size)
1097205Sgblack@eecs.umich.edu    : PciDev(name, mmu, cf, cd, bus, dev, func), tsunami(t), ioEnable(false),
11010196SCurtis.Dunham@arm.com      maxTxFifoSize(tx_fifo_size), maxRxFifoSize(rx_fifo_size),
1117205Sgblack@eecs.umich.edu      txPacket(0), rxPacket(0), txPacketBufPtr(NULL), rxPacketBufPtr(NULL),
1127205Sgblack@eecs.umich.edu      txXferLen(0), rxXferLen(0), txState(txIdle), txEnable(false),
1137205Sgblack@eecs.umich.edu      CTDD(false), txFifoAvail(tx_fifo_size),
1147205Sgblack@eecs.umich.edu      txFragPtr(0), txDescCnt(0), txDmaState(dmaIdle), rxState(rxIdle),
1157205Sgblack@eecs.umich.edu      rxEnable(false), CRDD(false), rxPktBytes(0), rxFifoCnt(0),
1167205Sgblack@eecs.umich.edu      rxFragPtr(0), rxDescCnt(0), rxDmaState(dmaIdle), extstsEnable(false),
1177205Sgblack@eecs.umich.edu      rxDmaReadEvent(this), rxDmaWriteEvent(this),
1187205Sgblack@eecs.umich.edu      txDmaReadEvent(this), txDmaWriteEvent(this),
1197205Sgblack@eecs.umich.edu      dmaDescFree(dma_desc_free), dmaDataFree(dma_data_free),
1207205Sgblack@eecs.umich.edu      txDelay(tx_delay), rxDelay(rx_delay), rxKickTick(0), txKickTick(0),
1217205Sgblack@eecs.umich.edu      txEvent(this), rxFilterEnable(rx_filter), acceptBroadcast(false),
1227205Sgblack@eecs.umich.edu      acceptMulticast(false), acceptUnicast(false),
1237205Sgblack@eecs.umich.edu      acceptPerfect(false), acceptArp(false),
1247205Sgblack@eecs.umich.edu      physmem(pmem), intctrl(i), intrTick(0), cpuPendingIntr(false),
1257205Sgblack@eecs.umich.edu      intrEvent(0), interface(0)
1268442Sgblack@eecs.umich.edu{
1278442Sgblack@eecs.umich.edu    tsunami->ethernet = this;
1287205Sgblack@eecs.umich.edu
1297597Sminkyu.jeong@arm.com    if (header_bus) {
1307597Sminkyu.jeong@arm.com        pioInterface = newPioInterface(name, hier, header_bus, this,
1317205Sgblack@eecs.umich.edu                                       &NSGigE::cacheAccess);
1327205Sgblack@eecs.umich.edu
1337205Sgblack@eecs.umich.edu        pioLatency = pio_latency * header_bus->clockRatio;
1347205Sgblack@eecs.umich.edu
1357205Sgblack@eecs.umich.edu        if (payload_bus)
1367205Sgblack@eecs.umich.edu            dmaInterface = new DMAInterface<Bus>(name + ".dma",
1377205Sgblack@eecs.umich.edu                                                 header_bus, payload_bus, 1);
1387205Sgblack@eecs.umich.edu        else
13910196SCurtis.Dunham@arm.com            dmaInterface = new DMAInterface<Bus>(name + ".dma",
1407205Sgblack@eecs.umich.edu                                                 header_bus, header_bus, 1);
1417205Sgblack@eecs.umich.edu    } else if (payload_bus) {
1427205Sgblack@eecs.umich.edu        pioInterface = newPioInterface(name, hier, payload_bus, this,
1437205Sgblack@eecs.umich.edu                                       &NSGigE::cacheAccess);
1447205Sgblack@eecs.umich.edu
1457205Sgblack@eecs.umich.edu        pioLatency = pio_latency * payload_bus->clockRatio;
1467205Sgblack@eecs.umich.edu
1477205Sgblack@eecs.umich.edu        dmaInterface = new DMAInterface<Bus>(name + ".dma", payload_bus,
1487205Sgblack@eecs.umich.edu                                         payload_bus, 1);
1497205Sgblack@eecs.umich.edu    }
1508442Sgblack@eecs.umich.edu
1518442Sgblack@eecs.umich.edu
1527205Sgblack@eecs.umich.edu    intrDelay = US2Ticks(intr_delay);
1537205Sgblack@eecs.umich.edu    dmaReadDelay = dma_read_delay;
1547205Sgblack@eecs.umich.edu    dmaWriteDelay = dma_write_delay;
1557205Sgblack@eecs.umich.edu    dmaReadFactor = dma_read_factor;
1567205Sgblack@eecs.umich.edu    dmaWriteFactor = dma_write_factor;
1577205Sgblack@eecs.umich.edu
1587205Sgblack@eecs.umich.edu    regsReset();
1597205Sgblack@eecs.umich.edu    rom.perfectMatch[0] = eaddr[0];
1607205Sgblack@eecs.umich.edu    rom.perfectMatch[1] = eaddr[1];
1617205Sgblack@eecs.umich.edu    rom.perfectMatch[2] = eaddr[2];
1627205Sgblack@eecs.umich.edu    rom.perfectMatch[3] = eaddr[3];
1637205Sgblack@eecs.umich.edu    rom.perfectMatch[4] = eaddr[4];
1647119Sgblack@eecs.umich.edu    rom.perfectMatch[5] = eaddr[5];
16510196SCurtis.Dunham@arm.com}
1667119Sgblack@eecs.umich.edu
1677119Sgblack@eecs.umich.eduNSGigE::~NSGigE()
1687119Sgblack@eecs.umich.edu{}
1697119Sgblack@eecs.umich.edu
1707119Sgblack@eecs.umich.eduvoid
1717119Sgblack@eecs.umich.eduNSGigE::regStats()
1727119Sgblack@eecs.umich.edu{
1737119Sgblack@eecs.umich.edu    txBytes
1747119Sgblack@eecs.umich.edu        .name(name() + ".txBytes")
1757119Sgblack@eecs.umich.edu        .desc("Bytes Transmitted")
1767119Sgblack@eecs.umich.edu        .prereq(txBytes)
1777119Sgblack@eecs.umich.edu        ;
1788442Sgblack@eecs.umich.edu
1797119Sgblack@eecs.umich.edu    rxBytes
1807119Sgblack@eecs.umich.edu        .name(name() + ".rxBytes")
1817119Sgblack@eecs.umich.edu        .desc("Bytes Received")
1827119Sgblack@eecs.umich.edu        .prereq(rxBytes)
1837119Sgblack@eecs.umich.edu        ;
1847119Sgblack@eecs.umich.edu
1857597Sminkyu.jeong@arm.com    txPackets
1867597Sminkyu.jeong@arm.com        .name(name() + ".txPackets")
1877119Sgblack@eecs.umich.edu        .desc("Number of Packets Transmitted")
1887119Sgblack@eecs.umich.edu        .prereq(txBytes)
1897119Sgblack@eecs.umich.edu        ;
1907119Sgblack@eecs.umich.edu
1917119Sgblack@eecs.umich.edu    rxPackets
1927119Sgblack@eecs.umich.edu        .name(name() + ".rxPackets")
1937639Sgblack@eecs.umich.edu        .desc("Number of Packets Received")
1947639Sgblack@eecs.umich.edu        .prereq(rxBytes)
1957639Sgblack@eecs.umich.edu        ;
19610196SCurtis.Dunham@arm.com
1977639Sgblack@eecs.umich.edu    txIPChecksums
1987639Sgblack@eecs.umich.edu        .name(name() + ".txIPChecksums")
1997639Sgblack@eecs.umich.edu        .desc("Number of tx IP Checksums done by device")
2007639Sgblack@eecs.umich.edu        .precision(0)
2017639Sgblack@eecs.umich.edu        .prereq(txBytes)
2027639Sgblack@eecs.umich.edu        ;
2037639Sgblack@eecs.umich.edu
2047639Sgblack@eecs.umich.edu    rxIPChecksums
2057639Sgblack@eecs.umich.edu        .name(name() + ".rxIPChecksums")
2067639Sgblack@eecs.umich.edu        .desc("Number of rx IP Checksums done by device")
2077639Sgblack@eecs.umich.edu        .precision(0)
2087639Sgblack@eecs.umich.edu        .prereq(rxBytes)
2097639Sgblack@eecs.umich.edu        ;
2107639Sgblack@eecs.umich.edu
2117639Sgblack@eecs.umich.edu    txTCPChecksums
2128444Sgblack@eecs.umich.edu        .name(name() + ".txTCPChecksums")
2137639Sgblack@eecs.umich.edu        .desc("Number of tx TCP Checksums done by device")
2147639Sgblack@eecs.umich.edu        .precision(0)
2157639Sgblack@eecs.umich.edu        .prereq(txBytes)
2167639Sgblack@eecs.umich.edu        ;
2177639Sgblack@eecs.umich.edu
2187639Sgblack@eecs.umich.edu    rxTCPChecksums
2198072SGiacomo.Gabrielli@arm.com        .name(name() + ".rxTCPChecksums")
2208072SGiacomo.Gabrielli@arm.com        .desc("Number of rx TCP Checksums done by device")
2217639Sgblack@eecs.umich.edu        .precision(0)
2227639Sgblack@eecs.umich.edu        .prereq(rxBytes)
2237639Sgblack@eecs.umich.edu        ;
2247639Sgblack@eecs.umich.edu
2257639Sgblack@eecs.umich.edu    descDmaReads
2267639Sgblack@eecs.umich.edu        .name(name() + ".descDMAReads")
2277120Sgblack@eecs.umich.edu        .desc("Number of descriptors the device read w/ DMA")
22810196SCurtis.Dunham@arm.com        .precision(0)
2297120Sgblack@eecs.umich.edu        ;
2307120Sgblack@eecs.umich.edu
2317120Sgblack@eecs.umich.edu    descDmaWrites
2327120Sgblack@eecs.umich.edu        .name(name() + ".descDMAWrites")
2337120Sgblack@eecs.umich.edu        .desc("Number of descriptors the device wrote w/ DMA")
2347120Sgblack@eecs.umich.edu        .precision(0)
2357120Sgblack@eecs.umich.edu        ;
2367120Sgblack@eecs.umich.edu
2377120Sgblack@eecs.umich.edu    descDmaRdBytes
2387120Sgblack@eecs.umich.edu        .name(name() + ".descDmaReadBytes")
2397120Sgblack@eecs.umich.edu        .desc("number of descriptor bytes read w/ DMA")
2407120Sgblack@eecs.umich.edu        .precision(0)
2417120Sgblack@eecs.umich.edu        ;
2427120Sgblack@eecs.umich.edu
2437120Sgblack@eecs.umich.edu   descDmaWrBytes
2447120Sgblack@eecs.umich.edu        .name(name() + ".descDmaWriteBytes")
2458442Sgblack@eecs.umich.edu        .desc("number of descriptor bytes write w/ DMA")
2468442Sgblack@eecs.umich.edu        .precision(0)
2477120Sgblack@eecs.umich.edu        ;
2487120Sgblack@eecs.umich.edu
2497120Sgblack@eecs.umich.edu
2507120Sgblack@eecs.umich.edu    txBandwidth
2517120Sgblack@eecs.umich.edu        .name(name() + ".txBandwidth")
2527597Sminkyu.jeong@arm.com        .desc("Transmit Bandwidth (bits/s)")
2537597Sminkyu.jeong@arm.com        .precision(0)
2547120Sgblack@eecs.umich.edu        .prereq(txBytes)
2557120Sgblack@eecs.umich.edu        ;
2567120Sgblack@eecs.umich.edu
2577120Sgblack@eecs.umich.edu    rxBandwidth
2587120Sgblack@eecs.umich.edu        .name(name() + ".rxBandwidth")
2597120Sgblack@eecs.umich.edu        .desc("Receive Bandwidth (bits/s)")
2607639Sgblack@eecs.umich.edu        .precision(0)
2617639Sgblack@eecs.umich.edu        .prereq(rxBytes)
2627639Sgblack@eecs.umich.edu        ;
26310196SCurtis.Dunham@arm.com
2647639Sgblack@eecs.umich.edu    txPacketRate
2657639Sgblack@eecs.umich.edu        .name(name() + ".txPPS")
2667639Sgblack@eecs.umich.edu        .desc("Packet Tranmission Rate (packets/s)")
2677639Sgblack@eecs.umich.edu        .precision(0)
2687639Sgblack@eecs.umich.edu        .prereq(txBytes)
2697639Sgblack@eecs.umich.edu        ;
2707639Sgblack@eecs.umich.edu
2717639Sgblack@eecs.umich.edu    rxPacketRate
2727639Sgblack@eecs.umich.edu        .name(name() + ".rxPPS")
2737639Sgblack@eecs.umich.edu        .desc("Packet Reception Rate (packets/s)")
2747639Sgblack@eecs.umich.edu        .precision(0)
2757639Sgblack@eecs.umich.edu        .prereq(rxBytes)
2767639Sgblack@eecs.umich.edu        ;
2777639Sgblack@eecs.umich.edu
2787639Sgblack@eecs.umich.edu    txBandwidth = txBytes * Stats::constant(8) / simSeconds;
2797639Sgblack@eecs.umich.edu    rxBandwidth = rxBytes * Stats::constant(8) / simSeconds;
2807639Sgblack@eecs.umich.edu    txPacketRate = txPackets / simSeconds;
2817639Sgblack@eecs.umich.edu    rxPacketRate = rxPackets / simSeconds;
2827639Sgblack@eecs.umich.edu}
2838444Sgblack@eecs.umich.edu
2848444Sgblack@eecs.umich.edu/**
2857639Sgblack@eecs.umich.edu * This is to read the PCI general configuration registers
2867639Sgblack@eecs.umich.edu */
2877639Sgblack@eecs.umich.eduvoid
2887639Sgblack@eecs.umich.eduNSGigE::ReadConfig(int offset, int size, uint8_t *data)
2897639Sgblack@eecs.umich.edu{
2908072SGiacomo.Gabrielli@arm.com    if (offset < PCI_DEVICE_SPECIFIC)
2918072SGiacomo.Gabrielli@arm.com        PciDev::ReadConfig(offset, size, data);
2927639Sgblack@eecs.umich.edu    else
2937639Sgblack@eecs.umich.edu        panic("Device specific PCI config space not implemented!\n");
2947639Sgblack@eecs.umich.edu}
2957639Sgblack@eecs.umich.edu
2967639Sgblack@eecs.umich.edu/**
2977639Sgblack@eecs.umich.edu * This is to write to the PCI general configuration registers
2987303Sgblack@eecs.umich.edu */
29910196SCurtis.Dunham@arm.comvoid
3007303Sgblack@eecs.umich.eduNSGigE::WriteConfig(int offset, int size, uint32_t data)
3017303Sgblack@eecs.umich.edu{
3027303Sgblack@eecs.umich.edu    if (offset < PCI_DEVICE_SPECIFIC)
3037303Sgblack@eecs.umich.edu        PciDev::WriteConfig(offset, size, data);
3047303Sgblack@eecs.umich.edu    else
3057303Sgblack@eecs.umich.edu        panic("Device specific PCI config space not implemented!\n");
3067303Sgblack@eecs.umich.edu
3077303Sgblack@eecs.umich.edu    // Need to catch writes to BARs to update the PIO interface
3087303Sgblack@eecs.umich.edu    switch (offset) {
3097303Sgblack@eecs.umich.edu        // seems to work fine without all these PCI settings, but i
3107303Sgblack@eecs.umich.edu        // put in the IO to double check, an assertion will fail if we
3117303Sgblack@eecs.umich.edu        // need to properly implement it
3127303Sgblack@eecs.umich.edu      case PCI_COMMAND:
3137303Sgblack@eecs.umich.edu        if (config.data[offset] & PCI_CMD_IOSE)
3147303Sgblack@eecs.umich.edu            ioEnable = true;
3157303Sgblack@eecs.umich.edu        else
3167303Sgblack@eecs.umich.edu            ioEnable = false;
3177303Sgblack@eecs.umich.edu
3188442Sgblack@eecs.umich.edu#if 0
3198442Sgblack@eecs.umich.edu        if (config.data[offset] & PCI_CMD_BME) {
3207303Sgblack@eecs.umich.edu            bmEnabled = true;
3217303Sgblack@eecs.umich.edu        }
3227303Sgblack@eecs.umich.edu        else {
3237303Sgblack@eecs.umich.edu            bmEnabled = false;
3247303Sgblack@eecs.umich.edu        }
3257303Sgblack@eecs.umich.edu
3267303Sgblack@eecs.umich.edu        if (config.data[offset] & PCI_CMD_MSE) {
3277303Sgblack@eecs.umich.edu            memEnable = true;
3287303Sgblack@eecs.umich.edu        }
3297597Sminkyu.jeong@arm.com        else {
3307597Sminkyu.jeong@arm.com            memEnable = false;
3317303Sgblack@eecs.umich.edu        }
3327303Sgblack@eecs.umich.edu#endif
3337303Sgblack@eecs.umich.edu        break;
3347303Sgblack@eecs.umich.edu
3357303Sgblack@eecs.umich.edu      case PCI0_BASE_ADDR0:
3367303Sgblack@eecs.umich.edu        if (BARAddrs[0] != 0) {
3377303Sgblack@eecs.umich.edu            if (pioInterface)
33810196SCurtis.Dunham@arm.com                pioInterface->addAddrRange(BARAddrs[0],
3397303Sgblack@eecs.umich.edu                                           BARAddrs[0] + BARSize[0] - 1);
3407303Sgblack@eecs.umich.edu
3417303Sgblack@eecs.umich.edu            BARAddrs[0] &= PA_UNCACHED_MASK;
3427303Sgblack@eecs.umich.edu        }
3437303Sgblack@eecs.umich.edu        break;
3447303Sgblack@eecs.umich.edu      case PCI0_BASE_ADDR1:
3457303Sgblack@eecs.umich.edu        if (BARAddrs[1] != 0) {
3467303Sgblack@eecs.umich.edu            if (pioInterface)
3477303Sgblack@eecs.umich.edu                pioInterface->addAddrRange(BARAddrs[1],
3487303Sgblack@eecs.umich.edu                                           BARAddrs[1] + BARSize[1] - 1);
3497303Sgblack@eecs.umich.edu
3507303Sgblack@eecs.umich.edu            BARAddrs[1] &= PA_UNCACHED_MASK;
3517303Sgblack@eecs.umich.edu        }
3527303Sgblack@eecs.umich.edu        break;
3537303Sgblack@eecs.umich.edu    }
3547303Sgblack@eecs.umich.edu}
3558442Sgblack@eecs.umich.edu
3568442Sgblack@eecs.umich.edu/**
3577303Sgblack@eecs.umich.edu * This reads the device registers, which are detailed in the NS83820
3587597Sminkyu.jeong@arm.com * spec sheet
3597597Sminkyu.jeong@arm.com */
3607303Sgblack@eecs.umich.eduFault
3617408Sgblack@eecs.umich.eduNSGigE::read(MemReqPtr &req, uint8_t *data)
3627303Sgblack@eecs.umich.edu{
3637303Sgblack@eecs.umich.edu    assert(ioEnable);
3647303Sgblack@eecs.umich.edu
3657303Sgblack@eecs.umich.edu    //The mask is to give you only the offset into the device register file
3667120Sgblack@eecs.umich.edu    Addr daddr = req->paddr & 0xfff;
36710196SCurtis.Dunham@arm.com    DPRINTF(EthernetPIO, "read  da=%#x pa=%#x va=%#x size=%d\n",
3687120Sgblack@eecs.umich.edu            daddr, req->paddr, req->vaddr, req->size);
3697120Sgblack@eecs.umich.edu
3707120Sgblack@eecs.umich.edu
3717120Sgblack@eecs.umich.edu    // there are some reserved registers, you can see ns_gige_reg.h and
3727120Sgblack@eecs.umich.edu    // the spec sheet for details
3737120Sgblack@eecs.umich.edu    if (daddr > LAST && daddr <=  RESERVED) {
3747120Sgblack@eecs.umich.edu        panic("Accessing reserved register");
3757120Sgblack@eecs.umich.edu    } else if (daddr > RESERVED && daddr <= 0x3FC) {
3767120Sgblack@eecs.umich.edu        ReadConfig(daddr & 0xff, req->size, data);
3777120Sgblack@eecs.umich.edu        return No_Fault;
3787120Sgblack@eecs.umich.edu    } else if (daddr >= MIB_START && daddr <= MIB_END) {
3797120Sgblack@eecs.umich.edu        // don't implement all the MIB's.  hopefully the kernel
3807120Sgblack@eecs.umich.edu        // doesn't actually DEPEND upon their values
3817120Sgblack@eecs.umich.edu        // MIB are just hardware stats keepers
3827120Sgblack@eecs.umich.edu        uint32_t &reg = *(uint32_t *) data;
3837120Sgblack@eecs.umich.edu        reg = 0;
3848442Sgblack@eecs.umich.edu        return No_Fault;
3858442Sgblack@eecs.umich.edu    } else if (daddr > 0x3FC)
3867120Sgblack@eecs.umich.edu        panic("Something is messed up!\n");
3877597Sminkyu.jeong@arm.com
3887597Sminkyu.jeong@arm.com    switch (req->size) {
3897120Sgblack@eecs.umich.edu      case sizeof(uint32_t):
3907120Sgblack@eecs.umich.edu        {
3917120Sgblack@eecs.umich.edu            uint32_t &reg = *(uint32_t *)data;
3927120Sgblack@eecs.umich.edu
3937120Sgblack@eecs.umich.edu            switch (daddr) {
3947120Sgblack@eecs.umich.edu              case CR:
3957639Sgblack@eecs.umich.edu                reg = regs.command;
3967639Sgblack@eecs.umich.edu                //these are supposed to be cleared on a read
3977639Sgblack@eecs.umich.edu                reg &= ~(CR_RXD | CR_TXD | CR_TXR | CR_RXR);
39810196SCurtis.Dunham@arm.com                break;
3997639Sgblack@eecs.umich.edu
4007639Sgblack@eecs.umich.edu              case CFG:
4017639Sgblack@eecs.umich.edu                reg = regs.config;
4027639Sgblack@eecs.umich.edu                break;
4037639Sgblack@eecs.umich.edu
4047639Sgblack@eecs.umich.edu              case MEAR:
4057639Sgblack@eecs.umich.edu                reg = regs.mear;
4067639Sgblack@eecs.umich.edu                break;
4077639Sgblack@eecs.umich.edu
4087639Sgblack@eecs.umich.edu              case PTSCR:
4097639Sgblack@eecs.umich.edu                reg = regs.ptscr;
4107639Sgblack@eecs.umich.edu                break;
4117639Sgblack@eecs.umich.edu
4127639Sgblack@eecs.umich.edu              case ISR:
4137639Sgblack@eecs.umich.edu                reg = regs.isr;
4147639Sgblack@eecs.umich.edu                devIntrClear(ISR_ALL);
4157639Sgblack@eecs.umich.edu                break;
4168444Sgblack@eecs.umich.edu
4178444Sgblack@eecs.umich.edu              case IMR:
4187639Sgblack@eecs.umich.edu                reg = regs.imr;
4198072SGiacomo.Gabrielli@arm.com                break;
4208072SGiacomo.Gabrielli@arm.com
4217639Sgblack@eecs.umich.edu              case IER:
4227639Sgblack@eecs.umich.edu                reg = regs.ier;
4237639Sgblack@eecs.umich.edu                break;
4247639Sgblack@eecs.umich.edu
4257639Sgblack@eecs.umich.edu              case IHR:
4267639Sgblack@eecs.umich.edu                reg = regs.ihr;
4277119Sgblack@eecs.umich.edu                break;
42810196SCurtis.Dunham@arm.com
4297119Sgblack@eecs.umich.edu              case TXDP:
4307119Sgblack@eecs.umich.edu                reg = regs.txdp;
4317119Sgblack@eecs.umich.edu                break;
4327119Sgblack@eecs.umich.edu
4337119Sgblack@eecs.umich.edu              case TXDP_HI:
4347119Sgblack@eecs.umich.edu                reg = regs.txdp_hi;
4357119Sgblack@eecs.umich.edu                break;
4367119Sgblack@eecs.umich.edu
4377119Sgblack@eecs.umich.edu              case TXCFG:
4387119Sgblack@eecs.umich.edu                reg = regs.txcfg;
4397119Sgblack@eecs.umich.edu                break;
4407119Sgblack@eecs.umich.edu
4418442Sgblack@eecs.umich.edu              case GPIOR:
4427119Sgblack@eecs.umich.edu                reg = regs.gpior;
4437597Sminkyu.jeong@arm.com                break;
4447597Sminkyu.jeong@arm.com
4457119Sgblack@eecs.umich.edu              case RXDP:
4467119Sgblack@eecs.umich.edu                reg = regs.rxdp;
4477119Sgblack@eecs.umich.edu                break;
4487119Sgblack@eecs.umich.edu
4497119Sgblack@eecs.umich.edu              case RXDP_HI:
4507119Sgblack@eecs.umich.edu                reg = regs.rxdp_hi;
4517639Sgblack@eecs.umich.edu                break;
4527639Sgblack@eecs.umich.edu
4537639Sgblack@eecs.umich.edu              case RXCFG:
45410196SCurtis.Dunham@arm.com                reg = regs.rxcfg;
4557639Sgblack@eecs.umich.edu                break;
4567639Sgblack@eecs.umich.edu
4577639Sgblack@eecs.umich.edu              case PQCR:
4587639Sgblack@eecs.umich.edu                reg = regs.pqcr;
4598207SAli.Saidi@ARM.com                break;
4608207SAli.Saidi@ARM.com
4617639Sgblack@eecs.umich.edu              case WCSR:
4627639Sgblack@eecs.umich.edu                reg = regs.wcsr;
4637639Sgblack@eecs.umich.edu                break;
4648207SAli.Saidi@ARM.com
4658207SAli.Saidi@ARM.com              case PCR:
4668207SAli.Saidi@ARM.com                reg = regs.pcr;
4677639Sgblack@eecs.umich.edu                break;
4687639Sgblack@eecs.umich.edu
4697639Sgblack@eecs.umich.edu                // see the spec sheet for how RFCR and RFDR work
4708444Sgblack@eecs.umich.edu                // basically, you write to RFCR to tell the machine
4717639Sgblack@eecs.umich.edu                // what you want to do next, then you act upon RFDR,
4728072SGiacomo.Gabrielli@arm.com                // and the device will be prepared b/c of what you
4738072SGiacomo.Gabrielli@arm.com                // wrote to RFCR
4747639Sgblack@eecs.umich.edu              case RFCR:
4757639Sgblack@eecs.umich.edu                reg = regs.rfcr;
4767639Sgblack@eecs.umich.edu                break;
4777639Sgblack@eecs.umich.edu
4787639Sgblack@eecs.umich.edu              case RFDR:
4797639Sgblack@eecs.umich.edu                switch (regs.rfcr & RFCR_RFADDR) {
4807119Sgblack@eecs.umich.edu                  case 0x000:
4817119Sgblack@eecs.umich.edu                    reg = rom.perfectMatch[1];
48210196SCurtis.Dunham@arm.com                    reg = reg << 8;
4837119Sgblack@eecs.umich.edu                    reg += rom.perfectMatch[0];
4847119Sgblack@eecs.umich.edu                    break;
4857119Sgblack@eecs.umich.edu                  case 0x002:
4867119Sgblack@eecs.umich.edu                    reg = rom.perfectMatch[3] << 8;
4877119Sgblack@eecs.umich.edu                    reg += rom.perfectMatch[2];
4887119Sgblack@eecs.umich.edu                    break;
4897119Sgblack@eecs.umich.edu                  case 0x004:
4907119Sgblack@eecs.umich.edu                    reg = rom.perfectMatch[5] << 8;
4917119Sgblack@eecs.umich.edu                    reg += rom.perfectMatch[4];
4927119Sgblack@eecs.umich.edu                    break;
4938442Sgblack@eecs.umich.edu                  default:
4947119Sgblack@eecs.umich.edu                    panic("reading RFDR for something other than PMATCH!\n");
4957119Sgblack@eecs.umich.edu                    // didn't implement other RFDR functionality b/c
4967119Sgblack@eecs.umich.edu                    // driver didn't use it
4977119Sgblack@eecs.umich.edu                }
4987119Sgblack@eecs.umich.edu                break;
4997119Sgblack@eecs.umich.edu
5007119Sgblack@eecs.umich.edu              case SRR:
5017119Sgblack@eecs.umich.edu                reg = regs.srr;
5027119Sgblack@eecs.umich.edu                break;
5037119Sgblack@eecs.umich.edu
5047119Sgblack@eecs.umich.edu              case MIBC:
5057119Sgblack@eecs.umich.edu                reg = regs.mibc;
5067119Sgblack@eecs.umich.edu                reg &= ~(MIBC_MIBS | MIBC_ACLR);
5077119Sgblack@eecs.umich.edu                break;
5087639Sgblack@eecs.umich.edu
5097639Sgblack@eecs.umich.edu              case VRCR:
5107639Sgblack@eecs.umich.edu                reg = regs.vrcr;
51110196SCurtis.Dunham@arm.com                break;
5127639Sgblack@eecs.umich.edu
5137639Sgblack@eecs.umich.edu              case VTCR:
5147639Sgblack@eecs.umich.edu                reg = regs.vtcr;
5157639Sgblack@eecs.umich.edu                break;
5167639Sgblack@eecs.umich.edu
5177639Sgblack@eecs.umich.edu              case VDR:
5187639Sgblack@eecs.umich.edu                reg = regs.vdr;
5197639Sgblack@eecs.umich.edu                break;
5207639Sgblack@eecs.umich.edu
5217639Sgblack@eecs.umich.edu              case CCSR:
5227639Sgblack@eecs.umich.edu                reg = regs.ccsr;
5237639Sgblack@eecs.umich.edu                break;
5247639Sgblack@eecs.umich.edu
5257639Sgblack@eecs.umich.edu              case TBICR:
5267639Sgblack@eecs.umich.edu                reg = regs.tbicr;
5277639Sgblack@eecs.umich.edu                break;
5287639Sgblack@eecs.umich.edu
5297639Sgblack@eecs.umich.edu              case TBISR:
5307639Sgblack@eecs.umich.edu                reg = regs.tbisr;
5317639Sgblack@eecs.umich.edu                break;
5327639Sgblack@eecs.umich.edu
5337639Sgblack@eecs.umich.edu              case TANAR:
5347639Sgblack@eecs.umich.edu                reg = regs.tanar;
5357639Sgblack@eecs.umich.edu                break;
5367639Sgblack@eecs.umich.edu
5377639Sgblack@eecs.umich.edu              case TANLPAR:
5387120Sgblack@eecs.umich.edu                reg = regs.tanlpar;
5397120Sgblack@eecs.umich.edu                break;
54010196SCurtis.Dunham@arm.com
5417120Sgblack@eecs.umich.edu              case TANER:
5427120Sgblack@eecs.umich.edu                reg = regs.taner;
5437712Sgblack@eecs.umich.edu                break;
5447120Sgblack@eecs.umich.edu
5457120Sgblack@eecs.umich.edu              case TESR:
5467120Sgblack@eecs.umich.edu                reg = regs.tesr;
5477639Sgblack@eecs.umich.edu                break;
5487639Sgblack@eecs.umich.edu
5497639Sgblack@eecs.umich.edu              default:
55010196SCurtis.Dunham@arm.com                panic("reading unimplemented register: addr=%#x", daddr);
5517639Sgblack@eecs.umich.edu            }
5527639Sgblack@eecs.umich.edu
5537712Sgblack@eecs.umich.edu            DPRINTF(EthernetPIO, "read from %#x: data=%d data=%#x\n",
5547639Sgblack@eecs.umich.edu                    daddr, reg, reg);
5557639Sgblack@eecs.umich.edu        }
5567639Sgblack@eecs.umich.edu        break;
5577303Sgblack@eecs.umich.edu
5587303Sgblack@eecs.umich.edu      default:
55910196SCurtis.Dunham@arm.com        panic("accessing register with invalid size: addr=%#x, size=%d",
5607303Sgblack@eecs.umich.edu              daddr, req->size);
5617303Sgblack@eecs.umich.edu    }
5627303Sgblack@eecs.umich.edu
5637303Sgblack@eecs.umich.edu    return No_Fault;
5647303Sgblack@eecs.umich.edu}
5657303Sgblack@eecs.umich.edu
5667303Sgblack@eecs.umich.eduFault
5677303Sgblack@eecs.umich.eduNSGigE::write(MemReqPtr &req, const uint8_t *data)
5687303Sgblack@eecs.umich.edu{
5697303Sgblack@eecs.umich.edu    assert(ioEnable);
5707303Sgblack@eecs.umich.edu
5717303Sgblack@eecs.umich.edu    Addr daddr = req->paddr & 0xfff;
5727303Sgblack@eecs.umich.edu    DPRINTF(EthernetPIO, "write da=%#x pa=%#x va=%#x size=%d\n",
5737303Sgblack@eecs.umich.edu            daddr, req->paddr, req->vaddr, req->size);
5747303Sgblack@eecs.umich.edu
5757303Sgblack@eecs.umich.edu    if (daddr > LAST && daddr <=  RESERVED) {
5767303Sgblack@eecs.umich.edu        panic("Accessing reserved register");
5777303Sgblack@eecs.umich.edu    } else if (daddr > RESERVED && daddr <= 0x3FC) {
5787303Sgblack@eecs.umich.edu        WriteConfig(daddr & 0xff, req->size, *(uint32_t *)data);
5797303Sgblack@eecs.umich.edu        return No_Fault;
5807303Sgblack@eecs.umich.edu    } else if (daddr > 0x3FC)
5817291Sgblack@eecs.umich.edu        panic("Something is messed up!\n");
5827291Sgblack@eecs.umich.edu
5837291Sgblack@eecs.umich.edu    if (req->size == sizeof(uint32_t)) {
5847291Sgblack@eecs.umich.edu        uint32_t reg = *(uint32_t *)data;
5857291Sgblack@eecs.umich.edu        DPRINTF(EthernetPIO, "write data=%d data=%#x\n", reg, reg);
5867291Sgblack@eecs.umich.edu
5877291Sgblack@eecs.umich.edu        switch (daddr) {
5887291Sgblack@eecs.umich.edu          case CR:
5897291Sgblack@eecs.umich.edu            regs.command = reg;
5907291Sgblack@eecs.umich.edu            if (reg & CR_TXD) {
5917291Sgblack@eecs.umich.edu                txEnable = false;
5927291Sgblack@eecs.umich.edu            } else if (reg & CR_TXE) {
5937291Sgblack@eecs.umich.edu                txEnable = true;
5947291Sgblack@eecs.umich.edu
5957291Sgblack@eecs.umich.edu                // the kernel is enabling the transmit machine
5967291Sgblack@eecs.umich.edu                if (txState == txIdle)
5977291Sgblack@eecs.umich.edu                    txKick();
5987291Sgblack@eecs.umich.edu            }
5997291Sgblack@eecs.umich.edu
6007291Sgblack@eecs.umich.edu            if (reg & CR_RXD) {
6017312Sgblack@eecs.umich.edu                rxEnable = false;
6027312Sgblack@eecs.umich.edu            } else if (reg & CR_RXE) {
6037312Sgblack@eecs.umich.edu                rxEnable = true;
6047312Sgblack@eecs.umich.edu
6057312Sgblack@eecs.umich.edu                if (rxState == rxIdle)
6067312Sgblack@eecs.umich.edu                    rxKick();
6077312Sgblack@eecs.umich.edu            }
6087312Sgblack@eecs.umich.edu
6097312Sgblack@eecs.umich.edu            if (reg & CR_TXR)
6107312Sgblack@eecs.umich.edu                txReset();
6117312Sgblack@eecs.umich.edu
6127312Sgblack@eecs.umich.edu            if (reg & CR_RXR)
6137312Sgblack@eecs.umich.edu                rxReset();
6147312Sgblack@eecs.umich.edu
6157312Sgblack@eecs.umich.edu            if (reg & CR_SWI)
6167312Sgblack@eecs.umich.edu                devIntrPost(ISR_SWI);
6177312Sgblack@eecs.umich.edu
6187312Sgblack@eecs.umich.edu            if (reg & CR_RST) {
6197312Sgblack@eecs.umich.edu                txReset();
6207312Sgblack@eecs.umich.edu                rxReset();
6217205Sgblack@eecs.umich.edu
6227205Sgblack@eecs.umich.edu                regsReset();
6237205Sgblack@eecs.umich.edu            }
6247205Sgblack@eecs.umich.edu            break;
6257205Sgblack@eecs.umich.edu
6267205Sgblack@eecs.umich.edu          case CFG:
6277205Sgblack@eecs.umich.edu            if (reg & CFG_LNKSTS ||
6287205Sgblack@eecs.umich.edu                reg & CFG_SPDSTS ||
6297205Sgblack@eecs.umich.edu                reg & CFG_DUPSTS ||
6307205Sgblack@eecs.umich.edu                reg & CFG_RESERVED ||
6317205Sgblack@eecs.umich.edu                reg & CFG_T64ADDR ||
6327205Sgblack@eecs.umich.edu                reg & CFG_PCI64_DET)
6337205Sgblack@eecs.umich.edu                panic("writing to read-only or reserved CFG bits!\n");
6347205Sgblack@eecs.umich.edu
6357205Sgblack@eecs.umich.edu            regs.config |= reg & ~(CFG_LNKSTS | CFG_SPDSTS | CFG_DUPSTS |
6367205Sgblack@eecs.umich.edu                                   CFG_RESERVED | CFG_T64ADDR | CFG_PCI64_DET);
6377205Sgblack@eecs.umich.edu
6387205Sgblack@eecs.umich.edu// all these #if 0's are because i don't THINK the kernel needs to
6397205Sgblack@eecs.umich.edu// have these implemented. if there is a problem relating to one of
6407205Sgblack@eecs.umich.edu// these, you may need to add functionality in.
6417279Sgblack@eecs.umich.edu#if 0
6427279Sgblack@eecs.umich.edu            if (reg & CFG_TBI_EN) ;
6437279Sgblack@eecs.umich.edu            if (reg & CFG_MODE_1000) ;
6447279Sgblack@eecs.umich.edu#endif
6457279Sgblack@eecs.umich.edu
6467279Sgblack@eecs.umich.edu            if (reg & CFG_AUTO_1000)
6477279Sgblack@eecs.umich.edu                panic("CFG_AUTO_1000 not implemented!\n");
6487279Sgblack@eecs.umich.edu
6497279Sgblack@eecs.umich.edu#if 0
6507279Sgblack@eecs.umich.edu            if (reg & CFG_PINT_DUPSTS ||
6517279Sgblack@eecs.umich.edu                reg & CFG_PINT_LNKSTS ||
6527279Sgblack@eecs.umich.edu                reg & CFG_PINT_SPDSTS)
6537279Sgblack@eecs.umich.edu                ;
6547279Sgblack@eecs.umich.edu
6557279Sgblack@eecs.umich.edu            if (reg & CFG_TMRTEST) ;
6567279Sgblack@eecs.umich.edu            if (reg & CFG_MRM_DIS) ;
6577279Sgblack@eecs.umich.edu            if (reg & CFG_MWI_DIS) ;
6587279Sgblack@eecs.umich.edu
6597279Sgblack@eecs.umich.edu            if (reg & CFG_T64ADDR)
6607279Sgblack@eecs.umich.edu                panic("CFG_T64ADDR is read only register!\n");
6617279Sgblack@eecs.umich.edu
6627303Sgblack@eecs.umich.edu            if (reg & CFG_PCI64_DET)
6637303Sgblack@eecs.umich.edu                panic("CFG_PCI64_DET is read only register!\n");
6647303Sgblack@eecs.umich.edu
6657303Sgblack@eecs.umich.edu            if (reg & CFG_DATA64_EN) ;
6667303Sgblack@eecs.umich.edu            if (reg & CFG_M64ADDR) ;
6677303Sgblack@eecs.umich.edu            if (reg & CFG_PHY_RST) ;
6687303Sgblack@eecs.umich.edu            if (reg & CFG_PHY_DIS) ;
6697303Sgblack@eecs.umich.edu#endif
6707303Sgblack@eecs.umich.edu
6717303Sgblack@eecs.umich.edu            if (reg & CFG_EXTSTS_EN)
6727303Sgblack@eecs.umich.edu                extstsEnable = true;
6737303Sgblack@eecs.umich.edu            else
6747303Sgblack@eecs.umich.edu                extstsEnable = false;
6757303Sgblack@eecs.umich.edu
6767303Sgblack@eecs.umich.edu#if 0
6777303Sgblack@eecs.umich.edu              if (reg & CFG_REQALG) ;
6787303Sgblack@eecs.umich.edu              if (reg & CFG_SB) ;
6797303Sgblack@eecs.umich.edu              if (reg & CFG_POW) ;
6807303Sgblack@eecs.umich.edu              if (reg & CFG_EXD) ;
6817303Sgblack@eecs.umich.edu              if (reg & CFG_PESEL) ;
6827303Sgblack@eecs.umich.edu              if (reg & CFG_BROM_DIS) ;
6837119Sgblack@eecs.umich.edu              if (reg & CFG_EXT_125) ;
6847119Sgblack@eecs.umich.edu              if (reg & CFG_BEM) ;
6857119Sgblack@eecs.umich.edu#endif
6867119Sgblack@eecs.umich.edu            break;
6877119Sgblack@eecs.umich.edu
6887119Sgblack@eecs.umich.edu          case MEAR:
6897119Sgblack@eecs.umich.edu            regs.mear = reg;
6907119Sgblack@eecs.umich.edu            // since phy is completely faked, MEAR_MD* don't matter
6917119Sgblack@eecs.umich.edu            // and since the driver never uses MEAR_EE*, they don't
6927119Sgblack@eecs.umich.edu            // matter
6937119Sgblack@eecs.umich.edu#if 0
6947119Sgblack@eecs.umich.edu            if (reg & MEAR_EEDI) ;
6957119Sgblack@eecs.umich.edu            if (reg & MEAR_EEDO) ; // this one is read only
6967119Sgblack@eecs.umich.edu            if (reg & MEAR_EECLK) ;
6977119Sgblack@eecs.umich.edu            if (reg & MEAR_EESEL) ;
6987119Sgblack@eecs.umich.edu            if (reg & MEAR_MDIO) ;
6997119Sgblack@eecs.umich.edu            if (reg & MEAR_MDDIR) ;
70010037SARM gem5 Developers            if (reg & MEAR_MDC) ;
70110037SARM gem5 Developers#endif
70210037SARM gem5 Developers            break;
70310037SARM gem5 Developers
70410037SARM gem5 Developers          case PTSCR:
7057119Sgblack@eecs.umich.edu            regs.ptscr = reg & ~(PTSCR_RBIST_RDONLY);
7067119Sgblack@eecs.umich.edu            // these control BISTs for various parts of chip - we
7077119Sgblack@eecs.umich.edu            // don't care or do just fake that the BIST is done
7087303Sgblack@eecs.umich.edu            if (reg & PTSCR_RBIST_EN)
7097303Sgblack@eecs.umich.edu                regs.ptscr |= PTSCR_RBIST_DONE;
7107303Sgblack@eecs.umich.edu            if (reg & PTSCR_EEBIST_EN)
7117303Sgblack@eecs.umich.edu                regs.ptscr &= ~PTSCR_EEBIST_EN;
7127303Sgblack@eecs.umich.edu            if (reg & PTSCR_EELOAD_EN)
7137303Sgblack@eecs.umich.edu                regs.ptscr &= ~PTSCR_EELOAD_EN;
7147303Sgblack@eecs.umich.edu            break;
7157303Sgblack@eecs.umich.edu
7167303Sgblack@eecs.umich.edu          case ISR: /* writing to the ISR has no effect */
7177303Sgblack@eecs.umich.edu            panic("ISR is a read only register!\n");
7187303Sgblack@eecs.umich.edu
7197303Sgblack@eecs.umich.edu          case IMR:
7207303Sgblack@eecs.umich.edu            regs.imr = reg;
7217303Sgblack@eecs.umich.edu            devIntrChangeMask();
7227303Sgblack@eecs.umich.edu            break;
7237303Sgblack@eecs.umich.edu
7247303Sgblack@eecs.umich.edu          case IER:
7257303Sgblack@eecs.umich.edu            regs.ier = reg;
7267303Sgblack@eecs.umich.edu            break;
7277303Sgblack@eecs.umich.edu
7287303Sgblack@eecs.umich.edu          case IHR:
7297646Sgene.wu@arm.com            regs.ihr = reg;
7307279Sgblack@eecs.umich.edu            /* not going to implement real interrupt holdoff */
7317279Sgblack@eecs.umich.edu            break;
7327279Sgblack@eecs.umich.edu
7337279Sgblack@eecs.umich.edu          case TXDP:
7347279Sgblack@eecs.umich.edu            regs.txdp = (reg & 0xFFFFFFFC);
7357279Sgblack@eecs.umich.edu            assert(txState == txIdle);
7367279Sgblack@eecs.umich.edu            CTDD = false;
7377279Sgblack@eecs.umich.edu            break;
7387279Sgblack@eecs.umich.edu
7397279Sgblack@eecs.umich.edu          case TXDP_HI:
7407279Sgblack@eecs.umich.edu            regs.txdp_hi = reg;
7417279Sgblack@eecs.umich.edu            break;
7427279Sgblack@eecs.umich.edu
7437279Sgblack@eecs.umich.edu          case TXCFG:
7447279Sgblack@eecs.umich.edu            regs.txcfg = reg;
7457279Sgblack@eecs.umich.edu#if 0
7467279Sgblack@eecs.umich.edu            if (reg & TXCFG_CSI) ;
7477279Sgblack@eecs.umich.edu            if (reg & TXCFG_HBI) ;
7487279Sgblack@eecs.umich.edu            if (reg & TXCFG_MLB) ;
7497279Sgblack@eecs.umich.edu            if (reg & TXCFG_ATP) ;
7507279Sgblack@eecs.umich.edu            if (reg & TXCFG_ECRETRY) {
7517279Sgblack@eecs.umich.edu                /*
7527646Sgene.wu@arm.com                 * this could easily be implemented, but considering
7537119Sgblack@eecs.umich.edu                 * the network is just a fake pipe, wouldn't make
7547119Sgblack@eecs.umich.edu                 * sense to do this
7557119Sgblack@eecs.umich.edu                 */
7567119Sgblack@eecs.umich.edu            }
7577119Sgblack@eecs.umich.edu
7587119Sgblack@eecs.umich.edu            if (reg & TXCFG_BRST_DIS) ;
7597119Sgblack@eecs.umich.edu#endif
7607119Sgblack@eecs.umich.edu
7617119Sgblack@eecs.umich.edu#if 0
7627119Sgblack@eecs.umich.edu            /* we handle our own DMA, ignore the kernel's exhortations */
7637119Sgblack@eecs.umich.edu            if (reg & TXCFG_MXDMA) ;
7647119Sgblack@eecs.umich.edu#endif
7657119Sgblack@eecs.umich.edu
7667119Sgblack@eecs.umich.edu            // also, we currently don't care about fill/drain
7677119Sgblack@eecs.umich.edu            // thresholds though this may change in the future with
7687119Sgblack@eecs.umich.edu            // more realistic networks or a driver which changes it
7697119Sgblack@eecs.umich.edu            // according to feedback
7707119Sgblack@eecs.umich.edu
77110037SARM gem5 Developers            break;
77210037SARM gem5 Developers
77310037SARM gem5 Developers          case GPIOR:
77410037SARM gem5 Developers            regs.gpior = reg;
77510037SARM gem5 Developers            /* these just control general purpose i/o pins, don't matter */
7767119Sgblack@eecs.umich.edu            break;
7777119Sgblack@eecs.umich.edu
7787119Sgblack@eecs.umich.edu          case RXDP:
7797646Sgene.wu@arm.com            regs.rxdp = reg;
7807646Sgene.wu@arm.com            CRDD = false;
7817646Sgene.wu@arm.com            break;
7827646Sgene.wu@arm.com
7837646Sgene.wu@arm.com          case RXDP_HI:
7847646Sgene.wu@arm.com            regs.rxdp_hi = reg;
7857646Sgene.wu@arm.com            break;
7867646Sgene.wu@arm.com
7877646Sgene.wu@arm.com          case RXCFG:
7887646Sgene.wu@arm.com            regs.rxcfg = reg;
7897646Sgene.wu@arm.com#if 0
7907646Sgene.wu@arm.com            if (reg & RXCFG_AEP) ;
7917646Sgene.wu@arm.com            if (reg & RXCFG_ARP) ;
7927646Sgene.wu@arm.com            if (reg & RXCFG_STRIPCRC) ;
7937646Sgene.wu@arm.com            if (reg & RXCFG_RX_RD) ;
7947646Sgene.wu@arm.com            if (reg & RXCFG_ALP) ;
7957646Sgene.wu@arm.com            if (reg & RXCFG_AIRL) ;
7967646Sgene.wu@arm.com
7977646Sgene.wu@arm.com            /* we handle our own DMA, ignore what kernel says about it */
7987646Sgene.wu@arm.com            if (reg & RXCFG_MXDMA) ;
7997646Sgene.wu@arm.com
8007646Sgene.wu@arm.com            //also, we currently don't care about fill/drain thresholds
8017646Sgene.wu@arm.com            //though this may change in the future with more realistic
8027646Sgene.wu@arm.com            //networks or a driver which changes it according to feedback
8037646Sgene.wu@arm.com            if (reg & (RXCFG_DRTH | RXCFG_DRTH0)) ;
8047646Sgene.wu@arm.com#endif
8057646Sgene.wu@arm.com            break;
8067646Sgene.wu@arm.com
8077646Sgene.wu@arm.com          case PQCR:
8087646Sgene.wu@arm.com            /* there is no priority queueing used in the linux 2.6 driver */
8097646Sgene.wu@arm.com            regs.pqcr = reg;
8107646Sgene.wu@arm.com            break;
8117646Sgene.wu@arm.com
8127646Sgene.wu@arm.com          case WCSR:
8137646Sgene.wu@arm.com            /* not going to implement wake on LAN */
8147646Sgene.wu@arm.com            regs.wcsr = reg;
8157646Sgene.wu@arm.com            break;
8167646Sgene.wu@arm.com
8177646Sgene.wu@arm.com          case PCR:
8187646Sgene.wu@arm.com            /* not going to implement pause control */
8197646Sgene.wu@arm.com            regs.pcr = reg;
8207646Sgene.wu@arm.com            break;
82110037SARM gem5 Developers
82210037SARM gem5 Developers          case RFCR:
82310037SARM gem5 Developers            regs.rfcr = reg;
82410037SARM gem5 Developers
82510037SARM gem5 Developers            rxFilterEnable = (reg & RFCR_RFEN) ? true : false;
8267646Sgene.wu@arm.com            acceptBroadcast = (reg & RFCR_AAB) ? true : false;
8277646Sgene.wu@arm.com            acceptMulticast = (reg & RFCR_AAM) ? true : false;
8287646Sgene.wu@arm.com            acceptUnicast = (reg & RFCR_AAU) ? true : false;
8297646Sgene.wu@arm.com            acceptPerfect = (reg & RFCR_APM) ? true : false;
8307646Sgene.wu@arm.com            acceptArp = (reg & RFCR_AARP) ? true : false;
8317646Sgene.wu@arm.com
8327646Sgene.wu@arm.com#if 0
8337646Sgene.wu@arm.com            if (reg & RFCR_APAT)
8347646Sgene.wu@arm.com                panic("RFCR_APAT not implemented!\n");
8357646Sgene.wu@arm.com#endif
8367646Sgene.wu@arm.com
8377646Sgene.wu@arm.com            if (reg & RFCR_MHEN || reg & RFCR_UHEN)
8387646Sgene.wu@arm.com                panic("hash filtering not implemented!\n");
8397646Sgene.wu@arm.com
8407646Sgene.wu@arm.com            if (reg & RFCR_ULM)
8417646Sgene.wu@arm.com                panic("RFCR_ULM not implemented!\n");
8427646Sgene.wu@arm.com
8437646Sgene.wu@arm.com            break;
8447646Sgene.wu@arm.com
8457646Sgene.wu@arm.com          case RFDR:
84610037SARM gem5 Developers            panic("the driver never writes to RFDR, something is wrong!\n");
84710037SARM gem5 Developers
84810037SARM gem5 Developers          case BRAR:
84910037SARM gem5 Developers            panic("the driver never uses BRAR, something is wrong!\n");
85010037SARM gem5 Developers
8517646Sgene.wu@arm.com          case BRDR:
8527646Sgene.wu@arm.com            panic("the driver never uses BRDR, something is wrong!\n");
8537646Sgene.wu@arm.com
8547119Sgblack@eecs.umich.edu          case SRR:
8557119Sgblack@eecs.umich.edu            panic("SRR is read only register!\n");
8567119Sgblack@eecs.umich.edu
8577119Sgblack@eecs.umich.edu          case MIBC:
8587119Sgblack@eecs.umich.edu            panic("the driver never uses MIBC, something is wrong!\n");
8597119Sgblack@eecs.umich.edu
8607119Sgblack@eecs.umich.edu          case VRCR:
8617119Sgblack@eecs.umich.edu            regs.vrcr = reg;
8627291Sgblack@eecs.umich.edu            break;
86310184SCurtis.Dunham@arm.com
8648140SMatt.Horsnell@arm.com          case VTCR:
8658140SMatt.Horsnell@arm.com            regs.vtcr = reg;
8668140SMatt.Horsnell@arm.com            break;
8677291Sgblack@eecs.umich.edu
8687291Sgblack@eecs.umich.edu          case VDR:
8697848SAli.Saidi@ARM.com            panic("the driver never uses VDR, something is wrong!\n");
8707848SAli.Saidi@ARM.com            break;
8717848SAli.Saidi@ARM.com
8727848SAli.Saidi@ARM.com          case CCSR:
8737848SAli.Saidi@ARM.com            /* not going to implement clockrun stuff */
8747646Sgene.wu@arm.com            regs.ccsr = reg;
8758140SMatt.Horsnell@arm.com            break;
8768140SMatt.Horsnell@arm.com
8778140SMatt.Horsnell@arm.com          case TBICR:
8788140SMatt.Horsnell@arm.com            regs.tbicr = reg;
8798140SMatt.Horsnell@arm.com            if (reg & TBICR_MR_LOOPBACK)
8808140SMatt.Horsnell@arm.com                panic("TBICR_MR_LOOPBACK never used, something wrong!\n");
8818140SMatt.Horsnell@arm.com
8828140SMatt.Horsnell@arm.com            if (reg & TBICR_MR_AN_ENABLE) {
8838140SMatt.Horsnell@arm.com                regs.tanlpar = regs.tanar;
8848140SMatt.Horsnell@arm.com                regs.tbisr |= (TBISR_MR_AN_COMPLETE | TBISR_MR_LINK_STATUS);
8858140SMatt.Horsnell@arm.com            }
8868140SMatt.Horsnell@arm.com
8877646Sgene.wu@arm.com#if 0
8887291Sgblack@eecs.umich.edu            if (reg & TBICR_MR_RESTART_AN) ;
8897291Sgblack@eecs.umich.edu#endif
8907291Sgblack@eecs.umich.edu
8917312Sgblack@eecs.umich.edu            break;
89210184SCurtis.Dunham@arm.com
8937312Sgblack@eecs.umich.edu          case TBISR:
8947312Sgblack@eecs.umich.edu            panic("TBISR is read only register!\n");
8957312Sgblack@eecs.umich.edu
8967312Sgblack@eecs.umich.edu          case TANAR:
8977312Sgblack@eecs.umich.edu            regs.tanar = reg;
8987848SAli.Saidi@ARM.com            if (reg & TANAR_PS2)
8997848SAli.Saidi@ARM.com                panic("this isn't used in driver, something wrong!\n");
9007848SAli.Saidi@ARM.com
9017848SAli.Saidi@ARM.com            if (reg & TANAR_PS1)
9027848SAli.Saidi@ARM.com                panic("this isn't used in driver, something wrong!\n");
9037646Sgene.wu@arm.com            break;
9047646Sgene.wu@arm.com
9057646Sgene.wu@arm.com          case TANLPAR:
9067646Sgene.wu@arm.com            panic("this should only be written to by the fake phy!\n");
9077724SAli.Saidi@ARM.com
9087646Sgene.wu@arm.com          case TANER:
9097646Sgene.wu@arm.com            panic("TANER is read only register!\n");
9107646Sgene.wu@arm.com
9117312Sgblack@eecs.umich.edu          case TESR:
9127312Sgblack@eecs.umich.edu            regs.tesr = reg;
9137312Sgblack@eecs.umich.edu            break;
9147205Sgblack@eecs.umich.edu
91510184SCurtis.Dunham@arm.com          default:
9167205Sgblack@eecs.umich.edu            panic("invalid register access daddr=%#x", daddr);
9177205Sgblack@eecs.umich.edu        }
9187205Sgblack@eecs.umich.edu    } else {
9197205Sgblack@eecs.umich.edu        panic("Invalid Request Size");
9207205Sgblack@eecs.umich.edu    }
9217848SAli.Saidi@ARM.com
9227848SAli.Saidi@ARM.com    return No_Fault;
9237848SAli.Saidi@ARM.com}
9247848SAli.Saidi@ARM.com
9257848SAli.Saidi@ARM.comvoid
9267205Sgblack@eecs.umich.eduNSGigE::devIntrPost(uint32_t interrupts)
9277205Sgblack@eecs.umich.edu{
9287205Sgblack@eecs.umich.edu    if (interrupts & ISR_RESERVE)
9297279Sgblack@eecs.umich.edu        panic("Cannot set a reserved interrupt");
93010184SCurtis.Dunham@arm.com
9317279Sgblack@eecs.umich.edu    if (interrupts & ISR_NOIMPL)
9327279Sgblack@eecs.umich.edu        warn("interrupt not implemented %#x\n", interrupts);
9337279Sgblack@eecs.umich.edu
9347279Sgblack@eecs.umich.edu    interrupts &= ~ISR_NOIMPL;
9357279Sgblack@eecs.umich.edu    regs.isr |= interrupts;
9367279Sgblack@eecs.umich.edu
9377279Sgblack@eecs.umich.edu    DPRINTF(EthernetIntr,
9387848SAli.Saidi@ARM.com            "interrupt written to ISR: intr=%#x isr=%#x imr=%#x\n",
9397848SAli.Saidi@ARM.com            interrupts, regs.isr, regs.imr);
9407848SAli.Saidi@ARM.com
9417848SAli.Saidi@ARM.com    if ((regs.isr & regs.imr)) {
9427848SAli.Saidi@ARM.com        Tick when = curTick;
9437646Sgene.wu@arm.com        if (!(regs.isr & regs.imr & ISR_NODELAY))
9447646Sgene.wu@arm.com            when += intrDelay;
9457646Sgene.wu@arm.com        cpuIntrPost(when);
9467646Sgene.wu@arm.com    }
9477724SAli.Saidi@ARM.com}
9487646Sgene.wu@arm.com
9497646Sgene.wu@arm.comvoid
9507646Sgene.wu@arm.comNSGigE::devIntrClear(uint32_t interrupts)
9517279Sgblack@eecs.umich.edu{
9527279Sgblack@eecs.umich.edu    if (interrupts & ISR_RESERVE)
9537279Sgblack@eecs.umich.edu        panic("Cannot clear a reserved interrupt");
9547303Sgblack@eecs.umich.edu
95510184SCurtis.Dunham@arm.com    interrupts &= ~ISR_NOIMPL;
9567303Sgblack@eecs.umich.edu    regs.isr &= ~interrupts;
9577303Sgblack@eecs.umich.edu
9587303Sgblack@eecs.umich.edu    DPRINTF(EthernetIntr,
9597303Sgblack@eecs.umich.edu            "interrupt cleared from ISR: intr=%x isr=%x imr=%x\n",
9607303Sgblack@eecs.umich.edu            interrupts, regs.isr, regs.imr);
9617303Sgblack@eecs.umich.edu
9627303Sgblack@eecs.umich.edu    if (!(regs.isr & regs.imr))
9637303Sgblack@eecs.umich.edu        cpuIntrClear();
9647848SAli.Saidi@ARM.com}
9657848SAli.Saidi@ARM.com
9667848SAli.Saidi@ARM.comvoid
9677848SAli.Saidi@ARM.comNSGigE::devIntrChangeMask()
9687848SAli.Saidi@ARM.com{
9697646Sgene.wu@arm.com    DPRINTF(EthernetIntr, "interrupt mask changed: isr=%x imr=%x masked=%x\n",
9707646Sgene.wu@arm.com            regs.isr, regs.imr, regs.isr & regs.imr);
9717646Sgene.wu@arm.com
9727646Sgene.wu@arm.com    if (regs.isr & regs.imr)
9737646Sgene.wu@arm.com        cpuIntrPost(curTick);
9747724SAli.Saidi@ARM.com    else
9757646Sgene.wu@arm.com        cpuIntrClear();
9767646Sgene.wu@arm.com}
9777646Sgene.wu@arm.com
9787303Sgblack@eecs.umich.eduvoid
9797303Sgblack@eecs.umich.eduNSGigE::cpuIntrPost(Tick when)
9807303Sgblack@eecs.umich.edu{
9817119Sgblack@eecs.umich.edu    // If the interrupt you want to post is later than an interrupt
98210184SCurtis.Dunham@arm.com    // already scheduled, just let it post in the coming one and don't
9837119Sgblack@eecs.umich.edu    // schedule another.
9847119Sgblack@eecs.umich.edu    // HOWEVER, must be sure that the scheduled intrTick is in the
9857119Sgblack@eecs.umich.edu    // future (this was formerly the source of a bug)
9867119Sgblack@eecs.umich.edu    /**
9877119Sgblack@eecs.umich.edu     * @todo this warning should be removed and the intrTick code should
9887848SAli.Saidi@ARM.com     * be fixed.
9897848SAli.Saidi@ARM.com     */
9907848SAli.Saidi@ARM.com    if (intrTick < curTick && intrTick != 0) {
9917848SAli.Saidi@ARM.com        warn("intrTick < curTick !!!  intrTick=%d curTick=%d\n",
9927848SAli.Saidi@ARM.com             intrTick, curTick);
9937646Sgene.wu@arm.com        intrTick = 0;
9947646Sgene.wu@arm.com    }
9957646Sgene.wu@arm.com    assert((intrTick >= curTick) || (intrTick == 0));
9967646Sgene.wu@arm.com    if (when > intrTick && intrTick != 0)
9977724SAli.Saidi@ARM.com        return;
9987646Sgene.wu@arm.com
9997646Sgene.wu@arm.com    intrTick = when;
10007646Sgene.wu@arm.com
10017119Sgblack@eecs.umich.edu    if (intrEvent) {
10027119Sgblack@eecs.umich.edu        intrEvent->squash();
10037119Sgblack@eecs.umich.edu        intrEvent = 0;
10047303Sgblack@eecs.umich.edu    }
100510184SCurtis.Dunham@arm.com
10067303Sgblack@eecs.umich.edu    if (when < curTick) {
10077303Sgblack@eecs.umich.edu        cpuInterrupt();
10087303Sgblack@eecs.umich.edu    } else {
10097303Sgblack@eecs.umich.edu        DPRINTF(EthernetIntr,
10107303Sgblack@eecs.umich.edu                "going to schedule an interrupt for intrTick=%d\n",
10117303Sgblack@eecs.umich.edu                intrTick);
10127303Sgblack@eecs.umich.edu        intrEvent = new IntrEvent(this, true);
10137848SAli.Saidi@ARM.com        intrEvent->schedule(intrTick);
10147848SAli.Saidi@ARM.com    }
10157848SAli.Saidi@ARM.com}
10167848SAli.Saidi@ARM.com
10177848SAli.Saidi@ARM.comvoid
10187646Sgene.wu@arm.comNSGigE::cpuInterrupt()
10197646Sgene.wu@arm.com{
10207646Sgene.wu@arm.com    // Don't send an interrupt if there's already one
10217646Sgene.wu@arm.com    if (cpuPendingIntr) {
10227646Sgene.wu@arm.com        DPRINTF(EthernetIntr,
10237724SAli.Saidi@ARM.com                "would send an interrupt now, but there's already pending\n");
10247646Sgene.wu@arm.com        intrTick = 0;
10257646Sgene.wu@arm.com        return;
10267646Sgene.wu@arm.com    }
10277303Sgblack@eecs.umich.edu    // Don't send an interrupt if it's supposed to be delayed
10287303Sgblack@eecs.umich.edu    if (intrTick > curTick) {
10297303Sgblack@eecs.umich.edu        DPRINTF(EthernetIntr,
10307646Sgene.wu@arm.com                "an interrupt is scheduled for %d, wait til then\n",
103110184SCurtis.Dunham@arm.com                intrTick);
10327279Sgblack@eecs.umich.edu        return;
10337279Sgblack@eecs.umich.edu    }
10347279Sgblack@eecs.umich.edu
10357279Sgblack@eecs.umich.edu    // Whether or not there's a pending interrupt, we don't care about
10367279Sgblack@eecs.umich.edu    // it anymore
10377279Sgblack@eecs.umich.edu    intrEvent = 0;
10387279Sgblack@eecs.umich.edu    intrTick = 0;
10397279Sgblack@eecs.umich.edu
10407279Sgblack@eecs.umich.edu    // Send interrupt
10417848SAli.Saidi@ARM.com    cpuPendingIntr = true;
10427848SAli.Saidi@ARM.com
10437848SAli.Saidi@ARM.com    DPRINTF(EthernetIntr, "posting cchip interrupt\n");
10447848SAli.Saidi@ARM.com    tsunami->cchip->postDRIR(configData->config.hdr.pci0.interruptLine);
10457848SAli.Saidi@ARM.com}
10467646Sgene.wu@arm.com
10477646Sgene.wu@arm.comvoid
10487646Sgene.wu@arm.comNSGigE::cpuIntrClear()
10497646Sgene.wu@arm.com{
10507646Sgene.wu@arm.com    if (!cpuPendingIntr)
10517724SAli.Saidi@ARM.com        return;
10527646Sgene.wu@arm.com
10537646Sgene.wu@arm.com    cpuPendingIntr = false;
10547646Sgene.wu@arm.com
10557279Sgblack@eecs.umich.edu    DPRINTF(EthernetIntr, "clearing cchip interrupt\n");
10567279Sgblack@eecs.umich.edu    tsunami->cchip->clearDRIR(configData->config.hdr.pci0.interruptLine);
10577279Sgblack@eecs.umich.edu}
10587646Sgene.wu@arm.com
105910184SCurtis.Dunham@arm.combool
10607119Sgblack@eecs.umich.eduNSGigE::cpuIntrPending() const
10617119Sgblack@eecs.umich.edu{ return cpuPendingIntr; }
10627119Sgblack@eecs.umich.edu
10637119Sgblack@eecs.umich.eduvoid
10647119Sgblack@eecs.umich.eduNSGigE::txReset()
10657119Sgblack@eecs.umich.edu{
10667119Sgblack@eecs.umich.edu
10677119Sgblack@eecs.umich.edu    DPRINTF(Ethernet, "transmit reset\n");
10687848SAli.Saidi@ARM.com
10697848SAli.Saidi@ARM.com    CTDD = false;
10707848SAli.Saidi@ARM.com    txFifoAvail = maxTxFifoSize;
10717848SAli.Saidi@ARM.com    txEnable = false;;
10727848SAli.Saidi@ARM.com    txFragPtr = 0;
10737646Sgene.wu@arm.com    assert(txDescCnt == 0);
10747646Sgene.wu@arm.com    txFifo.clear();
10757646Sgene.wu@arm.com    txState = txIdle;
10767646Sgene.wu@arm.com    assert(txDmaState == dmaIdle);
10777646Sgene.wu@arm.com}
10787724SAli.Saidi@ARM.com
10797646Sgene.wu@arm.comvoid
10807646Sgene.wu@arm.comNSGigE::rxReset()
10817646Sgene.wu@arm.com{
10827119Sgblack@eecs.umich.edu    DPRINTF(Ethernet, "receive reset\n");
10837119Sgblack@eecs.umich.edu
10847646Sgene.wu@arm.com    CRDD = false;
10857646Sgene.wu@arm.com    assert(rxPktBytes == 0);
108610184SCurtis.Dunham@arm.com    rxFifoCnt = 0;
10877646Sgene.wu@arm.com    rxEnable = false;
10887646Sgene.wu@arm.com    rxFragPtr = 0;
10897646Sgene.wu@arm.com    assert(rxDescCnt == 0);
10907646Sgene.wu@arm.com    assert(rxDmaState == dmaIdle);
10917646Sgene.wu@arm.com    rxFifo.clear();
10927646Sgene.wu@arm.com    rxState = rxIdle;
10937646Sgene.wu@arm.com}
10947646Sgene.wu@arm.com
10957646Sgene.wu@arm.comvoid
10967848SAli.Saidi@ARM.comNSGigE::regsReset()
10977848SAli.Saidi@ARM.com{
10987848SAli.Saidi@ARM.com    memset(&regs, 0, sizeof(regs));
10997848SAli.Saidi@ARM.com    regs.config = CFG_LNKSTS;
11007848SAli.Saidi@ARM.com    regs.mear = MEAR_MDDIR | MEAR_EEDO;
11017646Sgene.wu@arm.com    regs.txcfg = 0x120; // set drain threshold to 1024 bytes and
11027646Sgene.wu@arm.com                        // fill threshold to 32 bytes
11037646Sgene.wu@arm.com    regs.rxcfg = 0x4;   // set drain threshold to 16 bytes
11047646Sgene.wu@arm.com    regs.srr = 0x0103;  // set the silicon revision to rev B or 0x103
11057646Sgene.wu@arm.com    regs.mibc = MIBC_FRZ;
11067646Sgene.wu@arm.com    regs.vdr = 0x81;    // set the vlan tag type to 802.1q
11077724SAli.Saidi@ARM.com    regs.tesr = 0xc000; // TBI capable of both full and half duplex
11087646Sgene.wu@arm.com
11097646Sgene.wu@arm.com    extstsEnable = false;
11107724SAli.Saidi@ARM.com    acceptBroadcast = false;
11117646Sgene.wu@arm.com    acceptMulticast = false;
11127646Sgene.wu@arm.com    acceptUnicast = false;
11137646Sgene.wu@arm.com    acceptPerfect = false;
11147646Sgene.wu@arm.com    acceptArp = false;
11157646Sgene.wu@arm.com}
11167646Sgene.wu@arm.com
11177724SAli.Saidi@ARM.comvoid
11187646Sgene.wu@arm.comNSGigE::rxDmaReadCopy()
11197646Sgene.wu@arm.com{
11207646Sgene.wu@arm.com    assert(rxDmaState == dmaReading);
11217646Sgene.wu@arm.com
11227646Sgene.wu@arm.com    physmem->dma_read((uint8_t *)rxDmaData, rxDmaAddr, rxDmaLen);
11237646Sgene.wu@arm.com    rxDmaState = dmaIdle;
11247646Sgene.wu@arm.com
11257646Sgene.wu@arm.com    DPRINTF(EthernetDMA, "rx dma read  paddr=%#x len=%d\n",
112610184SCurtis.Dunham@arm.com            rxDmaAddr, rxDmaLen);
11277646Sgene.wu@arm.com    DDUMP(EthernetDMA, rxDmaData, rxDmaLen);
11287646Sgene.wu@arm.com}
11297646Sgene.wu@arm.com
11307646Sgene.wu@arm.combool
11317646Sgene.wu@arm.comNSGigE::doRxDmaRead()
11327646Sgene.wu@arm.com{
11337646Sgene.wu@arm.com    assert(rxDmaState == dmaIdle || rxDmaState == dmaReadWaiting);
11347646Sgene.wu@arm.com    rxDmaState = dmaReading;
11358607Sgblack@eecs.umich.edu
11367848SAli.Saidi@ARM.com    if (dmaInterface && !rxDmaFree) {
11378203SAli.Saidi@ARM.com        if (dmaInterface->busy())
11387848SAli.Saidi@ARM.com            rxDmaState = dmaReadWaiting;
11397848SAli.Saidi@ARM.com        else
11407848SAli.Saidi@ARM.com            dmaInterface->doDMA(Read, rxDmaAddr, rxDmaLen, curTick,
11417848SAli.Saidi@ARM.com                                &rxDmaReadEvent, true);
11427646Sgene.wu@arm.com        return true;
11437646Sgene.wu@arm.com    }
11447646Sgene.wu@arm.com
11459573Ssaidi@eecs.umich.edu    if (dmaReadDelay == 0 && dmaReadFactor == 0) {
11467646Sgene.wu@arm.com        rxDmaReadCopy();
11477646Sgene.wu@arm.com        return false;
11487646Sgene.wu@arm.com    }
11497724SAli.Saidi@ARM.com
11507646Sgene.wu@arm.com    Tick factor = ((rxDmaLen + ULL(63)) >> ULL(6)) * dmaReadFactor;
11517724SAli.Saidi@ARM.com    Tick start = curTick + dmaReadDelay + factor;
11527646Sgene.wu@arm.com    rxDmaReadEvent.schedule(start);
11538203SAli.Saidi@ARM.com    return true;
11548203SAli.Saidi@ARM.com}
11558203SAli.Saidi@ARM.com
11568203SAli.Saidi@ARM.comvoid
11578203SAli.Saidi@ARM.comNSGigE::rxDmaReadDone()
11588203SAli.Saidi@ARM.com{
11597646Sgene.wu@arm.com    assert(rxDmaState == dmaReading);
11607646Sgene.wu@arm.com    rxDmaReadCopy();
11617646Sgene.wu@arm.com
11627646Sgene.wu@arm.com    // If the transmit state machine has a pending DMA, let it go first
11637724SAli.Saidi@ARM.com    if (txDmaState == dmaReadWaiting || txDmaState == dmaWriteWaiting)
11647646Sgene.wu@arm.com        txKick();
11657646Sgene.wu@arm.com
11667724SAli.Saidi@ARM.com    rxKick();
11677646Sgene.wu@arm.com}
11687646Sgene.wu@arm.com
11697646Sgene.wu@arm.comvoid
11707646Sgene.wu@arm.comNSGigE::rxDmaWriteCopy()
11717646Sgene.wu@arm.com{
11727646Sgene.wu@arm.com    assert(rxDmaState == dmaWriting);
11737724SAli.Saidi@ARM.com
11747646Sgene.wu@arm.com    physmem->dma_write(rxDmaAddr, (uint8_t *)rxDmaData, rxDmaLen);
11757646Sgene.wu@arm.com    rxDmaState = dmaIdle;
11767646Sgene.wu@arm.com
11777646Sgene.wu@arm.com    DPRINTF(EthernetDMA, "rx dma write paddr=%#x len=%d\n",
11789250SAli.Saidi@ARM.com            rxDmaAddr, rxDmaLen);
11799573Ssaidi@eecs.umich.edu    DDUMP(EthernetDMA, rxDmaData, rxDmaLen);
11809250SAli.Saidi@ARM.com}
11819250SAli.Saidi@ARM.com
11829250SAli.Saidi@ARM.combool
11839250SAli.Saidi@ARM.comNSGigE::doRxDmaWrite()
11849250SAli.Saidi@ARM.com{
11859250SAli.Saidi@ARM.com    assert(rxDmaState == dmaIdle || rxDmaState == dmaWriteWaiting);
11869250SAli.Saidi@ARM.com    rxDmaState = dmaWriting;
11877646Sgene.wu@arm.com
11887646Sgene.wu@arm.com    if (dmaInterface && !rxDmaFree) {
11897646Sgene.wu@arm.com        if (dmaInterface->busy())
11907646Sgene.wu@arm.com            rxDmaState = dmaWriteWaiting;
11917646Sgene.wu@arm.com        else
119210184SCurtis.Dunham@arm.com            dmaInterface->doDMA(WriteInvalidate, rxDmaAddr, rxDmaLen, curTick,
11937646Sgene.wu@arm.com                                &rxDmaWriteEvent, true);
11947646Sgene.wu@arm.com        return true;
11957646Sgene.wu@arm.com    }
11967646Sgene.wu@arm.com
11977646Sgene.wu@arm.com    if (dmaWriteDelay == 0 && dmaWriteFactor == 0) {
11988607Sgblack@eecs.umich.edu        rxDmaWriteCopy();
11997848SAli.Saidi@ARM.com        return false;
12008203SAli.Saidi@ARM.com    }
12017848SAli.Saidi@ARM.com
12027848SAli.Saidi@ARM.com    Tick factor = ((rxDmaLen + ULL(63)) >> ULL(6)) * dmaWriteFactor;
12037848SAli.Saidi@ARM.com    Tick start = curTick + dmaWriteDelay + factor;
12047848SAli.Saidi@ARM.com    rxDmaWriteEvent.schedule(start);
12057646Sgene.wu@arm.com    return true;
12067646Sgene.wu@arm.com}
12077646Sgene.wu@arm.com
12089573Ssaidi@eecs.umich.eduvoid
12097646Sgene.wu@arm.comNSGigE::rxDmaWriteDone()
12107646Sgene.wu@arm.com{
12117724SAli.Saidi@ARM.com    assert(rxDmaState == dmaWriting);
12127646Sgene.wu@arm.com    rxDmaWriteCopy();
12137724SAli.Saidi@ARM.com
12147646Sgene.wu@arm.com    // If the transmit state machine has a pending DMA, let it go first
12158203SAli.Saidi@ARM.com    if (txDmaState == dmaReadWaiting || txDmaState == dmaWriteWaiting)
12168203SAli.Saidi@ARM.com        txKick();
121710199SAndrew.Bardsley@arm.com
121810199SAndrew.Bardsley@arm.com    rxKick();
121910199SAndrew.Bardsley@arm.com}
122010199SAndrew.Bardsley@arm.com
122110199SAndrew.Bardsley@arm.comvoid
12228203SAli.Saidi@ARM.comNSGigE::rxKick()
122310199SAndrew.Bardsley@arm.com{
122410199SAndrew.Bardsley@arm.com    DPRINTF(EthernetSM, "receive kick rxState=%s (rxBuf.size=%d)\n",
12258203SAli.Saidi@ARM.com            NsRxStateStrings[rxState], rxFifo.size());
122610199SAndrew.Bardsley@arm.com
122710199SAndrew.Bardsley@arm.com    if (rxKickTick > curTick) {
122810199SAndrew.Bardsley@arm.com        DPRINTF(EthernetSM, "receive kick exiting, can't run till %d\n",
12298203SAli.Saidi@ARM.com                rxKickTick);
123010199SAndrew.Bardsley@arm.com        return;
123110199SAndrew.Bardsley@arm.com    }
12327646Sgene.wu@arm.com
12337646Sgene.wu@arm.com  next:
12347646Sgene.wu@arm.com    switch(rxDmaState) {
12357724SAli.Saidi@ARM.com      case dmaReadWaiting:
12367646Sgene.wu@arm.com        if (doRxDmaRead())
12377646Sgene.wu@arm.com            goto exit;
12387646Sgene.wu@arm.com        break;
12399250SAli.Saidi@ARM.com      case dmaWriteWaiting:
12409573Ssaidi@eecs.umich.edu        if (doRxDmaWrite())
12419250SAli.Saidi@ARM.com            goto exit;
12429250SAli.Saidi@ARM.com        break;
12439250SAli.Saidi@ARM.com      default:
12449250SAli.Saidi@ARM.com        break;
12459250SAli.Saidi@ARM.com    }
12469250SAli.Saidi@ARM.com
12479250SAli.Saidi@ARM.com    // see state machine from spec for details
12487646Sgene.wu@arm.com    // the way this works is, if you finish work on one state and can
12497646Sgene.wu@arm.com    // go directly to another, you do that through jumping to the
12507646Sgene.wu@arm.com    // label "next".  however, if you have intermediate work, like DMA
12517646Sgene.wu@arm.com    // so that you can't go to the next state yet, you go to exit and
1252    // exit the loop.  however, when the DMA is done it will trigger
1253    // an event and come back to this loop.
1254    switch (rxState) {
1255      case rxIdle:
1256        if (!rxEnable) {
1257            DPRINTF(EthernetSM, "Receive Disabled! Nothing to do.\n");
1258            goto exit;
1259        }
1260
1261        if (CRDD) {
1262            rxState = rxDescRefr;
1263
1264            rxDmaAddr = regs.rxdp & 0x3fffffff;
1265            rxDmaData = &rxDescCache + offsetof(ns_desc, link);
1266            rxDmaLen = sizeof(rxDescCache.link);
1267            rxDmaFree = dmaDescFree;
1268
1269            descDmaReads++;
1270            descDmaRdBytes += rxDmaLen;
1271
1272            if (doRxDmaRead())
1273                goto exit;
1274        } else {
1275            rxState = rxDescRead;
1276
1277            rxDmaAddr = regs.rxdp & 0x3fffffff;
1278            rxDmaData = &rxDescCache;
1279            rxDmaLen = sizeof(ns_desc);
1280            rxDmaFree = dmaDescFree;
1281
1282            descDmaReads++;
1283            descDmaRdBytes += rxDmaLen;
1284
1285            if (doRxDmaRead())
1286                goto exit;
1287        }
1288        break;
1289
1290      case rxDescRefr:
1291        if (rxDmaState != dmaIdle)
1292            goto exit;
1293
1294        rxState = rxAdvance;
1295        break;
1296
1297     case rxDescRead:
1298        if (rxDmaState != dmaIdle)
1299            goto exit;
1300
1301        DPRINTF(EthernetDesc,
1302                "rxDescCache: addr=%08x read descriptor\n",
1303                regs.rxdp & 0x3fffffff);
1304        DPRINTF(EthernetDesc,
1305                "rxDescCache: link=%08x bufptr=%08x cmdsts=%08x extsts=%08x\n",
1306                rxDescCache.link, rxDescCache.bufptr, rxDescCache.cmdsts,
1307                rxDescCache.extsts);
1308
1309        if (rxDescCache.cmdsts & CMDSTS_OWN) {
1310            devIntrPost(ISR_RXIDLE);
1311            rxState = rxIdle;
1312            goto exit;
1313        } else {
1314            rxState = rxFifoBlock;
1315            rxFragPtr = rxDescCache.bufptr;
1316            rxDescCnt = rxDescCache.cmdsts & CMDSTS_LEN_MASK;
1317        }
1318        break;
1319
1320      case rxFifoBlock:
1321        if (!rxPacket) {
1322            /**
1323             * @todo in reality, we should be able to start processing
1324             * the packet as it arrives, and not have to wait for the
1325             * full packet ot be in the receive fifo.
1326             */
1327            if (rxFifo.empty())
1328                goto exit;
1329
1330            DPRINTF(EthernetSM, "****processing receive of new packet****\n");
1331
1332            // If we don't have a packet, grab a new one from the fifo.
1333            rxPacket = rxFifo.front();
1334            rxPktBytes = rxPacket->length;
1335            rxPacketBufPtr = rxPacket->data;
1336
1337#if TRACING_ON
1338            if (DTRACE(Ethernet)) {
1339                if (rxPacket->isIpPkt()) {
1340                    ip_header *ip = rxPacket->getIpHdr();
1341                    DPRINTF(Ethernet, "ID is %d\n", reverseEnd16(ip->ID));
1342                    if (rxPacket->isTcpPkt()) {
1343                        tcp_header *tcp = rxPacket->getTcpHdr(ip);
1344                        DPRINTF(Ethernet, "Src Port=%d, Dest Port=%d\n",
1345                                reverseEnd16(tcp->src_port_num),
1346                                reverseEnd16(tcp->dest_port_num));
1347                    }
1348                }
1349            }
1350#endif
1351
1352            // sanity check - i think the driver behaves like this
1353            assert(rxDescCnt >= rxPktBytes);
1354
1355            // Must clear the value before popping to decrement the
1356            // reference count
1357            rxFifo.front() = NULL;
1358            rxFifo.pop_front();
1359            rxFifoCnt -= rxPacket->length;
1360        }
1361
1362
1363        // dont' need the && rxDescCnt > 0 if driver sanity check
1364        // above holds
1365        if (rxPktBytes > 0) {
1366            rxState = rxFragWrite;
1367            // don't need min<>(rxPktBytes,rxDescCnt) if above sanity
1368            // check holds
1369            rxXferLen = rxPktBytes;
1370
1371            rxDmaAddr = rxFragPtr & 0x3fffffff;
1372            rxDmaData = rxPacketBufPtr;
1373            rxDmaLen = rxXferLen;
1374            rxDmaFree = dmaDataFree;
1375
1376            if (doRxDmaWrite())
1377                goto exit;
1378
1379        } else {
1380            rxState = rxDescWrite;
1381
1382            //if (rxPktBytes == 0) {  /* packet is done */
1383            assert(rxPktBytes == 0);
1384            DPRINTF(EthernetSM, "done with receiving packet\n");
1385
1386            rxDescCache.cmdsts |= CMDSTS_OWN;
1387            rxDescCache.cmdsts &= ~CMDSTS_MORE;
1388            rxDescCache.cmdsts |= CMDSTS_OK;
1389            rxDescCache.cmdsts &= 0xffff0000;
1390            rxDescCache.cmdsts += rxPacket->length;   //i.e. set CMDSTS_SIZE
1391
1392#if 0
1393            /*
1394             * all the driver uses these are for its own stats keeping
1395             * which we don't care about, aren't necessary for
1396             * functionality and doing this would just slow us down.
1397             * if they end up using this in a later version for
1398             * functional purposes, just undef
1399             */
1400            if (rxFilterEnable) {
1401                rxDescCache.cmdsts &= ~CMDSTS_DEST_MASK;
1402                if (rxFifo.front()->IsUnicast())
1403                    rxDescCache.cmdsts |= CMDSTS_DEST_SELF;
1404                if (rxFifo.front()->IsMulticast())
1405                    rxDescCache.cmdsts |= CMDSTS_DEST_MULTI;
1406                if (rxFifo.front()->IsBroadcast())
1407                    rxDescCache.cmdsts |= CMDSTS_DEST_MASK;
1408            }
1409#endif
1410
1411            if (rxPacket->isIpPkt() && extstsEnable) {
1412                rxDescCache.extsts |= EXTSTS_IPPKT;
1413                rxIPChecksums++;
1414                if (!ipChecksum(rxPacket, false)) {
1415                    DPRINTF(EthernetCksum, "Rx IP Checksum Error\n");
1416                    rxDescCache.extsts |= EXTSTS_IPERR;
1417                }
1418                if (rxPacket->isTcpPkt()) {
1419                    rxDescCache.extsts |= EXTSTS_TCPPKT;
1420                    rxTCPChecksums++;
1421                    if (!tcpChecksum(rxPacket, false)) {
1422                        DPRINTF(EthernetCksum, "Rx TCP Checksum Error\n");
1423                        rxDescCache.extsts |= EXTSTS_TCPERR;
1424
1425                    }
1426                } else if (rxPacket->isUdpPkt()) {
1427                    rxDescCache.extsts |= EXTSTS_UDPPKT;
1428                    if (!udpChecksum(rxPacket, false)) {
1429                        DPRINTF(EthernetCksum, "Rx UDP Checksum Error\n");
1430                        rxDescCache.extsts |= EXTSTS_UDPERR;
1431                    }
1432                }
1433            }
1434            rxPacket = 0;
1435
1436            /*
1437             * the driver seems to always receive into desc buffers
1438             * of size 1514, so you never have a pkt that is split
1439             * into multiple descriptors on the receive side, so
1440             * i don't implement that case, hence the assert above.
1441             */
1442
1443            DPRINTF(EthernetDesc,
1444                    "rxDescCache: addr=%08x writeback cmdsts extsts\n",
1445                    regs.rxdp & 0x3fffffff);
1446            DPRINTF(EthernetDesc,
1447                    "rxDescCache: link=%08x bufptr=%08x cmdsts=%08x extsts=%08x\n",
1448                    rxDescCache.link, rxDescCache.bufptr, rxDescCache.cmdsts,
1449                    rxDescCache.extsts);
1450
1451            rxDmaAddr = (regs.rxdp + offsetof(ns_desc, cmdsts)) & 0x3fffffff;
1452            rxDmaData = &(rxDescCache.cmdsts);
1453            rxDmaLen = sizeof(rxDescCache.cmdsts) + sizeof(rxDescCache.extsts);
1454            rxDmaFree = dmaDescFree;
1455
1456            descDmaWrites++;
1457            descDmaWrBytes += rxDmaLen;
1458
1459            if (doRxDmaWrite())
1460                goto exit;
1461        }
1462        break;
1463
1464      case rxFragWrite:
1465        if (rxDmaState != dmaIdle)
1466            goto exit;
1467
1468        rxPacketBufPtr += rxXferLen;
1469        rxFragPtr += rxXferLen;
1470        rxPktBytes -= rxXferLen;
1471
1472        rxState = rxFifoBlock;
1473        break;
1474
1475      case rxDescWrite:
1476        if (rxDmaState != dmaIdle)
1477            goto exit;
1478
1479        assert(rxDescCache.cmdsts & CMDSTS_OWN);
1480
1481        assert(rxPacket == 0);
1482        devIntrPost(ISR_RXOK);
1483
1484        if (rxDescCache.cmdsts & CMDSTS_INTR)
1485            devIntrPost(ISR_RXDESC);
1486
1487        if (!rxEnable) {
1488            DPRINTF(EthernetSM, "Halting the RX state machine\n");
1489            rxState = rxIdle;
1490            goto exit;
1491        } else
1492            rxState = rxAdvance;
1493        break;
1494
1495      case rxAdvance:
1496        if (rxDescCache.link == 0) {
1497            devIntrPost(ISR_RXIDLE);
1498            rxState = rxIdle;
1499            CRDD = true;
1500            goto exit;
1501        } else {
1502            rxState = rxDescRead;
1503            regs.rxdp = rxDescCache.link;
1504            CRDD = false;
1505
1506            rxDmaAddr = regs.rxdp & 0x3fffffff;
1507            rxDmaData = &rxDescCache;
1508            rxDmaLen = sizeof(ns_desc);
1509            rxDmaFree = dmaDescFree;
1510
1511            if (doRxDmaRead())
1512                goto exit;
1513        }
1514        break;
1515
1516      default:
1517        panic("Invalid rxState!");
1518    }
1519
1520    DPRINTF(EthernetSM, "entering next rxState=%s\n",
1521            NsRxStateStrings[rxState]);
1522
1523    goto next;
1524
1525  exit:
1526    /**
1527     * @todo do we want to schedule a future kick?
1528     */
1529    DPRINTF(EthernetSM, "rx state machine exited rxState=%s\n",
1530            NsRxStateStrings[rxState]);
1531}
1532
1533void
1534NSGigE::transmit()
1535{
1536    if (txFifo.empty()) {
1537        DPRINTF(Ethernet, "nothing to transmit\n");
1538        return;
1539    }
1540
1541    DPRINTF(Ethernet, "Attempt Pkt Transmit: txFifo length=%d\n",
1542            maxTxFifoSize - txFifoAvail);
1543    if (interface->sendPacket(txFifo.front())) {
1544#if TRACING_ON
1545        if (DTRACE(Ethernet)) {
1546            if (txFifo.front()->isIpPkt()) {
1547                ip_header *ip = txFifo.front()->getIpHdr();
1548                DPRINTF(Ethernet, "ID is %d\n", reverseEnd16(ip->ID));
1549                if (txFifo.front()->isTcpPkt()) {
1550                    tcp_header *tcp = txFifo.front()->getTcpHdr(ip);
1551                    DPRINTF(Ethernet, "Src Port=%d, Dest Port=%d\n",
1552                            reverseEnd16(tcp->src_port_num),
1553                            reverseEnd16(tcp->dest_port_num));
1554                }
1555            }
1556        }
1557#endif
1558
1559        DDUMP(Ethernet, txFifo.front()->data, txFifo.front()->length);
1560        txBytes += txFifo.front()->length;
1561        txPackets++;
1562
1563        txFifoAvail += txFifo.front()->length;
1564
1565        DPRINTF(Ethernet, "Successful Xmit! now txFifoAvail is %d\n",
1566                txFifoAvail);
1567        txFifo.front() = NULL;
1568        txFifo.pop_front();
1569
1570        /*
1571         * normally do a writeback of the descriptor here, and ONLY
1572         * after that is done, send this interrupt.  but since our
1573         * stuff never actually fails, just do this interrupt here,
1574         * otherwise the code has to stray from this nice format.
1575         * besides, it's functionally the same.
1576         */
1577        devIntrPost(ISR_TXOK);
1578    } else {
1579        DPRINTF(Ethernet,
1580                "May need to rethink always sending the descriptors back?\n");
1581    }
1582
1583   if (!txFifo.empty() && !txEvent.scheduled()) {
1584       DPRINTF(Ethernet, "reschedule transmit\n");
1585       txEvent.schedule(curTick + 1000);
1586   }
1587}
1588
1589void
1590NSGigE::txDmaReadCopy()
1591{
1592    assert(txDmaState == dmaReading);
1593
1594    physmem->dma_read((uint8_t *)txDmaData, txDmaAddr, txDmaLen);
1595    txDmaState = dmaIdle;
1596
1597    DPRINTF(EthernetDMA, "tx dma read  paddr=%#x len=%d\n",
1598            txDmaAddr, txDmaLen);
1599    DDUMP(EthernetDMA, txDmaData, txDmaLen);
1600}
1601
1602bool
1603NSGigE::doTxDmaRead()
1604{
1605    assert(txDmaState == dmaIdle || txDmaState == dmaReadWaiting);
1606    txDmaState = dmaReading;
1607
1608    if (dmaInterface && !txDmaFree) {
1609        if (dmaInterface->busy())
1610            txDmaState = dmaReadWaiting;
1611        else
1612            dmaInterface->doDMA(Read, txDmaAddr, txDmaLen, curTick,
1613                                &txDmaReadEvent, true);
1614        return true;
1615    }
1616
1617    if (dmaReadDelay == 0 && dmaReadFactor == 0.0) {
1618        txDmaReadCopy();
1619        return false;
1620    }
1621
1622    Tick factor = ((txDmaLen + ULL(63)) >> ULL(6)) * dmaReadFactor;
1623    Tick start = curTick + dmaReadDelay + factor;
1624    txDmaReadEvent.schedule(start);
1625    return true;
1626}
1627
1628void
1629NSGigE::txDmaReadDone()
1630{
1631    assert(txDmaState == dmaReading);
1632    txDmaReadCopy();
1633
1634    // If the receive state machine  has a pending DMA, let it go first
1635    if (rxDmaState == dmaReadWaiting || rxDmaState == dmaWriteWaiting)
1636        rxKick();
1637
1638    txKick();
1639}
1640
1641void
1642NSGigE::txDmaWriteCopy()
1643{
1644    assert(txDmaState == dmaWriting);
1645
1646    physmem->dma_write(txDmaAddr, (uint8_t *)txDmaData, txDmaLen);
1647    txDmaState = dmaIdle;
1648
1649    DPRINTF(EthernetDMA, "tx dma write paddr=%#x len=%d\n",
1650            txDmaAddr, txDmaLen);
1651    DDUMP(EthernetDMA, txDmaData, txDmaLen);
1652}
1653
1654bool
1655NSGigE::doTxDmaWrite()
1656{
1657    assert(txDmaState == dmaIdle || txDmaState == dmaWriteWaiting);
1658    txDmaState = dmaWriting;
1659
1660    if (dmaInterface && !txDmaFree) {
1661        if (dmaInterface->busy())
1662            txDmaState = dmaWriteWaiting;
1663        else
1664            dmaInterface->doDMA(WriteInvalidate, txDmaAddr, txDmaLen, curTick,
1665                                &txDmaWriteEvent, true);
1666        return true;
1667    }
1668
1669    if (dmaWriteDelay == 0 && dmaWriteFactor == 0.0) {
1670        txDmaWriteCopy();
1671        return false;
1672    }
1673
1674    Tick factor = ((txDmaLen + ULL(63)) >> ULL(6)) * dmaWriteFactor;
1675    Tick start = curTick + dmaWriteDelay + factor;
1676    txDmaWriteEvent.schedule(start);
1677    return true;
1678}
1679
1680void
1681NSGigE::txDmaWriteDone()
1682{
1683    assert(txDmaState == dmaWriting);
1684    txDmaWriteCopy();
1685
1686    // If the receive state machine  has a pending DMA, let it go first
1687    if (rxDmaState == dmaReadWaiting || rxDmaState == dmaWriteWaiting)
1688        rxKick();
1689
1690    txKick();
1691}
1692
1693void
1694NSGigE::txKick()
1695{
1696    DPRINTF(EthernetSM, "transmit kick txState=%s\n",
1697            NsTxStateStrings[txState]);
1698
1699    if (txKickTick > curTick) {
1700        DPRINTF(EthernetSM, "transmit kick exiting, can't run till %d\n",
1701                txKickTick);
1702
1703        return;
1704    }
1705
1706  next:
1707    switch(txDmaState) {
1708      case dmaReadWaiting:
1709        if (doTxDmaRead())
1710            goto exit;
1711        break;
1712      case dmaWriteWaiting:
1713        if (doTxDmaWrite())
1714            goto exit;
1715        break;
1716      default:
1717        break;
1718    }
1719
1720    switch (txState) {
1721      case txIdle:
1722        if (!txEnable) {
1723            DPRINTF(EthernetSM, "Transmit disabled.  Nothing to do.\n");
1724            goto exit;
1725        }
1726
1727        if (CTDD) {
1728            txState = txDescRefr;
1729
1730            txDmaAddr = regs.txdp & 0x3fffffff;
1731            txDmaData = &txDescCache + offsetof(ns_desc, link);
1732            txDmaLen = sizeof(txDescCache.link);
1733            txDmaFree = dmaDescFree;
1734
1735            descDmaReads++;
1736            descDmaRdBytes += txDmaLen;
1737
1738            if (doTxDmaRead())
1739                goto exit;
1740
1741        } else {
1742            txState = txDescRead;
1743
1744            txDmaAddr = regs.txdp & 0x3fffffff;
1745            txDmaData = &txDescCache;
1746            txDmaLen = sizeof(ns_desc);
1747            txDmaFree = dmaDescFree;
1748
1749            descDmaReads++;
1750            descDmaRdBytes += txDmaLen;
1751
1752            if (doTxDmaRead())
1753                goto exit;
1754        }
1755        break;
1756
1757      case txDescRefr:
1758        if (txDmaState != dmaIdle)
1759            goto exit;
1760
1761        txState = txAdvance;
1762        break;
1763
1764      case txDescRead:
1765        if (txDmaState != dmaIdle)
1766            goto exit;
1767
1768        DPRINTF(EthernetDesc,
1769                "txDescCache: link=%08x bufptr=%08x cmdsts=%08x extsts=%08x\n",
1770                txDescCache.link, txDescCache.bufptr, txDescCache.cmdsts,
1771                txDescCache.extsts);
1772
1773        if (txDescCache.cmdsts & CMDSTS_OWN) {
1774            txState = txFifoBlock;
1775            txFragPtr = txDescCache.bufptr;
1776            txDescCnt = txDescCache.cmdsts & CMDSTS_LEN_MASK;
1777        } else {
1778            devIntrPost(ISR_TXIDLE);
1779            txState = txIdle;
1780            goto exit;
1781        }
1782        break;
1783
1784      case txFifoBlock:
1785        if (!txPacket) {
1786            DPRINTF(EthernetSM, "****starting the tx of a new packet****\n");
1787            txPacket = new EtherPacket;
1788            txPacket->data = new uint8_t[16384];
1789            txPacketBufPtr = txPacket->data;
1790        }
1791
1792        if (txDescCnt == 0) {
1793            DPRINTF(EthernetSM, "the txDescCnt == 0, done with descriptor\n");
1794            if (txDescCache.cmdsts & CMDSTS_MORE) {
1795                DPRINTF(EthernetSM, "there are more descriptors to come\n");
1796                txState = txDescWrite;
1797
1798                txDescCache.cmdsts &= ~CMDSTS_OWN;
1799
1800                txDmaAddr = regs.txdp + offsetof(ns_desc, cmdsts);
1801                txDmaAddr &= 0x3fffffff;
1802                txDmaData = &(txDescCache.cmdsts);
1803                txDmaLen = sizeof(txDescCache.cmdsts);
1804                txDmaFree = dmaDescFree;
1805
1806                if (doTxDmaWrite())
1807                    goto exit;
1808
1809            } else { /* this packet is totally done */
1810                DPRINTF(EthernetSM, "This packet is done, let's wrap it up\n");
1811                /* deal with the the packet that just finished */
1812                if ((regs.vtcr & VTCR_PPCHK) && extstsEnable) {
1813                    if (txDescCache.extsts & EXTSTS_UDPPKT) {
1814                        udpChecksum(txPacket, true);
1815                    } else if (txDescCache.extsts & EXTSTS_TCPPKT) {
1816                        tcpChecksum(txPacket, true);
1817                        txTCPChecksums++;
1818                    }
1819                    if (txDescCache.extsts & EXTSTS_IPPKT) {
1820                        ipChecksum(txPacket, true);
1821                        txIPChecksums++;
1822                    }
1823                }
1824
1825                txPacket->length = txPacketBufPtr - txPacket->data;
1826                // this is just because the receive can't handle a
1827                // packet bigger want to make sure
1828                assert(txPacket->length <= 1514);
1829                txFifo.push_back(txPacket);
1830
1831                /*
1832                 * this following section is not tqo spec, but
1833                 * functionally shouldn't be any different.  normally,
1834                 * the chip will wait til the transmit has occurred
1835                 * before writing back the descriptor because it has
1836                 * to wait to see that it was successfully transmitted
1837                 * to decide whether to set CMDSTS_OK or not.
1838                 * however, in the simulator since it is always
1839                 * successfully transmitted, and writing it exactly to
1840                 * spec would complicate the code, we just do it here
1841                 */
1842
1843                txDescCache.cmdsts &= ~CMDSTS_OWN;
1844                txDescCache.cmdsts |= CMDSTS_OK;
1845
1846                DPRINTF(EthernetDesc,
1847                        "txDesc writeback: cmdsts=%08x extsts=%08x\n",
1848                        txDescCache.cmdsts, txDescCache.extsts);
1849
1850                txDmaAddr = regs.txdp + offsetof(ns_desc, cmdsts);
1851                txDmaAddr &= 0x3fffffff;
1852                txDmaData = &(txDescCache.cmdsts);
1853                txDmaLen = sizeof(txDescCache.cmdsts) +
1854                    sizeof(txDescCache.extsts);
1855                txDmaFree = dmaDescFree;
1856
1857                descDmaWrites++;
1858                descDmaWrBytes += txDmaLen;
1859
1860                transmit();
1861                txPacket = 0;
1862
1863                if (!txEnable) {
1864                    DPRINTF(EthernetSM, "halting TX state machine\n");
1865                    txState = txIdle;
1866                    goto exit;
1867                } else
1868                    txState = txAdvance;
1869
1870                if (doTxDmaWrite())
1871                    goto exit;
1872            }
1873        } else {
1874            DPRINTF(EthernetSM, "this descriptor isn't done yet\n");
1875            if (txFifoAvail) {
1876                txState = txFragRead;
1877
1878                /*
1879                 * The number of bytes transferred is either whatever
1880                 * is left in the descriptor (txDescCnt), or if there
1881                 * is not enough room in the fifo, just whatever room
1882                 * is left in the fifo
1883                 */
1884                txXferLen = min<uint32_t>(txDescCnt, txFifoAvail);
1885
1886                txDmaAddr = txFragPtr & 0x3fffffff;
1887                txDmaData = txPacketBufPtr;
1888                txDmaLen = txXferLen;
1889                txDmaFree = dmaDataFree;
1890
1891                if (doTxDmaRead())
1892                    goto exit;
1893            } else {
1894                txState = txFifoBlock;
1895                transmit();
1896
1897                goto exit;
1898            }
1899
1900        }
1901        break;
1902
1903      case txFragRead:
1904        if (txDmaState != dmaIdle)
1905            goto exit;
1906
1907        txPacketBufPtr += txXferLen;
1908        txFragPtr += txXferLen;
1909        txDescCnt -= txXferLen;
1910        txFifoAvail -= txXferLen;
1911
1912        txState = txFifoBlock;
1913        break;
1914
1915      case txDescWrite:
1916        if (txDmaState != dmaIdle)
1917            goto exit;
1918
1919        if (txDescCache.cmdsts & CMDSTS_INTR)
1920            devIntrPost(ISR_TXDESC);
1921
1922        txState = txAdvance;
1923        break;
1924
1925      case txAdvance:
1926        if (txDescCache.link == 0) {
1927            devIntrPost(ISR_TXIDLE);
1928            txState = txIdle;
1929            goto exit;
1930        } else {
1931            txState = txDescRead;
1932            regs.txdp = txDescCache.link;
1933            CTDD = false;
1934
1935            txDmaAddr = txDescCache.link & 0x3fffffff;
1936            txDmaData = &txDescCache;
1937            txDmaLen = sizeof(ns_desc);
1938            txDmaFree = dmaDescFree;
1939
1940            if (doTxDmaRead())
1941                goto exit;
1942        }
1943        break;
1944
1945      default:
1946        panic("invalid state");
1947    }
1948
1949    DPRINTF(EthernetSM, "entering next txState=%s\n",
1950            NsTxStateStrings[txState]);
1951
1952    goto next;
1953
1954  exit:
1955    /**
1956     * @todo do we want to schedule a future kick?
1957     */
1958    DPRINTF(EthernetSM, "tx state machine exited txState=%s\n",
1959            NsTxStateStrings[txState]);
1960}
1961
1962void
1963NSGigE::transferDone()
1964{
1965    if (txFifo.empty()) {
1966        DPRINTF(Ethernet, "transfer complete: txFifo empty...nothing to do\n");
1967        return;
1968    }
1969
1970    DPRINTF(Ethernet, "transfer complete: data in txFifo...schedule xmit\n");
1971
1972    if (txEvent.scheduled())
1973        txEvent.reschedule(curTick + 1);
1974    else
1975        txEvent.schedule(curTick + 1);
1976}
1977
1978bool
1979NSGigE::rxFilter(PacketPtr packet)
1980{
1981    bool drop = true;
1982    string type;
1983
1984    if (packet->IsUnicast()) {
1985        type = "unicast";
1986
1987        // If we're accepting all unicast addresses
1988        if (acceptUnicast)
1989            drop = false;
1990
1991        // If we make a perfect match
1992        if (acceptPerfect &&
1993            memcmp(rom.perfectMatch, packet->data, EADDR_LEN) == 0)
1994            drop = false;
1995
1996        eth_header *eth = (eth_header *) packet->data;
1997        if ((acceptArp) && (eth->type == 0x608))
1998            drop = false;
1999
2000    } else if (packet->IsBroadcast()) {
2001        type = "broadcast";
2002
2003        // if we're accepting broadcasts
2004        if (acceptBroadcast)
2005            drop = false;
2006
2007    } else if (packet->IsMulticast()) {
2008        type = "multicast";
2009
2010        // if we're accepting all multicasts
2011        if (acceptMulticast)
2012            drop = false;
2013
2014    } else {
2015        type = "unknown";
2016
2017        // oh well, punt on this one
2018    }
2019
2020    if (drop) {
2021        DPRINTF(Ethernet, "rxFilter drop\n");
2022        DDUMP(EthernetData, packet->data, packet->length);
2023    }
2024
2025    return drop;
2026}
2027
2028bool
2029NSGigE::recvPacket(PacketPtr packet)
2030{
2031    rxBytes += packet->length;
2032    rxPackets++;
2033
2034    DPRINTF(Ethernet, "Receiving packet from wire, rxFifoAvail=%d\n",
2035            maxRxFifoSize - rxFifoCnt);
2036
2037    if (!rxEnable) {
2038        DPRINTF(Ethernet, "receive disabled...packet dropped\n");
2039        debug_break();
2040        interface->recvDone();
2041        return true;
2042    }
2043
2044    if (rxFilterEnable && rxFilter(packet)) {
2045        DPRINTF(Ethernet, "packet filtered...dropped\n");
2046        interface->recvDone();
2047        return true;
2048    }
2049
2050    if ((rxFifoCnt + packet->length) >= maxRxFifoSize) {
2051        DPRINTF(Ethernet,
2052                "packet will not fit in receive buffer...packet dropped\n");
2053        devIntrPost(ISR_RXORN);
2054        return false;
2055    }
2056
2057    rxFifo.push_back(packet);
2058    rxFifoCnt += packet->length;
2059    interface->recvDone();
2060
2061    rxKick();
2062    return true;
2063}
2064
2065/**
2066 * does a udp checksum.  if gen is true, then it generates it and puts
2067 * it in the right place else, it just checks what it calculates
2068 * against the value in the header in packet
2069 */
2070bool
2071NSGigE::udpChecksum(PacketPtr packet, bool gen)
2072{
2073    ip_header *ip = packet->getIpHdr();
2074    udp_header *hdr = packet->getUdpHdr(ip);
2075
2076    pseudo_header *pseudo = new pseudo_header;
2077
2078    pseudo->src_ip_addr = ip->src_ip_addr;
2079    pseudo->dest_ip_addr = ip->dest_ip_addr;
2080    pseudo->protocol = ip->protocol;
2081    pseudo->len = hdr->len;
2082
2083    uint16_t cksum = checksumCalc((uint16_t *) pseudo, (uint16_t *) hdr,
2084                                  (uint32_t) hdr->len);
2085
2086    delete pseudo;
2087    if (gen)
2088        hdr->chksum = cksum;
2089    else
2090        if (cksum != 0)
2091            return false;
2092
2093    return true;
2094}
2095
2096bool
2097NSGigE::tcpChecksum(PacketPtr packet, bool gen)
2098{
2099    ip_header *ip = packet->getIpHdr();
2100    tcp_header *hdr = packet->getTcpHdr(ip);
2101
2102    uint16_t cksum;
2103    pseudo_header *pseudo = new pseudo_header;
2104    if (!gen) {
2105        pseudo->src_ip_addr = ip->src_ip_addr;
2106        pseudo->dest_ip_addr = ip->dest_ip_addr;
2107        pseudo->protocol = reverseEnd16(ip->protocol);
2108        pseudo->len = reverseEnd16(reverseEnd16(ip->dgram_len) -
2109                                   (ip->vers_len & 0xf)*4);
2110
2111        cksum = checksumCalc((uint16_t *) pseudo, (uint16_t *) hdr,
2112                             (uint32_t) reverseEnd16(pseudo->len));
2113    } else {
2114        pseudo->src_ip_addr = 0;
2115        pseudo->dest_ip_addr = 0;
2116        pseudo->protocol = hdr->chksum;
2117        pseudo->len = 0;
2118        hdr->chksum = 0;
2119        cksum = checksumCalc((uint16_t *) pseudo, (uint16_t *) hdr,
2120                             (uint32_t) (reverseEnd16(ip->dgram_len) -
2121                                         (ip->vers_len & 0xf)*4));
2122    }
2123
2124    delete pseudo;
2125    if (gen)
2126        hdr->chksum = cksum;
2127    else
2128        if (cksum != 0)
2129            return false;
2130
2131    return true;
2132}
2133
2134bool
2135NSGigE::ipChecksum(PacketPtr packet, bool gen)
2136{
2137    ip_header *hdr = packet->getIpHdr();
2138
2139    uint16_t cksum = checksumCalc(NULL, (uint16_t *) hdr,
2140                                  (hdr->vers_len & 0xf)*4);
2141
2142    if (gen) {
2143        DPRINTF(EthernetCksum, "generated checksum: %#x\n", cksum);
2144        hdr->hdr_chksum = cksum;
2145    }
2146    else
2147        if (cksum != 0)
2148            return false;
2149
2150    return true;
2151}
2152
2153uint16_t
2154NSGigE::checksumCalc(uint16_t *pseudo, uint16_t *buf, uint32_t len)
2155{
2156    uint32_t sum = 0;
2157
2158    uint16_t last_pad = 0;
2159    if (len & 1) {
2160        last_pad = buf[len/2] & 0xff;
2161        len--;
2162        sum += last_pad;
2163    }
2164
2165    if (pseudo) {
2166        sum = pseudo[0] + pseudo[1] + pseudo[2] +
2167            pseudo[3] + pseudo[4] + pseudo[5];
2168    }
2169
2170    for (int i=0; i < (len/2); ++i) {
2171        sum += buf[i];
2172    }
2173
2174    while (sum >> 16)
2175        sum = (sum >> 16) + (sum & 0xffff);
2176
2177    return ~sum;
2178}
2179
2180//=====================================================================
2181//
2182//
2183void
2184NSGigE::serialize(ostream &os)
2185{
2186    // Serialize the PciDev base class
2187    PciDev::serialize(os);
2188
2189    /*
2190     * Finalize any DMA events now.
2191     */
2192    if (rxDmaReadEvent.scheduled())
2193        rxDmaReadCopy();
2194    if (rxDmaWriteEvent.scheduled())
2195        rxDmaWriteCopy();
2196    if (txDmaReadEvent.scheduled())
2197        txDmaReadCopy();
2198    if (txDmaWriteEvent.scheduled())
2199        txDmaWriteCopy();
2200
2201    /*
2202     * Serialize the device registers
2203     */
2204    SERIALIZE_SCALAR(regs.command);
2205    SERIALIZE_SCALAR(regs.config);
2206    SERIALIZE_SCALAR(regs.mear);
2207    SERIALIZE_SCALAR(regs.ptscr);
2208    SERIALIZE_SCALAR(regs.isr);
2209    SERIALIZE_SCALAR(regs.imr);
2210    SERIALIZE_SCALAR(regs.ier);
2211    SERIALIZE_SCALAR(regs.ihr);
2212    SERIALIZE_SCALAR(regs.txdp);
2213    SERIALIZE_SCALAR(regs.txdp_hi);
2214    SERIALIZE_SCALAR(regs.txcfg);
2215    SERIALIZE_SCALAR(regs.gpior);
2216    SERIALIZE_SCALAR(regs.rxdp);
2217    SERIALIZE_SCALAR(regs.rxdp_hi);
2218    SERIALIZE_SCALAR(regs.rxcfg);
2219    SERIALIZE_SCALAR(regs.pqcr);
2220    SERIALIZE_SCALAR(regs.wcsr);
2221    SERIALIZE_SCALAR(regs.pcr);
2222    SERIALIZE_SCALAR(regs.rfcr);
2223    SERIALIZE_SCALAR(regs.rfdr);
2224    SERIALIZE_SCALAR(regs.srr);
2225    SERIALIZE_SCALAR(regs.mibc);
2226    SERIALIZE_SCALAR(regs.vrcr);
2227    SERIALIZE_SCALAR(regs.vtcr);
2228    SERIALIZE_SCALAR(regs.vdr);
2229    SERIALIZE_SCALAR(regs.ccsr);
2230    SERIALIZE_SCALAR(regs.tbicr);
2231    SERIALIZE_SCALAR(regs.tbisr);
2232    SERIALIZE_SCALAR(regs.tanar);
2233    SERIALIZE_SCALAR(regs.tanlpar);
2234    SERIALIZE_SCALAR(regs.taner);
2235    SERIALIZE_SCALAR(regs.tesr);
2236
2237    SERIALIZE_ARRAY(rom.perfectMatch, EADDR_LEN);
2238
2239    SERIALIZE_SCALAR(ioEnable);
2240
2241    /*
2242     * Serialize the data Fifos
2243     */
2244    int txNumPkts = txFifo.size();
2245    SERIALIZE_SCALAR(txNumPkts);
2246    int i = 0;
2247    pktiter_t end = txFifo.end();
2248    for (pktiter_t p = txFifo.begin(); p != end; ++p) {
2249        nameOut(os, csprintf("%s.txFifo%d", name(), i++));
2250        (*p)->serialize(os);
2251    }
2252
2253    int rxNumPkts = rxFifo.size();
2254    SERIALIZE_SCALAR(rxNumPkts);
2255    i = 0;
2256    end = rxFifo.end();
2257    for (pktiter_t p = rxFifo.begin(); p != end; ++p) {
2258        nameOut(os, csprintf("%s.rxFifo%d", name(), i++));
2259        (*p)->serialize(os);
2260    }
2261
2262    /*
2263     * Serialize the various helper variables
2264     */
2265    bool txPacketExists = txPacket;
2266    SERIALIZE_SCALAR(txPacketExists);
2267    if (txPacketExists) {
2268        nameOut(os, csprintf("%s.txPacket", name()));
2269        txPacket->serialize(os);
2270        uint32_t txPktBufPtr = (uint32_t) (txPacketBufPtr - txPacket->data);
2271        SERIALIZE_SCALAR(txPktBufPtr);
2272    }
2273
2274    bool rxPacketExists = rxPacket;
2275    SERIALIZE_SCALAR(rxPacketExists);
2276    if (rxPacketExists) {
2277        nameOut(os, csprintf("%s.rxPacket", name()));
2278        rxPacket->serialize(os);
2279        uint32_t rxPktBufPtr = (uint32_t) (rxPacketBufPtr - rxPacket->data);
2280        SERIALIZE_SCALAR(rxPktBufPtr);
2281    }
2282
2283    SERIALIZE_SCALAR(txXferLen);
2284    SERIALIZE_SCALAR(rxXferLen);
2285
2286    /*
2287     * Serialize DescCaches
2288     */
2289    SERIALIZE_SCALAR(txDescCache.link);
2290    SERIALIZE_SCALAR(txDescCache.bufptr);
2291    SERIALIZE_SCALAR(txDescCache.cmdsts);
2292    SERIALIZE_SCALAR(txDescCache.extsts);
2293    SERIALIZE_SCALAR(rxDescCache.link);
2294    SERIALIZE_SCALAR(rxDescCache.bufptr);
2295    SERIALIZE_SCALAR(rxDescCache.cmdsts);
2296    SERIALIZE_SCALAR(rxDescCache.extsts);
2297
2298    /*
2299     * Serialize tx state machine
2300     */
2301    int txState = this->txState;
2302    SERIALIZE_SCALAR(txState);
2303    SERIALIZE_SCALAR(txEnable);
2304    SERIALIZE_SCALAR(CTDD);
2305    SERIALIZE_SCALAR(txFifoAvail);
2306    SERIALIZE_SCALAR(txFragPtr);
2307    SERIALIZE_SCALAR(txDescCnt);
2308    int txDmaState = this->txDmaState;
2309    SERIALIZE_SCALAR(txDmaState);
2310
2311    /*
2312     * Serialize rx state machine
2313     */
2314    int rxState = this->rxState;
2315    SERIALIZE_SCALAR(rxState);
2316    SERIALIZE_SCALAR(rxEnable);
2317    SERIALIZE_SCALAR(CRDD);
2318    SERIALIZE_SCALAR(rxPktBytes);
2319    SERIALIZE_SCALAR(rxFifoCnt);
2320    SERIALIZE_SCALAR(rxDescCnt);
2321    int rxDmaState = this->rxDmaState;
2322    SERIALIZE_SCALAR(rxDmaState);
2323
2324    SERIALIZE_SCALAR(extstsEnable);
2325
2326    /*
2327     * If there's a pending transmit, store the time so we can
2328     * reschedule it later
2329     */
2330    Tick transmitTick = txEvent.scheduled() ? txEvent.when() - curTick : 0;
2331    SERIALIZE_SCALAR(transmitTick);
2332
2333    /*
2334     * receive address filter settings
2335     */
2336    SERIALIZE_SCALAR(rxFilterEnable);
2337    SERIALIZE_SCALAR(acceptBroadcast);
2338    SERIALIZE_SCALAR(acceptMulticast);
2339    SERIALIZE_SCALAR(acceptUnicast);
2340    SERIALIZE_SCALAR(acceptPerfect);
2341    SERIALIZE_SCALAR(acceptArp);
2342
2343    /*
2344     * Keep track of pending interrupt status.
2345     */
2346    SERIALIZE_SCALAR(intrTick);
2347    SERIALIZE_SCALAR(cpuPendingIntr);
2348    Tick intrEventTick = 0;
2349    if (intrEvent)
2350        intrEventTick = intrEvent->when();
2351    SERIALIZE_SCALAR(intrEventTick);
2352
2353}
2354
2355void
2356NSGigE::unserialize(Checkpoint *cp, const std::string &section)
2357{
2358    // Unserialize the PciDev base class
2359    PciDev::unserialize(cp, section);
2360
2361    UNSERIALIZE_SCALAR(regs.command);
2362    UNSERIALIZE_SCALAR(regs.config);
2363    UNSERIALIZE_SCALAR(regs.mear);
2364    UNSERIALIZE_SCALAR(regs.ptscr);
2365    UNSERIALIZE_SCALAR(regs.isr);
2366    UNSERIALIZE_SCALAR(regs.imr);
2367    UNSERIALIZE_SCALAR(regs.ier);
2368    UNSERIALIZE_SCALAR(regs.ihr);
2369    UNSERIALIZE_SCALAR(regs.txdp);
2370    UNSERIALIZE_SCALAR(regs.txdp_hi);
2371    UNSERIALIZE_SCALAR(regs.txcfg);
2372    UNSERIALIZE_SCALAR(regs.gpior);
2373    UNSERIALIZE_SCALAR(regs.rxdp);
2374    UNSERIALIZE_SCALAR(regs.rxdp_hi);
2375    UNSERIALIZE_SCALAR(regs.rxcfg);
2376    UNSERIALIZE_SCALAR(regs.pqcr);
2377    UNSERIALIZE_SCALAR(regs.wcsr);
2378    UNSERIALIZE_SCALAR(regs.pcr);
2379    UNSERIALIZE_SCALAR(regs.rfcr);
2380    UNSERIALIZE_SCALAR(regs.rfdr);
2381    UNSERIALIZE_SCALAR(regs.srr);
2382    UNSERIALIZE_SCALAR(regs.mibc);
2383    UNSERIALIZE_SCALAR(regs.vrcr);
2384    UNSERIALIZE_SCALAR(regs.vtcr);
2385    UNSERIALIZE_SCALAR(regs.vdr);
2386    UNSERIALIZE_SCALAR(regs.ccsr);
2387    UNSERIALIZE_SCALAR(regs.tbicr);
2388    UNSERIALIZE_SCALAR(regs.tbisr);
2389    UNSERIALIZE_SCALAR(regs.tanar);
2390    UNSERIALIZE_SCALAR(regs.tanlpar);
2391    UNSERIALIZE_SCALAR(regs.taner);
2392    UNSERIALIZE_SCALAR(regs.tesr);
2393
2394    UNSERIALIZE_ARRAY(rom.perfectMatch, EADDR_LEN);
2395
2396    UNSERIALIZE_SCALAR(ioEnable);
2397
2398    /*
2399     * unserialize the data fifos
2400     */
2401    int txNumPkts;
2402    UNSERIALIZE_SCALAR(txNumPkts);
2403    int i;
2404    for (i = 0; i < txNumPkts; ++i) {
2405        PacketPtr p = new EtherPacket;
2406        p->unserialize(cp, csprintf("%s.rxFifo%d", section, i));
2407        txFifo.push_back(p);
2408    }
2409
2410    int rxNumPkts;
2411    UNSERIALIZE_SCALAR(rxNumPkts);
2412    for (i = 0; i < rxNumPkts; ++i) {
2413        PacketPtr p = new EtherPacket;
2414        p->unserialize(cp, csprintf("%s.rxFifo%d", section, i));
2415        rxFifo.push_back(p);
2416    }
2417
2418    /*
2419     * unserialize the various helper variables
2420     */
2421    bool txPacketExists;
2422    UNSERIALIZE_SCALAR(txPacketExists);
2423    if (txPacketExists) {
2424        txPacket = new EtherPacket;
2425        txPacket->unserialize(cp, csprintf("%s.txPacket", section));
2426        uint32_t txPktBufPtr;
2427        UNSERIALIZE_SCALAR(txPktBufPtr);
2428        txPacketBufPtr = (uint8_t *) txPacket->data + txPktBufPtr;
2429    } else
2430        txPacket = 0;
2431
2432    bool rxPacketExists;
2433    UNSERIALIZE_SCALAR(rxPacketExists);
2434    rxPacket = 0;
2435    if (rxPacketExists) {
2436        rxPacket = new EtherPacket;
2437        rxPacket->unserialize(cp, csprintf("%s.rxPacket", section));
2438        uint32_t rxPktBufPtr;
2439        UNSERIALIZE_SCALAR(rxPktBufPtr);
2440        rxPacketBufPtr = (uint8_t *) rxPacket->data + rxPktBufPtr;
2441    } else
2442        rxPacket = 0;
2443
2444    UNSERIALIZE_SCALAR(txXferLen);
2445    UNSERIALIZE_SCALAR(rxXferLen);
2446
2447    /*
2448     * Unserialize DescCaches
2449     */
2450    UNSERIALIZE_SCALAR(txDescCache.link);
2451    UNSERIALIZE_SCALAR(txDescCache.bufptr);
2452    UNSERIALIZE_SCALAR(txDescCache.cmdsts);
2453    UNSERIALIZE_SCALAR(txDescCache.extsts);
2454    UNSERIALIZE_SCALAR(rxDescCache.link);
2455    UNSERIALIZE_SCALAR(rxDescCache.bufptr);
2456    UNSERIALIZE_SCALAR(rxDescCache.cmdsts);
2457    UNSERIALIZE_SCALAR(rxDescCache.extsts);
2458
2459    /*
2460     * unserialize tx state machine
2461     */
2462    int txState;
2463    UNSERIALIZE_SCALAR(txState);
2464    this->txState = (TxState) txState;
2465    UNSERIALIZE_SCALAR(txEnable);
2466    UNSERIALIZE_SCALAR(CTDD);
2467    UNSERIALIZE_SCALAR(txFifoAvail);
2468    UNSERIALIZE_SCALAR(txFragPtr);
2469    UNSERIALIZE_SCALAR(txDescCnt);
2470    int txDmaState;
2471    UNSERIALIZE_SCALAR(txDmaState);
2472    this->txDmaState = (DmaState) txDmaState;
2473
2474    /*
2475     * unserialize rx state machine
2476     */
2477    int rxState;
2478    UNSERIALIZE_SCALAR(rxState);
2479    this->rxState = (RxState) rxState;
2480    UNSERIALIZE_SCALAR(rxEnable);
2481    UNSERIALIZE_SCALAR(CRDD);
2482    UNSERIALIZE_SCALAR(rxPktBytes);
2483    UNSERIALIZE_SCALAR(rxFifoCnt);
2484    UNSERIALIZE_SCALAR(rxDescCnt);
2485    int rxDmaState;
2486    UNSERIALIZE_SCALAR(rxDmaState);
2487    this->rxDmaState = (DmaState) rxDmaState;
2488
2489    UNSERIALIZE_SCALAR(extstsEnable);
2490
2491     /*
2492     * If there's a pending transmit, reschedule it now
2493     */
2494    Tick transmitTick;
2495    UNSERIALIZE_SCALAR(transmitTick);
2496    if (transmitTick)
2497        txEvent.schedule(curTick + transmitTick);
2498
2499    /*
2500     * unserialize receive address filter settings
2501     */
2502    UNSERIALIZE_SCALAR(rxFilterEnable);
2503    UNSERIALIZE_SCALAR(acceptBroadcast);
2504    UNSERIALIZE_SCALAR(acceptMulticast);
2505    UNSERIALIZE_SCALAR(acceptUnicast);
2506    UNSERIALIZE_SCALAR(acceptPerfect);
2507    UNSERIALIZE_SCALAR(acceptArp);
2508
2509    /*
2510     * Keep track of pending interrupt status.
2511     */
2512    UNSERIALIZE_SCALAR(intrTick);
2513    UNSERIALIZE_SCALAR(cpuPendingIntr);
2514    Tick intrEventTick;
2515    UNSERIALIZE_SCALAR(intrEventTick);
2516    if (intrEventTick) {
2517        intrEvent = new IntrEvent(this, true);
2518        intrEvent->schedule(intrEventTick);
2519    }
2520
2521    /*
2522     * re-add addrRanges to bus bridges
2523     */
2524    if (pioInterface) {
2525        pioInterface->addAddrRange(BARAddrs[0], BARAddrs[0] + BARSize[0] - 1);
2526        pioInterface->addAddrRange(BARAddrs[1], BARAddrs[1] + BARSize[1] - 1);
2527    }
2528}
2529
2530Tick
2531NSGigE::cacheAccess(MemReqPtr &req)
2532{
2533    DPRINTF(EthernetPIO, "timing access to paddr=%#x (daddr=%#x)\n",
2534            req->paddr, req->paddr - addr);
2535    return curTick + pioLatency;
2536}
2537//=====================================================================
2538
2539
2540//********** helper functions******************************************
2541
2542uint16_t reverseEnd16(uint16_t num)
2543{
2544    uint16_t reverse = (num & 0xff)<<8;
2545    reverse += ((num & 0xff00) >> 8);
2546    return reverse;
2547}
2548
2549uint32_t reverseEnd32(uint32_t num)
2550{
2551    uint32_t reverse = (reverseEnd16(num & 0xffff)) << 16;
2552    reverse += reverseEnd16((uint16_t) ((num & 0xffff0000) >> 8));
2553    return reverse;
2554}
2555
2556
2557
2558//=====================================================================
2559
2560BEGIN_DECLARE_SIM_OBJECT_PARAMS(NSGigEInt)
2561
2562    SimObjectParam<EtherInt *> peer;
2563    SimObjectParam<NSGigE *> device;
2564
2565END_DECLARE_SIM_OBJECT_PARAMS(NSGigEInt)
2566
2567BEGIN_INIT_SIM_OBJECT_PARAMS(NSGigEInt)
2568
2569    INIT_PARAM_DFLT(peer, "peer interface", NULL),
2570    INIT_PARAM(device, "Ethernet device of this interface")
2571
2572END_INIT_SIM_OBJECT_PARAMS(NSGigEInt)
2573
2574CREATE_SIM_OBJECT(NSGigEInt)
2575{
2576    NSGigEInt *dev_int = new NSGigEInt(getInstanceName(), device);
2577
2578    EtherInt *p = (EtherInt *)peer;
2579    if (p) {
2580        dev_int->setPeer(p);
2581        p->setPeer(dev_int);
2582    }
2583
2584    return dev_int;
2585}
2586
2587REGISTER_SIM_OBJECT("NSGigEInt", NSGigEInt)
2588
2589
2590BEGIN_DECLARE_SIM_OBJECT_PARAMS(NSGigE)
2591
2592    Param<Tick> tx_delay;
2593    Param<Tick> rx_delay;
2594    SimObjectParam<IntrControl *> intr_ctrl;
2595    Param<Tick> intr_delay;
2596    SimObjectParam<MemoryController *> mmu;
2597    SimObjectParam<PhysicalMemory *> physmem;
2598    Param<bool> rx_filter;
2599    Param<string> hardware_address;
2600    SimObjectParam<Bus*> header_bus;
2601    SimObjectParam<Bus*> payload_bus;
2602    SimObjectParam<HierParams *> hier;
2603    Param<Tick> pio_latency;
2604    Param<bool> dma_desc_free;
2605    Param<bool> dma_data_free;
2606    Param<Tick> dma_read_delay;
2607    Param<Tick> dma_write_delay;
2608    Param<Tick> dma_read_factor;
2609    Param<Tick> dma_write_factor;
2610    SimObjectParam<PciConfigAll *> configspace;
2611    SimObjectParam<PciConfigData *> configdata;
2612    SimObjectParam<Tsunami *> tsunami;
2613    Param<uint32_t> pci_bus;
2614    Param<uint32_t> pci_dev;
2615    Param<uint32_t> pci_func;
2616    Param<uint32_t> tx_fifo_size;
2617    Param<uint32_t> rx_fifo_size;
2618
2619END_DECLARE_SIM_OBJECT_PARAMS(NSGigE)
2620
2621BEGIN_INIT_SIM_OBJECT_PARAMS(NSGigE)
2622
2623    INIT_PARAM_DFLT(tx_delay, "Transmit Delay", 1000),
2624    INIT_PARAM_DFLT(rx_delay, "Receive Delay", 1000),
2625    INIT_PARAM(intr_ctrl, "Interrupt Controller"),
2626    INIT_PARAM_DFLT(intr_delay, "Interrupt Delay in microseconds", 0),
2627    INIT_PARAM(mmu, "Memory Controller"),
2628    INIT_PARAM(physmem, "Physical Memory"),
2629    INIT_PARAM_DFLT(rx_filter, "Enable Receive Filter", true),
2630    INIT_PARAM_DFLT(hardware_address, "Ethernet Hardware Address",
2631                    "00:99:00:00:00:01"),
2632    INIT_PARAM_DFLT(header_bus, "The IO Bus to attach to for headers", NULL),
2633    INIT_PARAM_DFLT(payload_bus, "The IO Bus to attach to for payload", NULL),
2634    INIT_PARAM_DFLT(hier, "Hierarchy global variables", &defaultHierParams),
2635    INIT_PARAM_DFLT(pio_latency, "Programmed IO latency in bus cycles", 1),
2636    INIT_PARAM_DFLT(dma_desc_free, "DMA of Descriptors is free", false),
2637    INIT_PARAM_DFLT(dma_data_free, "DMA of Data is free", false),
2638    INIT_PARAM_DFLT(dma_read_delay, "fixed delay for dma reads", 0),
2639    INIT_PARAM_DFLT(dma_write_delay, "fixed delay for dma writes", 0),
2640    INIT_PARAM_DFLT(dma_read_factor, "multiplier for dma reads", 0),
2641    INIT_PARAM_DFLT(dma_write_factor, "multiplier for dma writes", 0),
2642    INIT_PARAM(configspace, "PCI Configspace"),
2643    INIT_PARAM(configdata, "PCI Config data"),
2644    INIT_PARAM(tsunami, "Tsunami"),
2645    INIT_PARAM(pci_bus, "PCI bus"),
2646    INIT_PARAM(pci_dev, "PCI device number"),
2647    INIT_PARAM(pci_func, "PCI function code"),
2648    INIT_PARAM_DFLT(tx_fifo_size, "max size in bytes of txFifo", 131072),
2649    INIT_PARAM_DFLT(rx_fifo_size, "max size in bytes of rxFifo", 131072)
2650
2651END_INIT_SIM_OBJECT_PARAMS(NSGigE)
2652
2653
2654CREATE_SIM_OBJECT(NSGigE)
2655{
2656    int eaddr[6];
2657    sscanf(((string)hardware_address).c_str(), "%x:%x:%x:%x:%x:%x",
2658           &eaddr[0], &eaddr[1], &eaddr[2], &eaddr[3], &eaddr[4], &eaddr[5]);
2659
2660    return new NSGigE(getInstanceName(), intr_ctrl, intr_delay,
2661                      physmem, tx_delay, rx_delay, mmu, hier, header_bus,
2662                      payload_bus, pio_latency, dma_desc_free, dma_data_free,
2663                      dma_read_delay, dma_write_delay, dma_read_factor,
2664                      dma_write_factor, configspace, configdata,
2665                      tsunami, pci_bus, pci_dev, pci_func, rx_filter, eaddr,
2666                      tx_fifo_size, rx_fifo_size);
2667}
2668
2669REGISTER_SIM_OBJECT("NSGigE", NSGigE)
2670