ns_gige.cc revision 1078
12292SN/A/*
28948Sandreas.hansson@arm.com * Copyright (c) 2004 The Regents of The University of Michigan
38707Sandreas.hansson@arm.com * All rights reserved.
48707Sandreas.hansson@arm.com *
58707Sandreas.hansson@arm.com * Redistribution and use in source and binary forms, with or without
68707Sandreas.hansson@arm.com * modification, are permitted provided that the following conditions are
78707Sandreas.hansson@arm.com * met: redistributions of source code must retain the above copyright
88707Sandreas.hansson@arm.com * notice, this list of conditions and the following disclaimer;
98707Sandreas.hansson@arm.com * redistributions in binary form must reproduce the above copyright
108707Sandreas.hansson@arm.com * notice, this list of conditions and the following disclaimer in the
118707Sandreas.hansson@arm.com * documentation and/or other materials provided with the distribution;
128707Sandreas.hansson@arm.com * neither the name of the copyright holders nor the names of its
138707Sandreas.hansson@arm.com * contributors may be used to endorse or promote products derived from
142727Sktlim@umich.edu * this software without specific prior written permission.
152292SN/A *
162292SN/A * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
172292SN/A * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
182292SN/A * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
192292SN/A * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
202292SN/A * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
212292SN/A * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
222292SN/A * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
232292SN/A * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
242292SN/A * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
252292SN/A * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
262292SN/A * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
272292SN/A */
282292SN/A
292292SN/A/* @file
302292SN/A * Device module for modelling the National Semiconductor
312292SN/A * DP83820 ethernet controller.  Does not support priority queueing
322292SN/A */
332292SN/A#include <cstdio>
342292SN/A#include <deque>
352292SN/A#include <string>
362292SN/A
372292SN/A#include "base/inet.hh"
382292SN/A#include "cpu/exec_context.hh"
392689Sktlim@umich.edu#include "cpu/intr_control.hh"
402689Sktlim@umich.edu#include "dev/dma.hh"
412292SN/A#include "dev/etherlink.hh"
422292SN/A#include "dev/ns_gige.hh"
432329SN/A#include "dev/pciconfigall.hh"
442980Sgblack@eecs.umich.edu#include "dev/tsunami_cchip.hh"
452329SN/A#include "mem/bus/bus.hh"
462329SN/A#include "mem/bus/dma_interface.hh"
472292SN/A#include "mem/bus/pio_interface.hh"
489444SAndreas.Sandberg@ARM.com#include "mem/bus/pio_interface_impl.hh"
498232Snate@binkert.org#include "mem/functional_mem/memory_control.hh"
508232Snate@binkert.org#include "mem/functional_mem/physical_memory.hh"
518232Snate@binkert.org#include "sim/builder.hh"
526221Snate@binkert.org#include "sim/debug.hh"
532292SN/A#include "sim/host.hh"
546221Snate@binkert.org#include "sim/sim_stats.hh"
555529Snate@binkert.org#include "targetarch/vtophys.hh"
562292SN/A
575529Snate@binkert.orgconst char *NsRxStateStrings[] =
588707Sandreas.hansson@arm.com{
594329Sktlim@umich.edu    "rxIdle",
604329Sktlim@umich.edu    "rxDescRefr",
615529Snate@binkert.org    "rxDescRead",
622907Sktlim@umich.edu    "rxFifoBlock",
632292SN/A    "rxFragWrite",
642292SN/A    "rxDescWrite",
652292SN/A    "rxAdvance"
662292SN/A};
672980Sgblack@eecs.umich.edu
682292SN/Aconst char *NsTxStateStrings[] =
692292SN/A{
702292SN/A    "txIdle",
712292SN/A    "txDescRefr",
722292SN/A    "txDescRead",
732292SN/A    "txFifoBlock",
742292SN/A    "txFragRead",
752292SN/A    "txDescWrite",
762292SN/A    "txAdvance"
772292SN/A};
782292SN/A
794329Sktlim@umich.educonst char *NsDmaState[] =
802292SN/A{
812292SN/A    "dmaIdle",
822292SN/A    "dmaReading",
832292SN/A    "dmaWriting",
842292SN/A    "dmaReadWaiting",
852292SN/A    "dmaWriteWaiting"
862292SN/A};
874329Sktlim@umich.edu
882292SN/Ausing namespace std;
898346Sksewell@umich.edu
902292SN/A
912292SN/A///////////////////////////////////////////////////////////////////////
922292SN/A//
932292SN/A// NSGigE PCI Device
942292SN/A//
952292SN/ANSGigE::NSGigE(const std::string &name, IntrControl *i, Tick intr_delay,
962292SN/A               PhysicalMemory *pmem, Tick tx_delay, Tick rx_delay,
972292SN/A               MemoryController *mmu, HierParams *hier, Bus *header_bus,
982292SN/A               Bus *payload_bus, Tick pio_latency, bool dma_desc_free,
992292SN/A               bool dma_data_free, Tick dma_read_delay, Tick dma_write_delay,
1002292SN/A               Tick dma_read_factor, Tick dma_write_factor, PciConfigAll *cf,
1012292SN/A               PciConfigData *cd, Tsunami *t, uint32_t bus, uint32_t dev,
1024329Sktlim@umich.edu               uint32_t func, bool rx_filter, const int eaddr[6],
1032292SN/A               uint32_t tx_fifo_size, uint32_t rx_fifo_size)
1048346Sksewell@umich.edu    : PciDev(name, mmu, cf, cd, bus, dev, func), tsunami(t), ioEnable(false),
1052292SN/A      maxTxFifoSize(tx_fifo_size), maxRxFifoSize(rx_fifo_size),
1062292SN/A      txPacket(0), rxPacket(0), txPacketBufPtr(NULL), rxPacketBufPtr(NULL),
1072292SN/A      txXferLen(0), rxXferLen(0), txState(txIdle), txEnable(false),
1082292SN/A      CTDD(false), txFifoAvail(tx_fifo_size),
1092292SN/A      txFragPtr(0), txDescCnt(0), txDmaState(dmaIdle), rxState(rxIdle),
1102292SN/A      rxEnable(false), CRDD(false), rxPktBytes(0), rxFifoCnt(0),
1112292SN/A      rxFragPtr(0), rxDescCnt(0), rxDmaState(dmaIdle), extstsEnable(false),
1126221Snate@binkert.org      rxDmaReadEvent(this), rxDmaWriteEvent(this),
1134329Sktlim@umich.edu      txDmaReadEvent(this), txDmaWriteEvent(this),
1144329Sktlim@umich.edu      dmaDescFree(dma_desc_free), dmaDataFree(dma_data_free),
1158850Sandreas.hansson@arm.com      txDelay(tx_delay), rxDelay(rx_delay), rxKickTick(0), txKickTick(0),
1162292SN/A      txEvent(this), rxFilterEnable(rx_filter), acceptBroadcast(false),
1172292SN/A      acceptMulticast(false), acceptUnicast(false),
1182292SN/A      acceptPerfect(false), acceptArp(false),
1192292SN/A      physmem(pmem), intctrl(i), intrTick(0), cpuPendingIntr(false),
1202292SN/A      intrEvent(0), interface(0)
1212292SN/A{
1222292SN/A    tsunami->ethernet = this;
1232292SN/A
1242292SN/A    if (header_bus) {
1252292SN/A        pioInterface = newPioInterface(name, hier, header_bus, this,
1262292SN/A                                       &NSGigE::cacheAccess);
1272292SN/A
1282292SN/A        pioLatency = pio_latency * header_bus->clockRatio;
1292727Sktlim@umich.edu
1302727Sktlim@umich.edu        if (payload_bus)
1312727Sktlim@umich.edu            dmaInterface = new DMAInterface<Bus>(name + ".dma",
1326221Snate@binkert.org                                                 header_bus, payload_bus, 1);
1332727Sktlim@umich.edu        else
1342727Sktlim@umich.edu            dmaInterface = new DMAInterface<Bus>(name + ".dma",
1352727Sktlim@umich.edu                                                 header_bus, header_bus, 1);
1362727Sktlim@umich.edu    } else if (payload_bus) {
1372727Sktlim@umich.edu        pioInterface = newPioInterface(name, hier, payload_bus, this,
1382727Sktlim@umich.edu                                       &NSGigE::cacheAccess);
1396221Snate@binkert.org
1402292SN/A        pioLatency = pio_latency * payload_bus->clockRatio;
1412292SN/A
1422292SN/A        dmaInterface = new DMAInterface<Bus>(name + ".dma", payload_bus,
1432292SN/A                                         payload_bus, 1);
1442292SN/A    }
1452292SN/A
1462307SN/A
1479444SAndreas.Sandberg@ARM.com    intrDelay = US2Ticks(intr_delay);
1482307SN/A    dmaReadDelay = dma_read_delay;
1499444SAndreas.Sandberg@ARM.com    dmaWriteDelay = dma_write_delay;
1509444SAndreas.Sandberg@ARM.com    dmaReadFactor = dma_read_factor;
1519444SAndreas.Sandberg@ARM.com    dmaWriteFactor = dma_write_factor;
1529444SAndreas.Sandberg@ARM.com
1539444SAndreas.Sandberg@ARM.com    regsReset();
1549444SAndreas.Sandberg@ARM.com    rom.perfectMatch[0] = eaddr[0];
1559444SAndreas.Sandberg@ARM.com    rom.perfectMatch[1] = eaddr[1];
1569444SAndreas.Sandberg@ARM.com    rom.perfectMatch[2] = eaddr[2];
1579444SAndreas.Sandberg@ARM.com    rom.perfectMatch[3] = eaddr[3];
1589444SAndreas.Sandberg@ARM.com    rom.perfectMatch[4] = eaddr[4];
1599444SAndreas.Sandberg@ARM.com    rom.perfectMatch[5] = eaddr[5];
1609444SAndreas.Sandberg@ARM.com}
1619444SAndreas.Sandberg@ARM.com
1629444SAndreas.Sandberg@ARM.comNSGigE::~NSGigE()
1639444SAndreas.Sandberg@ARM.com{}
1642307SN/A
1659444SAndreas.Sandberg@ARM.comvoid
1669444SAndreas.Sandberg@ARM.comNSGigE::regStats()
1679444SAndreas.Sandberg@ARM.com{
1689444SAndreas.Sandberg@ARM.com    txBytes
1699444SAndreas.Sandberg@ARM.com        .name(name() + ".txBytes")
1709444SAndreas.Sandberg@ARM.com        .desc("Bytes Transmitted")
1719444SAndreas.Sandberg@ARM.com        .prereq(txBytes)
1729444SAndreas.Sandberg@ARM.com        ;
1739444SAndreas.Sandberg@ARM.com
1749444SAndreas.Sandberg@ARM.com    rxBytes
1759444SAndreas.Sandberg@ARM.com        .name(name() + ".rxBytes")
1769444SAndreas.Sandberg@ARM.com        .desc("Bytes Received")
1772307SN/A        .prereq(rxBytes)
1782307SN/A        ;
1792307SN/A
1802307SN/A    txPackets
1812307SN/A        .name(name() + ".txPackets")
1822307SN/A        .desc("Number of Packets Transmitted")
1836221Snate@binkert.org        .prereq(txBytes)
1842307SN/A        ;
1852307SN/A
1862307SN/A    rxPackets
1872307SN/A        .name(name() + ".rxPackets")
1882307SN/A        .desc("Number of Packets Received")
1892292SN/A        .prereq(rxBytes)
1906221Snate@binkert.org        ;
1912292SN/A
1922292SN/A    txIpChecksums
1932292SN/A        .name(name() + ".txIpChecksums")
1942292SN/A        .desc("Number of tx IP Checksums done by device")
1952292SN/A        .precision(0)
1962292SN/A        .prereq(txBytes)
1972292SN/A        ;
1982292SN/A
1992292SN/A    rxIpChecksums
2002292SN/A        .name(name() + ".rxIpChecksums")
2012292SN/A        .desc("Number of rx IP Checksums done by device")
2022292SN/A        .precision(0)
2032292SN/A        .prereq(rxBytes)
2043867Sbinkertn@umich.edu        ;
2052292SN/A
2062292SN/A    txTcpChecksums
2072292SN/A        .name(name() + ".txTcpChecksums")
2082292SN/A        .desc("Number of tx TCP Checksums done by device")
2092292SN/A        .precision(0)
2102292SN/A        .prereq(txBytes)
2112292SN/A        ;
2122292SN/A
2132292SN/A    rxTcpChecksums
2142292SN/A        .name(name() + ".rxTcpChecksums")
2152292SN/A        .desc("Number of rx TCP Checksums done by device")
2166221Snate@binkert.org        .precision(0)
2176221Snate@binkert.org        .prereq(rxBytes)
2183867Sbinkertn@umich.edu        ;
2193867Sbinkertn@umich.edu
2206221Snate@binkert.org    txUdpChecksums
2213867Sbinkertn@umich.edu        .name(name() + ".txUdpChecksums")
2223867Sbinkertn@umich.edu        .desc("Number of tx UDP Checksums done by device")
2232292SN/A        .precision(0)
2242292SN/A        .prereq(txBytes)
2252292SN/A        ;
2262292SN/A
2272292SN/A    rxUdpChecksums
2282292SN/A        .name(name() + ".rxUdpChecksums")
2296221Snate@binkert.org        .desc("Number of rx UDP Checksums done by device")
2302292SN/A        .precision(0)
2312292SN/A        .prereq(rxBytes)
2322292SN/A        ;
2332292SN/A
2342292SN/A    descDmaReads
2352292SN/A        .name(name() + ".descDMAReads")
2362292SN/A        .desc("Number of descriptors the device read w/ DMA")
2376221Snate@binkert.org        .precision(0)
2382292SN/A        ;
2392292SN/A
2402292SN/A    descDmaWrites
2412292SN/A        .name(name() + ".descDMAWrites")
2422292SN/A        .desc("Number of descriptors the device wrote w/ DMA")
2432292SN/A        .precision(0)
2442292SN/A        ;
2452292SN/A
2462292SN/A    descDmaRdBytes
2476221Snate@binkert.org        .name(name() + ".descDmaReadBytes")
2486221Snate@binkert.org        .desc("number of descriptor bytes read w/ DMA")
2492292SN/A        .precision(0)
2503867Sbinkertn@umich.edu        ;
2516221Snate@binkert.org
2522292SN/A   descDmaWrBytes
2532292SN/A        .name(name() + ".descDmaWriteBytes")
2542292SN/A        .desc("number of descriptor bytes write w/ DMA")
2552292SN/A        .precision(0)
2562292SN/A        ;
2572292SN/A
2582292SN/A
2592292SN/A    txBandwidth
2602292SN/A        .name(name() + ".txBandwidth")
2616221Snate@binkert.org        .desc("Transmit Bandwidth (bits/s)")
2622292SN/A        .precision(0)
2632292SN/A        .prereq(txBytes)
2642292SN/A        ;
2652292SN/A
2662292SN/A    rxBandwidth
2672292SN/A        .name(name() + ".rxBandwidth")
2682292SN/A        .desc("Receive Bandwidth (bits/s)")
2692292SN/A        .precision(0)
2706221Snate@binkert.org        .prereq(rxBytes)
2712292SN/A        ;
2722292SN/A
2732292SN/A    txPacketRate
2742292SN/A        .name(name() + ".txPPS")
2752292SN/A        .desc("Packet Tranmission Rate (packets/s)")
2762292SN/A        .precision(0)
2772292SN/A        .prereq(txBytes)
2782292SN/A        ;
2796221Snate@binkert.org
2802292SN/A    rxPacketRate
2812292SN/A        .name(name() + ".rxPPS")
2822292SN/A        .desc("Packet Reception Rate (packets/s)")
2832292SN/A        .precision(0)
2842292SN/A        .prereq(rxBytes)
2852292SN/A        ;
2862292SN/A
2872292SN/A    txBandwidth = txBytes * Stats::constant(8) / simSeconds;
2886221Snate@binkert.org    rxBandwidth = rxBytes * Stats::constant(8) / simSeconds;
2892292SN/A    txPacketRate = txPackets / simSeconds;
2902292SN/A    rxPacketRate = rxPackets / simSeconds;
2912292SN/A}
2922292SN/A
2932292SN/A/**
2942292SN/A * This is to read the PCI general configuration registers
2952292SN/A */
2962292SN/Avoid
2976221Snate@binkert.orgNSGigE::ReadConfig(int offset, int size, uint8_t *data)
2986221Snate@binkert.org{
2992292SN/A    if (offset < PCI_DEVICE_SPECIFIC)
3003867Sbinkertn@umich.edu        PciDev::ReadConfig(offset, size, data);
3016221Snate@binkert.org    else
3022292SN/A        panic("Device specific PCI config space not implemented!\n");
3032292SN/A}
3042329SN/A
3052329SN/A/**
3062292SN/A * This is to write to the PCI general configuration registers
3072292SN/A */
3082292SN/Avoid
3092292SN/ANSGigE::WriteConfig(int offset, int size, uint32_t data)
3102292SN/A{
3112292SN/A    if (offset < PCI_DEVICE_SPECIFIC)
3122292SN/A        PciDev::WriteConfig(offset, size, data);
3132292SN/A    else
3142292SN/A        panic("Device specific PCI config space not implemented!\n");
3152292SN/A
3162292SN/A    // Need to catch writes to BARs to update the PIO interface
3176221Snate@binkert.org    switch (offset) {
3186221Snate@binkert.org        // seems to work fine without all these PCI settings, but i
3192292SN/A        // put in the IO to double check, an assertion will fail if we
3203867Sbinkertn@umich.edu        // need to properly implement it
3216221Snate@binkert.org      case PCI_COMMAND:
3223867Sbinkertn@umich.edu        if (config.data[offset] & PCI_CMD_IOSE)
3232292SN/A            ioEnable = true;
3242292SN/A        else
3252292SN/A            ioEnable = false;
3262292SN/A
3272292SN/A#if 0
3282292SN/A        if (config.data[offset] & PCI_CMD_BME) {
3292292SN/A            bmEnabled = true;
3308707Sandreas.hansson@arm.com        }
3318707Sandreas.hansson@arm.com        else {
3328707Sandreas.hansson@arm.com            bmEnabled = false;
3338707Sandreas.hansson@arm.com        }
3348707Sandreas.hansson@arm.com
3358707Sandreas.hansson@arm.com        if (config.data[offset] & PCI_CMD_MSE) {
3368707Sandreas.hansson@arm.com            memEnable = true;
3378707Sandreas.hansson@arm.com        }
3388707Sandreas.hansson@arm.com        else {
3398707Sandreas.hansson@arm.com            memEnable = false;
3408707Sandreas.hansson@arm.com        }
3418707Sandreas.hansson@arm.com#endif
3428707Sandreas.hansson@arm.com        break;
3438707Sandreas.hansson@arm.com
3448707Sandreas.hansson@arm.com      case PCI0_BASE_ADDR0:
3458707Sandreas.hansson@arm.com        if (BARAddrs[0] != 0) {
3468707Sandreas.hansson@arm.com            if (pioInterface)
3478707Sandreas.hansson@arm.com                pioInterface->addAddrRange(BARAddrs[0],
3488975Sandreas.hansson@arm.com                                           BARAddrs[0] + BARSize[0] - 1);
3498707Sandreas.hansson@arm.com
3508707Sandreas.hansson@arm.com            BARAddrs[0] &= PA_UNCACHED_MASK;
3518707Sandreas.hansson@arm.com        }
3528707Sandreas.hansson@arm.com        break;
3538948Sandreas.hansson@arm.com      case PCI0_BASE_ADDR1:
3548948Sandreas.hansson@arm.com        if (BARAddrs[1] != 0) {
3558948Sandreas.hansson@arm.com            if (pioInterface)
3568707Sandreas.hansson@arm.com                pioInterface->addAddrRange(BARAddrs[1],
3578948Sandreas.hansson@arm.com                                           BARAddrs[1] + BARSize[1] - 1);
3588975Sandreas.hansson@arm.com
3598975Sandreas.hansson@arm.com            BARAddrs[1] &= PA_UNCACHED_MASK;
3608948Sandreas.hansson@arm.com        }
3618948Sandreas.hansson@arm.com        break;
3628948Sandreas.hansson@arm.com    }
3638948Sandreas.hansson@arm.com}
3648948Sandreas.hansson@arm.com
3658948Sandreas.hansson@arm.com/**
3668948Sandreas.hansson@arm.com * This reads the device registers, which are detailed in the NS83820
3678948Sandreas.hansson@arm.com * spec sheet
3688948Sandreas.hansson@arm.com */
3698948Sandreas.hansson@arm.comFault
3708707Sandreas.hansson@arm.comNSGigE::read(MemReqPtr &req, uint8_t *data)
3718707Sandreas.hansson@arm.com{
3728707Sandreas.hansson@arm.com    assert(ioEnable);
3738707Sandreas.hansson@arm.com
3742292SN/A    //The mask is to give you only the offset into the device register file
3752292SN/A    Addr daddr = req->paddr & 0xfff;
3762292SN/A    DPRINTF(EthernetPIO, "read  da=%#x pa=%#x va=%#x size=%d\n",
3772292SN/A            daddr, req->paddr, req->vaddr, req->size);
3782292SN/A
3792292SN/A
3806221Snate@binkert.org    // there are some reserved registers, you can see ns_gige_reg.h and
3816221Snate@binkert.org    // the spec sheet for details
3822292SN/A    if (daddr > LAST && daddr <=  RESERVED) {
3833867Sbinkertn@umich.edu        panic("Accessing reserved register");
3846221Snate@binkert.org    } else if (daddr > RESERVED && daddr <= 0x3FC) {
3853867Sbinkertn@umich.edu        ReadConfig(daddr & 0xff, req->size, data);
3862292SN/A        return No_Fault;
3872292SN/A    } else if (daddr >= MIB_START && daddr <= MIB_END) {
3882292SN/A        // don't implement all the MIB's.  hopefully the kernel
3892292SN/A        // doesn't actually DEPEND upon their values
3902292SN/A        // MIB are just hardware stats keepers
3912292SN/A        uint32_t &reg = *(uint32_t *) data;
3922292SN/A        reg = 0;
3932292SN/A        return No_Fault;
3942292SN/A    } else if (daddr > 0x3FC)
3952292SN/A        panic("Something is messed up!\n");
3962292SN/A
3972292SN/A    switch (req->size) {
3986221Snate@binkert.org      case sizeof(uint32_t):
3996221Snate@binkert.org        {
4002292SN/A            uint32_t &reg = *(uint32_t *)data;
4013867Sbinkertn@umich.edu
4026221Snate@binkert.org            switch (daddr) {
4033867Sbinkertn@umich.edu              case CR:
4042292SN/A                reg = regs.command;
4052292SN/A                //these are supposed to be cleared on a read
4062292SN/A                reg &= ~(CR_RXD | CR_TXD | CR_TXR | CR_RXR);
4072292SN/A                break;
4082292SN/A
4092292SN/A              case CFG:
4102292SN/A                reg = regs.config;
4112292SN/A                break;
4122292SN/A
4132292SN/A              case MEAR:
4142292SN/A                reg = regs.mear;
4152292SN/A                break;
4166221Snate@binkert.org
4176221Snate@binkert.org              case PTSCR:
4182292SN/A                reg = regs.ptscr;
4193867Sbinkertn@umich.edu                break;
4206221Snate@binkert.org
4213867Sbinkertn@umich.edu              case ISR:
4222292SN/A                reg = regs.isr;
4232292SN/A                devIntrClear(ISR_ALL);
4242292SN/A                break;
4252292SN/A
4262292SN/A              case IMR:
4272292SN/A                reg = regs.imr;
4282292SN/A                break;
4292292SN/A
4302292SN/A              case IER:
4312292SN/A                reg = regs.ier;
4322292SN/A                break;
4332292SN/A
4346221Snate@binkert.org              case IHR:
4356221Snate@binkert.org                reg = regs.ihr;
4362292SN/A                break;
4373867Sbinkertn@umich.edu
4386221Snate@binkert.org              case TXDP:
4393867Sbinkertn@umich.edu                reg = regs.txdp;
4402292SN/A                break;
4412292SN/A
4422292SN/A              case TXDP_HI:
4432292SN/A                reg = regs.txdp_hi;
4442292SN/A                break;
4452292SN/A
4462292SN/A              case TXCFG:
4472292SN/A                reg = regs.txcfg;
4486221Snate@binkert.org                break;
4492292SN/A
4503870Sbinkertn@umich.edu              case GPIOR:
4512292SN/A                reg = regs.gpior;
4522292SN/A                break;
4532292SN/A
4542292SN/A              case RXDP:
4552292SN/A                reg = regs.rxdp;
4562292SN/A                break;
4572292SN/A
4582292SN/A              case RXDP_HI:
4592292SN/A                reg = regs.rxdp_hi;
4606221Snate@binkert.org                break;
4616221Snate@binkert.org
4622292SN/A              case RXCFG:
4633867Sbinkertn@umich.edu                reg = regs.rxcfg;
4646221Snate@binkert.org                break;
4653867Sbinkertn@umich.edu
4663867Sbinkertn@umich.edu              case PQCR:
4672292SN/A                reg = regs.pqcr;
4682292SN/A                break;
4692292SN/A
4702292SN/A              case WCSR:
4712292SN/A                reg = regs.wcsr;
4722292SN/A                break;
4732292SN/A
4742292SN/A              case PCR:
4756221Snate@binkert.org                reg = regs.pcr;
4762292SN/A                break;
4772292SN/A
4782292SN/A                // see the spec sheet for how RFCR and RFDR work
4793867Sbinkertn@umich.edu                // basically, you write to RFCR to tell the machine
4802292SN/A                // what you want to do next, then you act upon RFDR,
4812292SN/A                // and the device will be prepared b/c of what you
4822292SN/A                // wrote to RFCR
4832292SN/A              case RFCR:
4842292SN/A                reg = regs.rfcr;
4852292SN/A                break;
4862292SN/A
4879444SAndreas.Sandberg@ARM.com              case RFDR:
4889444SAndreas.Sandberg@ARM.com                switch (regs.rfcr & RFCR_RFADDR) {
4899444SAndreas.Sandberg@ARM.com                  case 0x000:
4909444SAndreas.Sandberg@ARM.com                    reg = rom.perfectMatch[1];
4919444SAndreas.Sandberg@ARM.com                    reg = reg << 8;
4929444SAndreas.Sandberg@ARM.com                    reg += rom.perfectMatch[0];
4939444SAndreas.Sandberg@ARM.com                    break;
4949444SAndreas.Sandberg@ARM.com                  case 0x002:
4959444SAndreas.Sandberg@ARM.com                    reg = rom.perfectMatch[3] << 8;
4969444SAndreas.Sandberg@ARM.com                    reg += rom.perfectMatch[2];
4979444SAndreas.Sandberg@ARM.com                    break;
4989444SAndreas.Sandberg@ARM.com                  case 0x004:
4999444SAndreas.Sandberg@ARM.com                    reg = rom.perfectMatch[5] << 8;
5009444SAndreas.Sandberg@ARM.com                    reg += rom.perfectMatch[4];
5019444SAndreas.Sandberg@ARM.com                    break;
5029444SAndreas.Sandberg@ARM.com                  default:
5039444SAndreas.Sandberg@ARM.com                    panic("reading RFDR for something other than PMATCH!\n");
5049444SAndreas.Sandberg@ARM.com                    // didn't implement other RFDR functionality b/c
5059444SAndreas.Sandberg@ARM.com                    // driver didn't use it
5069444SAndreas.Sandberg@ARM.com                }
5079444SAndreas.Sandberg@ARM.com                break;
5089444SAndreas.Sandberg@ARM.com
5099444SAndreas.Sandberg@ARM.com              case SRR:
5109444SAndreas.Sandberg@ARM.com                reg = regs.srr;
5119444SAndreas.Sandberg@ARM.com                break;
5129444SAndreas.Sandberg@ARM.com
5139444SAndreas.Sandberg@ARM.com              case MIBC:
5149444SAndreas.Sandberg@ARM.com                reg = regs.mibc;
5159444SAndreas.Sandberg@ARM.com                reg &= ~(MIBC_MIBS | MIBC_ACLR);
5169444SAndreas.Sandberg@ARM.com                break;
5179444SAndreas.Sandberg@ARM.com
5189444SAndreas.Sandberg@ARM.com              case VRCR:
5199444SAndreas.Sandberg@ARM.com                reg = regs.vrcr;
5209444SAndreas.Sandberg@ARM.com                break;
5219444SAndreas.Sandberg@ARM.com
5229444SAndreas.Sandberg@ARM.com              case VTCR:
5239444SAndreas.Sandberg@ARM.com                reg = regs.vtcr;
5249444SAndreas.Sandberg@ARM.com                break;
5259444SAndreas.Sandberg@ARM.com
5269444SAndreas.Sandberg@ARM.com              case VDR:
5279444SAndreas.Sandberg@ARM.com                reg = regs.vdr;
5282292SN/A                break;
5292292SN/A
5306221Snate@binkert.org              case CCSR:
5316221Snate@binkert.org                reg = regs.ccsr;
5322292SN/A                break;
5333867Sbinkertn@umich.edu
5346221Snate@binkert.org              case TBICR:
5353867Sbinkertn@umich.edu                reg = regs.tbicr;
5362292SN/A                break;
5372292SN/A
5382292SN/A              case TBISR:
5392292SN/A                reg = regs.tbisr;
5402292SN/A                break;
5412292SN/A
5422292SN/A              case TANAR:
5432292SN/A                reg = regs.tanar;
5442292SN/A                break;
5456221Snate@binkert.org
5462292SN/A              case TANLPAR:
5472292SN/A                reg = regs.tanlpar;
5482292SN/A                break;
5493870Sbinkertn@umich.edu
5502292SN/A              case TANER:
5512292SN/A                reg = regs.taner;
5522292SN/A                break;
5532292SN/A
5542292SN/A              case TESR:
5552292SN/A                reg = regs.tesr;
5562292SN/A                break;
5572292SN/A
5582292SN/A              default:
5596221Snate@binkert.org                panic("reading unimplemented register: addr=%#x", daddr);
5606221Snate@binkert.org            }
5612292SN/A
5623867Sbinkertn@umich.edu            DPRINTF(EthernetPIO, "read from %#x: data=%d data=%#x\n",
5636221Snate@binkert.org                    daddr, reg, reg);
5643867Sbinkertn@umich.edu        }
5652292SN/A        break;
5662292SN/A
5672292SN/A      default:
5682292SN/A        panic("accessing register with invalid size: addr=%#x, size=%d",
5692292SN/A              daddr, req->size);
5702292SN/A    }
5712292SN/A
5722292SN/A    return No_Fault;
5732292SN/A}
5746221Snate@binkert.org
5752292SN/AFault
5762292SN/ANSGigE::write(MemReqPtr &req, const uint8_t *data)
5772292SN/A{
5783870Sbinkertn@umich.edu    assert(ioEnable);
5792292SN/A
5802292SN/A    Addr daddr = req->paddr & 0xfff;
5812292SN/A    DPRINTF(EthernetPIO, "write da=%#x pa=%#x va=%#x size=%d\n",
5822292SN/A            daddr, req->paddr, req->vaddr, req->size);
5832292SN/A
5842292SN/A    if (daddr > LAST && daddr <=  RESERVED) {
5852292SN/A        panic("Accessing reserved register");
5862292SN/A    } else if (daddr > RESERVED && daddr <= 0x3FC) {
5872292SN/A        WriteConfig(daddr & 0xff, req->size, *(uint32_t *)data);
5886221Snate@binkert.org        return No_Fault;
5896221Snate@binkert.org    } else if (daddr > 0x3FC)
5902292SN/A        panic("Something is messed up!\n");
5913867Sbinkertn@umich.edu
5926221Snate@binkert.org    if (req->size == sizeof(uint32_t)) {
5933867Sbinkertn@umich.edu        uint32_t reg = *(uint32_t *)data;
5942292SN/A        DPRINTF(EthernetPIO, "write data=%d data=%#x\n", reg, reg);
5952292SN/A
5962292SN/A        switch (daddr) {
5972292SN/A          case CR:
5982292SN/A            regs.command = reg;
5992292SN/A            if (reg & CR_TXD) {
6002292SN/A                txEnable = false;
6012292SN/A            } else if (reg & CR_TXE) {
6022292SN/A                txEnable = true;
6036221Snate@binkert.org
6042292SN/A                // the kernel is enabling the transmit machine
6053870Sbinkertn@umich.edu                if (txState == txIdle)
6062292SN/A                    txKick();
6072292SN/A            }
6082292SN/A
6092292SN/A            if (reg & CR_RXD) {
6102292SN/A                rxEnable = false;
6112292SN/A            } else if (reg & CR_RXE) {
6122292SN/A                rxEnable = true;
6132292SN/A
6142292SN/A                if (rxState == rxIdle)
6156221Snate@binkert.org                    rxKick();
6166221Snate@binkert.org            }
6172292SN/A
6183867Sbinkertn@umich.edu            if (reg & CR_TXR)
6196221Snate@binkert.org                txReset();
6203867Sbinkertn@umich.edu
6215557Sktlim@umich.edu            if (reg & CR_RXR)
6225557Sktlim@umich.edu                rxReset();
6232292SN/A
6242292SN/A            if (reg & CR_SWI)
6255557Sktlim@umich.edu                devIntrPost(ISR_SWI);
6262292SN/A
6272292SN/A            if (reg & CR_RST) {
6282292SN/A                txReset();
6292292SN/A                rxReset();
6302292SN/A
6312292SN/A                regsReset();
6326221Snate@binkert.org            }
6336221Snate@binkert.org            break;
6342292SN/A
6353867Sbinkertn@umich.edu          case CFG:
6366221Snate@binkert.org            if (reg & CFG_LNKSTS ||
6373867Sbinkertn@umich.edu                reg & CFG_SPDSTS ||
6385557Sktlim@umich.edu                reg & CFG_DUPSTS ||
6395557Sktlim@umich.edu                reg & CFG_RESERVED ||
6402292SN/A                reg & CFG_T64ADDR ||
6412292SN/A                reg & CFG_PCI64_DET)
6425557Sktlim@umich.edu                panic("writing to read-only or reserved CFG bits!\n");
6432292SN/A
6442292SN/A            regs.config |= reg & ~(CFG_LNKSTS | CFG_SPDSTS | CFG_DUPSTS |
6452292SN/A                                   CFG_RESERVED | CFG_T64ADDR | CFG_PCI64_DET);
6462292SN/A
6479440SAndreas.Sandberg@ARM.com// all these #if 0's are because i don't THINK the kernel needs to
6482292SN/A// have these implemented. if there is a problem relating to one of
6499440SAndreas.Sandberg@ARM.com// these, you may need to add functionality in.
6509440SAndreas.Sandberg@ARM.com#if 0
6512292SN/A            if (reg & CFG_TBI_EN) ;
6523867Sbinkertn@umich.edu            if (reg & CFG_MODE_1000) ;
6536221Snate@binkert.org#endif
6543867Sbinkertn@umich.edu
6552292SN/A            if (reg & CFG_AUTO_1000)
6562292SN/A                panic("CFG_AUTO_1000 not implemented!\n");
6572292SN/A
658#if 0
659            if (reg & CFG_PINT_DUPSTS ||
660                reg & CFG_PINT_LNKSTS ||
661                reg & CFG_PINT_SPDSTS)
662                ;
663
664            if (reg & CFG_TMRTEST) ;
665            if (reg & CFG_MRM_DIS) ;
666            if (reg & CFG_MWI_DIS) ;
667
668            if (reg & CFG_T64ADDR)
669                panic("CFG_T64ADDR is read only register!\n");
670
671            if (reg & CFG_PCI64_DET)
672                panic("CFG_PCI64_DET is read only register!\n");
673
674            if (reg & CFG_DATA64_EN) ;
675            if (reg & CFG_M64ADDR) ;
676            if (reg & CFG_PHY_RST) ;
677            if (reg & CFG_PHY_DIS) ;
678#endif
679
680            if (reg & CFG_EXTSTS_EN)
681                extstsEnable = true;
682            else
683                extstsEnable = false;
684
685#if 0
686              if (reg & CFG_REQALG) ;
687              if (reg & CFG_SB) ;
688              if (reg & CFG_POW) ;
689              if (reg & CFG_EXD) ;
690              if (reg & CFG_PESEL) ;
691              if (reg & CFG_BROM_DIS) ;
692              if (reg & CFG_EXT_125) ;
693              if (reg & CFG_BEM) ;
694#endif
695            break;
696
697          case MEAR:
698            regs.mear = reg;
699            // since phy is completely faked, MEAR_MD* don't matter
700            // and since the driver never uses MEAR_EE*, they don't
701            // matter
702#if 0
703            if (reg & MEAR_EEDI) ;
704            if (reg & MEAR_EEDO) ; // this one is read only
705            if (reg & MEAR_EECLK) ;
706            if (reg & MEAR_EESEL) ;
707            if (reg & MEAR_MDIO) ;
708            if (reg & MEAR_MDDIR) ;
709            if (reg & MEAR_MDC) ;
710#endif
711            break;
712
713          case PTSCR:
714            regs.ptscr = reg & ~(PTSCR_RBIST_RDONLY);
715            // these control BISTs for various parts of chip - we
716            // don't care or do just fake that the BIST is done
717            if (reg & PTSCR_RBIST_EN)
718                regs.ptscr |= PTSCR_RBIST_DONE;
719            if (reg & PTSCR_EEBIST_EN)
720                regs.ptscr &= ~PTSCR_EEBIST_EN;
721            if (reg & PTSCR_EELOAD_EN)
722                regs.ptscr &= ~PTSCR_EELOAD_EN;
723            break;
724
725          case ISR: /* writing to the ISR has no effect */
726            panic("ISR is a read only register!\n");
727
728          case IMR:
729            regs.imr = reg;
730            devIntrChangeMask();
731            break;
732
733          case IER:
734            regs.ier = reg;
735            break;
736
737          case IHR:
738            regs.ihr = reg;
739            /* not going to implement real interrupt holdoff */
740            break;
741
742          case TXDP:
743            regs.txdp = (reg & 0xFFFFFFFC);
744            assert(txState == txIdle);
745            CTDD = false;
746            break;
747
748          case TXDP_HI:
749            regs.txdp_hi = reg;
750            break;
751
752          case TXCFG:
753            regs.txcfg = reg;
754#if 0
755            if (reg & TXCFG_CSI) ;
756            if (reg & TXCFG_HBI) ;
757            if (reg & TXCFG_MLB) ;
758            if (reg & TXCFG_ATP) ;
759            if (reg & TXCFG_ECRETRY) {
760                /*
761                 * this could easily be implemented, but considering
762                 * the network is just a fake pipe, wouldn't make
763                 * sense to do this
764                 */
765            }
766
767            if (reg & TXCFG_BRST_DIS) ;
768#endif
769
770#if 0
771            /* we handle our own DMA, ignore the kernel's exhortations */
772            if (reg & TXCFG_MXDMA) ;
773#endif
774
775            // also, we currently don't care about fill/drain
776            // thresholds though this may change in the future with
777            // more realistic networks or a driver which changes it
778            // according to feedback
779
780            break;
781
782          case GPIOR:
783            regs.gpior = reg;
784            /* these just control general purpose i/o pins, don't matter */
785            break;
786
787          case RXDP:
788            regs.rxdp = reg;
789            CRDD = false;
790            break;
791
792          case RXDP_HI:
793            regs.rxdp_hi = reg;
794            break;
795
796          case RXCFG:
797            regs.rxcfg = reg;
798#if 0
799            if (reg & RXCFG_AEP) ;
800            if (reg & RXCFG_ARP) ;
801            if (reg & RXCFG_STRIPCRC) ;
802            if (reg & RXCFG_RX_RD) ;
803            if (reg & RXCFG_ALP) ;
804            if (reg & RXCFG_AIRL) ;
805
806            /* we handle our own DMA, ignore what kernel says about it */
807            if (reg & RXCFG_MXDMA) ;
808
809            //also, we currently don't care about fill/drain thresholds
810            //though this may change in the future with more realistic
811            //networks or a driver which changes it according to feedback
812            if (reg & (RXCFG_DRTH | RXCFG_DRTH0)) ;
813#endif
814            break;
815
816          case PQCR:
817            /* there is no priority queueing used in the linux 2.6 driver */
818            regs.pqcr = reg;
819            break;
820
821          case WCSR:
822            /* not going to implement wake on LAN */
823            regs.wcsr = reg;
824            break;
825
826          case PCR:
827            /* not going to implement pause control */
828            regs.pcr = reg;
829            break;
830
831          case RFCR:
832            regs.rfcr = reg;
833
834            rxFilterEnable = (reg & RFCR_RFEN) ? true : false;
835            acceptBroadcast = (reg & RFCR_AAB) ? true : false;
836            acceptMulticast = (reg & RFCR_AAM) ? true : false;
837            acceptUnicast = (reg & RFCR_AAU) ? true : false;
838            acceptPerfect = (reg & RFCR_APM) ? true : false;
839            acceptArp = (reg & RFCR_AARP) ? true : false;
840
841#if 0
842            if (reg & RFCR_APAT)
843                panic("RFCR_APAT not implemented!\n");
844#endif
845
846            if (reg & RFCR_MHEN || reg & RFCR_UHEN)
847                panic("hash filtering not implemented!\n");
848
849            if (reg & RFCR_ULM)
850                panic("RFCR_ULM not implemented!\n");
851
852            break;
853
854          case RFDR:
855            panic("the driver never writes to RFDR, something is wrong!\n");
856
857          case BRAR:
858            panic("the driver never uses BRAR, something is wrong!\n");
859
860          case BRDR:
861            panic("the driver never uses BRDR, something is wrong!\n");
862
863          case SRR:
864            panic("SRR is read only register!\n");
865
866          case MIBC:
867            panic("the driver never uses MIBC, something is wrong!\n");
868
869          case VRCR:
870            regs.vrcr = reg;
871            break;
872
873          case VTCR:
874            regs.vtcr = reg;
875            break;
876
877          case VDR:
878            panic("the driver never uses VDR, something is wrong!\n");
879            break;
880
881          case CCSR:
882            /* not going to implement clockrun stuff */
883            regs.ccsr = reg;
884            break;
885
886          case TBICR:
887            regs.tbicr = reg;
888            if (reg & TBICR_MR_LOOPBACK)
889                panic("TBICR_MR_LOOPBACK never used, something wrong!\n");
890
891            if (reg & TBICR_MR_AN_ENABLE) {
892                regs.tanlpar = regs.tanar;
893                regs.tbisr |= (TBISR_MR_AN_COMPLETE | TBISR_MR_LINK_STATUS);
894            }
895
896#if 0
897            if (reg & TBICR_MR_RESTART_AN) ;
898#endif
899
900            break;
901
902          case TBISR:
903            panic("TBISR is read only register!\n");
904
905          case TANAR:
906            regs.tanar = reg;
907            if (reg & TANAR_PS2)
908                panic("this isn't used in driver, something wrong!\n");
909
910            if (reg & TANAR_PS1)
911                panic("this isn't used in driver, something wrong!\n");
912            break;
913
914          case TANLPAR:
915            panic("this should only be written to by the fake phy!\n");
916
917          case TANER:
918            panic("TANER is read only register!\n");
919
920          case TESR:
921            regs.tesr = reg;
922            break;
923
924          default:
925            panic("invalid register access daddr=%#x", daddr);
926        }
927    } else {
928        panic("Invalid Request Size");
929    }
930
931    return No_Fault;
932}
933
934void
935NSGigE::devIntrPost(uint32_t interrupts)
936{
937    if (interrupts & ISR_RESERVE)
938        panic("Cannot set a reserved interrupt");
939
940    if (interrupts & ISR_NOIMPL)
941        warn("interrupt not implemented %#x\n", interrupts);
942
943    interrupts &= ~ISR_NOIMPL;
944    regs.isr |= interrupts;
945
946    DPRINTF(EthernetIntr,
947            "interrupt written to ISR: intr=%#x isr=%#x imr=%#x\n",
948            interrupts, regs.isr, regs.imr);
949
950    if ((regs.isr & regs.imr)) {
951        Tick when = curTick;
952        if (!(regs.isr & regs.imr & ISR_NODELAY))
953            when += intrDelay;
954        cpuIntrPost(when);
955    }
956}
957
958void
959NSGigE::devIntrClear(uint32_t interrupts)
960{
961    if (interrupts & ISR_RESERVE)
962        panic("Cannot clear a reserved interrupt");
963
964    interrupts &= ~ISR_NOIMPL;
965    regs.isr &= ~interrupts;
966
967    DPRINTF(EthernetIntr,
968            "interrupt cleared from ISR: intr=%x isr=%x imr=%x\n",
969            interrupts, regs.isr, regs.imr);
970
971    if (!(regs.isr & regs.imr))
972        cpuIntrClear();
973}
974
975void
976NSGigE::devIntrChangeMask()
977{
978    DPRINTF(EthernetIntr, "interrupt mask changed: isr=%x imr=%x masked=%x\n",
979            regs.isr, regs.imr, regs.isr & regs.imr);
980
981    if (regs.isr & regs.imr)
982        cpuIntrPost(curTick);
983    else
984        cpuIntrClear();
985}
986
987void
988NSGigE::cpuIntrPost(Tick when)
989{
990    // If the interrupt you want to post is later than an interrupt
991    // already scheduled, just let it post in the coming one and don't
992    // schedule another.
993    // HOWEVER, must be sure that the scheduled intrTick is in the
994    // future (this was formerly the source of a bug)
995    /**
996     * @todo this warning should be removed and the intrTick code should
997     * be fixed.
998     */
999    assert(when >= curTick);
1000    assert(intrTick >= curTick || intrTick == 0);
1001    if (when > intrTick && intrTick != 0) {
1002        DPRINTF(EthernetIntr, "don't need to schedule event...intrTick=%d\n",
1003                intrTick);
1004        return;
1005    }
1006
1007    intrTick = when;
1008    if (intrTick < curTick) {
1009        debug_break();
1010        intrTick = curTick;
1011    }
1012
1013    DPRINTF(EthernetIntr, "going to schedule an interrupt for intrTick=%d\n",
1014            intrTick);
1015
1016    if (intrEvent)
1017        intrEvent->squash();
1018    intrEvent = new IntrEvent(this, true);
1019    intrEvent->schedule(intrTick);
1020}
1021
1022void
1023NSGigE::cpuInterrupt()
1024{
1025    assert(intrTick == curTick);
1026
1027    // Whether or not there's a pending interrupt, we don't care about
1028    // it anymore
1029    intrEvent = 0;
1030    intrTick = 0;
1031
1032    // Don't send an interrupt if there's already one
1033    if (cpuPendingIntr) {
1034        DPRINTF(EthernetIntr,
1035                "would send an interrupt now, but there's already pending\n");
1036    } else {
1037        // Send interrupt
1038        cpuPendingIntr = true;
1039
1040        DPRINTF(EthernetIntr, "posting cchip interrupt\n");
1041        tsunami->cchip->postDRIR(configData->config.hdr.pci0.interruptLine);
1042    }
1043}
1044
1045void
1046NSGigE::cpuIntrClear()
1047{
1048    if (!cpuPendingIntr)
1049        return;
1050
1051    if (intrEvent) {
1052        intrEvent->squash();
1053        intrEvent = 0;
1054    }
1055
1056    intrTick = 0;
1057
1058    cpuPendingIntr = false;
1059
1060    DPRINTF(EthernetIntr, "clearing cchip interrupt\n");
1061    tsunami->cchip->clearDRIR(configData->config.hdr.pci0.interruptLine);
1062}
1063
1064bool
1065NSGigE::cpuIntrPending() const
1066{ return cpuPendingIntr; }
1067
1068void
1069NSGigE::txReset()
1070{
1071
1072    DPRINTF(Ethernet, "transmit reset\n");
1073
1074    CTDD = false;
1075    txFifoAvail = maxTxFifoSize;
1076    txEnable = false;;
1077    txFragPtr = 0;
1078    assert(txDescCnt == 0);
1079    txFifo.clear();
1080    txState = txIdle;
1081    assert(txDmaState == dmaIdle);
1082}
1083
1084void
1085NSGigE::rxReset()
1086{
1087    DPRINTF(Ethernet, "receive reset\n");
1088
1089    CRDD = false;
1090    assert(rxPktBytes == 0);
1091    rxFifoCnt = 0;
1092    rxEnable = false;
1093    rxFragPtr = 0;
1094    assert(rxDescCnt == 0);
1095    assert(rxDmaState == dmaIdle);
1096    rxFifo.clear();
1097    rxState = rxIdle;
1098}
1099
1100void
1101NSGigE::regsReset()
1102{
1103    memset(&regs, 0, sizeof(regs));
1104    regs.config = CFG_LNKSTS;
1105    regs.mear = MEAR_MDDIR | MEAR_EEDO;
1106    regs.txcfg = 0x120; // set drain threshold to 1024 bytes and
1107                        // fill threshold to 32 bytes
1108    regs.rxcfg = 0x4;   // set drain threshold to 16 bytes
1109    regs.srr = 0x0103;  // set the silicon revision to rev B or 0x103
1110    regs.mibc = MIBC_FRZ;
1111    regs.vdr = 0x81;    // set the vlan tag type to 802.1q
1112    regs.tesr = 0xc000; // TBI capable of both full and half duplex
1113
1114    extstsEnable = false;
1115    acceptBroadcast = false;
1116    acceptMulticast = false;
1117    acceptUnicast = false;
1118    acceptPerfect = false;
1119    acceptArp = false;
1120}
1121
1122void
1123NSGigE::rxDmaReadCopy()
1124{
1125    assert(rxDmaState == dmaReading);
1126
1127    physmem->dma_read((uint8_t *)rxDmaData, rxDmaAddr, rxDmaLen);
1128    rxDmaState = dmaIdle;
1129
1130    DPRINTF(EthernetDMA, "rx dma read  paddr=%#x len=%d\n",
1131            rxDmaAddr, rxDmaLen);
1132    DDUMP(EthernetDMA, rxDmaData, rxDmaLen);
1133}
1134
1135bool
1136NSGigE::doRxDmaRead()
1137{
1138    assert(rxDmaState == dmaIdle || rxDmaState == dmaReadWaiting);
1139    rxDmaState = dmaReading;
1140
1141    if (dmaInterface && !rxDmaFree) {
1142        if (dmaInterface->busy())
1143            rxDmaState = dmaReadWaiting;
1144        else
1145            dmaInterface->doDMA(Read, rxDmaAddr, rxDmaLen, curTick,
1146                                &rxDmaReadEvent, true);
1147        return true;
1148    }
1149
1150    if (dmaReadDelay == 0 && dmaReadFactor == 0) {
1151        rxDmaReadCopy();
1152        return false;
1153    }
1154
1155    Tick factor = ((rxDmaLen + ULL(63)) >> ULL(6)) * dmaReadFactor;
1156    Tick start = curTick + dmaReadDelay + factor;
1157    rxDmaReadEvent.schedule(start);
1158    return true;
1159}
1160
1161void
1162NSGigE::rxDmaReadDone()
1163{
1164    assert(rxDmaState == dmaReading);
1165    rxDmaReadCopy();
1166
1167    // If the transmit state machine has a pending DMA, let it go first
1168    if (txDmaState == dmaReadWaiting || txDmaState == dmaWriteWaiting)
1169        txKick();
1170
1171    rxKick();
1172}
1173
1174void
1175NSGigE::rxDmaWriteCopy()
1176{
1177    assert(rxDmaState == dmaWriting);
1178
1179    physmem->dma_write(rxDmaAddr, (uint8_t *)rxDmaData, rxDmaLen);
1180    rxDmaState = dmaIdle;
1181
1182    DPRINTF(EthernetDMA, "rx dma write paddr=%#x len=%d\n",
1183            rxDmaAddr, rxDmaLen);
1184    DDUMP(EthernetDMA, rxDmaData, rxDmaLen);
1185}
1186
1187bool
1188NSGigE::doRxDmaWrite()
1189{
1190    assert(rxDmaState == dmaIdle || rxDmaState == dmaWriteWaiting);
1191    rxDmaState = dmaWriting;
1192
1193    if (dmaInterface && !rxDmaFree) {
1194        if (dmaInterface->busy())
1195            rxDmaState = dmaWriteWaiting;
1196        else
1197            dmaInterface->doDMA(WriteInvalidate, rxDmaAddr, rxDmaLen, curTick,
1198                                &rxDmaWriteEvent, true);
1199        return true;
1200    }
1201
1202    if (dmaWriteDelay == 0 && dmaWriteFactor == 0) {
1203        rxDmaWriteCopy();
1204        return false;
1205    }
1206
1207    Tick factor = ((rxDmaLen + ULL(63)) >> ULL(6)) * dmaWriteFactor;
1208    Tick start = curTick + dmaWriteDelay + factor;
1209    rxDmaWriteEvent.schedule(start);
1210    return true;
1211}
1212
1213void
1214NSGigE::rxDmaWriteDone()
1215{
1216    assert(rxDmaState == dmaWriting);
1217    rxDmaWriteCopy();
1218
1219    // If the transmit state machine has a pending DMA, let it go first
1220    if (txDmaState == dmaReadWaiting || txDmaState == dmaWriteWaiting)
1221        txKick();
1222
1223    rxKick();
1224}
1225
1226void
1227NSGigE::rxKick()
1228{
1229    DPRINTF(EthernetSM, "receive kick rxState=%s (rxBuf.size=%d)\n",
1230            NsRxStateStrings[rxState], rxFifo.size());
1231
1232    if (rxKickTick > curTick) {
1233        DPRINTF(EthernetSM, "receive kick exiting, can't run till %d\n",
1234                rxKickTick);
1235        return;
1236    }
1237
1238  next:
1239    switch(rxDmaState) {
1240      case dmaReadWaiting:
1241        if (doRxDmaRead())
1242            goto exit;
1243        break;
1244      case dmaWriteWaiting:
1245        if (doRxDmaWrite())
1246            goto exit;
1247        break;
1248      default:
1249        break;
1250    }
1251
1252    // see state machine from spec for details
1253    // the way this works is, if you finish work on one state and can
1254    // go directly to another, you do that through jumping to the
1255    // label "next".  however, if you have intermediate work, like DMA
1256    // so that you can't go to the next state yet, you go to exit and
1257    // exit the loop.  however, when the DMA is done it will trigger
1258    // an event and come back to this loop.
1259    switch (rxState) {
1260      case rxIdle:
1261        if (!rxEnable) {
1262            DPRINTF(EthernetSM, "Receive Disabled! Nothing to do.\n");
1263            goto exit;
1264        }
1265
1266        if (CRDD) {
1267            rxState = rxDescRefr;
1268
1269            rxDmaAddr = regs.rxdp & 0x3fffffff;
1270            rxDmaData = &rxDescCache + offsetof(ns_desc, link);
1271            rxDmaLen = sizeof(rxDescCache.link);
1272            rxDmaFree = dmaDescFree;
1273
1274            descDmaReads++;
1275            descDmaRdBytes += rxDmaLen;
1276
1277            if (doRxDmaRead())
1278                goto exit;
1279        } else {
1280            rxState = rxDescRead;
1281
1282            rxDmaAddr = regs.rxdp & 0x3fffffff;
1283            rxDmaData = &rxDescCache;
1284            rxDmaLen = sizeof(ns_desc);
1285            rxDmaFree = dmaDescFree;
1286
1287            descDmaReads++;
1288            descDmaRdBytes += rxDmaLen;
1289
1290            if (doRxDmaRead())
1291                goto exit;
1292        }
1293        break;
1294
1295      case rxDescRefr:
1296        if (rxDmaState != dmaIdle)
1297            goto exit;
1298
1299        rxState = rxAdvance;
1300        break;
1301
1302     case rxDescRead:
1303        if (rxDmaState != dmaIdle)
1304            goto exit;
1305
1306        DPRINTF(EthernetDesc,
1307                "rxDescCache: addr=%08x read descriptor\n",
1308                regs.rxdp & 0x3fffffff);
1309        DPRINTF(EthernetDesc,
1310                "rxDescCache: link=%08x bufptr=%08x cmdsts=%08x extsts=%08x\n",
1311                rxDescCache.link, rxDescCache.bufptr, rxDescCache.cmdsts,
1312                rxDescCache.extsts);
1313
1314        if (rxDescCache.cmdsts & CMDSTS_OWN) {
1315            devIntrPost(ISR_RXIDLE);
1316            rxState = rxIdle;
1317            goto exit;
1318        } else {
1319            rxState = rxFifoBlock;
1320            rxFragPtr = rxDescCache.bufptr;
1321            rxDescCnt = rxDescCache.cmdsts & CMDSTS_LEN_MASK;
1322        }
1323        break;
1324
1325      case rxFifoBlock:
1326        if (!rxPacket) {
1327            /**
1328             * @todo in reality, we should be able to start processing
1329             * the packet as it arrives, and not have to wait for the
1330             * full packet ot be in the receive fifo.
1331             */
1332            if (rxFifo.empty())
1333                goto exit;
1334
1335            DPRINTF(EthernetSM, "****processing receive of new packet****\n");
1336
1337            // If we don't have a packet, grab a new one from the fifo.
1338            rxPacket = rxFifo.front();
1339            rxPktBytes = rxPacket->length;
1340            rxPacketBufPtr = rxPacket->data;
1341
1342#if TRACING_ON
1343            if (DTRACE(Ethernet)) {
1344                const IpHdr *ip = rxPacket->ip();
1345                if (ip) {
1346                    DPRINTF(Ethernet, "ID is %d\n", ip->id());
1347                    const TcpHdr *tcp = rxPacket->tcp();
1348                    if (tcp) {
1349                        DPRINTF(Ethernet, "Src Port=%d, Dest Port=%d\n",
1350                                tcp->sport(), tcp->dport());
1351                    }
1352                }
1353            }
1354#endif
1355
1356            // sanity check - i think the driver behaves like this
1357            assert(rxDescCnt >= rxPktBytes);
1358
1359            // Must clear the value before popping to decrement the
1360            // reference count
1361            rxFifo.front() = NULL;
1362            rxFifo.pop_front();
1363            rxFifoCnt -= rxPacket->length;
1364        }
1365
1366
1367        // dont' need the && rxDescCnt > 0 if driver sanity check
1368        // above holds
1369        if (rxPktBytes > 0) {
1370            rxState = rxFragWrite;
1371            // don't need min<>(rxPktBytes,rxDescCnt) if above sanity
1372            // check holds
1373            rxXferLen = rxPktBytes;
1374
1375            rxDmaAddr = rxFragPtr & 0x3fffffff;
1376            rxDmaData = rxPacketBufPtr;
1377            rxDmaLen = rxXferLen;
1378            rxDmaFree = dmaDataFree;
1379
1380            if (doRxDmaWrite())
1381                goto exit;
1382
1383        } else {
1384            rxState = rxDescWrite;
1385
1386            //if (rxPktBytes == 0) {  /* packet is done */
1387            assert(rxPktBytes == 0);
1388            DPRINTF(EthernetSM, "done with receiving packet\n");
1389
1390            rxDescCache.cmdsts |= CMDSTS_OWN;
1391            rxDescCache.cmdsts &= ~CMDSTS_MORE;
1392            rxDescCache.cmdsts |= CMDSTS_OK;
1393            rxDescCache.cmdsts &= 0xffff0000;
1394            rxDescCache.cmdsts += rxPacket->length;   //i.e. set CMDSTS_SIZE
1395
1396#if 0
1397            /*
1398             * all the driver uses these are for its own stats keeping
1399             * which we don't care about, aren't necessary for
1400             * functionality and doing this would just slow us down.
1401             * if they end up using this in a later version for
1402             * functional purposes, just undef
1403             */
1404            if (rxFilterEnable) {
1405                rxDescCache.cmdsts &= ~CMDSTS_DEST_MASK;
1406                EthHdr *eth = rxFifoFront()->eth();
1407                if (eth->unicast())
1408                    rxDescCache.cmdsts |= CMDSTS_DEST_SELF;
1409                if (eth->multicast())
1410                    rxDescCache.cmdsts |= CMDSTS_DEST_MULTI;
1411                if (eth->broadcast())
1412                    rxDescCache.cmdsts |= CMDSTS_DEST_MASK;
1413            }
1414#endif
1415
1416            if (extstsEnable && rxPacket->ip()) {
1417                rxDescCache.extsts |= EXTSTS_IPPKT;
1418                rxIpChecksums++;
1419                IpHdr *ip = rxPacket->ip();
1420                if (ip->ip_cksum() != 0) {
1421                    DPRINTF(EthernetCksum, "Rx IP Checksum Error\n");
1422                    rxDescCache.extsts |= EXTSTS_IPERR;
1423                }
1424                if (rxPacket->tcp()) {
1425                    rxDescCache.extsts |= EXTSTS_TCPPKT;
1426                    rxTcpChecksums++;
1427                    if (ip->tu_cksum() != 0) {
1428                        DPRINTF(EthernetCksum, "Rx TCP Checksum Error\n");
1429                        rxDescCache.extsts |= EXTSTS_TCPERR;
1430
1431                    }
1432                } else if (rxPacket->udp()) {
1433                    rxDescCache.extsts |= EXTSTS_UDPPKT;
1434                    rxUdpChecksums++;
1435                    if (ip->tu_cksum() != 0) {
1436                        DPRINTF(EthernetCksum, "Rx UDP Checksum Error\n");
1437                        rxDescCache.extsts |= EXTSTS_UDPERR;
1438                    }
1439                }
1440            }
1441            rxPacket = 0;
1442
1443            /*
1444             * the driver seems to always receive into desc buffers
1445             * of size 1514, so you never have a pkt that is split
1446             * into multiple descriptors on the receive side, so
1447             * i don't implement that case, hence the assert above.
1448             */
1449
1450            DPRINTF(EthernetDesc,
1451                    "rxDescCache: addr=%08x writeback cmdsts extsts\n",
1452                    regs.rxdp & 0x3fffffff);
1453            DPRINTF(EthernetDesc,
1454                    "rxDescCache: link=%08x bufptr=%08x cmdsts=%08x extsts=%08x\n",
1455                    rxDescCache.link, rxDescCache.bufptr, rxDescCache.cmdsts,
1456                    rxDescCache.extsts);
1457
1458            rxDmaAddr = (regs.rxdp + offsetof(ns_desc, cmdsts)) & 0x3fffffff;
1459            rxDmaData = &(rxDescCache.cmdsts);
1460            rxDmaLen = sizeof(rxDescCache.cmdsts) + sizeof(rxDescCache.extsts);
1461            rxDmaFree = dmaDescFree;
1462
1463            descDmaWrites++;
1464            descDmaWrBytes += rxDmaLen;
1465
1466            if (doRxDmaWrite())
1467                goto exit;
1468        }
1469        break;
1470
1471      case rxFragWrite:
1472        if (rxDmaState != dmaIdle)
1473            goto exit;
1474
1475        rxPacketBufPtr += rxXferLen;
1476        rxFragPtr += rxXferLen;
1477        rxPktBytes -= rxXferLen;
1478
1479        rxState = rxFifoBlock;
1480        break;
1481
1482      case rxDescWrite:
1483        if (rxDmaState != dmaIdle)
1484            goto exit;
1485
1486        assert(rxDescCache.cmdsts & CMDSTS_OWN);
1487
1488        assert(rxPacket == 0);
1489        devIntrPost(ISR_RXOK);
1490
1491        if (rxDescCache.cmdsts & CMDSTS_INTR)
1492            devIntrPost(ISR_RXDESC);
1493
1494        if (!rxEnable) {
1495            DPRINTF(EthernetSM, "Halting the RX state machine\n");
1496            rxState = rxIdle;
1497            goto exit;
1498        } else
1499            rxState = rxAdvance;
1500        break;
1501
1502      case rxAdvance:
1503        if (rxDescCache.link == 0) {
1504            devIntrPost(ISR_RXIDLE);
1505            rxState = rxIdle;
1506            CRDD = true;
1507            goto exit;
1508        } else {
1509            rxState = rxDescRead;
1510            regs.rxdp = rxDescCache.link;
1511            CRDD = false;
1512
1513            rxDmaAddr = regs.rxdp & 0x3fffffff;
1514            rxDmaData = &rxDescCache;
1515            rxDmaLen = sizeof(ns_desc);
1516            rxDmaFree = dmaDescFree;
1517
1518            if (doRxDmaRead())
1519                goto exit;
1520        }
1521        break;
1522
1523      default:
1524        panic("Invalid rxState!");
1525    }
1526
1527    DPRINTF(EthernetSM, "entering next rxState=%s\n",
1528            NsRxStateStrings[rxState]);
1529
1530    goto next;
1531
1532  exit:
1533    /**
1534     * @todo do we want to schedule a future kick?
1535     */
1536    DPRINTF(EthernetSM, "rx state machine exited rxState=%s\n",
1537            NsRxStateStrings[rxState]);
1538}
1539
1540void
1541NSGigE::transmit()
1542{
1543    if (txFifo.empty()) {
1544        DPRINTF(Ethernet, "nothing to transmit\n");
1545        return;
1546    }
1547
1548    DPRINTF(Ethernet, "Attempt Pkt Transmit: txFifo length=%d\n",
1549            maxTxFifoSize - txFifoAvail);
1550    if (interface->sendPacket(txFifo.front())) {
1551#if TRACING_ON
1552        if (DTRACE(Ethernet)) {
1553            const IpHdr *ip = txFifo.front()->ip();
1554            if (ip) {
1555                DPRINTF(Ethernet, "ID is %d\n", ip->id());
1556                const TcpHdr *tcp = txFifo.front()->tcp();
1557                if (tcp) {
1558                    DPRINTF(Ethernet, "Src Port=%d, Dest Port=%d\n",
1559                            tcp->sport(), tcp->dport());
1560                }
1561            }
1562        }
1563#endif
1564
1565        DDUMP(Ethernet, txFifo.front()->data, txFifo.front()->length);
1566        txBytes += txFifo.front()->length;
1567        txPackets++;
1568
1569        txFifoAvail += txFifo.front()->length;
1570
1571        DPRINTF(Ethernet, "Successful Xmit! now txFifoAvail is %d\n",
1572                txFifoAvail);
1573        txFifo.front() = NULL;
1574        txFifo.pop_front();
1575
1576        /*
1577         * normally do a writeback of the descriptor here, and ONLY
1578         * after that is done, send this interrupt.  but since our
1579         * stuff never actually fails, just do this interrupt here,
1580         * otherwise the code has to stray from this nice format.
1581         * besides, it's functionally the same.
1582         */
1583        devIntrPost(ISR_TXOK);
1584    } else {
1585        DPRINTF(Ethernet,
1586                "May need to rethink always sending the descriptors back?\n");
1587    }
1588
1589   if (!txFifo.empty() && !txEvent.scheduled()) {
1590       DPRINTF(Ethernet, "reschedule transmit\n");
1591       txEvent.schedule(curTick + 1000);
1592   }
1593}
1594
1595void
1596NSGigE::txDmaReadCopy()
1597{
1598    assert(txDmaState == dmaReading);
1599
1600    physmem->dma_read((uint8_t *)txDmaData, txDmaAddr, txDmaLen);
1601    txDmaState = dmaIdle;
1602
1603    DPRINTF(EthernetDMA, "tx dma read  paddr=%#x len=%d\n",
1604            txDmaAddr, txDmaLen);
1605    DDUMP(EthernetDMA, txDmaData, txDmaLen);
1606}
1607
1608bool
1609NSGigE::doTxDmaRead()
1610{
1611    assert(txDmaState == dmaIdle || txDmaState == dmaReadWaiting);
1612    txDmaState = dmaReading;
1613
1614    if (dmaInterface && !txDmaFree) {
1615        if (dmaInterface->busy())
1616            txDmaState = dmaReadWaiting;
1617        else
1618            dmaInterface->doDMA(Read, txDmaAddr, txDmaLen, curTick,
1619                                &txDmaReadEvent, true);
1620        return true;
1621    }
1622
1623    if (dmaReadDelay == 0 && dmaReadFactor == 0.0) {
1624        txDmaReadCopy();
1625        return false;
1626    }
1627
1628    Tick factor = ((txDmaLen + ULL(63)) >> ULL(6)) * dmaReadFactor;
1629    Tick start = curTick + dmaReadDelay + factor;
1630    txDmaReadEvent.schedule(start);
1631    return true;
1632}
1633
1634void
1635NSGigE::txDmaReadDone()
1636{
1637    assert(txDmaState == dmaReading);
1638    txDmaReadCopy();
1639
1640    // If the receive state machine  has a pending DMA, let it go first
1641    if (rxDmaState == dmaReadWaiting || rxDmaState == dmaWriteWaiting)
1642        rxKick();
1643
1644    txKick();
1645}
1646
1647void
1648NSGigE::txDmaWriteCopy()
1649{
1650    assert(txDmaState == dmaWriting);
1651
1652    physmem->dma_write(txDmaAddr, (uint8_t *)txDmaData, txDmaLen);
1653    txDmaState = dmaIdle;
1654
1655    DPRINTF(EthernetDMA, "tx dma write paddr=%#x len=%d\n",
1656            txDmaAddr, txDmaLen);
1657    DDUMP(EthernetDMA, txDmaData, txDmaLen);
1658}
1659
1660bool
1661NSGigE::doTxDmaWrite()
1662{
1663    assert(txDmaState == dmaIdle || txDmaState == dmaWriteWaiting);
1664    txDmaState = dmaWriting;
1665
1666    if (dmaInterface && !txDmaFree) {
1667        if (dmaInterface->busy())
1668            txDmaState = dmaWriteWaiting;
1669        else
1670            dmaInterface->doDMA(WriteInvalidate, txDmaAddr, txDmaLen, curTick,
1671                                &txDmaWriteEvent, true);
1672        return true;
1673    }
1674
1675    if (dmaWriteDelay == 0 && dmaWriteFactor == 0.0) {
1676        txDmaWriteCopy();
1677        return false;
1678    }
1679
1680    Tick factor = ((txDmaLen + ULL(63)) >> ULL(6)) * dmaWriteFactor;
1681    Tick start = curTick + dmaWriteDelay + factor;
1682    txDmaWriteEvent.schedule(start);
1683    return true;
1684}
1685
1686void
1687NSGigE::txDmaWriteDone()
1688{
1689    assert(txDmaState == dmaWriting);
1690    txDmaWriteCopy();
1691
1692    // If the receive state machine  has a pending DMA, let it go first
1693    if (rxDmaState == dmaReadWaiting || rxDmaState == dmaWriteWaiting)
1694        rxKick();
1695
1696    txKick();
1697}
1698
1699void
1700NSGigE::txKick()
1701{
1702    DPRINTF(EthernetSM, "transmit kick txState=%s\n",
1703            NsTxStateStrings[txState]);
1704
1705    if (txKickTick > curTick) {
1706        DPRINTF(EthernetSM, "transmit kick exiting, can't run till %d\n",
1707                txKickTick);
1708
1709        return;
1710    }
1711
1712  next:
1713    switch(txDmaState) {
1714      case dmaReadWaiting:
1715        if (doTxDmaRead())
1716            goto exit;
1717        break;
1718      case dmaWriteWaiting:
1719        if (doTxDmaWrite())
1720            goto exit;
1721        break;
1722      default:
1723        break;
1724    }
1725
1726    switch (txState) {
1727      case txIdle:
1728        if (!txEnable) {
1729            DPRINTF(EthernetSM, "Transmit disabled.  Nothing to do.\n");
1730            goto exit;
1731        }
1732
1733        if (CTDD) {
1734            txState = txDescRefr;
1735
1736            txDmaAddr = regs.txdp & 0x3fffffff;
1737            txDmaData = &txDescCache + offsetof(ns_desc, link);
1738            txDmaLen = sizeof(txDescCache.link);
1739            txDmaFree = dmaDescFree;
1740
1741            descDmaReads++;
1742            descDmaRdBytes += txDmaLen;
1743
1744            if (doTxDmaRead())
1745                goto exit;
1746
1747        } else {
1748            txState = txDescRead;
1749
1750            txDmaAddr = regs.txdp & 0x3fffffff;
1751            txDmaData = &txDescCache;
1752            txDmaLen = sizeof(ns_desc);
1753            txDmaFree = dmaDescFree;
1754
1755            descDmaReads++;
1756            descDmaRdBytes += txDmaLen;
1757
1758            if (doTxDmaRead())
1759                goto exit;
1760        }
1761        break;
1762
1763      case txDescRefr:
1764        if (txDmaState != dmaIdle)
1765            goto exit;
1766
1767        txState = txAdvance;
1768        break;
1769
1770      case txDescRead:
1771        if (txDmaState != dmaIdle)
1772            goto exit;
1773
1774        DPRINTF(EthernetDesc,
1775                "txDescCache: link=%08x bufptr=%08x cmdsts=%08x extsts=%08x\n",
1776                txDescCache.link, txDescCache.bufptr, txDescCache.cmdsts,
1777                txDescCache.extsts);
1778
1779        if (txDescCache.cmdsts & CMDSTS_OWN) {
1780            txState = txFifoBlock;
1781            txFragPtr = txDescCache.bufptr;
1782            txDescCnt = txDescCache.cmdsts & CMDSTS_LEN_MASK;
1783        } else {
1784            devIntrPost(ISR_TXIDLE);
1785            txState = txIdle;
1786            goto exit;
1787        }
1788        break;
1789
1790      case txFifoBlock:
1791        if (!txPacket) {
1792            DPRINTF(EthernetSM, "****starting the tx of a new packet****\n");
1793            txPacket = new PacketData;
1794            txPacket->data = new uint8_t[16384];
1795            txPacketBufPtr = txPacket->data;
1796        }
1797
1798        if (txDescCnt == 0) {
1799            DPRINTF(EthernetSM, "the txDescCnt == 0, done with descriptor\n");
1800            if (txDescCache.cmdsts & CMDSTS_MORE) {
1801                DPRINTF(EthernetSM, "there are more descriptors to come\n");
1802                txState = txDescWrite;
1803
1804                txDescCache.cmdsts &= ~CMDSTS_OWN;
1805
1806                txDmaAddr = regs.txdp + offsetof(ns_desc, cmdsts);
1807                txDmaAddr &= 0x3fffffff;
1808                txDmaData = &(txDescCache.cmdsts);
1809                txDmaLen = sizeof(txDescCache.cmdsts);
1810                txDmaFree = dmaDescFree;
1811
1812                if (doTxDmaWrite())
1813                    goto exit;
1814
1815            } else { /* this packet is totally done */
1816                DPRINTF(EthernetSM, "This packet is done, let's wrap it up\n");
1817                /* deal with the the packet that just finished */
1818                if ((regs.vtcr & VTCR_PPCHK) && extstsEnable) {
1819                    IpHdr *ip = txPacket->ip();
1820                    if (txDescCache.extsts & EXTSTS_UDPPKT) {
1821                        UdpHdr *udp = txPacket->udp();
1822                        udp->sum(0);
1823                        udp->sum(ip->tu_cksum());
1824                        txUdpChecksums++;
1825                    } else if (txDescCache.extsts & EXTSTS_TCPPKT) {
1826                        TcpHdr *tcp = txPacket->tcp();
1827                        tcp->sum(0);
1828                        tcp->sum(ip->tu_cksum());
1829                        txTcpChecksums++;
1830                    }
1831                    if (txDescCache.extsts & EXTSTS_IPPKT) {
1832                        ip->sum(0);
1833                        ip->sum(ip->ip_cksum());
1834                        txIpChecksums++;
1835                    }
1836                }
1837
1838                txPacket->length = txPacketBufPtr - txPacket->data;
1839                // this is just because the receive can't handle a
1840                // packet bigger want to make sure
1841                assert(txPacket->length <= 1514);
1842                txFifo.push_back(txPacket);
1843
1844                /*
1845                 * this following section is not tqo spec, but
1846                 * functionally shouldn't be any different.  normally,
1847                 * the chip will wait til the transmit has occurred
1848                 * before writing back the descriptor because it has
1849                 * to wait to see that it was successfully transmitted
1850                 * to decide whether to set CMDSTS_OK or not.
1851                 * however, in the simulator since it is always
1852                 * successfully transmitted, and writing it exactly to
1853                 * spec would complicate the code, we just do it here
1854                 */
1855
1856                txDescCache.cmdsts &= ~CMDSTS_OWN;
1857                txDescCache.cmdsts |= CMDSTS_OK;
1858
1859                DPRINTF(EthernetDesc,
1860                        "txDesc writeback: cmdsts=%08x extsts=%08x\n",
1861                        txDescCache.cmdsts, txDescCache.extsts);
1862
1863                txDmaAddr = regs.txdp + offsetof(ns_desc, cmdsts);
1864                txDmaAddr &= 0x3fffffff;
1865                txDmaData = &(txDescCache.cmdsts);
1866                txDmaLen = sizeof(txDescCache.cmdsts) +
1867                    sizeof(txDescCache.extsts);
1868                txDmaFree = dmaDescFree;
1869
1870                descDmaWrites++;
1871                descDmaWrBytes += txDmaLen;
1872
1873                transmit();
1874                txPacket = 0;
1875
1876                if (!txEnable) {
1877                    DPRINTF(EthernetSM, "halting TX state machine\n");
1878                    txState = txIdle;
1879                    goto exit;
1880                } else
1881                    txState = txAdvance;
1882
1883                if (doTxDmaWrite())
1884                    goto exit;
1885            }
1886        } else {
1887            DPRINTF(EthernetSM, "this descriptor isn't done yet\n");
1888            if (txFifoAvail) {
1889                txState = txFragRead;
1890
1891                /*
1892                 * The number of bytes transferred is either whatever
1893                 * is left in the descriptor (txDescCnt), or if there
1894                 * is not enough room in the fifo, just whatever room
1895                 * is left in the fifo
1896                 */
1897                txXferLen = min<uint32_t>(txDescCnt, txFifoAvail);
1898
1899                txDmaAddr = txFragPtr & 0x3fffffff;
1900                txDmaData = txPacketBufPtr;
1901                txDmaLen = txXferLen;
1902                txDmaFree = dmaDataFree;
1903
1904                if (doTxDmaRead())
1905                    goto exit;
1906            } else {
1907                txState = txFifoBlock;
1908                transmit();
1909
1910                goto exit;
1911            }
1912
1913        }
1914        break;
1915
1916      case txFragRead:
1917        if (txDmaState != dmaIdle)
1918            goto exit;
1919
1920        txPacketBufPtr += txXferLen;
1921        txFragPtr += txXferLen;
1922        txDescCnt -= txXferLen;
1923        txFifoAvail -= txXferLen;
1924
1925        txState = txFifoBlock;
1926        break;
1927
1928      case txDescWrite:
1929        if (txDmaState != dmaIdle)
1930            goto exit;
1931
1932        if (txDescCache.cmdsts & CMDSTS_INTR)
1933            devIntrPost(ISR_TXDESC);
1934
1935        txState = txAdvance;
1936        break;
1937
1938      case txAdvance:
1939        if (txDescCache.link == 0) {
1940            devIntrPost(ISR_TXIDLE);
1941            txState = txIdle;
1942            goto exit;
1943        } else {
1944            txState = txDescRead;
1945            regs.txdp = txDescCache.link;
1946            CTDD = false;
1947
1948            txDmaAddr = txDescCache.link & 0x3fffffff;
1949            txDmaData = &txDescCache;
1950            txDmaLen = sizeof(ns_desc);
1951            txDmaFree = dmaDescFree;
1952
1953            if (doTxDmaRead())
1954                goto exit;
1955        }
1956        break;
1957
1958      default:
1959        panic("invalid state");
1960    }
1961
1962    DPRINTF(EthernetSM, "entering next txState=%s\n",
1963            NsTxStateStrings[txState]);
1964
1965    goto next;
1966
1967  exit:
1968    /**
1969     * @todo do we want to schedule a future kick?
1970     */
1971    DPRINTF(EthernetSM, "tx state machine exited txState=%s\n",
1972            NsTxStateStrings[txState]);
1973}
1974
1975void
1976NSGigE::transferDone()
1977{
1978    if (txFifo.empty()) {
1979        DPRINTF(Ethernet, "transfer complete: txFifo empty...nothing to do\n");
1980        return;
1981    }
1982
1983    DPRINTF(Ethernet, "transfer complete: data in txFifo...schedule xmit\n");
1984
1985    if (txEvent.scheduled())
1986        txEvent.reschedule(curTick + 1);
1987    else
1988        txEvent.schedule(curTick + 1);
1989}
1990
1991bool
1992NSGigE::rxFilter(PacketPtr packet)
1993{
1994    bool drop = true;
1995    string type;
1996
1997    EthHdr *eth = packet->eth();
1998    if (eth->unicast()) {
1999        // If we're accepting all unicast addresses
2000        if (acceptUnicast)
2001            drop = false;
2002
2003        // If we make a perfect match
2004        if (acceptPerfect &&
2005            memcmp(rom.perfectMatch, packet->data, EADDR_LEN) == 0)
2006            drop = false;
2007
2008        if (acceptArp && eth->type() == ETH_TYPE_ARP)
2009            drop = false;
2010
2011    } else if (eth->broadcast()) {
2012        // if we're accepting broadcasts
2013        if (acceptBroadcast)
2014            drop = false;
2015
2016    } else if (eth->multicast()) {
2017        // if we're accepting all multicasts
2018        if (acceptMulticast)
2019            drop = false;
2020
2021    }
2022
2023    if (drop) {
2024        DPRINTF(Ethernet, "rxFilter drop\n");
2025        DDUMP(EthernetData, packet->data, packet->length);
2026    }
2027
2028    return drop;
2029}
2030
2031bool
2032NSGigE::recvPacket(PacketPtr packet)
2033{
2034    rxBytes += packet->length;
2035    rxPackets++;
2036
2037    DPRINTF(Ethernet, "Receiving packet from wire, rxFifoAvail=%d\n",
2038            maxRxFifoSize - rxFifoCnt);
2039
2040    if (!rxEnable) {
2041        DPRINTF(Ethernet, "receive disabled...packet dropped\n");
2042        debug_break();
2043        interface->recvDone();
2044        return true;
2045    }
2046
2047    if (rxFilterEnable && rxFilter(packet)) {
2048        DPRINTF(Ethernet, "packet filtered...dropped\n");
2049        interface->recvDone();
2050        return true;
2051    }
2052
2053    if ((rxFifoCnt + packet->length) >= maxRxFifoSize) {
2054        DPRINTF(Ethernet,
2055                "packet will not fit in receive buffer...packet dropped\n");
2056        devIntrPost(ISR_RXORN);
2057        return false;
2058    }
2059
2060    rxFifo.push_back(packet);
2061    rxFifoCnt += packet->length;
2062    interface->recvDone();
2063
2064    rxKick();
2065    return true;
2066}
2067
2068//=====================================================================
2069//
2070//
2071void
2072NSGigE::serialize(ostream &os)
2073{
2074    // Serialize the PciDev base class
2075    PciDev::serialize(os);
2076
2077    /*
2078     * Finalize any DMA events now.
2079     */
2080    if (rxDmaReadEvent.scheduled())
2081        rxDmaReadCopy();
2082    if (rxDmaWriteEvent.scheduled())
2083        rxDmaWriteCopy();
2084    if (txDmaReadEvent.scheduled())
2085        txDmaReadCopy();
2086    if (txDmaWriteEvent.scheduled())
2087        txDmaWriteCopy();
2088
2089    /*
2090     * Serialize the device registers
2091     */
2092    SERIALIZE_SCALAR(regs.command);
2093    SERIALIZE_SCALAR(regs.config);
2094    SERIALIZE_SCALAR(regs.mear);
2095    SERIALIZE_SCALAR(regs.ptscr);
2096    SERIALIZE_SCALAR(regs.isr);
2097    SERIALIZE_SCALAR(regs.imr);
2098    SERIALIZE_SCALAR(regs.ier);
2099    SERIALIZE_SCALAR(regs.ihr);
2100    SERIALIZE_SCALAR(regs.txdp);
2101    SERIALIZE_SCALAR(regs.txdp_hi);
2102    SERIALIZE_SCALAR(regs.txcfg);
2103    SERIALIZE_SCALAR(regs.gpior);
2104    SERIALIZE_SCALAR(regs.rxdp);
2105    SERIALIZE_SCALAR(regs.rxdp_hi);
2106    SERIALIZE_SCALAR(regs.rxcfg);
2107    SERIALIZE_SCALAR(regs.pqcr);
2108    SERIALIZE_SCALAR(regs.wcsr);
2109    SERIALIZE_SCALAR(regs.pcr);
2110    SERIALIZE_SCALAR(regs.rfcr);
2111    SERIALIZE_SCALAR(regs.rfdr);
2112    SERIALIZE_SCALAR(regs.srr);
2113    SERIALIZE_SCALAR(regs.mibc);
2114    SERIALIZE_SCALAR(regs.vrcr);
2115    SERIALIZE_SCALAR(regs.vtcr);
2116    SERIALIZE_SCALAR(regs.vdr);
2117    SERIALIZE_SCALAR(regs.ccsr);
2118    SERIALIZE_SCALAR(regs.tbicr);
2119    SERIALIZE_SCALAR(regs.tbisr);
2120    SERIALIZE_SCALAR(regs.tanar);
2121    SERIALIZE_SCALAR(regs.tanlpar);
2122    SERIALIZE_SCALAR(regs.taner);
2123    SERIALIZE_SCALAR(regs.tesr);
2124
2125    SERIALIZE_ARRAY(rom.perfectMatch, EADDR_LEN);
2126
2127    SERIALIZE_SCALAR(ioEnable);
2128
2129    /*
2130     * Serialize the data Fifos
2131     */
2132    int txNumPkts = txFifo.size();
2133    SERIALIZE_SCALAR(txNumPkts);
2134    int i = 0;
2135    pktiter_t end = txFifo.end();
2136    for (pktiter_t p = txFifo.begin(); p != end; ++p) {
2137        nameOut(os, csprintf("%s.txFifo%d", name(), i++));
2138        (*p)->serialize(os);
2139    }
2140
2141    int rxNumPkts = rxFifo.size();
2142    SERIALIZE_SCALAR(rxNumPkts);
2143    i = 0;
2144    end = rxFifo.end();
2145    for (pktiter_t p = rxFifo.begin(); p != end; ++p) {
2146        nameOut(os, csprintf("%s.rxFifo%d", name(), i++));
2147        (*p)->serialize(os);
2148    }
2149
2150    /*
2151     * Serialize the various helper variables
2152     */
2153    bool txPacketExists = txPacket;
2154    SERIALIZE_SCALAR(txPacketExists);
2155    if (txPacketExists) {
2156        nameOut(os, csprintf("%s.txPacket", name()));
2157        txPacket->serialize(os);
2158        uint32_t txPktBufPtr = (uint32_t) (txPacketBufPtr - txPacket->data);
2159        SERIALIZE_SCALAR(txPktBufPtr);
2160    }
2161
2162    bool rxPacketExists = rxPacket;
2163    SERIALIZE_SCALAR(rxPacketExists);
2164    if (rxPacketExists) {
2165        nameOut(os, csprintf("%s.rxPacket", name()));
2166        rxPacket->serialize(os);
2167        uint32_t rxPktBufPtr = (uint32_t) (rxPacketBufPtr - rxPacket->data);
2168        SERIALIZE_SCALAR(rxPktBufPtr);
2169    }
2170
2171    SERIALIZE_SCALAR(txXferLen);
2172    SERIALIZE_SCALAR(rxXferLen);
2173
2174    /*
2175     * Serialize DescCaches
2176     */
2177    SERIALIZE_SCALAR(txDescCache.link);
2178    SERIALIZE_SCALAR(txDescCache.bufptr);
2179    SERIALIZE_SCALAR(txDescCache.cmdsts);
2180    SERIALIZE_SCALAR(txDescCache.extsts);
2181    SERIALIZE_SCALAR(rxDescCache.link);
2182    SERIALIZE_SCALAR(rxDescCache.bufptr);
2183    SERIALIZE_SCALAR(rxDescCache.cmdsts);
2184    SERIALIZE_SCALAR(rxDescCache.extsts);
2185
2186    /*
2187     * Serialize tx state machine
2188     */
2189    int txState = this->txState;
2190    SERIALIZE_SCALAR(txState);
2191    SERIALIZE_SCALAR(txEnable);
2192    SERIALIZE_SCALAR(CTDD);
2193    SERIALIZE_SCALAR(txFifoAvail);
2194    SERIALIZE_SCALAR(txFragPtr);
2195    SERIALIZE_SCALAR(txDescCnt);
2196    int txDmaState = this->txDmaState;
2197    SERIALIZE_SCALAR(txDmaState);
2198
2199    /*
2200     * Serialize rx state machine
2201     */
2202    int rxState = this->rxState;
2203    SERIALIZE_SCALAR(rxState);
2204    SERIALIZE_SCALAR(rxEnable);
2205    SERIALIZE_SCALAR(CRDD);
2206    SERIALIZE_SCALAR(rxPktBytes);
2207    SERIALIZE_SCALAR(rxFifoCnt);
2208    SERIALIZE_SCALAR(rxDescCnt);
2209    int rxDmaState = this->rxDmaState;
2210    SERIALIZE_SCALAR(rxDmaState);
2211
2212    SERIALIZE_SCALAR(extstsEnable);
2213
2214    /*
2215     * If there's a pending transmit, store the time so we can
2216     * reschedule it later
2217     */
2218    Tick transmitTick = txEvent.scheduled() ? txEvent.when() - curTick : 0;
2219    SERIALIZE_SCALAR(transmitTick);
2220
2221    /*
2222     * receive address filter settings
2223     */
2224    SERIALIZE_SCALAR(rxFilterEnable);
2225    SERIALIZE_SCALAR(acceptBroadcast);
2226    SERIALIZE_SCALAR(acceptMulticast);
2227    SERIALIZE_SCALAR(acceptUnicast);
2228    SERIALIZE_SCALAR(acceptPerfect);
2229    SERIALIZE_SCALAR(acceptArp);
2230
2231    /*
2232     * Keep track of pending interrupt status.
2233     */
2234    SERIALIZE_SCALAR(intrTick);
2235    SERIALIZE_SCALAR(cpuPendingIntr);
2236    Tick intrEventTick = 0;
2237    if (intrEvent)
2238        intrEventTick = intrEvent->when();
2239    SERIALIZE_SCALAR(intrEventTick);
2240
2241}
2242
2243void
2244NSGigE::unserialize(Checkpoint *cp, const std::string &section)
2245{
2246    // Unserialize the PciDev base class
2247    PciDev::unserialize(cp, section);
2248
2249    UNSERIALIZE_SCALAR(regs.command);
2250    UNSERIALIZE_SCALAR(regs.config);
2251    UNSERIALIZE_SCALAR(regs.mear);
2252    UNSERIALIZE_SCALAR(regs.ptscr);
2253    UNSERIALIZE_SCALAR(regs.isr);
2254    UNSERIALIZE_SCALAR(regs.imr);
2255    UNSERIALIZE_SCALAR(regs.ier);
2256    UNSERIALIZE_SCALAR(regs.ihr);
2257    UNSERIALIZE_SCALAR(regs.txdp);
2258    UNSERIALIZE_SCALAR(regs.txdp_hi);
2259    UNSERIALIZE_SCALAR(regs.txcfg);
2260    UNSERIALIZE_SCALAR(regs.gpior);
2261    UNSERIALIZE_SCALAR(regs.rxdp);
2262    UNSERIALIZE_SCALAR(regs.rxdp_hi);
2263    UNSERIALIZE_SCALAR(regs.rxcfg);
2264    UNSERIALIZE_SCALAR(regs.pqcr);
2265    UNSERIALIZE_SCALAR(regs.wcsr);
2266    UNSERIALIZE_SCALAR(regs.pcr);
2267    UNSERIALIZE_SCALAR(regs.rfcr);
2268    UNSERIALIZE_SCALAR(regs.rfdr);
2269    UNSERIALIZE_SCALAR(regs.srr);
2270    UNSERIALIZE_SCALAR(regs.mibc);
2271    UNSERIALIZE_SCALAR(regs.vrcr);
2272    UNSERIALIZE_SCALAR(regs.vtcr);
2273    UNSERIALIZE_SCALAR(regs.vdr);
2274    UNSERIALIZE_SCALAR(regs.ccsr);
2275    UNSERIALIZE_SCALAR(regs.tbicr);
2276    UNSERIALIZE_SCALAR(regs.tbisr);
2277    UNSERIALIZE_SCALAR(regs.tanar);
2278    UNSERIALIZE_SCALAR(regs.tanlpar);
2279    UNSERIALIZE_SCALAR(regs.taner);
2280    UNSERIALIZE_SCALAR(regs.tesr);
2281
2282    UNSERIALIZE_ARRAY(rom.perfectMatch, EADDR_LEN);
2283
2284    UNSERIALIZE_SCALAR(ioEnable);
2285
2286    /*
2287     * unserialize the data fifos
2288     */
2289    int txNumPkts;
2290    UNSERIALIZE_SCALAR(txNumPkts);
2291    int i;
2292    for (i = 0; i < txNumPkts; ++i) {
2293        PacketPtr p = new PacketData;
2294        p->unserialize(cp, csprintf("%s.rxFifo%d", section, i));
2295        txFifo.push_back(p);
2296    }
2297
2298    int rxNumPkts;
2299    UNSERIALIZE_SCALAR(rxNumPkts);
2300    for (i = 0; i < rxNumPkts; ++i) {
2301        PacketPtr p = new PacketData;
2302        p->unserialize(cp, csprintf("%s.rxFifo%d", section, i));
2303        rxFifo.push_back(p);
2304    }
2305
2306    /*
2307     * unserialize the various helper variables
2308     */
2309    bool txPacketExists;
2310    UNSERIALIZE_SCALAR(txPacketExists);
2311    if (txPacketExists) {
2312        txPacket = new PacketData;
2313        txPacket->unserialize(cp, csprintf("%s.txPacket", section));
2314        uint32_t txPktBufPtr;
2315        UNSERIALIZE_SCALAR(txPktBufPtr);
2316        txPacketBufPtr = (uint8_t *) txPacket->data + txPktBufPtr;
2317    } else
2318        txPacket = 0;
2319
2320    bool rxPacketExists;
2321    UNSERIALIZE_SCALAR(rxPacketExists);
2322    rxPacket = 0;
2323    if (rxPacketExists) {
2324        rxPacket = new PacketData;
2325        rxPacket->unserialize(cp, csprintf("%s.rxPacket", section));
2326        uint32_t rxPktBufPtr;
2327        UNSERIALIZE_SCALAR(rxPktBufPtr);
2328        rxPacketBufPtr = (uint8_t *) rxPacket->data + rxPktBufPtr;
2329    } else
2330        rxPacket = 0;
2331
2332    UNSERIALIZE_SCALAR(txXferLen);
2333    UNSERIALIZE_SCALAR(rxXferLen);
2334
2335    /*
2336     * Unserialize DescCaches
2337     */
2338    UNSERIALIZE_SCALAR(txDescCache.link);
2339    UNSERIALIZE_SCALAR(txDescCache.bufptr);
2340    UNSERIALIZE_SCALAR(txDescCache.cmdsts);
2341    UNSERIALIZE_SCALAR(txDescCache.extsts);
2342    UNSERIALIZE_SCALAR(rxDescCache.link);
2343    UNSERIALIZE_SCALAR(rxDescCache.bufptr);
2344    UNSERIALIZE_SCALAR(rxDescCache.cmdsts);
2345    UNSERIALIZE_SCALAR(rxDescCache.extsts);
2346
2347    /*
2348     * unserialize tx state machine
2349     */
2350    int txState;
2351    UNSERIALIZE_SCALAR(txState);
2352    this->txState = (TxState) txState;
2353    UNSERIALIZE_SCALAR(txEnable);
2354    UNSERIALIZE_SCALAR(CTDD);
2355    UNSERIALIZE_SCALAR(txFifoAvail);
2356    UNSERIALIZE_SCALAR(txFragPtr);
2357    UNSERIALIZE_SCALAR(txDescCnt);
2358    int txDmaState;
2359    UNSERIALIZE_SCALAR(txDmaState);
2360    this->txDmaState = (DmaState) txDmaState;
2361
2362    /*
2363     * unserialize rx state machine
2364     */
2365    int rxState;
2366    UNSERIALIZE_SCALAR(rxState);
2367    this->rxState = (RxState) rxState;
2368    UNSERIALIZE_SCALAR(rxEnable);
2369    UNSERIALIZE_SCALAR(CRDD);
2370    UNSERIALIZE_SCALAR(rxPktBytes);
2371    UNSERIALIZE_SCALAR(rxFifoCnt);
2372    UNSERIALIZE_SCALAR(rxDescCnt);
2373    int rxDmaState;
2374    UNSERIALIZE_SCALAR(rxDmaState);
2375    this->rxDmaState = (DmaState) rxDmaState;
2376
2377    UNSERIALIZE_SCALAR(extstsEnable);
2378
2379     /*
2380     * If there's a pending transmit, reschedule it now
2381     */
2382    Tick transmitTick;
2383    UNSERIALIZE_SCALAR(transmitTick);
2384    if (transmitTick)
2385        txEvent.schedule(curTick + transmitTick);
2386
2387    /*
2388     * unserialize receive address filter settings
2389     */
2390    UNSERIALIZE_SCALAR(rxFilterEnable);
2391    UNSERIALIZE_SCALAR(acceptBroadcast);
2392    UNSERIALIZE_SCALAR(acceptMulticast);
2393    UNSERIALIZE_SCALAR(acceptUnicast);
2394    UNSERIALIZE_SCALAR(acceptPerfect);
2395    UNSERIALIZE_SCALAR(acceptArp);
2396
2397    /*
2398     * Keep track of pending interrupt status.
2399     */
2400    UNSERIALIZE_SCALAR(intrTick);
2401    UNSERIALIZE_SCALAR(cpuPendingIntr);
2402    Tick intrEventTick;
2403    UNSERIALIZE_SCALAR(intrEventTick);
2404    if (intrEventTick) {
2405        intrEvent = new IntrEvent(this, true);
2406        intrEvent->schedule(intrEventTick);
2407    }
2408
2409    /*
2410     * re-add addrRanges to bus bridges
2411     */
2412    if (pioInterface) {
2413        pioInterface->addAddrRange(BARAddrs[0], BARAddrs[0] + BARSize[0] - 1);
2414        pioInterface->addAddrRange(BARAddrs[1], BARAddrs[1] + BARSize[1] - 1);
2415    }
2416}
2417
2418Tick
2419NSGigE::cacheAccess(MemReqPtr &req)
2420{
2421    DPRINTF(EthernetPIO, "timing access to paddr=%#x (daddr=%#x)\n",
2422            req->paddr, req->paddr - addr);
2423    return curTick + pioLatency;
2424}
2425
2426BEGIN_DECLARE_SIM_OBJECT_PARAMS(NSGigEInt)
2427
2428    SimObjectParam<EtherInt *> peer;
2429    SimObjectParam<NSGigE *> device;
2430
2431END_DECLARE_SIM_OBJECT_PARAMS(NSGigEInt)
2432
2433BEGIN_INIT_SIM_OBJECT_PARAMS(NSGigEInt)
2434
2435    INIT_PARAM_DFLT(peer, "peer interface", NULL),
2436    INIT_PARAM(device, "Ethernet device of this interface")
2437
2438END_INIT_SIM_OBJECT_PARAMS(NSGigEInt)
2439
2440CREATE_SIM_OBJECT(NSGigEInt)
2441{
2442    NSGigEInt *dev_int = new NSGigEInt(getInstanceName(), device);
2443
2444    EtherInt *p = (EtherInt *)peer;
2445    if (p) {
2446        dev_int->setPeer(p);
2447        p->setPeer(dev_int);
2448    }
2449
2450    return dev_int;
2451}
2452
2453REGISTER_SIM_OBJECT("NSGigEInt", NSGigEInt)
2454
2455
2456BEGIN_DECLARE_SIM_OBJECT_PARAMS(NSGigE)
2457
2458    Param<Tick> tx_delay;
2459    Param<Tick> rx_delay;
2460    SimObjectParam<IntrControl *> intr_ctrl;
2461    Param<Tick> intr_delay;
2462    SimObjectParam<MemoryController *> mmu;
2463    SimObjectParam<PhysicalMemory *> physmem;
2464    Param<bool> rx_filter;
2465    Param<string> hardware_address;
2466    SimObjectParam<Bus*> header_bus;
2467    SimObjectParam<Bus*> payload_bus;
2468    SimObjectParam<HierParams *> hier;
2469    Param<Tick> pio_latency;
2470    Param<bool> dma_desc_free;
2471    Param<bool> dma_data_free;
2472    Param<Tick> dma_read_delay;
2473    Param<Tick> dma_write_delay;
2474    Param<Tick> dma_read_factor;
2475    Param<Tick> dma_write_factor;
2476    SimObjectParam<PciConfigAll *> configspace;
2477    SimObjectParam<PciConfigData *> configdata;
2478    SimObjectParam<Tsunami *> tsunami;
2479    Param<uint32_t> pci_bus;
2480    Param<uint32_t> pci_dev;
2481    Param<uint32_t> pci_func;
2482    Param<uint32_t> tx_fifo_size;
2483    Param<uint32_t> rx_fifo_size;
2484
2485END_DECLARE_SIM_OBJECT_PARAMS(NSGigE)
2486
2487BEGIN_INIT_SIM_OBJECT_PARAMS(NSGigE)
2488
2489    INIT_PARAM_DFLT(tx_delay, "Transmit Delay", 1000),
2490    INIT_PARAM_DFLT(rx_delay, "Receive Delay", 1000),
2491    INIT_PARAM(intr_ctrl, "Interrupt Controller"),
2492    INIT_PARAM_DFLT(intr_delay, "Interrupt Delay in microseconds", 0),
2493    INIT_PARAM(mmu, "Memory Controller"),
2494    INIT_PARAM(physmem, "Physical Memory"),
2495    INIT_PARAM_DFLT(rx_filter, "Enable Receive Filter", true),
2496    INIT_PARAM_DFLT(hardware_address, "Ethernet Hardware Address",
2497                    "00:99:00:00:00:01"),
2498    INIT_PARAM_DFLT(header_bus, "The IO Bus to attach to for headers", NULL),
2499    INIT_PARAM_DFLT(payload_bus, "The IO Bus to attach to for payload", NULL),
2500    INIT_PARAM_DFLT(hier, "Hierarchy global variables", &defaultHierParams),
2501    INIT_PARAM_DFLT(pio_latency, "Programmed IO latency in bus cycles", 1),
2502    INIT_PARAM_DFLT(dma_desc_free, "DMA of Descriptors is free", false),
2503    INIT_PARAM_DFLT(dma_data_free, "DMA of Data is free", false),
2504    INIT_PARAM_DFLT(dma_read_delay, "fixed delay for dma reads", 0),
2505    INIT_PARAM_DFLT(dma_write_delay, "fixed delay for dma writes", 0),
2506    INIT_PARAM_DFLT(dma_read_factor, "multiplier for dma reads", 0),
2507    INIT_PARAM_DFLT(dma_write_factor, "multiplier for dma writes", 0),
2508    INIT_PARAM(configspace, "PCI Configspace"),
2509    INIT_PARAM(configdata, "PCI Config data"),
2510    INIT_PARAM(tsunami, "Tsunami"),
2511    INIT_PARAM(pci_bus, "PCI bus"),
2512    INIT_PARAM(pci_dev, "PCI device number"),
2513    INIT_PARAM(pci_func, "PCI function code"),
2514    INIT_PARAM_DFLT(tx_fifo_size, "max size in bytes of txFifo", 131072),
2515    INIT_PARAM_DFLT(rx_fifo_size, "max size in bytes of rxFifo", 131072)
2516
2517END_INIT_SIM_OBJECT_PARAMS(NSGigE)
2518
2519
2520CREATE_SIM_OBJECT(NSGigE)
2521{
2522    int eaddr[6];
2523    sscanf(((string)hardware_address).c_str(), "%x:%x:%x:%x:%x:%x",
2524           &eaddr[0], &eaddr[1], &eaddr[2], &eaddr[3], &eaddr[4], &eaddr[5]);
2525
2526    return new NSGigE(getInstanceName(), intr_ctrl, intr_delay,
2527                      physmem, tx_delay, rx_delay, mmu, hier, header_bus,
2528                      payload_bus, pio_latency, dma_desc_free, dma_data_free,
2529                      dma_read_delay, dma_write_delay, dma_read_factor,
2530                      dma_write_factor, configspace, configdata,
2531                      tsunami, pci_bus, pci_dev, pci_func, rx_filter, eaddr,
2532                      tx_fifo_size, rx_fifo_size);
2533}
2534
2535REGISTER_SIM_OBJECT("NSGigE", NSGigE)
2536