ns_gige.cc revision 1072
19793Sakash.bagdia@arm.com/*
27586SAli.Saidi@arm.com * Copyright (c) 2004 The Regents of The University of Michigan
37586SAli.Saidi@arm.com * All rights reserved.
47586SAli.Saidi@arm.com *
57586SAli.Saidi@arm.com * Redistribution and use in source and binary forms, with or without
67586SAli.Saidi@arm.com * modification, are permitted provided that the following conditions are
77586SAli.Saidi@arm.com * met: redistributions of source code must retain the above copyright
87586SAli.Saidi@arm.com * notice, this list of conditions and the following disclaimer;
97586SAli.Saidi@arm.com * redistributions in binary form must reproduce the above copyright
107586SAli.Saidi@arm.com * notice, this list of conditions and the following disclaimer in the
117586SAli.Saidi@arm.com * documentation and/or other materials provided with the distribution;
127586SAli.Saidi@arm.com * neither the name of the copyright holders nor the names of its
1310118Snilay@cs.wisc.edu * contributors may be used to endorse or promote products derived from
1410118Snilay@cs.wisc.edu * this software without specific prior written permission.
153970Sgblack@eecs.umich.edu *
163005Sstever@eecs.umich.edu * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
173005Sstever@eecs.umich.edu * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
183005Sstever@eecs.umich.edu * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
193005Sstever@eecs.umich.edu * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
203005Sstever@eecs.umich.edu * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
213005Sstever@eecs.umich.edu * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
223005Sstever@eecs.umich.edu * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
233005Sstever@eecs.umich.edu * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
243005Sstever@eecs.umich.edu * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
253005Sstever@eecs.umich.edu * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
263005Sstever@eecs.umich.edu * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
273005Sstever@eecs.umich.edu */
283005Sstever@eecs.umich.edu
293005Sstever@eecs.umich.edu/* @file
303005Sstever@eecs.umich.edu * Device module for modelling the National Semiconductor
313005Sstever@eecs.umich.edu * DP83820 ethernet controller.  Does not support priority queueing
323005Sstever@eecs.umich.edu */
333005Sstever@eecs.umich.edu#include <cstdio>
343005Sstever@eecs.umich.edu#include <deque>
353005Sstever@eecs.umich.edu#include <string>
363005Sstever@eecs.umich.edu
373005Sstever@eecs.umich.edu#include "base/inet.hh"
383005Sstever@eecs.umich.edu#include "cpu/exec_context.hh"
393005Sstever@eecs.umich.edu#include "cpu/intr_control.hh"
403005Sstever@eecs.umich.edu#include "dev/dma.hh"
413005Sstever@eecs.umich.edu#include "dev/etherlink.hh"
4210118Snilay@cs.wisc.edu#include "dev/ns_gige.hh"
433005Sstever@eecs.umich.edu#include "dev/pciconfigall.hh"
446654Snate@binkert.org#include "dev/tsunami_cchip.hh"
456654Snate@binkert.org#include "mem/bus/bus.hh"
462889SN/A#include "mem/bus/dma_interface.hh"
472710SN/A#include "mem/bus/pio_interface.hh"
486654Snate@binkert.org#include "mem/bus/pio_interface_impl.hh"
496654Snate@binkert.org#include "mem/functional_mem/memory_control.hh"
506654Snate@binkert.org#include "mem/functional_mem/physical_memory.hh"
515457Ssaidi@eecs.umich.edu#include "sim/builder.hh"
526654Snate@binkert.org#include "sim/debug.hh"
5310118Snilay@cs.wisc.edu#include "sim/host.hh"
5410118Snilay@cs.wisc.edu#include "sim/sim_stats.hh"
5510118Snilay@cs.wisc.edu#include "targetarch/vtophys.hh"
566654Snate@binkert.org
572934SN/Aconst char *NsRxStateStrings[] =
582549SN/A{
592995SN/A    "rxIdle",
603395Shsul@eecs.umich.edu    "rxDescRefr",
616981SLisa.Hsu@amd.com    "rxDescRead",
629836Sandreas.hansson@arm.com    "rxFifoBlock",
633448Shsul@eecs.umich.edu    "rxFragWrite",
648920Snilay@cs.wisc.edu    "rxDescWrite",
653444Sktlim@umich.edu    "rxAdvance"
663304Sstever@eecs.umich.edu};
679653SAndreas.Sandberg@ARM.com
689653SAndreas.Sandberg@ARM.comconst char *NsTxStateStrings[] =
699653SAndreas.Sandberg@ARM.com{
709653SAndreas.Sandberg@ARM.com    "txIdle",
719653SAndreas.Sandberg@ARM.com    "txDescRefr",
729653SAndreas.Sandberg@ARM.com    "txDescRead",
739653SAndreas.Sandberg@ARM.com    "txFifoBlock",
7410594Sgabeblack@google.com    "txFragRead",
7510594Sgabeblack@google.com    "txDescWrite",
7610594Sgabeblack@google.com    "txAdvance"
7710594Sgabeblack@google.com};
7810594Sgabeblack@google.com
7910594Sgabeblack@google.comconst char *NsDmaState[] =
8010594Sgabeblack@google.com{
8110594Sgabeblack@google.com    "dmaIdle",
8210594Sgabeblack@google.com    "dmaReading",
8310594Sgabeblack@google.com    "dmaWriting",
8410594Sgabeblack@google.com    "dmaReadWaiting",
8510119Snilay@cs.wisc.edu    "dmaWriteWaiting"
8610594Sgabeblack@google.com};
8710119Snilay@cs.wisc.edu
8810594Sgabeblack@google.comusing namespace std;
8910594Sgabeblack@google.com
9010119Snilay@cs.wisc.edu// helper function declarations
9110594Sgabeblack@google.com// These functions reverse Endianness so we can evaluate network data
9210119Snilay@cs.wisc.edu// correctly
9310594Sgabeblack@google.comuint16_t reverseEnd16(uint16_t);
9410119Snilay@cs.wisc.eduuint32_t reverseEnd32(uint32_t);
9510119Snilay@cs.wisc.edu
9610594Sgabeblack@google.com///////////////////////////////////////////////////////////////////////
9710119Snilay@cs.wisc.edu//
9810512SAli.Saidi@ARM.com// NSGigE PCI Device
9910512SAli.Saidi@ARM.com//
10010594Sgabeblack@google.comNSGigE::NSGigE(const std::string &name, IntrControl *i, Tick intr_delay,
10110594Sgabeblack@google.com               PhysicalMemory *pmem, Tick tx_delay, Tick rx_delay,
10210119Snilay@cs.wisc.edu               MemoryController *mmu, HierParams *hier, Bus *header_bus,
10310119Snilay@cs.wisc.edu               Bus *payload_bus, Tick pio_latency, bool dma_desc_free,
10410119Snilay@cs.wisc.edu               bool dma_data_free, Tick dma_read_delay, Tick dma_write_delay,
10510119Snilay@cs.wisc.edu               Tick dma_read_factor, Tick dma_write_factor, PciConfigAll *cf,
1062566SN/A               PciConfigData *cd, Tsunami *t, uint32_t bus, uint32_t dev,
10710119Snilay@cs.wisc.edu               uint32_t func, bool rx_filter, const int eaddr[6],
10810119Snilay@cs.wisc.edu               uint32_t tx_fifo_size, uint32_t rx_fifo_size)
1099665Sandreas.hansson@arm.com    : PciDev(name, mmu, cf, cd, bus, dev, func), tsunami(t), ioEnable(false),
11010119Snilay@cs.wisc.edu      maxTxFifoSize(tx_fifo_size), maxRxFifoSize(rx_fifo_size),
11110119Snilay@cs.wisc.edu      txPacket(0), rxPacket(0), txPacketBufPtr(NULL), rxPacketBufPtr(NULL),
11210119Snilay@cs.wisc.edu      txXferLen(0), rxXferLen(0), txState(txIdle), txEnable(false),
11310119Snilay@cs.wisc.edu      CTDD(false), txFifoAvail(tx_fifo_size),
11410119Snilay@cs.wisc.edu      txFragPtr(0), txDescCnt(0), txDmaState(dmaIdle), rxState(rxIdle),
11510119Snilay@cs.wisc.edu      rxEnable(false), CRDD(false), rxPktBytes(0), rxFifoCnt(0),
11610119Snilay@cs.wisc.edu      rxFragPtr(0), rxDescCnt(0), rxDmaState(dmaIdle), extstsEnable(false),
11710119Snilay@cs.wisc.edu      rxDmaReadEvent(this), rxDmaWriteEvent(this),
11810119Snilay@cs.wisc.edu      txDmaReadEvent(this), txDmaWriteEvent(this),
11910119Snilay@cs.wisc.edu      dmaDescFree(dma_desc_free), dmaDataFree(dma_data_free),
12010119Snilay@cs.wisc.edu      txDelay(tx_delay), rxDelay(rx_delay), rxKickTick(0), txKickTick(0),
12110119Snilay@cs.wisc.edu      txEvent(this), rxFilterEnable(rx_filter), acceptBroadcast(false),
12210119Snilay@cs.wisc.edu      acceptMulticast(false), acceptUnicast(false),
12310119Snilay@cs.wisc.edu      acceptPerfect(false), acceptArp(false),
12410119Snilay@cs.wisc.edu      physmem(pmem), intctrl(i), intrTick(0), cpuPendingIntr(false),
12510119Snilay@cs.wisc.edu      intrEvent(0), interface(0)
12610119Snilay@cs.wisc.edu{
12710119Snilay@cs.wisc.edu    tsunami->ethernet = this;
12810119Snilay@cs.wisc.edu
12910119Snilay@cs.wisc.edu    if (header_bus) {
13010119Snilay@cs.wisc.edu        pioInterface = newPioInterface(name, hier, header_bus, this,
13110119Snilay@cs.wisc.edu                                       &NSGigE::cacheAccess);
13210119Snilay@cs.wisc.edu
13310119Snilay@cs.wisc.edu        pioLatency = pio_latency * header_bus->clockRatio;
13410119Snilay@cs.wisc.edu
13510119Snilay@cs.wisc.edu        if (payload_bus)
13610119Snilay@cs.wisc.edu            dmaInterface = new DMAInterface<Bus>(name + ".dma",
13710119Snilay@cs.wisc.edu                                                 header_bus, payload_bus, 1);
13810119Snilay@cs.wisc.edu        else
13910119Snilay@cs.wisc.edu            dmaInterface = new DMAInterface<Bus>(name + ".dma",
14010119Snilay@cs.wisc.edu                                                 header_bus, header_bus, 1);
14110119Snilay@cs.wisc.edu    } else if (payload_bus) {
14210119Snilay@cs.wisc.edu        pioInterface = newPioInterface(name, hier, payload_bus, this,
14310119Snilay@cs.wisc.edu                                       &NSGigE::cacheAccess);
14410119Snilay@cs.wisc.edu
14510119Snilay@cs.wisc.edu        pioLatency = pio_latency * payload_bus->clockRatio;
14610119Snilay@cs.wisc.edu
14710119Snilay@cs.wisc.edu        dmaInterface = new DMAInterface<Bus>(name + ".dma", payload_bus,
14810119Snilay@cs.wisc.edu                                         payload_bus, 1);
14910119Snilay@cs.wisc.edu    }
15010119Snilay@cs.wisc.edu
15110119Snilay@cs.wisc.edu
15210519Snilay@cs.wisc.edu    intrDelay = US2Ticks(intr_delay);
15310519Snilay@cs.wisc.edu    dmaReadDelay = dma_read_delay;
15410119Snilay@cs.wisc.edu    dmaWriteDelay = dma_write_delay;
15510119Snilay@cs.wisc.edu    dmaReadFactor = dma_read_factor;
15610119Snilay@cs.wisc.edu    dmaWriteFactor = dma_write_factor;
15710119Snilay@cs.wisc.edu
15810119Snilay@cs.wisc.edu    regsReset();
15910547Snilay@cs.wisc.edu    rom.perfectMatch[0] = eaddr[0];
16010547Snilay@cs.wisc.edu    rom.perfectMatch[1] = eaddr[1];
16110547Snilay@cs.wisc.edu    rom.perfectMatch[2] = eaddr[2];
16210547Snilay@cs.wisc.edu    rom.perfectMatch[3] = eaddr[3];
16310119Snilay@cs.wisc.edu    rom.perfectMatch[4] = eaddr[4];
16410119Snilay@cs.wisc.edu    rom.perfectMatch[5] = eaddr[5];
16510119Snilay@cs.wisc.edu}
16610119Snilay@cs.wisc.edu
16710119Snilay@cs.wisc.eduNSGigE::~NSGigE()
16810119Snilay@cs.wisc.edu{}
16910119Snilay@cs.wisc.edu
17010119Snilay@cs.wisc.eduvoid
17110120Snilay@cs.wisc.eduNSGigE::regStats()
17210120Snilay@cs.wisc.edu{
17310119Snilay@cs.wisc.edu    txBytes
17410119Snilay@cs.wisc.edu        .name(name() + ".txBytes")
17510120Snilay@cs.wisc.edu        .desc("Bytes Transmitted")
17610120Snilay@cs.wisc.edu        .prereq(txBytes)
17710119Snilay@cs.wisc.edu        ;
17810120Snilay@cs.wisc.edu
17910120Snilay@cs.wisc.edu    rxBytes
18010120Snilay@cs.wisc.edu        .name(name() + ".rxBytes")
18110119Snilay@cs.wisc.edu        .desc("Bytes Received")
1822995SN/A        .prereq(rxBytes)
18310119Snilay@cs.wisc.edu        ;
18410119Snilay@cs.wisc.edu
18510119Snilay@cs.wisc.edu    txPackets
18610119Snilay@cs.wisc.edu        .name(name() + ".txPackets")
18710119Snilay@cs.wisc.edu        .desc("Number of Packets Transmitted")
18810119Snilay@cs.wisc.edu        .prereq(txBytes)
18910119Snilay@cs.wisc.edu        ;
19010119Snilay@cs.wisc.edu
19110119Snilay@cs.wisc.edu    rxPackets
1923304Sstever@eecs.umich.edu        .name(name() + ".rxPackets")
19310119Snilay@cs.wisc.edu        .desc("Number of Packets Received")
19410119Snilay@cs.wisc.edu        .prereq(rxBytes)
19510119Snilay@cs.wisc.edu        ;
19610119Snilay@cs.wisc.edu
19710119Snilay@cs.wisc.edu    txIPChecksums
19810119Snilay@cs.wisc.edu        .name(name() + ".txIPChecksums")
1996135Sgblack@eecs.umich.edu        .desc("Number of tx IP Checksums done by device")
20010608Sdam.sunwoo@arm.com        .precision(0)
20110608Sdam.sunwoo@arm.com        .prereq(txBytes)
20210608Sdam.sunwoo@arm.com        ;
20310608Sdam.sunwoo@arm.com
20410608Sdam.sunwoo@arm.com    rxIPChecksums
20510608Sdam.sunwoo@arm.com        .name(name() + ".rxIPChecksums")
20610608Sdam.sunwoo@arm.com        .desc("Number of rx IP Checksums done by device")
20710119Snilay@cs.wisc.edu        .precision(0)
20810119Snilay@cs.wisc.edu        .prereq(rxBytes)
20910119Snilay@cs.wisc.edu        ;
21010608Sdam.sunwoo@arm.com
21110608Sdam.sunwoo@arm.com    txTCPChecksums
21210119Snilay@cs.wisc.edu        .name(name() + ".txTCPChecksums")
21310119Snilay@cs.wisc.edu        .desc("Number of tx TCP Checksums done by device")
21410119Snilay@cs.wisc.edu        .precision(0)
2153819Shsul@eecs.umich.edu        .prereq(txBytes)
21610119Snilay@cs.wisc.edu        ;
21710119Snilay@cs.wisc.edu
21810118Snilay@cs.wisc.edu    rxTCPChecksums
21910119Snilay@cs.wisc.edu        .name(name() + ".rxTCPChecksums")
2209827Sakash.bagdia@arm.com        .desc("Number of rx TCP Checksums done by device")
22110119Snilay@cs.wisc.edu        .precision(0)
22210119Snilay@cs.wisc.edu        .prereq(rxBytes)
22310119Snilay@cs.wisc.edu        ;
22410119Snilay@cs.wisc.edu
22510119Snilay@cs.wisc.edu    descDmaReads
22610119Snilay@cs.wisc.edu        .name(name() + ".descDMAReads")
2279827Sakash.bagdia@arm.com        .desc("Number of descriptors the device read w/ DMA")
22810594Sgabeblack@google.com        .precision(0)
2296654Snate@binkert.org        ;
23010594Sgabeblack@google.com
2316654Snate@binkert.org    descDmaWrites
23210594Sgabeblack@google.com        .name(name() + ".descDMAWrites")
2336654Snate@binkert.org        .desc("Number of descriptors the device wrote w/ DMA")
23410594Sgabeblack@google.com        .precision(0)
2356654Snate@binkert.org        ;
23610594Sgabeblack@google.com
23710594Sgabeblack@google.com    descDmaRdBytes
2387586SAli.Saidi@arm.com        .name(name() + ".descDmaReadBytes")
23910594Sgabeblack@google.com        .desc("number of descriptor bytes read w/ DMA")
24010594Sgabeblack@google.com        .precision(0)
2418661SAli.Saidi@ARM.com        ;
2429827Sakash.bagdia@arm.com
2439827Sakash.bagdia@arm.com   descDmaWrBytes
2449827Sakash.bagdia@arm.com        .name(name() + ".descDmaWriteBytes")
2459793Sakash.bagdia@arm.com        .desc("number of descriptor bytes write w/ DMA")
24610119Snilay@cs.wisc.edu        .precision(0)
24710119Snilay@cs.wisc.edu        ;
2489790Sakash.bagdia@arm.com
2499827Sakash.bagdia@arm.com
2509827Sakash.bagdia@arm.com    txBandwidth
2519827Sakash.bagdia@arm.com        .name(name() + ".txBandwidth")
2529793Sakash.bagdia@arm.com        .desc("Transmit Bandwidth (bits/s)")
2539827Sakash.bagdia@arm.com        .precision(0)
2549827Sakash.bagdia@arm.com        .prereq(txBytes)
2559827Sakash.bagdia@arm.com        ;
2569793Sakash.bagdia@arm.com
2579793Sakash.bagdia@arm.com    rxBandwidth
2589793Sakash.bagdia@arm.com        .name(name() + ".rxBandwidth")
2599384SAndreas.Sandberg@arm.com        .desc("Receive Bandwidth (bits/s)")
2608863Snilay@cs.wisc.edu        .precision(0)
2617876Sgblack@eecs.umich.edu        .prereq(rxBytes)
2624968Sacolyte@umich.edu        ;
2638926Sandreas.hansson@arm.com
2644837Ssaidi@eecs.umich.edu    txPacketRate
2654837Ssaidi@eecs.umich.edu        .name(name() + ".txPPS")
2669408Sandreas.hansson@arm.com        .desc("Packet Tranmission Rate (packets/s)")
2679653SAndreas.Sandberg@ARM.com        .precision(0)
2689653SAndreas.Sandberg@ARM.com        .prereq(txBytes)
2699653SAndreas.Sandberg@ARM.com        ;
2709164Sandreas.hansson@arm.com
2719408Sandreas.hansson@arm.com    rxPacketRate
2728845Sandreas.hansson@arm.com        .name(name() + ".rxPPS")
2738845Sandreas.hansson@arm.com        .desc("Packet Reception Rate (packets/s)")
2744837Ssaidi@eecs.umich.edu        .precision(0)
2759826Sandreas.hansson@arm.com        .prereq(rxBytes)
2769826Sandreas.hansson@arm.com        ;
2779835Sandreas.hansson@arm.com
2789826Sandreas.hansson@arm.com    txBandwidth = txBytes * Stats::constant(8) / simSeconds;
2799826Sandreas.hansson@arm.com    rxBandwidth = rxBytes * Stats::constant(8) / simSeconds;
2809826Sandreas.hansson@arm.com    txPacketRate = txPackets / simSeconds;
2819826Sandreas.hansson@arm.com    rxPacketRate = rxPackets / simSeconds;
2828659SAli.Saidi@ARM.com}
28310119Snilay@cs.wisc.edu
28410119Snilay@cs.wisc.edu/**
28510119Snilay@cs.wisc.edu * This is to read the PCI general configuration registers
28610119Snilay@cs.wisc.edu */
28710119Snilay@cs.wisc.eduvoid
28810119Snilay@cs.wisc.eduNSGigE::ReadConfig(int offset, int size, uint8_t *data)
28910119Snilay@cs.wisc.edu{
29010119Snilay@cs.wisc.edu    if (offset < PCI_DEVICE_SPECIFIC)
29110119Snilay@cs.wisc.edu        PciDev::ReadConfig(offset, size, data);
29210119Snilay@cs.wisc.edu    else
29310119Snilay@cs.wisc.edu        panic("Device specific PCI config space not implemented!\n");
29410119Snilay@cs.wisc.edu}
29510119Snilay@cs.wisc.edu
29610119Snilay@cs.wisc.edu/**
29710119Snilay@cs.wisc.edu * This is to write to the PCI general configuration registers
29810119Snilay@cs.wisc.edu */
29910119Snilay@cs.wisc.eduvoid
30010119Snilay@cs.wisc.eduNSGigE::WriteConfig(int offset, int size, uint32_t data)
30110119Snilay@cs.wisc.edu{
30210119Snilay@cs.wisc.edu    if (offset < PCI_DEVICE_SPECIFIC)
30310119Snilay@cs.wisc.edu        PciDev::WriteConfig(offset, size, data);
30410119Snilay@cs.wisc.edu    else
30510119Snilay@cs.wisc.edu        panic("Device specific PCI config space not implemented!\n");
30610119Snilay@cs.wisc.edu
30710119Snilay@cs.wisc.edu    // Need to catch writes to BARs to update the PIO interface
30810119Snilay@cs.wisc.edu    switch (offset) {
30910119Snilay@cs.wisc.edu        // seems to work fine without all these PCI settings, but i
31010119Snilay@cs.wisc.edu        // put in the IO to double check, an assertion will fail if we
31110119Snilay@cs.wisc.edu        // need to properly implement it
31210119Snilay@cs.wisc.edu      case PCI_COMMAND:
31310119Snilay@cs.wisc.edu        if (config.data[offset] & PCI_CMD_IOSE)
31410119Snilay@cs.wisc.edu            ioEnable = true;
31510119Snilay@cs.wisc.edu        else
31610119Snilay@cs.wisc.edu            ioEnable = false;
31710119Snilay@cs.wisc.edu
31810119Snilay@cs.wisc.edu#if 0
31910119Snilay@cs.wisc.edu        if (config.data[offset] & PCI_CMD_BME) {
32010119Snilay@cs.wisc.edu            bmEnabled = true;
32110119Snilay@cs.wisc.edu        }
32210119Snilay@cs.wisc.edu        else {
32310119Snilay@cs.wisc.edu            bmEnabled = false;
32410119Snilay@cs.wisc.edu        }
32510119Snilay@cs.wisc.edu
3268801Sgblack@eecs.umich.edu        if (config.data[offset] & PCI_CMD_MSE) {
3273005Sstever@eecs.umich.edu            memEnable = true;
3288801Sgblack@eecs.umich.edu        }
3293005Sstever@eecs.umich.edu        else {
3303005Sstever@eecs.umich.edu            memEnable = false;
3313005Sstever@eecs.umich.edu        }
3322566SN/A#endif
3337861Sgblack@eecs.umich.edu        break;
3347861Sgblack@eecs.umich.edu
3357861Sgblack@eecs.umich.edu      case PCI0_BASE_ADDR0:
3368635Schris.emmons@arm.com        if (BARAddrs[0] != 0) {
3378635Schris.emmons@arm.com            if (pioInterface)
3388635Schris.emmons@arm.com                pioInterface->addAddrRange(BARAddrs[0],
3399061Snilay@cs.wisc.edu                                           BARAddrs[0] + BARSize[0] - 1);
3403481Shsul@eecs.umich.edu
341            BARAddrs[0] &= PA_UNCACHED_MASK;
342        }
343        break;
344      case PCI0_BASE_ADDR1:
345        if (BARAddrs[1] != 0) {
346            if (pioInterface)
347                pioInterface->addAddrRange(BARAddrs[1],
348                                           BARAddrs[1] + BARSize[1] - 1);
349
350            BARAddrs[1] &= PA_UNCACHED_MASK;
351        }
352        break;
353    }
354}
355
356/**
357 * This reads the device registers, which are detailed in the NS83820
358 * spec sheet
359 */
360Fault
361NSGigE::read(MemReqPtr &req, uint8_t *data)
362{
363    assert(ioEnable);
364
365    //The mask is to give you only the offset into the device register file
366    Addr daddr = req->paddr & 0xfff;
367    DPRINTF(EthernetPIO, "read  da=%#x pa=%#x va=%#x size=%d\n",
368            daddr, req->paddr, req->vaddr, req->size);
369
370
371    // there are some reserved registers, you can see ns_gige_reg.h and
372    // the spec sheet for details
373    if (daddr > LAST && daddr <=  RESERVED) {
374        panic("Accessing reserved register");
375    } else if (daddr > RESERVED && daddr <= 0x3FC) {
376        ReadConfig(daddr & 0xff, req->size, data);
377        return No_Fault;
378    } else if (daddr >= MIB_START && daddr <= MIB_END) {
379        // don't implement all the MIB's.  hopefully the kernel
380        // doesn't actually DEPEND upon their values
381        // MIB are just hardware stats keepers
382        uint32_t &reg = *(uint32_t *) data;
383        reg = 0;
384        return No_Fault;
385    } else if (daddr > 0x3FC)
386        panic("Something is messed up!\n");
387
388    switch (req->size) {
389      case sizeof(uint32_t):
390        {
391            uint32_t &reg = *(uint32_t *)data;
392
393            switch (daddr) {
394              case CR:
395                reg = regs.command;
396                //these are supposed to be cleared on a read
397                reg &= ~(CR_RXD | CR_TXD | CR_TXR | CR_RXR);
398                break;
399
400              case CFG:
401                reg = regs.config;
402                break;
403
404              case MEAR:
405                reg = regs.mear;
406                break;
407
408              case PTSCR:
409                reg = regs.ptscr;
410                break;
411
412              case ISR:
413                reg = regs.isr;
414                devIntrClear(ISR_ALL);
415                break;
416
417              case IMR:
418                reg = regs.imr;
419                break;
420
421              case IER:
422                reg = regs.ier;
423                break;
424
425              case IHR:
426                reg = regs.ihr;
427                break;
428
429              case TXDP:
430                reg = regs.txdp;
431                break;
432
433              case TXDP_HI:
434                reg = regs.txdp_hi;
435                break;
436
437              case TXCFG:
438                reg = regs.txcfg;
439                break;
440
441              case GPIOR:
442                reg = regs.gpior;
443                break;
444
445              case RXDP:
446                reg = regs.rxdp;
447                break;
448
449              case RXDP_HI:
450                reg = regs.rxdp_hi;
451                break;
452
453              case RXCFG:
454                reg = regs.rxcfg;
455                break;
456
457              case PQCR:
458                reg = regs.pqcr;
459                break;
460
461              case WCSR:
462                reg = regs.wcsr;
463                break;
464
465              case PCR:
466                reg = regs.pcr;
467                break;
468
469                // see the spec sheet for how RFCR and RFDR work
470                // basically, you write to RFCR to tell the machine
471                // what you want to do next, then you act upon RFDR,
472                // and the device will be prepared b/c of what you
473                // wrote to RFCR
474              case RFCR:
475                reg = regs.rfcr;
476                break;
477
478              case RFDR:
479                switch (regs.rfcr & RFCR_RFADDR) {
480                  case 0x000:
481                    reg = rom.perfectMatch[1];
482                    reg = reg << 8;
483                    reg += rom.perfectMatch[0];
484                    break;
485                  case 0x002:
486                    reg = rom.perfectMatch[3] << 8;
487                    reg += rom.perfectMatch[2];
488                    break;
489                  case 0x004:
490                    reg = rom.perfectMatch[5] << 8;
491                    reg += rom.perfectMatch[4];
492                    break;
493                  default:
494                    panic("reading RFDR for something other than PMATCH!\n");
495                    // didn't implement other RFDR functionality b/c
496                    // driver didn't use it
497                }
498                break;
499
500              case SRR:
501                reg = regs.srr;
502                break;
503
504              case MIBC:
505                reg = regs.mibc;
506                reg &= ~(MIBC_MIBS | MIBC_ACLR);
507                break;
508
509              case VRCR:
510                reg = regs.vrcr;
511                break;
512
513              case VTCR:
514                reg = regs.vtcr;
515                break;
516
517              case VDR:
518                reg = regs.vdr;
519                break;
520
521              case CCSR:
522                reg = regs.ccsr;
523                break;
524
525              case TBICR:
526                reg = regs.tbicr;
527                break;
528
529              case TBISR:
530                reg = regs.tbisr;
531                break;
532
533              case TANAR:
534                reg = regs.tanar;
535                break;
536
537              case TANLPAR:
538                reg = regs.tanlpar;
539                break;
540
541              case TANER:
542                reg = regs.taner;
543                break;
544
545              case TESR:
546                reg = regs.tesr;
547                break;
548
549              default:
550                panic("reading unimplemented register: addr=%#x", daddr);
551            }
552
553            DPRINTF(EthernetPIO, "read from %#x: data=%d data=%#x\n",
554                    daddr, reg, reg);
555        }
556        break;
557
558      default:
559        panic("accessing register with invalid size: addr=%#x, size=%d",
560              daddr, req->size);
561    }
562
563    return No_Fault;
564}
565
566Fault
567NSGigE::write(MemReqPtr &req, const uint8_t *data)
568{
569    assert(ioEnable);
570
571    Addr daddr = req->paddr & 0xfff;
572    DPRINTF(EthernetPIO, "write da=%#x pa=%#x va=%#x size=%d\n",
573            daddr, req->paddr, req->vaddr, req->size);
574
575    if (daddr > LAST && daddr <=  RESERVED) {
576        panic("Accessing reserved register");
577    } else if (daddr > RESERVED && daddr <= 0x3FC) {
578        WriteConfig(daddr & 0xff, req->size, *(uint32_t *)data);
579        return No_Fault;
580    } else if (daddr > 0x3FC)
581        panic("Something is messed up!\n");
582
583    if (req->size == sizeof(uint32_t)) {
584        uint32_t reg = *(uint32_t *)data;
585        DPRINTF(EthernetPIO, "write data=%d data=%#x\n", reg, reg);
586
587        switch (daddr) {
588          case CR:
589            regs.command = reg;
590            if (reg & CR_TXD) {
591                txEnable = false;
592            } else if (reg & CR_TXE) {
593                txEnable = true;
594
595                // the kernel is enabling the transmit machine
596                if (txState == txIdle)
597                    txKick();
598            }
599
600            if (reg & CR_RXD) {
601                rxEnable = false;
602            } else if (reg & CR_RXE) {
603                rxEnable = true;
604
605                if (rxState == rxIdle)
606                    rxKick();
607            }
608
609            if (reg & CR_TXR)
610                txReset();
611
612            if (reg & CR_RXR)
613                rxReset();
614
615            if (reg & CR_SWI)
616                devIntrPost(ISR_SWI);
617
618            if (reg & CR_RST) {
619                txReset();
620                rxReset();
621
622                regsReset();
623            }
624            break;
625
626          case CFG:
627            if (reg & CFG_LNKSTS ||
628                reg & CFG_SPDSTS ||
629                reg & CFG_DUPSTS ||
630                reg & CFG_RESERVED ||
631                reg & CFG_T64ADDR ||
632                reg & CFG_PCI64_DET)
633                panic("writing to read-only or reserved CFG bits!\n");
634
635            regs.config |= reg & ~(CFG_LNKSTS | CFG_SPDSTS | CFG_DUPSTS |
636                                   CFG_RESERVED | CFG_T64ADDR | CFG_PCI64_DET);
637
638// all these #if 0's are because i don't THINK the kernel needs to
639// have these implemented. if there is a problem relating to one of
640// these, you may need to add functionality in.
641#if 0
642            if (reg & CFG_TBI_EN) ;
643            if (reg & CFG_MODE_1000) ;
644#endif
645
646            if (reg & CFG_AUTO_1000)
647                panic("CFG_AUTO_1000 not implemented!\n");
648
649#if 0
650            if (reg & CFG_PINT_DUPSTS ||
651                reg & CFG_PINT_LNKSTS ||
652                reg & CFG_PINT_SPDSTS)
653                ;
654
655            if (reg & CFG_TMRTEST) ;
656            if (reg & CFG_MRM_DIS) ;
657            if (reg & CFG_MWI_DIS) ;
658
659            if (reg & CFG_T64ADDR)
660                panic("CFG_T64ADDR is read only register!\n");
661
662            if (reg & CFG_PCI64_DET)
663                panic("CFG_PCI64_DET is read only register!\n");
664
665            if (reg & CFG_DATA64_EN) ;
666            if (reg & CFG_M64ADDR) ;
667            if (reg & CFG_PHY_RST) ;
668            if (reg & CFG_PHY_DIS) ;
669#endif
670
671            if (reg & CFG_EXTSTS_EN)
672                extstsEnable = true;
673            else
674                extstsEnable = false;
675
676#if 0
677              if (reg & CFG_REQALG) ;
678              if (reg & CFG_SB) ;
679              if (reg & CFG_POW) ;
680              if (reg & CFG_EXD) ;
681              if (reg & CFG_PESEL) ;
682              if (reg & CFG_BROM_DIS) ;
683              if (reg & CFG_EXT_125) ;
684              if (reg & CFG_BEM) ;
685#endif
686            break;
687
688          case MEAR:
689            regs.mear = reg;
690            // since phy is completely faked, MEAR_MD* don't matter
691            // and since the driver never uses MEAR_EE*, they don't
692            // matter
693#if 0
694            if (reg & MEAR_EEDI) ;
695            if (reg & MEAR_EEDO) ; // this one is read only
696            if (reg & MEAR_EECLK) ;
697            if (reg & MEAR_EESEL) ;
698            if (reg & MEAR_MDIO) ;
699            if (reg & MEAR_MDDIR) ;
700            if (reg & MEAR_MDC) ;
701#endif
702            break;
703
704          case PTSCR:
705            regs.ptscr = reg & ~(PTSCR_RBIST_RDONLY);
706            // these control BISTs for various parts of chip - we
707            // don't care or do just fake that the BIST is done
708            if (reg & PTSCR_RBIST_EN)
709                regs.ptscr |= PTSCR_RBIST_DONE;
710            if (reg & PTSCR_EEBIST_EN)
711                regs.ptscr &= ~PTSCR_EEBIST_EN;
712            if (reg & PTSCR_EELOAD_EN)
713                regs.ptscr &= ~PTSCR_EELOAD_EN;
714            break;
715
716          case ISR: /* writing to the ISR has no effect */
717            panic("ISR is a read only register!\n");
718
719          case IMR:
720            regs.imr = reg;
721            devIntrChangeMask();
722            break;
723
724          case IER:
725            regs.ier = reg;
726            break;
727
728          case IHR:
729            regs.ihr = reg;
730            /* not going to implement real interrupt holdoff */
731            break;
732
733          case TXDP:
734            regs.txdp = (reg & 0xFFFFFFFC);
735            assert(txState == txIdle);
736            CTDD = false;
737            break;
738
739          case TXDP_HI:
740            regs.txdp_hi = reg;
741            break;
742
743          case TXCFG:
744            regs.txcfg = reg;
745#if 0
746            if (reg & TXCFG_CSI) ;
747            if (reg & TXCFG_HBI) ;
748            if (reg & TXCFG_MLB) ;
749            if (reg & TXCFG_ATP) ;
750            if (reg & TXCFG_ECRETRY) {
751                /*
752                 * this could easily be implemented, but considering
753                 * the network is just a fake pipe, wouldn't make
754                 * sense to do this
755                 */
756            }
757
758            if (reg & TXCFG_BRST_DIS) ;
759#endif
760
761#if 0
762            /* we handle our own DMA, ignore the kernel's exhortations */
763            if (reg & TXCFG_MXDMA) ;
764#endif
765
766            // also, we currently don't care about fill/drain
767            // thresholds though this may change in the future with
768            // more realistic networks or a driver which changes it
769            // according to feedback
770
771            break;
772
773          case GPIOR:
774            regs.gpior = reg;
775            /* these just control general purpose i/o pins, don't matter */
776            break;
777
778          case RXDP:
779            regs.rxdp = reg;
780            CRDD = false;
781            break;
782
783          case RXDP_HI:
784            regs.rxdp_hi = reg;
785            break;
786
787          case RXCFG:
788            regs.rxcfg = reg;
789#if 0
790            if (reg & RXCFG_AEP) ;
791            if (reg & RXCFG_ARP) ;
792            if (reg & RXCFG_STRIPCRC) ;
793            if (reg & RXCFG_RX_RD) ;
794            if (reg & RXCFG_ALP) ;
795            if (reg & RXCFG_AIRL) ;
796
797            /* we handle our own DMA, ignore what kernel says about it */
798            if (reg & RXCFG_MXDMA) ;
799
800            //also, we currently don't care about fill/drain thresholds
801            //though this may change in the future with more realistic
802            //networks or a driver which changes it according to feedback
803            if (reg & (RXCFG_DRTH | RXCFG_DRTH0)) ;
804#endif
805            break;
806
807          case PQCR:
808            /* there is no priority queueing used in the linux 2.6 driver */
809            regs.pqcr = reg;
810            break;
811
812          case WCSR:
813            /* not going to implement wake on LAN */
814            regs.wcsr = reg;
815            break;
816
817          case PCR:
818            /* not going to implement pause control */
819            regs.pcr = reg;
820            break;
821
822          case RFCR:
823            regs.rfcr = reg;
824
825            rxFilterEnable = (reg & RFCR_RFEN) ? true : false;
826            acceptBroadcast = (reg & RFCR_AAB) ? true : false;
827            acceptMulticast = (reg & RFCR_AAM) ? true : false;
828            acceptUnicast = (reg & RFCR_AAU) ? true : false;
829            acceptPerfect = (reg & RFCR_APM) ? true : false;
830            acceptArp = (reg & RFCR_AARP) ? true : false;
831
832#if 0
833            if (reg & RFCR_APAT)
834                panic("RFCR_APAT not implemented!\n");
835#endif
836
837            if (reg & RFCR_MHEN || reg & RFCR_UHEN)
838                panic("hash filtering not implemented!\n");
839
840            if (reg & RFCR_ULM)
841                panic("RFCR_ULM not implemented!\n");
842
843            break;
844
845          case RFDR:
846            panic("the driver never writes to RFDR, something is wrong!\n");
847
848          case BRAR:
849            panic("the driver never uses BRAR, something is wrong!\n");
850
851          case BRDR:
852            panic("the driver never uses BRDR, something is wrong!\n");
853
854          case SRR:
855            panic("SRR is read only register!\n");
856
857          case MIBC:
858            panic("the driver never uses MIBC, something is wrong!\n");
859
860          case VRCR:
861            regs.vrcr = reg;
862            break;
863
864          case VTCR:
865            regs.vtcr = reg;
866            break;
867
868          case VDR:
869            panic("the driver never uses VDR, something is wrong!\n");
870            break;
871
872          case CCSR:
873            /* not going to implement clockrun stuff */
874            regs.ccsr = reg;
875            break;
876
877          case TBICR:
878            regs.tbicr = reg;
879            if (reg & TBICR_MR_LOOPBACK)
880                panic("TBICR_MR_LOOPBACK never used, something wrong!\n");
881
882            if (reg & TBICR_MR_AN_ENABLE) {
883                regs.tanlpar = regs.tanar;
884                regs.tbisr |= (TBISR_MR_AN_COMPLETE | TBISR_MR_LINK_STATUS);
885            }
886
887#if 0
888            if (reg & TBICR_MR_RESTART_AN) ;
889#endif
890
891            break;
892
893          case TBISR:
894            panic("TBISR is read only register!\n");
895
896          case TANAR:
897            regs.tanar = reg;
898            if (reg & TANAR_PS2)
899                panic("this isn't used in driver, something wrong!\n");
900
901            if (reg & TANAR_PS1)
902                panic("this isn't used in driver, something wrong!\n");
903            break;
904
905          case TANLPAR:
906            panic("this should only be written to by the fake phy!\n");
907
908          case TANER:
909            panic("TANER is read only register!\n");
910
911          case TESR:
912            regs.tesr = reg;
913            break;
914
915          default:
916            panic("invalid register access daddr=%#x", daddr);
917        }
918    } else {
919        panic("Invalid Request Size");
920    }
921
922    return No_Fault;
923}
924
925void
926NSGigE::devIntrPost(uint32_t interrupts)
927{
928    if (interrupts & ISR_RESERVE)
929        panic("Cannot set a reserved interrupt");
930
931    if (interrupts & ISR_NOIMPL)
932        warn("interrupt not implemented %#x\n", interrupts);
933
934    interrupts &= ~ISR_NOIMPL;
935    regs.isr |= interrupts;
936
937    DPRINTF(EthernetIntr,
938            "interrupt written to ISR: intr=%#x isr=%#x imr=%#x\n",
939            interrupts, regs.isr, regs.imr);
940
941    if ((regs.isr & regs.imr)) {
942        Tick when = curTick;
943        if (!(regs.isr & regs.imr & ISR_NODELAY))
944            when += intrDelay;
945        cpuIntrPost(when);
946    }
947}
948
949void
950NSGigE::devIntrClear(uint32_t interrupts)
951{
952    if (interrupts & ISR_RESERVE)
953        panic("Cannot clear a reserved interrupt");
954
955    interrupts &= ~ISR_NOIMPL;
956    regs.isr &= ~interrupts;
957
958    DPRINTF(EthernetIntr,
959            "interrupt cleared from ISR: intr=%x isr=%x imr=%x\n",
960            interrupts, regs.isr, regs.imr);
961
962    if (!(regs.isr & regs.imr))
963        cpuIntrClear();
964}
965
966void
967NSGigE::devIntrChangeMask()
968{
969    DPRINTF(EthernetIntr, "interrupt mask changed: isr=%x imr=%x masked=%x\n",
970            regs.isr, regs.imr, regs.isr & regs.imr);
971
972    if (regs.isr & regs.imr)
973        cpuIntrPost(curTick);
974    else
975        cpuIntrClear();
976}
977
978void
979NSGigE::cpuIntrPost(Tick when)
980{
981    // If the interrupt you want to post is later than an interrupt
982    // already scheduled, just let it post in the coming one and don't
983    // schedule another.
984    // HOWEVER, must be sure that the scheduled intrTick is in the
985    // future (this was formerly the source of a bug)
986    /**
987     * @todo this warning should be removed and the intrTick code should
988     * be fixed.
989     */
990    assert(when >= curTick);
991    assert(intrTick >= curTick || intrTick == 0);
992    if (when > intrTick && intrTick != 0) {
993        DPRINTF(EthernetIntr, "don't need to schedule event...intrTick=%d\n",
994                intrTick);
995        return;
996    }
997
998    intrTick = when;
999    if (intrTick < curTick) {
1000        debug_break();
1001        intrTick = curTick;
1002    }
1003
1004    DPRINTF(EthernetIntr, "going to schedule an interrupt for intrTick=%d\n",
1005            intrTick);
1006
1007    if (intrEvent)
1008        intrEvent->squash();
1009    intrEvent = new IntrEvent(this, true);
1010    intrEvent->schedule(intrTick);
1011}
1012
1013void
1014NSGigE::cpuInterrupt()
1015{
1016    assert(intrTick == curTick);
1017
1018    // Whether or not there's a pending interrupt, we don't care about
1019    // it anymore
1020    intrEvent = 0;
1021    intrTick = 0;
1022
1023    // Don't send an interrupt if there's already one
1024    if (cpuPendingIntr) {
1025        DPRINTF(EthernetIntr,
1026                "would send an interrupt now, but there's already pending\n");
1027    } else {
1028        // Send interrupt
1029        cpuPendingIntr = true;
1030
1031        DPRINTF(EthernetIntr, "posting cchip interrupt\n");
1032        tsunami->cchip->postDRIR(configData->config.hdr.pci0.interruptLine);
1033    }
1034}
1035
1036void
1037NSGigE::cpuIntrClear()
1038{
1039    if (!cpuPendingIntr)
1040        return;
1041
1042    if (intrEvent) {
1043        intrEvent->squash();
1044        intrEvent = 0;
1045    }
1046
1047    intrTick = 0;
1048
1049    cpuPendingIntr = false;
1050
1051    DPRINTF(EthernetIntr, "clearing cchip interrupt\n");
1052    tsunami->cchip->clearDRIR(configData->config.hdr.pci0.interruptLine);
1053}
1054
1055bool
1056NSGigE::cpuIntrPending() const
1057{ return cpuPendingIntr; }
1058
1059void
1060NSGigE::txReset()
1061{
1062
1063    DPRINTF(Ethernet, "transmit reset\n");
1064
1065    CTDD = false;
1066    txFifoAvail = maxTxFifoSize;
1067    txEnable = false;;
1068    txFragPtr = 0;
1069    assert(txDescCnt == 0);
1070    txFifo.clear();
1071    txState = txIdle;
1072    assert(txDmaState == dmaIdle);
1073}
1074
1075void
1076NSGigE::rxReset()
1077{
1078    DPRINTF(Ethernet, "receive reset\n");
1079
1080    CRDD = false;
1081    assert(rxPktBytes == 0);
1082    rxFifoCnt = 0;
1083    rxEnable = false;
1084    rxFragPtr = 0;
1085    assert(rxDescCnt == 0);
1086    assert(rxDmaState == dmaIdle);
1087    rxFifo.clear();
1088    rxState = rxIdle;
1089}
1090
1091void
1092NSGigE::regsReset()
1093{
1094    memset(&regs, 0, sizeof(regs));
1095    regs.config = CFG_LNKSTS;
1096    regs.mear = MEAR_MDDIR | MEAR_EEDO;
1097    regs.txcfg = 0x120; // set drain threshold to 1024 bytes and
1098                        // fill threshold to 32 bytes
1099    regs.rxcfg = 0x4;   // set drain threshold to 16 bytes
1100    regs.srr = 0x0103;  // set the silicon revision to rev B or 0x103
1101    regs.mibc = MIBC_FRZ;
1102    regs.vdr = 0x81;    // set the vlan tag type to 802.1q
1103    regs.tesr = 0xc000; // TBI capable of both full and half duplex
1104
1105    extstsEnable = false;
1106    acceptBroadcast = false;
1107    acceptMulticast = false;
1108    acceptUnicast = false;
1109    acceptPerfect = false;
1110    acceptArp = false;
1111}
1112
1113void
1114NSGigE::rxDmaReadCopy()
1115{
1116    assert(rxDmaState == dmaReading);
1117
1118    physmem->dma_read((uint8_t *)rxDmaData, rxDmaAddr, rxDmaLen);
1119    rxDmaState = dmaIdle;
1120
1121    DPRINTF(EthernetDMA, "rx dma read  paddr=%#x len=%d\n",
1122            rxDmaAddr, rxDmaLen);
1123    DDUMP(EthernetDMA, rxDmaData, rxDmaLen);
1124}
1125
1126bool
1127NSGigE::doRxDmaRead()
1128{
1129    assert(rxDmaState == dmaIdle || rxDmaState == dmaReadWaiting);
1130    rxDmaState = dmaReading;
1131
1132    if (dmaInterface && !rxDmaFree) {
1133        if (dmaInterface->busy())
1134            rxDmaState = dmaReadWaiting;
1135        else
1136            dmaInterface->doDMA(Read, rxDmaAddr, rxDmaLen, curTick,
1137                                &rxDmaReadEvent, true);
1138        return true;
1139    }
1140
1141    if (dmaReadDelay == 0 && dmaReadFactor == 0) {
1142        rxDmaReadCopy();
1143        return false;
1144    }
1145
1146    Tick factor = ((rxDmaLen + ULL(63)) >> ULL(6)) * dmaReadFactor;
1147    Tick start = curTick + dmaReadDelay + factor;
1148    rxDmaReadEvent.schedule(start);
1149    return true;
1150}
1151
1152void
1153NSGigE::rxDmaReadDone()
1154{
1155    assert(rxDmaState == dmaReading);
1156    rxDmaReadCopy();
1157
1158    // If the transmit state machine has a pending DMA, let it go first
1159    if (txDmaState == dmaReadWaiting || txDmaState == dmaWriteWaiting)
1160        txKick();
1161
1162    rxKick();
1163}
1164
1165void
1166NSGigE::rxDmaWriteCopy()
1167{
1168    assert(rxDmaState == dmaWriting);
1169
1170    physmem->dma_write(rxDmaAddr, (uint8_t *)rxDmaData, rxDmaLen);
1171    rxDmaState = dmaIdle;
1172
1173    DPRINTF(EthernetDMA, "rx dma write paddr=%#x len=%d\n",
1174            rxDmaAddr, rxDmaLen);
1175    DDUMP(EthernetDMA, rxDmaData, rxDmaLen);
1176}
1177
1178bool
1179NSGigE::doRxDmaWrite()
1180{
1181    assert(rxDmaState == dmaIdle || rxDmaState == dmaWriteWaiting);
1182    rxDmaState = dmaWriting;
1183
1184    if (dmaInterface && !rxDmaFree) {
1185        if (dmaInterface->busy())
1186            rxDmaState = dmaWriteWaiting;
1187        else
1188            dmaInterface->doDMA(WriteInvalidate, rxDmaAddr, rxDmaLen, curTick,
1189                                &rxDmaWriteEvent, true);
1190        return true;
1191    }
1192
1193    if (dmaWriteDelay == 0 && dmaWriteFactor == 0) {
1194        rxDmaWriteCopy();
1195        return false;
1196    }
1197
1198    Tick factor = ((rxDmaLen + ULL(63)) >> ULL(6)) * dmaWriteFactor;
1199    Tick start = curTick + dmaWriteDelay + factor;
1200    rxDmaWriteEvent.schedule(start);
1201    return true;
1202}
1203
1204void
1205NSGigE::rxDmaWriteDone()
1206{
1207    assert(rxDmaState == dmaWriting);
1208    rxDmaWriteCopy();
1209
1210    // If the transmit state machine has a pending DMA, let it go first
1211    if (txDmaState == dmaReadWaiting || txDmaState == dmaWriteWaiting)
1212        txKick();
1213
1214    rxKick();
1215}
1216
1217void
1218NSGigE::rxKick()
1219{
1220    DPRINTF(EthernetSM, "receive kick rxState=%s (rxBuf.size=%d)\n",
1221            NsRxStateStrings[rxState], rxFifo.size());
1222
1223    if (rxKickTick > curTick) {
1224        DPRINTF(EthernetSM, "receive kick exiting, can't run till %d\n",
1225                rxKickTick);
1226        return;
1227    }
1228
1229  next:
1230    switch(rxDmaState) {
1231      case dmaReadWaiting:
1232        if (doRxDmaRead())
1233            goto exit;
1234        break;
1235      case dmaWriteWaiting:
1236        if (doRxDmaWrite())
1237            goto exit;
1238        break;
1239      default:
1240        break;
1241    }
1242
1243    // see state machine from spec for details
1244    // the way this works is, if you finish work on one state and can
1245    // go directly to another, you do that through jumping to the
1246    // label "next".  however, if you have intermediate work, like DMA
1247    // so that you can't go to the next state yet, you go to exit and
1248    // exit the loop.  however, when the DMA is done it will trigger
1249    // an event and come back to this loop.
1250    switch (rxState) {
1251      case rxIdle:
1252        if (!rxEnable) {
1253            DPRINTF(EthernetSM, "Receive Disabled! Nothing to do.\n");
1254            goto exit;
1255        }
1256
1257        if (CRDD) {
1258            rxState = rxDescRefr;
1259
1260            rxDmaAddr = regs.rxdp & 0x3fffffff;
1261            rxDmaData = &rxDescCache + offsetof(ns_desc, link);
1262            rxDmaLen = sizeof(rxDescCache.link);
1263            rxDmaFree = dmaDescFree;
1264
1265            descDmaReads++;
1266            descDmaRdBytes += rxDmaLen;
1267
1268            if (doRxDmaRead())
1269                goto exit;
1270        } else {
1271            rxState = rxDescRead;
1272
1273            rxDmaAddr = regs.rxdp & 0x3fffffff;
1274            rxDmaData = &rxDescCache;
1275            rxDmaLen = sizeof(ns_desc);
1276            rxDmaFree = dmaDescFree;
1277
1278            descDmaReads++;
1279            descDmaRdBytes += rxDmaLen;
1280
1281            if (doRxDmaRead())
1282                goto exit;
1283        }
1284        break;
1285
1286      case rxDescRefr:
1287        if (rxDmaState != dmaIdle)
1288            goto exit;
1289
1290        rxState = rxAdvance;
1291        break;
1292
1293     case rxDescRead:
1294        if (rxDmaState != dmaIdle)
1295            goto exit;
1296
1297        DPRINTF(EthernetDesc,
1298                "rxDescCache: addr=%08x read descriptor\n",
1299                regs.rxdp & 0x3fffffff);
1300        DPRINTF(EthernetDesc,
1301                "rxDescCache: link=%08x bufptr=%08x cmdsts=%08x extsts=%08x\n",
1302                rxDescCache.link, rxDescCache.bufptr, rxDescCache.cmdsts,
1303                rxDescCache.extsts);
1304
1305        if (rxDescCache.cmdsts & CMDSTS_OWN) {
1306            devIntrPost(ISR_RXIDLE);
1307            rxState = rxIdle;
1308            goto exit;
1309        } else {
1310            rxState = rxFifoBlock;
1311            rxFragPtr = rxDescCache.bufptr;
1312            rxDescCnt = rxDescCache.cmdsts & CMDSTS_LEN_MASK;
1313        }
1314        break;
1315
1316      case rxFifoBlock:
1317        if (!rxPacket) {
1318            /**
1319             * @todo in reality, we should be able to start processing
1320             * the packet as it arrives, and not have to wait for the
1321             * full packet ot be in the receive fifo.
1322             */
1323            if (rxFifo.empty())
1324                goto exit;
1325
1326            DPRINTF(EthernetSM, "****processing receive of new packet****\n");
1327
1328            // If we don't have a packet, grab a new one from the fifo.
1329            rxPacket = rxFifo.front();
1330            rxPktBytes = rxPacket->length;
1331            rxPacketBufPtr = rxPacket->data;
1332
1333#if TRACING_ON
1334            if (DTRACE(Ethernet)) {
1335                if (rxPacket->isIpPkt()) {
1336                    ip_header *ip = rxPacket->getIpHdr();
1337                    DPRINTF(Ethernet, "ID is %d\n", reverseEnd16(ip->ID));
1338                    if (rxPacket->isTcpPkt()) {
1339                        tcp_header *tcp = rxPacket->getTcpHdr(ip);
1340                        DPRINTF(Ethernet, "Src Port=%d, Dest Port=%d\n",
1341                                reverseEnd16(tcp->src_port_num),
1342                                reverseEnd16(tcp->dest_port_num));
1343                    }
1344                }
1345            }
1346#endif
1347
1348            // sanity check - i think the driver behaves like this
1349            assert(rxDescCnt >= rxPktBytes);
1350
1351            // Must clear the value before popping to decrement the
1352            // reference count
1353            rxFifo.front() = NULL;
1354            rxFifo.pop_front();
1355            rxFifoCnt -= rxPacket->length;
1356        }
1357
1358
1359        // dont' need the && rxDescCnt > 0 if driver sanity check
1360        // above holds
1361        if (rxPktBytes > 0) {
1362            rxState = rxFragWrite;
1363            // don't need min<>(rxPktBytes,rxDescCnt) if above sanity
1364            // check holds
1365            rxXferLen = rxPktBytes;
1366
1367            rxDmaAddr = rxFragPtr & 0x3fffffff;
1368            rxDmaData = rxPacketBufPtr;
1369            rxDmaLen = rxXferLen;
1370            rxDmaFree = dmaDataFree;
1371
1372            if (doRxDmaWrite())
1373                goto exit;
1374
1375        } else {
1376            rxState = rxDescWrite;
1377
1378            //if (rxPktBytes == 0) {  /* packet is done */
1379            assert(rxPktBytes == 0);
1380            DPRINTF(EthernetSM, "done with receiving packet\n");
1381
1382            rxDescCache.cmdsts |= CMDSTS_OWN;
1383            rxDescCache.cmdsts &= ~CMDSTS_MORE;
1384            rxDescCache.cmdsts |= CMDSTS_OK;
1385            rxDescCache.cmdsts &= 0xffff0000;
1386            rxDescCache.cmdsts += rxPacket->length;   //i.e. set CMDSTS_SIZE
1387
1388#if 0
1389            /*
1390             * all the driver uses these are for its own stats keeping
1391             * which we don't care about, aren't necessary for
1392             * functionality and doing this would just slow us down.
1393             * if they end up using this in a later version for
1394             * functional purposes, just undef
1395             */
1396            if (rxFilterEnable) {
1397                rxDescCache.cmdsts &= ~CMDSTS_DEST_MASK;
1398                if (rxFifo.front()->IsUnicast())
1399                    rxDescCache.cmdsts |= CMDSTS_DEST_SELF;
1400                if (rxFifo.front()->IsMulticast())
1401                    rxDescCache.cmdsts |= CMDSTS_DEST_MULTI;
1402                if (rxFifo.front()->IsBroadcast())
1403                    rxDescCache.cmdsts |= CMDSTS_DEST_MASK;
1404            }
1405#endif
1406
1407            if (rxPacket->isIpPkt() && extstsEnable) {
1408                rxDescCache.extsts |= EXTSTS_IPPKT;
1409                rxIPChecksums++;
1410                if (!ipChecksum(rxPacket, false)) {
1411                    DPRINTF(EthernetCksum, "Rx IP Checksum Error\n");
1412                    rxDescCache.extsts |= EXTSTS_IPERR;
1413                }
1414                if (rxPacket->isTcpPkt()) {
1415                    rxDescCache.extsts |= EXTSTS_TCPPKT;
1416                    rxTCPChecksums++;
1417                    if (!tcpChecksum(rxPacket, false)) {
1418                        DPRINTF(EthernetCksum, "Rx TCP Checksum Error\n");
1419                        rxDescCache.extsts |= EXTSTS_TCPERR;
1420
1421                    }
1422                } else if (rxPacket->isUdpPkt()) {
1423                    rxDescCache.extsts |= EXTSTS_UDPPKT;
1424                    if (!udpChecksum(rxPacket, false)) {
1425                        DPRINTF(EthernetCksum, "Rx UDP Checksum Error\n");
1426                        rxDescCache.extsts |= EXTSTS_UDPERR;
1427                    }
1428                }
1429            }
1430            rxPacket = 0;
1431
1432            /*
1433             * the driver seems to always receive into desc buffers
1434             * of size 1514, so you never have a pkt that is split
1435             * into multiple descriptors on the receive side, so
1436             * i don't implement that case, hence the assert above.
1437             */
1438
1439            DPRINTF(EthernetDesc,
1440                    "rxDescCache: addr=%08x writeback cmdsts extsts\n",
1441                    regs.rxdp & 0x3fffffff);
1442            DPRINTF(EthernetDesc,
1443                    "rxDescCache: link=%08x bufptr=%08x cmdsts=%08x extsts=%08x\n",
1444                    rxDescCache.link, rxDescCache.bufptr, rxDescCache.cmdsts,
1445                    rxDescCache.extsts);
1446
1447            rxDmaAddr = (regs.rxdp + offsetof(ns_desc, cmdsts)) & 0x3fffffff;
1448            rxDmaData = &(rxDescCache.cmdsts);
1449            rxDmaLen = sizeof(rxDescCache.cmdsts) + sizeof(rxDescCache.extsts);
1450            rxDmaFree = dmaDescFree;
1451
1452            descDmaWrites++;
1453            descDmaWrBytes += rxDmaLen;
1454
1455            if (doRxDmaWrite())
1456                goto exit;
1457        }
1458        break;
1459
1460      case rxFragWrite:
1461        if (rxDmaState != dmaIdle)
1462            goto exit;
1463
1464        rxPacketBufPtr += rxXferLen;
1465        rxFragPtr += rxXferLen;
1466        rxPktBytes -= rxXferLen;
1467
1468        rxState = rxFifoBlock;
1469        break;
1470
1471      case rxDescWrite:
1472        if (rxDmaState != dmaIdle)
1473            goto exit;
1474
1475        assert(rxDescCache.cmdsts & CMDSTS_OWN);
1476
1477        assert(rxPacket == 0);
1478        devIntrPost(ISR_RXOK);
1479
1480        if (rxDescCache.cmdsts & CMDSTS_INTR)
1481            devIntrPost(ISR_RXDESC);
1482
1483        if (!rxEnable) {
1484            DPRINTF(EthernetSM, "Halting the RX state machine\n");
1485            rxState = rxIdle;
1486            goto exit;
1487        } else
1488            rxState = rxAdvance;
1489        break;
1490
1491      case rxAdvance:
1492        if (rxDescCache.link == 0) {
1493            devIntrPost(ISR_RXIDLE);
1494            rxState = rxIdle;
1495            CRDD = true;
1496            goto exit;
1497        } else {
1498            rxState = rxDescRead;
1499            regs.rxdp = rxDescCache.link;
1500            CRDD = false;
1501
1502            rxDmaAddr = regs.rxdp & 0x3fffffff;
1503            rxDmaData = &rxDescCache;
1504            rxDmaLen = sizeof(ns_desc);
1505            rxDmaFree = dmaDescFree;
1506
1507            if (doRxDmaRead())
1508                goto exit;
1509        }
1510        break;
1511
1512      default:
1513        panic("Invalid rxState!");
1514    }
1515
1516    DPRINTF(EthernetSM, "entering next rxState=%s\n",
1517            NsRxStateStrings[rxState]);
1518
1519    goto next;
1520
1521  exit:
1522    /**
1523     * @todo do we want to schedule a future kick?
1524     */
1525    DPRINTF(EthernetSM, "rx state machine exited rxState=%s\n",
1526            NsRxStateStrings[rxState]);
1527}
1528
1529void
1530NSGigE::transmit()
1531{
1532    if (txFifo.empty()) {
1533        DPRINTF(Ethernet, "nothing to transmit\n");
1534        return;
1535    }
1536
1537    DPRINTF(Ethernet, "Attempt Pkt Transmit: txFifo length=%d\n",
1538            maxTxFifoSize - txFifoAvail);
1539    if (interface->sendPacket(txFifo.front())) {
1540#if TRACING_ON
1541        if (DTRACE(Ethernet)) {
1542            if (txFifo.front()->isIpPkt()) {
1543                ip_header *ip = txFifo.front()->getIpHdr();
1544                DPRINTF(Ethernet, "ID is %d\n", reverseEnd16(ip->ID));
1545                if (txFifo.front()->isTcpPkt()) {
1546                    tcp_header *tcp = txFifo.front()->getTcpHdr(ip);
1547                    DPRINTF(Ethernet, "Src Port=%d, Dest Port=%d\n",
1548                            reverseEnd16(tcp->src_port_num),
1549                            reverseEnd16(tcp->dest_port_num));
1550                }
1551            }
1552        }
1553#endif
1554
1555        DDUMP(Ethernet, txFifo.front()->data, txFifo.front()->length);
1556        txBytes += txFifo.front()->length;
1557        txPackets++;
1558
1559        txFifoAvail += txFifo.front()->length;
1560
1561        DPRINTF(Ethernet, "Successful Xmit! now txFifoAvail is %d\n",
1562                txFifoAvail);
1563        txFifo.front() = NULL;
1564        txFifo.pop_front();
1565
1566        /*
1567         * normally do a writeback of the descriptor here, and ONLY
1568         * after that is done, send this interrupt.  but since our
1569         * stuff never actually fails, just do this interrupt here,
1570         * otherwise the code has to stray from this nice format.
1571         * besides, it's functionally the same.
1572         */
1573        devIntrPost(ISR_TXOK);
1574    } else {
1575        DPRINTF(Ethernet,
1576                "May need to rethink always sending the descriptors back?\n");
1577    }
1578
1579   if (!txFifo.empty() && !txEvent.scheduled()) {
1580       DPRINTF(Ethernet, "reschedule transmit\n");
1581       txEvent.schedule(curTick + 1000);
1582   }
1583}
1584
1585void
1586NSGigE::txDmaReadCopy()
1587{
1588    assert(txDmaState == dmaReading);
1589
1590    physmem->dma_read((uint8_t *)txDmaData, txDmaAddr, txDmaLen);
1591    txDmaState = dmaIdle;
1592
1593    DPRINTF(EthernetDMA, "tx dma read  paddr=%#x len=%d\n",
1594            txDmaAddr, txDmaLen);
1595    DDUMP(EthernetDMA, txDmaData, txDmaLen);
1596}
1597
1598bool
1599NSGigE::doTxDmaRead()
1600{
1601    assert(txDmaState == dmaIdle || txDmaState == dmaReadWaiting);
1602    txDmaState = dmaReading;
1603
1604    if (dmaInterface && !txDmaFree) {
1605        if (dmaInterface->busy())
1606            txDmaState = dmaReadWaiting;
1607        else
1608            dmaInterface->doDMA(Read, txDmaAddr, txDmaLen, curTick,
1609                                &txDmaReadEvent, true);
1610        return true;
1611    }
1612
1613    if (dmaReadDelay == 0 && dmaReadFactor == 0.0) {
1614        txDmaReadCopy();
1615        return false;
1616    }
1617
1618    Tick factor = ((txDmaLen + ULL(63)) >> ULL(6)) * dmaReadFactor;
1619    Tick start = curTick + dmaReadDelay + factor;
1620    txDmaReadEvent.schedule(start);
1621    return true;
1622}
1623
1624void
1625NSGigE::txDmaReadDone()
1626{
1627    assert(txDmaState == dmaReading);
1628    txDmaReadCopy();
1629
1630    // If the receive state machine  has a pending DMA, let it go first
1631    if (rxDmaState == dmaReadWaiting || rxDmaState == dmaWriteWaiting)
1632        rxKick();
1633
1634    txKick();
1635}
1636
1637void
1638NSGigE::txDmaWriteCopy()
1639{
1640    assert(txDmaState == dmaWriting);
1641
1642    physmem->dma_write(txDmaAddr, (uint8_t *)txDmaData, txDmaLen);
1643    txDmaState = dmaIdle;
1644
1645    DPRINTF(EthernetDMA, "tx dma write paddr=%#x len=%d\n",
1646            txDmaAddr, txDmaLen);
1647    DDUMP(EthernetDMA, txDmaData, txDmaLen);
1648}
1649
1650bool
1651NSGigE::doTxDmaWrite()
1652{
1653    assert(txDmaState == dmaIdle || txDmaState == dmaWriteWaiting);
1654    txDmaState = dmaWriting;
1655
1656    if (dmaInterface && !txDmaFree) {
1657        if (dmaInterface->busy())
1658            txDmaState = dmaWriteWaiting;
1659        else
1660            dmaInterface->doDMA(WriteInvalidate, txDmaAddr, txDmaLen, curTick,
1661                                &txDmaWriteEvent, true);
1662        return true;
1663    }
1664
1665    if (dmaWriteDelay == 0 && dmaWriteFactor == 0.0) {
1666        txDmaWriteCopy();
1667        return false;
1668    }
1669
1670    Tick factor = ((txDmaLen + ULL(63)) >> ULL(6)) * dmaWriteFactor;
1671    Tick start = curTick + dmaWriteDelay + factor;
1672    txDmaWriteEvent.schedule(start);
1673    return true;
1674}
1675
1676void
1677NSGigE::txDmaWriteDone()
1678{
1679    assert(txDmaState == dmaWriting);
1680    txDmaWriteCopy();
1681
1682    // If the receive state machine  has a pending DMA, let it go first
1683    if (rxDmaState == dmaReadWaiting || rxDmaState == dmaWriteWaiting)
1684        rxKick();
1685
1686    txKick();
1687}
1688
1689void
1690NSGigE::txKick()
1691{
1692    DPRINTF(EthernetSM, "transmit kick txState=%s\n",
1693            NsTxStateStrings[txState]);
1694
1695    if (txKickTick > curTick) {
1696        DPRINTF(EthernetSM, "transmit kick exiting, can't run till %d\n",
1697                txKickTick);
1698
1699        return;
1700    }
1701
1702  next:
1703    switch(txDmaState) {
1704      case dmaReadWaiting:
1705        if (doTxDmaRead())
1706            goto exit;
1707        break;
1708      case dmaWriteWaiting:
1709        if (doTxDmaWrite())
1710            goto exit;
1711        break;
1712      default:
1713        break;
1714    }
1715
1716    switch (txState) {
1717      case txIdle:
1718        if (!txEnable) {
1719            DPRINTF(EthernetSM, "Transmit disabled.  Nothing to do.\n");
1720            goto exit;
1721        }
1722
1723        if (CTDD) {
1724            txState = txDescRefr;
1725
1726            txDmaAddr = regs.txdp & 0x3fffffff;
1727            txDmaData = &txDescCache + offsetof(ns_desc, link);
1728            txDmaLen = sizeof(txDescCache.link);
1729            txDmaFree = dmaDescFree;
1730
1731            descDmaReads++;
1732            descDmaRdBytes += txDmaLen;
1733
1734            if (doTxDmaRead())
1735                goto exit;
1736
1737        } else {
1738            txState = txDescRead;
1739
1740            txDmaAddr = regs.txdp & 0x3fffffff;
1741            txDmaData = &txDescCache;
1742            txDmaLen = sizeof(ns_desc);
1743            txDmaFree = dmaDescFree;
1744
1745            descDmaReads++;
1746            descDmaRdBytes += txDmaLen;
1747
1748            if (doTxDmaRead())
1749                goto exit;
1750        }
1751        break;
1752
1753      case txDescRefr:
1754        if (txDmaState != dmaIdle)
1755            goto exit;
1756
1757        txState = txAdvance;
1758        break;
1759
1760      case txDescRead:
1761        if (txDmaState != dmaIdle)
1762            goto exit;
1763
1764        DPRINTF(EthernetDesc,
1765                "txDescCache: link=%08x bufptr=%08x cmdsts=%08x extsts=%08x\n",
1766                txDescCache.link, txDescCache.bufptr, txDescCache.cmdsts,
1767                txDescCache.extsts);
1768
1769        if (txDescCache.cmdsts & CMDSTS_OWN) {
1770            txState = txFifoBlock;
1771            txFragPtr = txDescCache.bufptr;
1772            txDescCnt = txDescCache.cmdsts & CMDSTS_LEN_MASK;
1773        } else {
1774            devIntrPost(ISR_TXIDLE);
1775            txState = txIdle;
1776            goto exit;
1777        }
1778        break;
1779
1780      case txFifoBlock:
1781        if (!txPacket) {
1782            DPRINTF(EthernetSM, "****starting the tx of a new packet****\n");
1783            txPacket = new EtherPacket;
1784            txPacket->data = new uint8_t[16384];
1785            txPacketBufPtr = txPacket->data;
1786        }
1787
1788        if (txDescCnt == 0) {
1789            DPRINTF(EthernetSM, "the txDescCnt == 0, done with descriptor\n");
1790            if (txDescCache.cmdsts & CMDSTS_MORE) {
1791                DPRINTF(EthernetSM, "there are more descriptors to come\n");
1792                txState = txDescWrite;
1793
1794                txDescCache.cmdsts &= ~CMDSTS_OWN;
1795
1796                txDmaAddr = regs.txdp + offsetof(ns_desc, cmdsts);
1797                txDmaAddr &= 0x3fffffff;
1798                txDmaData = &(txDescCache.cmdsts);
1799                txDmaLen = sizeof(txDescCache.cmdsts);
1800                txDmaFree = dmaDescFree;
1801
1802                if (doTxDmaWrite())
1803                    goto exit;
1804
1805            } else { /* this packet is totally done */
1806                DPRINTF(EthernetSM, "This packet is done, let's wrap it up\n");
1807                /* deal with the the packet that just finished */
1808                if ((regs.vtcr & VTCR_PPCHK) && extstsEnable) {
1809                    if (txDescCache.extsts & EXTSTS_UDPPKT) {
1810                        udpChecksum(txPacket, true);
1811                    } else if (txDescCache.extsts & EXTSTS_TCPPKT) {
1812                        tcpChecksum(txPacket, true);
1813                        txTCPChecksums++;
1814                    }
1815                    if (txDescCache.extsts & EXTSTS_IPPKT) {
1816                        ipChecksum(txPacket, true);
1817                        txIPChecksums++;
1818                    }
1819                }
1820
1821                txPacket->length = txPacketBufPtr - txPacket->data;
1822                // this is just because the receive can't handle a
1823                // packet bigger want to make sure
1824                assert(txPacket->length <= 1514);
1825                txFifo.push_back(txPacket);
1826
1827                /*
1828                 * this following section is not tqo spec, but
1829                 * functionally shouldn't be any different.  normally,
1830                 * the chip will wait til the transmit has occurred
1831                 * before writing back the descriptor because it has
1832                 * to wait to see that it was successfully transmitted
1833                 * to decide whether to set CMDSTS_OK or not.
1834                 * however, in the simulator since it is always
1835                 * successfully transmitted, and writing it exactly to
1836                 * spec would complicate the code, we just do it here
1837                 */
1838
1839                txDescCache.cmdsts &= ~CMDSTS_OWN;
1840                txDescCache.cmdsts |= CMDSTS_OK;
1841
1842                DPRINTF(EthernetDesc,
1843                        "txDesc writeback: cmdsts=%08x extsts=%08x\n",
1844                        txDescCache.cmdsts, txDescCache.extsts);
1845
1846                txDmaAddr = regs.txdp + offsetof(ns_desc, cmdsts);
1847                txDmaAddr &= 0x3fffffff;
1848                txDmaData = &(txDescCache.cmdsts);
1849                txDmaLen = sizeof(txDescCache.cmdsts) +
1850                    sizeof(txDescCache.extsts);
1851                txDmaFree = dmaDescFree;
1852
1853                descDmaWrites++;
1854                descDmaWrBytes += txDmaLen;
1855
1856                transmit();
1857                txPacket = 0;
1858
1859                if (!txEnable) {
1860                    DPRINTF(EthernetSM, "halting TX state machine\n");
1861                    txState = txIdle;
1862                    goto exit;
1863                } else
1864                    txState = txAdvance;
1865
1866                if (doTxDmaWrite())
1867                    goto exit;
1868            }
1869        } else {
1870            DPRINTF(EthernetSM, "this descriptor isn't done yet\n");
1871            if (txFifoAvail) {
1872                txState = txFragRead;
1873
1874                /*
1875                 * The number of bytes transferred is either whatever
1876                 * is left in the descriptor (txDescCnt), or if there
1877                 * is not enough room in the fifo, just whatever room
1878                 * is left in the fifo
1879                 */
1880                txXferLen = min<uint32_t>(txDescCnt, txFifoAvail);
1881
1882                txDmaAddr = txFragPtr & 0x3fffffff;
1883                txDmaData = txPacketBufPtr;
1884                txDmaLen = txXferLen;
1885                txDmaFree = dmaDataFree;
1886
1887                if (doTxDmaRead())
1888                    goto exit;
1889            } else {
1890                txState = txFifoBlock;
1891                transmit();
1892
1893                goto exit;
1894            }
1895
1896        }
1897        break;
1898
1899      case txFragRead:
1900        if (txDmaState != dmaIdle)
1901            goto exit;
1902
1903        txPacketBufPtr += txXferLen;
1904        txFragPtr += txXferLen;
1905        txDescCnt -= txXferLen;
1906        txFifoAvail -= txXferLen;
1907
1908        txState = txFifoBlock;
1909        break;
1910
1911      case txDescWrite:
1912        if (txDmaState != dmaIdle)
1913            goto exit;
1914
1915        if (txDescCache.cmdsts & CMDSTS_INTR)
1916            devIntrPost(ISR_TXDESC);
1917
1918        txState = txAdvance;
1919        break;
1920
1921      case txAdvance:
1922        if (txDescCache.link == 0) {
1923            devIntrPost(ISR_TXIDLE);
1924            txState = txIdle;
1925            goto exit;
1926        } else {
1927            txState = txDescRead;
1928            regs.txdp = txDescCache.link;
1929            CTDD = false;
1930
1931            txDmaAddr = txDescCache.link & 0x3fffffff;
1932            txDmaData = &txDescCache;
1933            txDmaLen = sizeof(ns_desc);
1934            txDmaFree = dmaDescFree;
1935
1936            if (doTxDmaRead())
1937                goto exit;
1938        }
1939        break;
1940
1941      default:
1942        panic("invalid state");
1943    }
1944
1945    DPRINTF(EthernetSM, "entering next txState=%s\n",
1946            NsTxStateStrings[txState]);
1947
1948    goto next;
1949
1950  exit:
1951    /**
1952     * @todo do we want to schedule a future kick?
1953     */
1954    DPRINTF(EthernetSM, "tx state machine exited txState=%s\n",
1955            NsTxStateStrings[txState]);
1956}
1957
1958void
1959NSGigE::transferDone()
1960{
1961    if (txFifo.empty()) {
1962        DPRINTF(Ethernet, "transfer complete: txFifo empty...nothing to do\n");
1963        return;
1964    }
1965
1966    DPRINTF(Ethernet, "transfer complete: data in txFifo...schedule xmit\n");
1967
1968    if (txEvent.scheduled())
1969        txEvent.reschedule(curTick + 1);
1970    else
1971        txEvent.schedule(curTick + 1);
1972}
1973
1974bool
1975NSGigE::rxFilter(PacketPtr packet)
1976{
1977    bool drop = true;
1978    string type;
1979
1980    if (packet->IsUnicast()) {
1981        type = "unicast";
1982
1983        // If we're accepting all unicast addresses
1984        if (acceptUnicast)
1985            drop = false;
1986
1987        // If we make a perfect match
1988        if (acceptPerfect &&
1989            memcmp(rom.perfectMatch, packet->data, EADDR_LEN) == 0)
1990            drop = false;
1991
1992        eth_header *eth = (eth_header *) packet->data;
1993        if ((acceptArp) && (eth->type == 0x608))
1994            drop = false;
1995
1996    } else if (packet->IsBroadcast()) {
1997        type = "broadcast";
1998
1999        // if we're accepting broadcasts
2000        if (acceptBroadcast)
2001            drop = false;
2002
2003    } else if (packet->IsMulticast()) {
2004        type = "multicast";
2005
2006        // if we're accepting all multicasts
2007        if (acceptMulticast)
2008            drop = false;
2009
2010    } else {
2011        type = "unknown";
2012
2013        // oh well, punt on this one
2014    }
2015
2016    if (drop) {
2017        DPRINTF(Ethernet, "rxFilter drop\n");
2018        DDUMP(EthernetData, packet->data, packet->length);
2019    }
2020
2021    return drop;
2022}
2023
2024bool
2025NSGigE::recvPacket(PacketPtr packet)
2026{
2027    rxBytes += packet->length;
2028    rxPackets++;
2029
2030    DPRINTF(Ethernet, "Receiving packet from wire, rxFifoAvail=%d\n",
2031            maxRxFifoSize - rxFifoCnt);
2032
2033    if (!rxEnable) {
2034        DPRINTF(Ethernet, "receive disabled...packet dropped\n");
2035        debug_break();
2036        interface->recvDone();
2037        return true;
2038    }
2039
2040    if (rxFilterEnable && rxFilter(packet)) {
2041        DPRINTF(Ethernet, "packet filtered...dropped\n");
2042        interface->recvDone();
2043        return true;
2044    }
2045
2046    if ((rxFifoCnt + packet->length) >= maxRxFifoSize) {
2047        DPRINTF(Ethernet,
2048                "packet will not fit in receive buffer...packet dropped\n");
2049        devIntrPost(ISR_RXORN);
2050        return false;
2051    }
2052
2053    rxFifo.push_back(packet);
2054    rxFifoCnt += packet->length;
2055    interface->recvDone();
2056
2057    rxKick();
2058    return true;
2059}
2060
2061/**
2062 * does a udp checksum.  if gen is true, then it generates it and puts
2063 * it in the right place else, it just checks what it calculates
2064 * against the value in the header in packet
2065 */
2066bool
2067NSGigE::udpChecksum(PacketPtr packet, bool gen)
2068{
2069    ip_header *ip = packet->getIpHdr();
2070    udp_header *hdr = packet->getUdpHdr(ip);
2071
2072    pseudo_header *pseudo = new pseudo_header;
2073
2074    pseudo->src_ip_addr = ip->src_ip_addr;
2075    pseudo->dest_ip_addr = ip->dest_ip_addr;
2076    pseudo->protocol = ip->protocol;
2077    pseudo->len = hdr->len;
2078
2079    uint16_t cksum = checksumCalc((uint16_t *) pseudo, (uint16_t *) hdr,
2080                                  (uint32_t) hdr->len);
2081
2082    delete pseudo;
2083    if (gen)
2084        hdr->chksum = cksum;
2085    else
2086        if (cksum != 0)
2087            return false;
2088
2089    return true;
2090}
2091
2092bool
2093NSGigE::tcpChecksum(PacketPtr packet, bool gen)
2094{
2095    ip_header *ip = packet->getIpHdr();
2096    tcp_header *hdr = packet->getTcpHdr(ip);
2097
2098    uint16_t cksum;
2099    pseudo_header *pseudo = new pseudo_header;
2100    if (!gen) {
2101        pseudo->src_ip_addr = ip->src_ip_addr;
2102        pseudo->dest_ip_addr = ip->dest_ip_addr;
2103        pseudo->protocol = reverseEnd16(ip->protocol);
2104        pseudo->len = reverseEnd16(reverseEnd16(ip->dgram_len) -
2105                                   (ip->vers_len & 0xf)*4);
2106
2107        cksum = checksumCalc((uint16_t *) pseudo, (uint16_t *) hdr,
2108                             (uint32_t) reverseEnd16(pseudo->len));
2109    } else {
2110        pseudo->src_ip_addr = 0;
2111        pseudo->dest_ip_addr = 0;
2112        pseudo->protocol = hdr->chksum;
2113        pseudo->len = 0;
2114        hdr->chksum = 0;
2115        cksum = checksumCalc((uint16_t *) pseudo, (uint16_t *) hdr,
2116                             (uint32_t) (reverseEnd16(ip->dgram_len) -
2117                                         (ip->vers_len & 0xf)*4));
2118    }
2119
2120    delete pseudo;
2121    if (gen)
2122        hdr->chksum = cksum;
2123    else
2124        if (cksum != 0)
2125            return false;
2126
2127    return true;
2128}
2129
2130bool
2131NSGigE::ipChecksum(PacketPtr packet, bool gen)
2132{
2133    ip_header *hdr = packet->getIpHdr();
2134
2135    uint16_t cksum = checksumCalc(NULL, (uint16_t *) hdr,
2136                                  (hdr->vers_len & 0xf)*4);
2137
2138    if (gen) {
2139        DPRINTF(EthernetCksum, "generated checksum: %#x\n", cksum);
2140        hdr->hdr_chksum = cksum;
2141    }
2142    else
2143        if (cksum != 0)
2144            return false;
2145
2146    return true;
2147}
2148
2149uint16_t
2150NSGigE::checksumCalc(uint16_t *pseudo, uint16_t *buf, uint32_t len)
2151{
2152    uint32_t sum = 0;
2153
2154    uint16_t last_pad = 0;
2155    if (len & 1) {
2156        last_pad = buf[len/2] & 0xff;
2157        len--;
2158        sum += last_pad;
2159    }
2160
2161    if (pseudo) {
2162        sum = pseudo[0] + pseudo[1] + pseudo[2] +
2163            pseudo[3] + pseudo[4] + pseudo[5];
2164    }
2165
2166    for (int i=0; i < (len/2); ++i) {
2167        sum += buf[i];
2168    }
2169
2170    while (sum >> 16)
2171        sum = (sum >> 16) + (sum & 0xffff);
2172
2173    return ~sum;
2174}
2175
2176//=====================================================================
2177//
2178//
2179void
2180NSGigE::serialize(ostream &os)
2181{
2182    // Serialize the PciDev base class
2183    PciDev::serialize(os);
2184
2185    /*
2186     * Finalize any DMA events now.
2187     */
2188    if (rxDmaReadEvent.scheduled())
2189        rxDmaReadCopy();
2190    if (rxDmaWriteEvent.scheduled())
2191        rxDmaWriteCopy();
2192    if (txDmaReadEvent.scheduled())
2193        txDmaReadCopy();
2194    if (txDmaWriteEvent.scheduled())
2195        txDmaWriteCopy();
2196
2197    /*
2198     * Serialize the device registers
2199     */
2200    SERIALIZE_SCALAR(regs.command);
2201    SERIALIZE_SCALAR(regs.config);
2202    SERIALIZE_SCALAR(regs.mear);
2203    SERIALIZE_SCALAR(regs.ptscr);
2204    SERIALIZE_SCALAR(regs.isr);
2205    SERIALIZE_SCALAR(regs.imr);
2206    SERIALIZE_SCALAR(regs.ier);
2207    SERIALIZE_SCALAR(regs.ihr);
2208    SERIALIZE_SCALAR(regs.txdp);
2209    SERIALIZE_SCALAR(regs.txdp_hi);
2210    SERIALIZE_SCALAR(regs.txcfg);
2211    SERIALIZE_SCALAR(regs.gpior);
2212    SERIALIZE_SCALAR(regs.rxdp);
2213    SERIALIZE_SCALAR(regs.rxdp_hi);
2214    SERIALIZE_SCALAR(regs.rxcfg);
2215    SERIALIZE_SCALAR(regs.pqcr);
2216    SERIALIZE_SCALAR(regs.wcsr);
2217    SERIALIZE_SCALAR(regs.pcr);
2218    SERIALIZE_SCALAR(regs.rfcr);
2219    SERIALIZE_SCALAR(regs.rfdr);
2220    SERIALIZE_SCALAR(regs.srr);
2221    SERIALIZE_SCALAR(regs.mibc);
2222    SERIALIZE_SCALAR(regs.vrcr);
2223    SERIALIZE_SCALAR(regs.vtcr);
2224    SERIALIZE_SCALAR(regs.vdr);
2225    SERIALIZE_SCALAR(regs.ccsr);
2226    SERIALIZE_SCALAR(regs.tbicr);
2227    SERIALIZE_SCALAR(regs.tbisr);
2228    SERIALIZE_SCALAR(regs.tanar);
2229    SERIALIZE_SCALAR(regs.tanlpar);
2230    SERIALIZE_SCALAR(regs.taner);
2231    SERIALIZE_SCALAR(regs.tesr);
2232
2233    SERIALIZE_ARRAY(rom.perfectMatch, EADDR_LEN);
2234
2235    SERIALIZE_SCALAR(ioEnable);
2236
2237    /*
2238     * Serialize the data Fifos
2239     */
2240    int txNumPkts = txFifo.size();
2241    SERIALIZE_SCALAR(txNumPkts);
2242    int i = 0;
2243    pktiter_t end = txFifo.end();
2244    for (pktiter_t p = txFifo.begin(); p != end; ++p) {
2245        nameOut(os, csprintf("%s.txFifo%d", name(), i++));
2246        (*p)->serialize(os);
2247    }
2248
2249    int rxNumPkts = rxFifo.size();
2250    SERIALIZE_SCALAR(rxNumPkts);
2251    i = 0;
2252    end = rxFifo.end();
2253    for (pktiter_t p = rxFifo.begin(); p != end; ++p) {
2254        nameOut(os, csprintf("%s.rxFifo%d", name(), i++));
2255        (*p)->serialize(os);
2256    }
2257
2258    /*
2259     * Serialize the various helper variables
2260     */
2261    bool txPacketExists = txPacket;
2262    SERIALIZE_SCALAR(txPacketExists);
2263    if (txPacketExists) {
2264        nameOut(os, csprintf("%s.txPacket", name()));
2265        txPacket->serialize(os);
2266        uint32_t txPktBufPtr = (uint32_t) (txPacketBufPtr - txPacket->data);
2267        SERIALIZE_SCALAR(txPktBufPtr);
2268    }
2269
2270    bool rxPacketExists = rxPacket;
2271    SERIALIZE_SCALAR(rxPacketExists);
2272    if (rxPacketExists) {
2273        nameOut(os, csprintf("%s.rxPacket", name()));
2274        rxPacket->serialize(os);
2275        uint32_t rxPktBufPtr = (uint32_t) (rxPacketBufPtr - rxPacket->data);
2276        SERIALIZE_SCALAR(rxPktBufPtr);
2277    }
2278
2279    SERIALIZE_SCALAR(txXferLen);
2280    SERIALIZE_SCALAR(rxXferLen);
2281
2282    /*
2283     * Serialize DescCaches
2284     */
2285    SERIALIZE_SCALAR(txDescCache.link);
2286    SERIALIZE_SCALAR(txDescCache.bufptr);
2287    SERIALIZE_SCALAR(txDescCache.cmdsts);
2288    SERIALIZE_SCALAR(txDescCache.extsts);
2289    SERIALIZE_SCALAR(rxDescCache.link);
2290    SERIALIZE_SCALAR(rxDescCache.bufptr);
2291    SERIALIZE_SCALAR(rxDescCache.cmdsts);
2292    SERIALIZE_SCALAR(rxDescCache.extsts);
2293
2294    /*
2295     * Serialize tx state machine
2296     */
2297    int txState = this->txState;
2298    SERIALIZE_SCALAR(txState);
2299    SERIALIZE_SCALAR(txEnable);
2300    SERIALIZE_SCALAR(CTDD);
2301    SERIALIZE_SCALAR(txFifoAvail);
2302    SERIALIZE_SCALAR(txFragPtr);
2303    SERIALIZE_SCALAR(txDescCnt);
2304    int txDmaState = this->txDmaState;
2305    SERIALIZE_SCALAR(txDmaState);
2306
2307    /*
2308     * Serialize rx state machine
2309     */
2310    int rxState = this->rxState;
2311    SERIALIZE_SCALAR(rxState);
2312    SERIALIZE_SCALAR(rxEnable);
2313    SERIALIZE_SCALAR(CRDD);
2314    SERIALIZE_SCALAR(rxPktBytes);
2315    SERIALIZE_SCALAR(rxFifoCnt);
2316    SERIALIZE_SCALAR(rxDescCnt);
2317    int rxDmaState = this->rxDmaState;
2318    SERIALIZE_SCALAR(rxDmaState);
2319
2320    SERIALIZE_SCALAR(extstsEnable);
2321
2322    /*
2323     * If there's a pending transmit, store the time so we can
2324     * reschedule it later
2325     */
2326    Tick transmitTick = txEvent.scheduled() ? txEvent.when() - curTick : 0;
2327    SERIALIZE_SCALAR(transmitTick);
2328
2329    /*
2330     * receive address filter settings
2331     */
2332    SERIALIZE_SCALAR(rxFilterEnable);
2333    SERIALIZE_SCALAR(acceptBroadcast);
2334    SERIALIZE_SCALAR(acceptMulticast);
2335    SERIALIZE_SCALAR(acceptUnicast);
2336    SERIALIZE_SCALAR(acceptPerfect);
2337    SERIALIZE_SCALAR(acceptArp);
2338
2339    /*
2340     * Keep track of pending interrupt status.
2341     */
2342    SERIALIZE_SCALAR(intrTick);
2343    SERIALIZE_SCALAR(cpuPendingIntr);
2344    Tick intrEventTick = 0;
2345    if (intrEvent)
2346        intrEventTick = intrEvent->when();
2347    SERIALIZE_SCALAR(intrEventTick);
2348
2349}
2350
2351void
2352NSGigE::unserialize(Checkpoint *cp, const std::string &section)
2353{
2354    // Unserialize the PciDev base class
2355    PciDev::unserialize(cp, section);
2356
2357    UNSERIALIZE_SCALAR(regs.command);
2358    UNSERIALIZE_SCALAR(regs.config);
2359    UNSERIALIZE_SCALAR(regs.mear);
2360    UNSERIALIZE_SCALAR(regs.ptscr);
2361    UNSERIALIZE_SCALAR(regs.isr);
2362    UNSERIALIZE_SCALAR(regs.imr);
2363    UNSERIALIZE_SCALAR(regs.ier);
2364    UNSERIALIZE_SCALAR(regs.ihr);
2365    UNSERIALIZE_SCALAR(regs.txdp);
2366    UNSERIALIZE_SCALAR(regs.txdp_hi);
2367    UNSERIALIZE_SCALAR(regs.txcfg);
2368    UNSERIALIZE_SCALAR(regs.gpior);
2369    UNSERIALIZE_SCALAR(regs.rxdp);
2370    UNSERIALIZE_SCALAR(regs.rxdp_hi);
2371    UNSERIALIZE_SCALAR(regs.rxcfg);
2372    UNSERIALIZE_SCALAR(regs.pqcr);
2373    UNSERIALIZE_SCALAR(regs.wcsr);
2374    UNSERIALIZE_SCALAR(regs.pcr);
2375    UNSERIALIZE_SCALAR(regs.rfcr);
2376    UNSERIALIZE_SCALAR(regs.rfdr);
2377    UNSERIALIZE_SCALAR(regs.srr);
2378    UNSERIALIZE_SCALAR(regs.mibc);
2379    UNSERIALIZE_SCALAR(regs.vrcr);
2380    UNSERIALIZE_SCALAR(regs.vtcr);
2381    UNSERIALIZE_SCALAR(regs.vdr);
2382    UNSERIALIZE_SCALAR(regs.ccsr);
2383    UNSERIALIZE_SCALAR(regs.tbicr);
2384    UNSERIALIZE_SCALAR(regs.tbisr);
2385    UNSERIALIZE_SCALAR(regs.tanar);
2386    UNSERIALIZE_SCALAR(regs.tanlpar);
2387    UNSERIALIZE_SCALAR(regs.taner);
2388    UNSERIALIZE_SCALAR(regs.tesr);
2389
2390    UNSERIALIZE_ARRAY(rom.perfectMatch, EADDR_LEN);
2391
2392    UNSERIALIZE_SCALAR(ioEnable);
2393
2394    /*
2395     * unserialize the data fifos
2396     */
2397    int txNumPkts;
2398    UNSERIALIZE_SCALAR(txNumPkts);
2399    int i;
2400    for (i = 0; i < txNumPkts; ++i) {
2401        PacketPtr p = new EtherPacket;
2402        p->unserialize(cp, csprintf("%s.rxFifo%d", section, i));
2403        txFifo.push_back(p);
2404    }
2405
2406    int rxNumPkts;
2407    UNSERIALIZE_SCALAR(rxNumPkts);
2408    for (i = 0; i < rxNumPkts; ++i) {
2409        PacketPtr p = new EtherPacket;
2410        p->unserialize(cp, csprintf("%s.rxFifo%d", section, i));
2411        rxFifo.push_back(p);
2412    }
2413
2414    /*
2415     * unserialize the various helper variables
2416     */
2417    bool txPacketExists;
2418    UNSERIALIZE_SCALAR(txPacketExists);
2419    if (txPacketExists) {
2420        txPacket = new EtherPacket;
2421        txPacket->unserialize(cp, csprintf("%s.txPacket", section));
2422        uint32_t txPktBufPtr;
2423        UNSERIALIZE_SCALAR(txPktBufPtr);
2424        txPacketBufPtr = (uint8_t *) txPacket->data + txPktBufPtr;
2425    } else
2426        txPacket = 0;
2427
2428    bool rxPacketExists;
2429    UNSERIALIZE_SCALAR(rxPacketExists);
2430    rxPacket = 0;
2431    if (rxPacketExists) {
2432        rxPacket = new EtherPacket;
2433        rxPacket->unserialize(cp, csprintf("%s.rxPacket", section));
2434        uint32_t rxPktBufPtr;
2435        UNSERIALIZE_SCALAR(rxPktBufPtr);
2436        rxPacketBufPtr = (uint8_t *) rxPacket->data + rxPktBufPtr;
2437    } else
2438        rxPacket = 0;
2439
2440    UNSERIALIZE_SCALAR(txXferLen);
2441    UNSERIALIZE_SCALAR(rxXferLen);
2442
2443    /*
2444     * Unserialize DescCaches
2445     */
2446    UNSERIALIZE_SCALAR(txDescCache.link);
2447    UNSERIALIZE_SCALAR(txDescCache.bufptr);
2448    UNSERIALIZE_SCALAR(txDescCache.cmdsts);
2449    UNSERIALIZE_SCALAR(txDescCache.extsts);
2450    UNSERIALIZE_SCALAR(rxDescCache.link);
2451    UNSERIALIZE_SCALAR(rxDescCache.bufptr);
2452    UNSERIALIZE_SCALAR(rxDescCache.cmdsts);
2453    UNSERIALIZE_SCALAR(rxDescCache.extsts);
2454
2455    /*
2456     * unserialize tx state machine
2457     */
2458    int txState;
2459    UNSERIALIZE_SCALAR(txState);
2460    this->txState = (TxState) txState;
2461    UNSERIALIZE_SCALAR(txEnable);
2462    UNSERIALIZE_SCALAR(CTDD);
2463    UNSERIALIZE_SCALAR(txFifoAvail);
2464    UNSERIALIZE_SCALAR(txFragPtr);
2465    UNSERIALIZE_SCALAR(txDescCnt);
2466    int txDmaState;
2467    UNSERIALIZE_SCALAR(txDmaState);
2468    this->txDmaState = (DmaState) txDmaState;
2469
2470    /*
2471     * unserialize rx state machine
2472     */
2473    int rxState;
2474    UNSERIALIZE_SCALAR(rxState);
2475    this->rxState = (RxState) rxState;
2476    UNSERIALIZE_SCALAR(rxEnable);
2477    UNSERIALIZE_SCALAR(CRDD);
2478    UNSERIALIZE_SCALAR(rxPktBytes);
2479    UNSERIALIZE_SCALAR(rxFifoCnt);
2480    UNSERIALIZE_SCALAR(rxDescCnt);
2481    int rxDmaState;
2482    UNSERIALIZE_SCALAR(rxDmaState);
2483    this->rxDmaState = (DmaState) rxDmaState;
2484
2485    UNSERIALIZE_SCALAR(extstsEnable);
2486
2487     /*
2488     * If there's a pending transmit, reschedule it now
2489     */
2490    Tick transmitTick;
2491    UNSERIALIZE_SCALAR(transmitTick);
2492    if (transmitTick)
2493        txEvent.schedule(curTick + transmitTick);
2494
2495    /*
2496     * unserialize receive address filter settings
2497     */
2498    UNSERIALIZE_SCALAR(rxFilterEnable);
2499    UNSERIALIZE_SCALAR(acceptBroadcast);
2500    UNSERIALIZE_SCALAR(acceptMulticast);
2501    UNSERIALIZE_SCALAR(acceptUnicast);
2502    UNSERIALIZE_SCALAR(acceptPerfect);
2503    UNSERIALIZE_SCALAR(acceptArp);
2504
2505    /*
2506     * Keep track of pending interrupt status.
2507     */
2508    UNSERIALIZE_SCALAR(intrTick);
2509    UNSERIALIZE_SCALAR(cpuPendingIntr);
2510    Tick intrEventTick;
2511    UNSERIALIZE_SCALAR(intrEventTick);
2512    if (intrEventTick) {
2513        intrEvent = new IntrEvent(this, true);
2514        intrEvent->schedule(intrEventTick);
2515    }
2516
2517    /*
2518     * re-add addrRanges to bus bridges
2519     */
2520    if (pioInterface) {
2521        pioInterface->addAddrRange(BARAddrs[0], BARAddrs[0] + BARSize[0] - 1);
2522        pioInterface->addAddrRange(BARAddrs[1], BARAddrs[1] + BARSize[1] - 1);
2523    }
2524}
2525
2526Tick
2527NSGigE::cacheAccess(MemReqPtr &req)
2528{
2529    DPRINTF(EthernetPIO, "timing access to paddr=%#x (daddr=%#x)\n",
2530            req->paddr, req->paddr - addr);
2531    return curTick + pioLatency;
2532}
2533//=====================================================================
2534
2535
2536//********** helper functions******************************************
2537
2538uint16_t reverseEnd16(uint16_t num)
2539{
2540    uint16_t reverse = (num & 0xff)<<8;
2541    reverse += ((num & 0xff00) >> 8);
2542    return reverse;
2543}
2544
2545uint32_t reverseEnd32(uint32_t num)
2546{
2547    uint32_t reverse = (reverseEnd16(num & 0xffff)) << 16;
2548    reverse += reverseEnd16((uint16_t) ((num & 0xffff0000) >> 8));
2549    return reverse;
2550}
2551
2552
2553
2554//=====================================================================
2555
2556BEGIN_DECLARE_SIM_OBJECT_PARAMS(NSGigEInt)
2557
2558    SimObjectParam<EtherInt *> peer;
2559    SimObjectParam<NSGigE *> device;
2560
2561END_DECLARE_SIM_OBJECT_PARAMS(NSGigEInt)
2562
2563BEGIN_INIT_SIM_OBJECT_PARAMS(NSGigEInt)
2564
2565    INIT_PARAM_DFLT(peer, "peer interface", NULL),
2566    INIT_PARAM(device, "Ethernet device of this interface")
2567
2568END_INIT_SIM_OBJECT_PARAMS(NSGigEInt)
2569
2570CREATE_SIM_OBJECT(NSGigEInt)
2571{
2572    NSGigEInt *dev_int = new NSGigEInt(getInstanceName(), device);
2573
2574    EtherInt *p = (EtherInt *)peer;
2575    if (p) {
2576        dev_int->setPeer(p);
2577        p->setPeer(dev_int);
2578    }
2579
2580    return dev_int;
2581}
2582
2583REGISTER_SIM_OBJECT("NSGigEInt", NSGigEInt)
2584
2585
2586BEGIN_DECLARE_SIM_OBJECT_PARAMS(NSGigE)
2587
2588    Param<Tick> tx_delay;
2589    Param<Tick> rx_delay;
2590    SimObjectParam<IntrControl *> intr_ctrl;
2591    Param<Tick> intr_delay;
2592    SimObjectParam<MemoryController *> mmu;
2593    SimObjectParam<PhysicalMemory *> physmem;
2594    Param<bool> rx_filter;
2595    Param<string> hardware_address;
2596    SimObjectParam<Bus*> header_bus;
2597    SimObjectParam<Bus*> payload_bus;
2598    SimObjectParam<HierParams *> hier;
2599    Param<Tick> pio_latency;
2600    Param<bool> dma_desc_free;
2601    Param<bool> dma_data_free;
2602    Param<Tick> dma_read_delay;
2603    Param<Tick> dma_write_delay;
2604    Param<Tick> dma_read_factor;
2605    Param<Tick> dma_write_factor;
2606    SimObjectParam<PciConfigAll *> configspace;
2607    SimObjectParam<PciConfigData *> configdata;
2608    SimObjectParam<Tsunami *> tsunami;
2609    Param<uint32_t> pci_bus;
2610    Param<uint32_t> pci_dev;
2611    Param<uint32_t> pci_func;
2612    Param<uint32_t> tx_fifo_size;
2613    Param<uint32_t> rx_fifo_size;
2614
2615END_DECLARE_SIM_OBJECT_PARAMS(NSGigE)
2616
2617BEGIN_INIT_SIM_OBJECT_PARAMS(NSGigE)
2618
2619    INIT_PARAM_DFLT(tx_delay, "Transmit Delay", 1000),
2620    INIT_PARAM_DFLT(rx_delay, "Receive Delay", 1000),
2621    INIT_PARAM(intr_ctrl, "Interrupt Controller"),
2622    INIT_PARAM_DFLT(intr_delay, "Interrupt Delay in microseconds", 0),
2623    INIT_PARAM(mmu, "Memory Controller"),
2624    INIT_PARAM(physmem, "Physical Memory"),
2625    INIT_PARAM_DFLT(rx_filter, "Enable Receive Filter", true),
2626    INIT_PARAM_DFLT(hardware_address, "Ethernet Hardware Address",
2627                    "00:99:00:00:00:01"),
2628    INIT_PARAM_DFLT(header_bus, "The IO Bus to attach to for headers", NULL),
2629    INIT_PARAM_DFLT(payload_bus, "The IO Bus to attach to for payload", NULL),
2630    INIT_PARAM_DFLT(hier, "Hierarchy global variables", &defaultHierParams),
2631    INIT_PARAM_DFLT(pio_latency, "Programmed IO latency in bus cycles", 1),
2632    INIT_PARAM_DFLT(dma_desc_free, "DMA of Descriptors is free", false),
2633    INIT_PARAM_DFLT(dma_data_free, "DMA of Data is free", false),
2634    INIT_PARAM_DFLT(dma_read_delay, "fixed delay for dma reads", 0),
2635    INIT_PARAM_DFLT(dma_write_delay, "fixed delay for dma writes", 0),
2636    INIT_PARAM_DFLT(dma_read_factor, "multiplier for dma reads", 0),
2637    INIT_PARAM_DFLT(dma_write_factor, "multiplier for dma writes", 0),
2638    INIT_PARAM(configspace, "PCI Configspace"),
2639    INIT_PARAM(configdata, "PCI Config data"),
2640    INIT_PARAM(tsunami, "Tsunami"),
2641    INIT_PARAM(pci_bus, "PCI bus"),
2642    INIT_PARAM(pci_dev, "PCI device number"),
2643    INIT_PARAM(pci_func, "PCI function code"),
2644    INIT_PARAM_DFLT(tx_fifo_size, "max size in bytes of txFifo", 131072),
2645    INIT_PARAM_DFLT(rx_fifo_size, "max size in bytes of rxFifo", 131072)
2646
2647END_INIT_SIM_OBJECT_PARAMS(NSGigE)
2648
2649
2650CREATE_SIM_OBJECT(NSGigE)
2651{
2652    int eaddr[6];
2653    sscanf(((string)hardware_address).c_str(), "%x:%x:%x:%x:%x:%x",
2654           &eaddr[0], &eaddr[1], &eaddr[2], &eaddr[3], &eaddr[4], &eaddr[5]);
2655
2656    return new NSGigE(getInstanceName(), intr_ctrl, intr_delay,
2657                      physmem, tx_delay, rx_delay, mmu, hier, header_bus,
2658                      payload_bus, pio_latency, dma_desc_free, dma_data_free,
2659                      dma_read_delay, dma_write_delay, dma_read_factor,
2660                      dma_write_factor, configspace, configdata,
2661                      tsunami, pci_bus, pci_dev, pci_func, rx_filter, eaddr,
2662                      tx_fifo_size, rx_fifo_size);
2663}
2664
2665REGISTER_SIM_OBJECT("NSGigE", NSGigE)
2666