ns_gige.cc revision 9339
19814Sandreas.hansson@arm.com/*
22292SN/A * Copyright (c) 2004-2005 The Regents of The University of Michigan
313590Srekai.gonzalezalberquilla@arm.com * All rights reserved.
410239Sbinhpham@cs.rutgers.edu *
57597Sminkyu.jeong@arm.com * Redistribution and use in source and binary forms, with or without
67597Sminkyu.jeong@arm.com * modification, are permitted provided that the following conditions are
77597Sminkyu.jeong@arm.com * met: redistributions of source code must retain the above copyright
87597Sminkyu.jeong@arm.com * notice, this list of conditions and the following disclaimer;
97597Sminkyu.jeong@arm.com * redistributions in binary form must reproduce the above copyright
107597Sminkyu.jeong@arm.com * notice, this list of conditions and the following disclaimer in the
117597Sminkyu.jeong@arm.com * documentation and/or other materials provided with the distribution;
127597Sminkyu.jeong@arm.com * neither the name of the copyright holders nor the names of its
137597Sminkyu.jeong@arm.com * contributors may be used to endorse or promote products derived from
147597Sminkyu.jeong@arm.com * this software without specific prior written permission.
157597Sminkyu.jeong@arm.com *
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 * Authors: Nathan Binkert
292292SN/A *          Lisa Hsu
302292SN/A */
312292SN/A
322292SN/A/** @file
332292SN/A * Device module for modelling the National Semiconductor
342292SN/A * DP83820 ethernet controller.  Does not support priority queueing
352292SN/A */
362292SN/A#include <deque>
372292SN/A#include <string>
382292SN/A
392292SN/A#include "base/debug.hh"
402292SN/A#include "base/inet.hh"
412689Sktlim@umich.edu#include "base/types.hh"
422689Sktlim@umich.edu#include "config/the_isa.hh"
432689Sktlim@umich.edu#include "cpu/thread_context.hh"
442292SN/A#include "debug/EthernetAll.hh"
452292SN/A#include "dev/etherlink.hh"
469944Smatt.horsnell@ARM.com#include "dev/ns_gige.hh"
479944Smatt.horsnell@ARM.com#include "dev/pciconfigall.hh"
489944Smatt.horsnell@ARM.com#include "mem/packet.hh"
498591Sgblack@eecs.umich.edu#include "mem/packet_access.hh"
503326Sktlim@umich.edu#include "params/NSGigE.hh"
518229Snate@binkert.org#include "sim/system.hh"
526658Snate@binkert.org
538887Sgeoffrey.blake@arm.com// clang complains about std::set being overloaded with Packet::set if
542907Sktlim@umich.edu// we open up the entire namespace std
552292SN/Ausing std::min;
568232Snate@binkert.orgusing std::ostream;
578232Snate@binkert.orgusing std::string;
588232Snate@binkert.org
599527SMatt.Horsnell@arm.comconst char *NsRxStateStrings[] =
602722Sktlim@umich.edu{
612669Sktlim@umich.edu    "rxIdle",
622292SN/A    "rxDescRefr",
632669Sktlim@umich.edu    "rxDescRead",
6413429Srekai.gonzalezalberquilla@arm.com    "rxFifoBlock",
6513429Srekai.gonzalezalberquilla@arm.com    "rxFragWrite",
668581Ssteve.reinhardt@amd.com    "rxDescWrite",
678581Ssteve.reinhardt@amd.com    "rxAdvance"
682292SN/A};
6913590Srekai.gonzalezalberquilla@arm.com
7013590Srekai.gonzalezalberquilla@arm.comconst char *NsTxStateStrings[] =
712292SN/A{
722292SN/A    "txIdle",
732669Sktlim@umich.edu    "txDescRefr",
742292SN/A    "txDescRead",
752678Sktlim@umich.edu    "txFifoBlock",
762292SN/A    "txFragRead",
779444SAndreas.Sandberg@ARM.com    "txDescWrite",
789444SAndreas.Sandberg@ARM.com    "txAdvance"
799444SAndreas.Sandberg@ARM.com};
804319Sktlim@umich.edu
8113590Srekai.gonzalezalberquilla@arm.comconst char *NsDmaState[] =
8213590Srekai.gonzalezalberquilla@arm.com{
832678Sktlim@umich.edu    "dmaIdle",
842678Sktlim@umich.edu    "dmaReading",
852292SN/A    "dmaWriting",
862678Sktlim@umich.edu    "dmaReadWaiting",
872678Sktlim@umich.edu    "dmaWriteWaiting"
885336Shines@cs.fsu.edu};
892678Sktlim@umich.edu
904873Sstever@eecs.umich.eduusing namespace Net;
912678Sktlim@umich.eduusing namespace TheISA;
922292SN/A
9313590Srekai.gonzalezalberquilla@arm.com///////////////////////////////////////////////////////////////////////
9413590Srekai.gonzalezalberquilla@arm.com//
9513590Srekai.gonzalezalberquilla@arm.com// NSGigE PCI Device
9613590Srekai.gonzalezalberquilla@arm.com//
9713590Srekai.gonzalezalberquilla@arm.comNSGigE::NSGigE(Params *p)
9813590Srekai.gonzalezalberquilla@arm.com    : EtherDevBase(p), ioEnable(false),
9913590Srekai.gonzalezalberquilla@arm.com      txFifo(p->tx_fifo_size), rxFifo(p->rx_fifo_size),
10013590Srekai.gonzalezalberquilla@arm.com      txPacket(0), rxPacket(0), txPacketBufPtr(NULL), rxPacketBufPtr(NULL),
10113590Srekai.gonzalezalberquilla@arm.com      txXferLen(0), rxXferLen(0), rxDmaFree(false), txDmaFree(false),
10213590Srekai.gonzalezalberquilla@arm.com      txState(txIdle), txEnable(false), CTDD(false), txHalt(false),
10313590Srekai.gonzalezalberquilla@arm.com      txFragPtr(0), txDescCnt(0), txDmaState(dmaIdle), rxState(rxIdle),
10413590Srekai.gonzalezalberquilla@arm.com      rxEnable(false), CRDD(false), rxPktBytes(0), rxHalt(false),
10513590Srekai.gonzalezalberquilla@arm.com      rxFragPtr(0), rxDescCnt(0), rxDmaState(dmaIdle), extstsEnable(false),
10613590Srekai.gonzalezalberquilla@arm.com      eepromState(eepromStart), eepromClk(false), eepromBitsToRx(0),
10713590Srekai.gonzalezalberquilla@arm.com      eepromOpcode(0), eepromAddress(0), eepromData(0),
10813590Srekai.gonzalezalberquilla@arm.com      dmaReadDelay(p->dma_read_delay), dmaWriteDelay(p->dma_write_delay),
10913590Srekai.gonzalezalberquilla@arm.com      dmaReadFactor(p->dma_read_factor), dmaWriteFactor(p->dma_write_factor),
11013590Srekai.gonzalezalberquilla@arm.com      rxDmaData(NULL), rxDmaAddr(0), rxDmaLen(0),
1112678Sktlim@umich.edu      txDmaData(NULL), txDmaAddr(0), txDmaLen(0),
1122678Sktlim@umich.edu      rxDmaReadEvent(this), rxDmaWriteEvent(this),
1132678Sktlim@umich.edu      txDmaReadEvent(this), txDmaWriteEvent(this),
1142678Sktlim@umich.edu      dmaDescFree(p->dma_desc_free), dmaDataFree(p->dma_data_free),
1152678Sktlim@umich.edu      txDelay(p->tx_delay), rxDelay(p->rx_delay),
1162678Sktlim@umich.edu      rxKickTick(0), rxKickEvent(this), txKickTick(0), txKickEvent(this),
1172344SN/A      txEvent(this), rxFilterEnable(p->rx_filter),
11813590Srekai.gonzalezalberquilla@arm.com      acceptBroadcast(false), acceptMulticast(false), acceptUnicast(false),
1192678Sktlim@umich.edu      acceptPerfect(false), acceptArp(false), multicastHashEnable(false),
12013590Srekai.gonzalezalberquilla@arm.com      intrDelay(p->intr_delay), intrTick(0), cpuPendingIntr(false),
12113590Srekai.gonzalezalberquilla@arm.com      intrEvent(0), interface(0)
12213590Srekai.gonzalezalberquilla@arm.com{
1236974Stjones1@inf.ed.ac.uk
1249444SAndreas.Sandberg@ARM.com
12510327Smitch.hayenga@arm.com    interface = new NSGigEInt(name() + ".int0", this);
12613590Srekai.gonzalezalberquilla@arm.com
12713652Sqtt2@cornell.edu    regsReset();
12812216Snikos.nikoleris@arm.com    memcpy(&rom.perfectMatch, p->hardware_address.bytes(), ETH_ADDR_LEN);
12913652Sqtt2@cornell.edu
13013652Sqtt2@cornell.edu    memset(&rxDesc32, 0, sizeof(rxDesc32));
13113590Srekai.gonzalezalberquilla@arm.com    memset(&txDesc32, 0, sizeof(txDesc32));
13213652Sqtt2@cornell.edu    memset(&rxDesc64, 0, sizeof(rxDesc64));
13313590Srekai.gonzalezalberquilla@arm.com    memset(&txDesc64, 0, sizeof(txDesc64));
13413590Srekai.gonzalezalberquilla@arm.com}
13513590Srekai.gonzalezalberquilla@arm.com
1366974Stjones1@inf.ed.ac.ukNSGigE::~NSGigE()
13713590Srekai.gonzalezalberquilla@arm.com{
13813652Sqtt2@cornell.edu    delete interface;
13913652Sqtt2@cornell.edu}
14013590Srekai.gonzalezalberquilla@arm.com
1412678Sktlim@umich.edu/**
1422344SN/A * This is to write to the PCI general configuration registers
1432292SN/A */
1442292SN/ATick
1452292SN/ANSGigE::writeConfig(PacketPtr pkt)
14613472Srekai.gonzalezalberquilla@arm.com{
14713472Srekai.gonzalezalberquilla@arm.com    int offset = pkt->getAddr() & PCI_CONFIG_SIZE;
14813472Srekai.gonzalezalberquilla@arm.com    if (offset < PCI_DEVICE_SPECIFIC)
14913590Srekai.gonzalezalberquilla@arm.com        PciDev::writeConfig(pkt);
15013590Srekai.gonzalezalberquilla@arm.com    else
1512292SN/A        panic("Device specific PCI config space not implemented!\n");
1522292SN/A
1532292SN/A    switch (offset) {
1542292SN/A        // seems to work fine without all these PCI settings, but i
1552292SN/A        // put in the IO to double check, an assertion will fail if we
1565529Snate@binkert.org        // need to properly implement it
15713472Srekai.gonzalezalberquilla@arm.com      case PCI_COMMAND:
1582292SN/A        if (config.data[offset] & PCI_CMD_IOSE)
15913472Srekai.gonzalezalberquilla@arm.com            ioEnable = true;
16013472Srekai.gonzalezalberquilla@arm.com        else
1614329Sktlim@umich.edu            ioEnable = false;
1624329Sktlim@umich.edu        break;
1634329Sktlim@umich.edu    }
1642907Sktlim@umich.edu
1652907Sktlim@umich.edu    return configDelay;
16613472Srekai.gonzalezalberquilla@arm.com}
1672292SN/A
1688199SAli.Saidi@ARM.comEtherInt*
1698199SAli.Saidi@ARM.comNSGigE::getEthPort(const std::string &if_name, int idx)
1709444SAndreas.Sandberg@ARM.com{
1719444SAndreas.Sandberg@ARM.com    if (if_name == "interface") {
1729444SAndreas.Sandberg@ARM.com       if (interface->getPeer())
1739444SAndreas.Sandberg@ARM.com           panic("interface already connected to\n");
1749444SAndreas.Sandberg@ARM.com       return interface;
1759444SAndreas.Sandberg@ARM.com    }
1769444SAndreas.Sandberg@ARM.com    return NULL;
1779444SAndreas.Sandberg@ARM.com}
1789444SAndreas.Sandberg@ARM.com
1799444SAndreas.Sandberg@ARM.com/**
1809444SAndreas.Sandberg@ARM.com * This reads the device registers, which are detailed in the NS83820
1818199SAli.Saidi@ARM.com * spec sheet
1822292SN/A */
18313590Srekai.gonzalezalberquilla@arm.comTick
1842292SN/ANSGigE::read(PacketPtr pkt)
1853492Sktlim@umich.edu{
1862329SN/A    assert(ioEnable);
1872292SN/A
1889444SAndreas.Sandberg@ARM.com    pkt->allocate();
1899444SAndreas.Sandberg@ARM.com
1909814Sandreas.hansson@arm.com    //The mask is to give you only the offset into the device register file
1912292SN/A    Addr daddr = pkt->getAddr() & 0xfff;
1922292SN/A    DPRINTF(EthernetPIO, "read  da=%#x pa=%#x size=%d\n",
1932292SN/A            daddr, pkt->getAddr(), pkt->getSize());
1942292SN/A
1952292SN/A
1962292SN/A    // there are some reserved registers, you can see ns_gige_reg.h and
1972292SN/A    // the spec sheet for details
1982292SN/A    if (daddr > LAST && daddr <=  RESERVED) {
1992292SN/A        panic("Accessing reserved register");
20010386Sandreas.hansson@arm.com    } else if (daddr > RESERVED && daddr <= 0x3FC) {
2012292SN/A        return readConfig(pkt);
2022292SN/A    } else if (daddr >= MIB_START && daddr <= MIB_END) {
2032292SN/A        // don't implement all the MIB's.  hopefully the kernel
2042292SN/A        // doesn't actually DEPEND upon their values
2052292SN/A        // MIB are just hardware stats keepers
2062727Sktlim@umich.edu        pkt->set<uint32_t>(0);
2072727Sktlim@umich.edu        pkt->makeAtomicResponse();
2082727Sktlim@umich.edu        return pioDelay;
2092727Sktlim@umich.edu    } else if (daddr > 0x3FC)
2102727Sktlim@umich.edu        panic("Something is messed up!\n");
2112727Sktlim@umich.edu
2122727Sktlim@umich.edu    assert(pkt->getSize() == sizeof(uint32_t));
2132727Sktlim@umich.edu        uint32_t &reg = *pkt->getPtr<uint32_t>();
2142727Sktlim@umich.edu        uint16_t rfaddr;
2152727Sktlim@umich.edu
2162727Sktlim@umich.edu        switch (daddr) {
2172727Sktlim@umich.edu          case CR:
2182727Sktlim@umich.edu            reg = regs.command;
2192727Sktlim@umich.edu            //these are supposed to be cleared on a read
2202727Sktlim@umich.edu            reg &= ~(CR_RXD | CR_TXD | CR_TXR | CR_RXR);
2212727Sktlim@umich.edu            break;
2222727Sktlim@umich.edu
2232727Sktlim@umich.edu          case CFGR:
2242361SN/A            reg = regs.config;
2252361SN/A            break;
2262361SN/A
2272361SN/A          case MEAR:
2282727Sktlim@umich.edu            reg = regs.mear;
2292727Sktlim@umich.edu            break;
2302727Sktlim@umich.edu
2312727Sktlim@umich.edu          case PTSCR:
2322727Sktlim@umich.edu            reg = regs.ptscr;
2332727Sktlim@umich.edu            break;
2342727Sktlim@umich.edu
2352727Sktlim@umich.edu          case ISR:
2362727Sktlim@umich.edu            reg = regs.isr;
2372727Sktlim@umich.edu            devIntrClear(ISR_ALL);
2382727Sktlim@umich.edu            break;
2392727Sktlim@umich.edu
2402727Sktlim@umich.edu          case IMR:
2412727Sktlim@umich.edu            reg = regs.imr;
2422727Sktlim@umich.edu            break;
2432727Sktlim@umich.edu
2442727Sktlim@umich.edu          case IER:
2452727Sktlim@umich.edu            reg = regs.ier;
2462727Sktlim@umich.edu            break;
2472727Sktlim@umich.edu
2482727Sktlim@umich.edu          case IHR:
2492727Sktlim@umich.edu            reg = regs.ihr;
2502727Sktlim@umich.edu            break;
2518922Swilliam.wang@arm.com
2524329Sktlim@umich.edu          case TXDP:
2534329Sktlim@umich.edu            reg = regs.txdp;
2544329Sktlim@umich.edu            break;
2554329Sktlim@umich.edu
2564329Sktlim@umich.edu          case TXDP_HI:
2574329Sktlim@umich.edu            reg = regs.txdp_hi;
2589444SAndreas.Sandberg@ARM.com            break;
2592307SN/A
26013590Srekai.gonzalezalberquilla@arm.com          case TX_CFG:
26113590Srekai.gonzalezalberquilla@arm.com            reg = regs.txcfg;
2622307SN/A            break;
2632329SN/A
2649444SAndreas.Sandberg@ARM.com          case GPIOR:
2652307SN/A            reg = regs.gpior;
2662307SN/A            break;
2672307SN/A
2682307SN/A          case RXDP:
2692307SN/A            reg = regs.rxdp;
2702307SN/A            break;
2719444SAndreas.Sandberg@ARM.com
2722307SN/A          case RXDP_HI:
2732307SN/A            reg = regs.rxdp_hi;
2742292SN/A            break;
2752292SN/A
27613429Srekai.gonzalezalberquilla@arm.com          case RX_CFG:
2772292SN/A            reg = regs.rxcfg;
2782292SN/A            break;
2792292SN/A
28013652Sqtt2@cornell.edu          case PQCR:
2812292SN/A            reg = regs.pqcr;
2822292SN/A            break;
2832292SN/A
2842292SN/A          case WCSR:
2852292SN/A            reg = regs.wcsr;
2862292SN/A            break;
2872292SN/A
2882292SN/A          case PCR:
2892292SN/A            reg = regs.pcr;
2902292SN/A            break;
2912292SN/A
2922292SN/A            // see the spec sheet for how RFCR and RFDR work
29313429Srekai.gonzalezalberquilla@arm.com            // basically, you write to RFCR to tell the machine
2942292SN/A            // what you want to do next, then you act upon RFDR,
29513590Srekai.gonzalezalberquilla@arm.com            // and the device will be prepared b/c of what you
29613590Srekai.gonzalezalberquilla@arm.com            // wrote to RFCR
2972292SN/A          case RFCR:
2987720Sgblack@eecs.umich.edu            reg = regs.rfcr;
29913590Srekai.gonzalezalberquilla@arm.com            break;
3002292SN/A
30113590Srekai.gonzalezalberquilla@arm.com          case RFDR:
30213590Srekai.gonzalezalberquilla@arm.com            rfaddr = (uint16_t)(regs.rfcr & RFCR_RFADDR);
3032292SN/A            switch (rfaddr) {
30413590Srekai.gonzalezalberquilla@arm.com              // Read from perfect match ROM octets
3052292SN/A              case 0x000:
30613590Srekai.gonzalezalberquilla@arm.com                reg = rom.perfectMatch[1];
30713590Srekai.gonzalezalberquilla@arm.com                reg = reg << 8;
30813590Srekai.gonzalezalberquilla@arm.com                reg += rom.perfectMatch[0];
30913590Srekai.gonzalezalberquilla@arm.com                break;
3102292SN/A              case 0x002:
3112292SN/A                reg = rom.perfectMatch[3] << 8;
3122292SN/A                reg += rom.perfectMatch[2];
3132292SN/A                break;
3142292SN/A              case 0x004:
3152292SN/A                reg = rom.perfectMatch[5] << 8;
31613590Srekai.gonzalezalberquilla@arm.com                reg += rom.perfectMatch[4];
3172292SN/A                break;
3182292SN/A              default:
31913590Srekai.gonzalezalberquilla@arm.com                // Read filter hash table
32013590Srekai.gonzalezalberquilla@arm.com                if (rfaddr >= FHASH_ADDR &&
3212292SN/A                    rfaddr < FHASH_ADDR + FHASH_SIZE) {
3227720Sgblack@eecs.umich.edu
32313590Srekai.gonzalezalberquilla@arm.com                    // Only word-aligned reads supported
32413590Srekai.gonzalezalberquilla@arm.com                    if (rfaddr % 2)
3252292SN/A                        panic("unaligned read from filter hash table!");
32613590Srekai.gonzalezalberquilla@arm.com
32713590Srekai.gonzalezalberquilla@arm.com                    reg = rom.filterHash[rfaddr - FHASH_ADDR + 1] << 8;
32813590Srekai.gonzalezalberquilla@arm.com                    reg += rom.filterHash[rfaddr - FHASH_ADDR];
3292292SN/A                    break;
33013590Srekai.gonzalezalberquilla@arm.com                }
3312292SN/A
3322292SN/A                panic("reading RFDR for something other than pattern"
3332292SN/A                      " matching or hashing! %#x\n", rfaddr);
3342292SN/A            }
3352292SN/A            break;
3362292SN/A
3372292SN/A          case SRR:
3382292SN/A            reg = regs.srr;
3392292SN/A            break;
3402292SN/A
3412292SN/A          case MIBC:
3422292SN/A            reg = regs.mibc;
3432292SN/A            reg &= ~(MIBC_MIBS | MIBC_ACLR);
3442292SN/A            break;
3452292SN/A
3462292SN/A          case VRCR:
3472292SN/A            reg = regs.vrcr;
34810239Sbinhpham@cs.rutgers.edu            break;
3492292SN/A
35010239Sbinhpham@cs.rutgers.edu          case VTCR:
35110239Sbinhpham@cs.rutgers.edu            reg = regs.vtcr;
35213590Srekai.gonzalezalberquilla@arm.com            break;
35313590Srekai.gonzalezalberquilla@arm.com
35413590Srekai.gonzalezalberquilla@arm.com          case VDR:
35510239Sbinhpham@cs.rutgers.edu            reg = regs.vdr;
3562292SN/A            break;
35710239Sbinhpham@cs.rutgers.edu
35810239Sbinhpham@cs.rutgers.edu          case CCSR:
35910239Sbinhpham@cs.rutgers.edu            reg = regs.ccsr;
36010239Sbinhpham@cs.rutgers.edu            break;
36110239Sbinhpham@cs.rutgers.edu
36210239Sbinhpham@cs.rutgers.edu          case TBICR:
36313590Srekai.gonzalezalberquilla@arm.com            reg = regs.tbicr;
36413590Srekai.gonzalezalberquilla@arm.com            break;
36513590Srekai.gonzalezalberquilla@arm.com
36610239Sbinhpham@cs.rutgers.edu          case TBISR:
36710239Sbinhpham@cs.rutgers.edu            reg = regs.tbisr;
3682292SN/A            break;
3692292SN/A
3708545Ssaidi@eecs.umich.edu          case TANAR:
3718545Ssaidi@eecs.umich.edu            reg = regs.tanar;
3728545Ssaidi@eecs.umich.edu            break;
37311357Sstephan.diestelhorst@arm.com
37411357Sstephan.diestelhorst@arm.com          case TANLPAR:
37511357Sstephan.diestelhorst@arm.com            reg = regs.tanlpar;
37610030SAli.Saidi@ARM.com            break;
3778545Ssaidi@eecs.umich.edu
37810030SAli.Saidi@ARM.com          case TANER:
3799383SAli.Saidi@ARM.com            reg = regs.taner;
3809383SAli.Saidi@ARM.com            break;
3819383SAli.Saidi@ARM.com
3829383SAli.Saidi@ARM.com          case TESR:
3839383SAli.Saidi@ARM.com            reg = regs.tesr;
3849383SAli.Saidi@ARM.com            break;
3859383SAli.Saidi@ARM.com
38613590Srekai.gonzalezalberquilla@arm.com          case M5REG:
38713590Srekai.gonzalezalberquilla@arm.com            reg = 0;
38813590Srekai.gonzalezalberquilla@arm.com            if (params()->rx_thread)
38913590Srekai.gonzalezalberquilla@arm.com                reg |= M5REG_RX_THREAD;
39013590Srekai.gonzalezalberquilla@arm.com            if (params()->tx_thread)
39110030SAli.Saidi@ARM.com                reg |= M5REG_TX_THREAD;
39210030SAli.Saidi@ARM.com            if (params()->rss)
39313590Srekai.gonzalezalberquilla@arm.com                reg |= M5REG_RSS;
39413590Srekai.gonzalezalberquilla@arm.com            break;
39513590Srekai.gonzalezalberquilla@arm.com
39611097Songal@cs.wisc.edu          default:
39713590Srekai.gonzalezalberquilla@arm.com            panic("reading unimplemented register: addr=%#x", daddr);
39813590Srekai.gonzalezalberquilla@arm.com        }
39913590Srekai.gonzalezalberquilla@arm.com
40013590Srekai.gonzalezalberquilla@arm.com        DPRINTF(EthernetPIO, "read from %#x: data=%d data=%#x\n",
40113590Srekai.gonzalezalberquilla@arm.com                daddr, reg, reg);
4028545Ssaidi@eecs.umich.edu
40310149Smarco.elver@ed.ac.uk    pkt->makeAtomicResponse();
40410149Smarco.elver@ed.ac.uk    return pioDelay;
40513590Srekai.gonzalezalberquilla@arm.com}
40613590Srekai.gonzalezalberquilla@arm.com
40713590Srekai.gonzalezalberquilla@arm.comTick
40813590Srekai.gonzalezalberquilla@arm.comNSGigE::write(PacketPtr pkt)
40913590Srekai.gonzalezalberquilla@arm.com{
41013590Srekai.gonzalezalberquilla@arm.com    assert(ioEnable);
4118545Ssaidi@eecs.umich.edu
41213590Srekai.gonzalezalberquilla@arm.com    Addr daddr = pkt->getAddr() & 0xfff;
41313590Srekai.gonzalezalberquilla@arm.com    DPRINTF(EthernetPIO, "write da=%#x pa=%#x size=%d\n",
4148545Ssaidi@eecs.umich.edu            daddr, pkt->getAddr(), pkt->getSize());
41513590Srekai.gonzalezalberquilla@arm.com
41613590Srekai.gonzalezalberquilla@arm.com    if (daddr > LAST && daddr <=  RESERVED) {
41710149Smarco.elver@ed.ac.uk        panic("Accessing reserved register");
41810149Smarco.elver@ed.ac.uk    } else if (daddr > RESERVED && daddr <= 0x3FC) {
41910149Smarco.elver@ed.ac.uk        return writeConfig(pkt);
42010149Smarco.elver@ed.ac.uk    } else if (daddr > 0x3FC)
42110149Smarco.elver@ed.ac.uk        panic("Something is messed up!\n");
42210149Smarco.elver@ed.ac.uk
42310149Smarco.elver@ed.ac.uk    if (pkt->getSize() == sizeof(uint32_t)) {
4248545Ssaidi@eecs.umich.edu        uint32_t reg = pkt->get<uint32_t>();
42510030SAli.Saidi@ARM.com        uint16_t rfaddr;
4268545Ssaidi@eecs.umich.edu
4278545Ssaidi@eecs.umich.edu        DPRINTF(EthernetPIO, "write data=%d data=%#x\n", reg, reg);
42810474Sandreas.hansson@arm.com
4298545Ssaidi@eecs.umich.edu        switch (daddr) {
43010030SAli.Saidi@ARM.com          case CR:
43110030SAli.Saidi@ARM.com            regs.command = reg;
43210030SAli.Saidi@ARM.com            if (reg & CR_TXD) {
43310030SAli.Saidi@ARM.com                txEnable = false;
43410030SAli.Saidi@ARM.com            } else if (reg & CR_TXE) {
43510030SAli.Saidi@ARM.com                txEnable = true;
43610030SAli.Saidi@ARM.com
43710030SAli.Saidi@ARM.com                // the kernel is enabling the transmit machine
43810030SAli.Saidi@ARM.com                if (txState == txIdle)
4398545Ssaidi@eecs.umich.edu                    txKick();
4408545Ssaidi@eecs.umich.edu            }
4418545Ssaidi@eecs.umich.edu
4429046SAli.Saidi@ARM.com            if (reg & CR_RXD) {
4438545Ssaidi@eecs.umich.edu                rxEnable = false;
4448545Ssaidi@eecs.umich.edu            } else if (reg & CR_RXE) {
4458545Ssaidi@eecs.umich.edu                rxEnable = true;
4468545Ssaidi@eecs.umich.edu
4478545Ssaidi@eecs.umich.edu                if (rxState == rxIdle)
4488545Ssaidi@eecs.umich.edu                    rxKick();
4498545Ssaidi@eecs.umich.edu            }
4502292SN/A
45113590Srekai.gonzalezalberquilla@arm.com            if (reg & CR_TXR)
45213590Srekai.gonzalezalberquilla@arm.com                txReset();
4538199SAli.Saidi@ARM.com
4548199SAli.Saidi@ARM.com            if (reg & CR_RXR)
4558199SAli.Saidi@ARM.com                rxReset();
4568199SAli.Saidi@ARM.com
4578199SAli.Saidi@ARM.com            if (reg & CR_SWI)
4588199SAli.Saidi@ARM.com                devIntrPost(ISR_SWI);
4598199SAli.Saidi@ARM.com
4608199SAli.Saidi@ARM.com            if (reg & CR_RST) {
4618199SAli.Saidi@ARM.com                txReset();
46213590Srekai.gonzalezalberquilla@arm.com                rxReset();
46313590Srekai.gonzalezalberquilla@arm.com
46410824SAndreas.Sandberg@ARM.com                regsReset();
46513590Srekai.gonzalezalberquilla@arm.com            }
4668199SAli.Saidi@ARM.com            break;
4678199SAli.Saidi@ARM.com
4688199SAli.Saidi@ARM.com          case CFGR:
4698199SAli.Saidi@ARM.com            if (reg & CFGR_LNKSTS ||
4708199SAli.Saidi@ARM.com                reg & CFGR_SPDSTS ||
4718199SAli.Saidi@ARM.com                reg & CFGR_DUPSTS ||
4728199SAli.Saidi@ARM.com                reg & CFGR_RESERVED ||
4738272SAli.Saidi@ARM.com                reg & CFGR_T64ADDR ||
4748545Ssaidi@eecs.umich.edu                reg & CFGR_PCI64_DET) {
4758545Ssaidi@eecs.umich.edu                // First clear all writable bits
4768545Ssaidi@eecs.umich.edu                regs.config &= CFGR_LNKSTS | CFGR_SPDSTS | CFGR_DUPSTS |
4778545Ssaidi@eecs.umich.edu                    CFGR_RESERVED | CFGR_T64ADDR |
4789046SAli.Saidi@ARM.com                    CFGR_PCI64_DET;
4798545Ssaidi@eecs.umich.edu                // Now set the appropriate writable bits
4808545Ssaidi@eecs.umich.edu                regs.config |= reg & ~(CFGR_LNKSTS | CFGR_SPDSTS | CFGR_DUPSTS |
4818545Ssaidi@eecs.umich.edu                                       CFGR_RESERVED | CFGR_T64ADDR |
4828592Sgblack@eecs.umich.edu                                       CFGR_PCI64_DET);
4838592Sgblack@eecs.umich.edu            }
4848545Ssaidi@eecs.umich.edu
4858199SAli.Saidi@ARM.com// all these #if 0's are because i don't THINK the kernel needs to
4868545Ssaidi@eecs.umich.edu// have these implemented. if there is a problem relating to one of
4878199SAli.Saidi@ARM.com// these, you may need to add functionality in.
48810474Sandreas.hansson@arm.com
48910474Sandreas.hansson@arm.com// grouped together and #if 0'ed to avoid empty if body and make clang happy
49010474Sandreas.hansson@arm.com#if 0
49110474Sandreas.hansson@arm.com            if (reg & CFGR_TBI_EN) ;
4928545Ssaidi@eecs.umich.edu            if (reg & CFGR_MODE_1000) ;
4938545Ssaidi@eecs.umich.edu
4948199SAli.Saidi@ARM.com            if (reg & CFGR_PINT_DUPSTS ||
4958545Ssaidi@eecs.umich.edu                reg & CFGR_PINT_LNKSTS ||
4968545Ssaidi@eecs.umich.edu                reg & CFGR_PINT_SPDSTS)
4979046SAli.Saidi@ARM.com                ;
49810575SMarco.Elver@ARM.com
4998545Ssaidi@eecs.umich.edu            if (reg & CFGR_TMRTEST) ;
5008545Ssaidi@eecs.umich.edu            if (reg & CFGR_MRM_DIS) ;
5018545Ssaidi@eecs.umich.edu            if (reg & CFGR_MWI_DIS) ;
5028545Ssaidi@eecs.umich.edu
5038545Ssaidi@eecs.umich.edu            if (reg & CFGR_DATA64_EN) ;
5048545Ssaidi@eecs.umich.edu            if (reg & CFGR_M64ADDR) ;
5058545Ssaidi@eecs.umich.edu            if (reg & CFGR_PHY_RST) ;
5068545Ssaidi@eecs.umich.edu            if (reg & CFGR_PHY_DIS) ;
5078545Ssaidi@eecs.umich.edu
5088592Sgblack@eecs.umich.edu            if (reg & CFGR_REQALG) ;
5098592Sgblack@eecs.umich.edu            if (reg & CFGR_SB) ;
5108592Sgblack@eecs.umich.edu            if (reg & CFGR_POW) ;
5118545Ssaidi@eecs.umich.edu            if (reg & CFGR_EXD) ;
5128545Ssaidi@eecs.umich.edu            if (reg & CFGR_PESEL) ;
5138545Ssaidi@eecs.umich.edu            if (reg & CFGR_BROM_DIS) ;
5148545Ssaidi@eecs.umich.edu            if (reg & CFGR_EXT_125) ;
51510474Sandreas.hansson@arm.com            if (reg & CFGR_BEM) ;
51610474Sandreas.hansson@arm.com
51710474Sandreas.hansson@arm.com            if (reg & CFGR_T64ADDR) ;
51810474Sandreas.hansson@arm.com            // panic("CFGR_T64ADDR is read only register!\n");
5198545Ssaidi@eecs.umich.edu#endif
5208199SAli.Saidi@ARM.com            if (reg & CFGR_AUTO_1000)
5218199SAli.Saidi@ARM.com                panic("CFGR_AUTO_1000 not implemented!\n");
52213590Srekai.gonzalezalberquilla@arm.com
5238199SAli.Saidi@ARM.com            if (reg & CFGR_PCI64_DET)
5248199SAli.Saidi@ARM.com                panic("CFGR_PCI64_DET is read only register!\n");
5258199SAli.Saidi@ARM.com
5268199SAli.Saidi@ARM.com            if (reg & CFGR_EXTSTS_EN)
5278199SAli.Saidi@ARM.com                extstsEnable = true;
5288199SAli.Saidi@ARM.com            else
5298199SAli.Saidi@ARM.com                extstsEnable = false;
5308199SAli.Saidi@ARM.com            break;
5318199SAli.Saidi@ARM.com
53213429Srekai.gonzalezalberquilla@arm.com          case MEAR:
5332292SN/A            // Clear writable bits
5344032Sktlim@umich.edu            regs.mear &= MEAR_EEDO;
5352292SN/A            // Set appropriate writable bits
5362292SN/A            regs.mear |= reg & ~MEAR_EEDO;
5372292SN/A
5387720Sgblack@eecs.umich.edu            // FreeBSD uses the EEPROM to read PMATCH (for the MAC address)
5397944SGiacomo.Gabrielli@arm.com            // even though it could get it through RFDR
5402292SN/A            if (reg & MEAR_EESEL) {
5414032Sktlim@umich.edu                // Rising edge of clock
5424032Sktlim@umich.edu                if (reg & MEAR_EECLK && !eepromClk)
5432669Sktlim@umich.edu                    eepromKick();
5442292SN/A            }
54513954Sgiacomo.gabrielli@arm.com            else {
54613953Sgiacomo.gabrielli@arm.com                eepromState = eepromStart;
54713953Sgiacomo.gabrielli@arm.com                regs.mear &= ~MEAR_EEDI;
54813953Sgiacomo.gabrielli@arm.com            }
54913953Sgiacomo.gabrielli@arm.com
55013953Sgiacomo.gabrielli@arm.com            eepromClk = reg & MEAR_EECLK;
55113953Sgiacomo.gabrielli@arm.com
55213953Sgiacomo.gabrielli@arm.com            // since phy is completely faked, MEAR_MD* don't matter
55313953Sgiacomo.gabrielli@arm.com
55413590Srekai.gonzalezalberquilla@arm.com// grouped together and #if 0'ed to avoid empty if body and make clang happy
5557944SGiacomo.Gabrielli@arm.com#if 0
5567944SGiacomo.Gabrielli@arm.com            if (reg & MEAR_MDIO) ;
5577597Sminkyu.jeong@arm.com            if (reg & MEAR_MDDIR) ;
5587597Sminkyu.jeong@arm.com            if (reg & MEAR_MDC) ;
55910231Ssteve.reinhardt@amd.com#endif
5602329SN/A            break;
56110824SAndreas.Sandberg@ARM.com
56210824SAndreas.Sandberg@ARM.com          case PTSCR:
56310824SAndreas.Sandberg@ARM.com            regs.ptscr = reg & ~(PTSCR_RBIST_RDONLY);
56410231Ssteve.reinhardt@amd.com            // these control BISTs for various parts of chip - we
5657848SAli.Saidi@ARM.com            // don't care or do just fake that the BIST is done
5667600Sminkyu.jeong@arm.com            if (reg & PTSCR_RBIST_EN)
5677600Sminkyu.jeong@arm.com                regs.ptscr |= PTSCR_RBIST_DONE;
5687600Sminkyu.jeong@arm.com            if (reg & PTSCR_EEBIST_EN)
56910824SAndreas.Sandberg@ARM.com                regs.ptscr &= ~PTSCR_EEBIST_EN;
5703731Sktlim@umich.edu            if (reg & PTSCR_EELOAD_EN)
5712367SN/A                regs.ptscr &= ~PTSCR_EELOAD_EN;
5722367SN/A            break;
5732292SN/A
5742292SN/A          case ISR: /* writing to the ISR has no effect */
57510333Smitch.hayenga@arm.com            panic("ISR is a read only register!\n");
57613590Srekai.gonzalezalberquilla@arm.com
57713590Srekai.gonzalezalberquilla@arm.com          case IMR:
57813590Srekai.gonzalezalberquilla@arm.com            regs.imr = reg;
5794032Sktlim@umich.edu            devIntrChangeMask();
58013590Srekai.gonzalezalberquilla@arm.com            break;
58113590Srekai.gonzalezalberquilla@arm.com
58213590Srekai.gonzalezalberquilla@arm.com          case IER:
5832292SN/A            regs.ier = reg;
5842292SN/A            break;
5852292SN/A
5862292SN/A          case IHR:
5872292SN/A            regs.ihr = reg;
5882292SN/A            /* not going to implement real interrupt holdoff */
5892292SN/A            break;
59013429Srekai.gonzalezalberquilla@arm.com
5912292SN/A          case TXDP:
5922292SN/A            regs.txdp = (reg & 0xFFFFFFFC);
5932292SN/A            assert(txState == txIdle);
5942292SN/A            CTDD = false;
5952292SN/A            break;
5962292SN/A
5972292SN/A          case TXDP_HI:
5987720Sgblack@eecs.umich.edu            regs.txdp_hi = reg;
5997720Sgblack@eecs.umich.edu            break;
6002292SN/A
6014032Sktlim@umich.edu          case TX_CFG:
6024032Sktlim@umich.edu            regs.txcfg = reg;
6032292SN/A#if 0
6042292SN/A            if (reg & TX_CFG_CSI) ;
60513590Srekai.gonzalezalberquilla@arm.com            if (reg & TX_CFG_HBI) ;
6062292SN/A            if (reg & TX_CFG_MLB) ;
6072292SN/A            if (reg & TX_CFG_ATP) ;
6082292SN/A            if (reg & TX_CFG_ECRETRY) {
6097944SGiacomo.Gabrielli@arm.com                /*
6107944SGiacomo.Gabrielli@arm.com                 * this could easily be implemented, but considering
6117944SGiacomo.Gabrielli@arm.com                 * the network is just a fake pipe, wouldn't make
6127944SGiacomo.Gabrielli@arm.com                 * sense to do this
61312217Snikos.nikoleris@arm.com                 */
61412217Snikos.nikoleris@arm.com            }
61512217Snikos.nikoleris@arm.com
6167848SAli.Saidi@ARM.com            if (reg & TX_CFG_BRST_DIS) ;
61712217Snikos.nikoleris@arm.com#endif
61812217Snikos.nikoleris@arm.com
6197848SAli.Saidi@ARM.com#if 0
62013590Srekai.gonzalezalberquilla@arm.com            /* we handle our own DMA, ignore the kernel's exhortations */
6217782Sminkyu.jeong@arm.com            if (reg & TX_CFG_MXDMA) ;
6227720Sgblack@eecs.umich.edu#endif
6232292SN/A
6242292SN/A            // also, we currently don't care about fill/drain
6252292SN/A            // thresholds though this may change in the future with
6262292SN/A            // more realistic networks or a driver which changes it
6272292SN/A            // according to feedback
6282292SN/A
62913652Sqtt2@cornell.edu            break;
63013652Sqtt2@cornell.edu
6312336SN/A          case GPIOR:
63213590Srekai.gonzalezalberquilla@arm.com            // Only write writable bits
6332292SN/A            regs.gpior &= GPIOR_UNUSED | GPIOR_GP5_IN | GPIOR_GP4_IN
6342329SN/A                        | GPIOR_GP3_IN | GPIOR_GP2_IN | GPIOR_GP1_IN;
6352292SN/A            regs.gpior |= reg & ~(GPIOR_UNUSED | GPIOR_GP5_IN | GPIOR_GP4_IN
6362292SN/A                                | GPIOR_GP3_IN | GPIOR_GP2_IN | GPIOR_GP1_IN);
63713590Srekai.gonzalezalberquilla@arm.com            /* these just control general purpose i/o pins, don't matter */
6382292SN/A            break;
6392292SN/A
6402292SN/A          case RXDP:
6412292SN/A            regs.rxdp = reg;
6422292SN/A            CRDD = false;
6432292SN/A            break;
6442292SN/A
64513590Srekai.gonzalezalberquilla@arm.com          case RXDP_HI:
6462292SN/A            regs.rxdp_hi = reg;
6477720Sgblack@eecs.umich.edu            break;
64813590Srekai.gonzalezalberquilla@arm.com
6492292SN/A          case RX_CFG:
65013590Srekai.gonzalezalberquilla@arm.com            regs.rxcfg = reg;
65113590Srekai.gonzalezalberquilla@arm.com#if 0
6522292SN/A            if (reg & RX_CFG_AEP) ;
6532292SN/A            if (reg & RX_CFG_ARP) ;
6542292SN/A            if (reg & RX_CFG_STRIPCRC) ;
6552292SN/A            if (reg & RX_CFG_RX_RD) ;
6562292SN/A            if (reg & RX_CFG_ALP) ;
6572292SN/A            if (reg & RX_CFG_AIRL) ;
6582292SN/A
6592292SN/A            /* we handle our own DMA, ignore what kernel says about it */
66013590Srekai.gonzalezalberquilla@arm.com            if (reg & RX_CFG_MXDMA) ;
6612292SN/A
66213590Srekai.gonzalezalberquilla@arm.com            //also, we currently don't care about fill/drain thresholds
66313590Srekai.gonzalezalberquilla@arm.com            //though this may change in the future with more realistic
6642292SN/A            //networks or a driver which changes it according to feedback
6652292SN/A            if (reg & (RX_CFG_DRTH | RX_CFG_DRTH0)) ;
6662292SN/A#endif
6672292SN/A            break;
6682292SN/A
6692292SN/A          case PQCR:
6702292SN/A            /* there is no priority queueing used in the linux 2.6 driver */
6712292SN/A            regs.pqcr = reg;
67213590Srekai.gonzalezalberquilla@arm.com            break;
6732292SN/A
67413590Srekai.gonzalezalberquilla@arm.com          case WCSR:
67513590Srekai.gonzalezalberquilla@arm.com            /* not going to implement wake on LAN */
67613590Srekai.gonzalezalberquilla@arm.com            regs.wcsr = reg;
6772329SN/A            break;
6782329SN/A
67913590Srekai.gonzalezalberquilla@arm.com          case PCR:
68013590Srekai.gonzalezalberquilla@arm.com            /* not going to implement pause control */
6812292SN/A            regs.pcr = reg;
6822292SN/A            break;
6832292SN/A
6847720Sgblack@eecs.umich.edu          case RFCR:
68513590Srekai.gonzalezalberquilla@arm.com            regs.rfcr = reg;
68613590Srekai.gonzalezalberquilla@arm.com
6872292SN/A            rxFilterEnable = (reg & RFCR_RFEN) ? true : false;
68813590Srekai.gonzalezalberquilla@arm.com            acceptBroadcast = (reg & RFCR_AAB) ? true : false;
6892292SN/A            acceptMulticast = (reg & RFCR_AAM) ? true : false;
6902292SN/A            acceptUnicast = (reg & RFCR_AAU) ? true : false;
6912292SN/A            acceptPerfect = (reg & RFCR_APM) ? true : false;
6922292SN/A            acceptArp = (reg & RFCR_AARP) ? true : false;
6932292SN/A            multicastHashEnable = (reg & RFCR_MHEN) ? true : false;
6942292SN/A
6952292SN/A#if 0
6962292SN/A            if (reg & RFCR_APAT)
69713590Srekai.gonzalezalberquilla@arm.com                panic("RFCR_APAT not implemented!\n");
6986974Stjones1@inf.ed.ac.uk#endif
69913590Srekai.gonzalezalberquilla@arm.com            if (reg & RFCR_UHEN)
70013590Srekai.gonzalezalberquilla@arm.com                panic("Unicast hash filtering not used by drivers!\n");
70113590Srekai.gonzalezalberquilla@arm.com
70213590Srekai.gonzalezalberquilla@arm.com            if (reg & RFCR_ULM)
7036974Stjones1@inf.ed.ac.uk                panic("RFCR_ULM not implemented!\n");
7046974Stjones1@inf.ed.ac.uk
7056974Stjones1@inf.ed.ac.uk            break;
7066974Stjones1@inf.ed.ac.uk
7076974Stjones1@inf.ed.ac.uk          case RFDR:
7082292SN/A            rfaddr = (uint16_t)(regs.rfcr & RFCR_RFADDR);
7092292SN/A            switch (rfaddr) {
71013590Srekai.gonzalezalberquilla@arm.com              case 0x000:
71113590Srekai.gonzalezalberquilla@arm.com                rom.perfectMatch[0] = (uint8_t)reg;
71213590Srekai.gonzalezalberquilla@arm.com                rom.perfectMatch[1] = (uint8_t)(reg >> 8);
7136974Stjones1@inf.ed.ac.uk                break;
7146974Stjones1@inf.ed.ac.uk              case 0x002:
7152292SN/A                rom.perfectMatch[2] = (uint8_t)reg;
71613590Srekai.gonzalezalberquilla@arm.com                rom.perfectMatch[3] = (uint8_t)(reg >> 8);
71713590Srekai.gonzalezalberquilla@arm.com                break;
71813590Srekai.gonzalezalberquilla@arm.com              case 0x004:
7198727Snilay@cs.wisc.edu                rom.perfectMatch[4] = (uint8_t)reg;
72013710Sgabor.dozsa@arm.com                rom.perfectMatch[5] = (uint8_t)(reg >> 8);
7212292SN/A                break;
72210333Smitch.hayenga@arm.com              default:
7232678Sktlim@umich.edu
7242678Sktlim@umich.edu                if (rfaddr >= FHASH_ADDR &&
7252678Sktlim@umich.edu                    rfaddr < FHASH_ADDR + FHASH_SIZE) {
7262678Sktlim@umich.edu
7272678Sktlim@umich.edu                    // Only word-aligned writes supported
7282329SN/A                    if (rfaddr % 2)
7292329SN/A                        panic("unaligned write to filter hash table!");
73013590Srekai.gonzalezalberquilla@arm.com
73113590Srekai.gonzalezalberquilla@arm.com                    rom.filterHash[rfaddr - FHASH_ADDR] = (uint8_t)reg;
73213590Srekai.gonzalezalberquilla@arm.com                    rom.filterHash[rfaddr - FHASH_ADDR + 1]
73313590Srekai.gonzalezalberquilla@arm.com                        = (uint8_t)(reg >> 8);
73413590Srekai.gonzalezalberquilla@arm.com                    break;
7352292SN/A                }
7362292SN/A                panic("writing RFDR for something other than pattern matching\
7372678Sktlim@umich.edu                    or hashing! %#x\n", rfaddr);
73813590Srekai.gonzalezalberquilla@arm.com            }
73913590Srekai.gonzalezalberquilla@arm.com
7402292SN/A          case BRAR:
7412292SN/A            regs.brar = reg;
7422292SN/A            break;
74313590Srekai.gonzalezalberquilla@arm.com
74413590Srekai.gonzalezalberquilla@arm.com          case BRDR:
7452292SN/A            panic("the driver never uses BRDR, something is wrong!\n");
74613590Srekai.gonzalezalberquilla@arm.com
74713590Srekai.gonzalezalberquilla@arm.com          case SRR:
74813590Srekai.gonzalezalberquilla@arm.com            panic("SRR is read only register!\n");
7492292SN/A
7502669Sktlim@umich.edu          case MIBC:
75113590Srekai.gonzalezalberquilla@arm.com            panic("the driver never uses MIBC, something is wrong!\n");
7523772Sgblack@eecs.umich.edu
75313590Srekai.gonzalezalberquilla@arm.com          case VRCR:
75413590Srekai.gonzalezalberquilla@arm.com            regs.vrcr = reg;
75510031SAli.Saidi@ARM.com            break;
75613590Srekai.gonzalezalberquilla@arm.com
7572669Sktlim@umich.edu          case VTCR:
7582292SN/A            regs.vtcr = reg;
75913590Srekai.gonzalezalberquilla@arm.com            break;
76013590Srekai.gonzalezalberquilla@arm.com
76113590Srekai.gonzalezalberquilla@arm.com          case VDR:
76213590Srekai.gonzalezalberquilla@arm.com            panic("the driver never uses VDR, something is wrong!\n");
76313590Srekai.gonzalezalberquilla@arm.com
7646974Stjones1@inf.ed.ac.uk          case CCSR:
76513590Srekai.gonzalezalberquilla@arm.com            /* not going to implement clockrun stuff */
76613652Sqtt2@cornell.edu            regs.ccsr = reg;
76713652Sqtt2@cornell.edu            break;
76813590Srekai.gonzalezalberquilla@arm.com
76913590Srekai.gonzalezalberquilla@arm.com          case TBICR:
7706974Stjones1@inf.ed.ac.uk            regs.tbicr = reg;
77113590Srekai.gonzalezalberquilla@arm.com            if (reg & TBICR_MR_LOOPBACK)
7722678Sktlim@umich.edu                panic("TBICR_MR_LOOPBACK never used, something wrong!\n");
7737720Sgblack@eecs.umich.edu
7742292SN/A            if (reg & TBICR_MR_AN_ENABLE) {
77513590Srekai.gonzalezalberquilla@arm.com                regs.tanlpar = regs.tanar;
77613590Srekai.gonzalezalberquilla@arm.com                regs.tbisr |= (TBISR_MR_AN_COMPLETE | TBISR_MR_LINK_STATUS);
7773221Sktlim@umich.edu            }
7782292SN/A
7792693Sktlim@umich.edu#if 0
7804350Sgblack@eecs.umich.edu            if (reg & TBICR_MR_RESTART_AN) ;
7813326Sktlim@umich.edu#endif
7823326Sktlim@umich.edu
7833326Sktlim@umich.edu            break;
7849046SAli.Saidi@ARM.com
78513590Srekai.gonzalezalberquilla@arm.com          case TBISR:
78613590Srekai.gonzalezalberquilla@arm.com            panic("TBISR is read only register!\n");
7879046SAli.Saidi@ARM.com
78813590Srekai.gonzalezalberquilla@arm.com          case TANAR:
7893326Sktlim@umich.edu            // Only write the writable bits
7903326Sktlim@umich.edu            regs.tanar &= TANAR_RF1 | TANAR_RF2 | TANAR_UNUSED;
79113590Srekai.gonzalezalberquilla@arm.com            regs.tanar |= reg & ~(TANAR_RF1 | TANAR_RF2 | TANAR_UNUSED);
7923326Sktlim@umich.edu
7933326Sktlim@umich.edu            // Pause capability unimplemented
7943326Sktlim@umich.edu#if 0
7953326Sktlim@umich.edu            if (reg & TANAR_PS2) ;
79613590Srekai.gonzalezalberquilla@arm.com            if (reg & TANAR_PS1) ;
79713590Srekai.gonzalezalberquilla@arm.com#endif
79813590Srekai.gonzalezalberquilla@arm.com
7997823Ssteve.reinhardt@amd.com            break;
80013590Srekai.gonzalezalberquilla@arm.com
80113590Srekai.gonzalezalberquilla@arm.com          case TANLPAR:
80213590Srekai.gonzalezalberquilla@arm.com            panic("this should only be written to by the fake phy!\n");
80313590Srekai.gonzalezalberquilla@arm.com
80413590Srekai.gonzalezalberquilla@arm.com          case TANER:
8053326Sktlim@umich.edu            panic("TANER is read only register!\n");
8062693Sktlim@umich.edu
8072693Sktlim@umich.edu          case TESR:
8082693Sktlim@umich.edu            regs.tesr = reg;
80913590Srekai.gonzalezalberquilla@arm.com            break;
81013590Srekai.gonzalezalberquilla@arm.com
81113590Srekai.gonzalezalberquilla@arm.com          default:
81213590Srekai.gonzalezalberquilla@arm.com            panic("invalid register access daddr=%#x", daddr);
81313590Srekai.gonzalezalberquilla@arm.com        }
81413590Srekai.gonzalezalberquilla@arm.com    } else {
81513590Srekai.gonzalezalberquilla@arm.com        panic("Invalid Request Size");
81613590Srekai.gonzalezalberquilla@arm.com    }
81713590Srekai.gonzalezalberquilla@arm.com    pkt->makeAtomicResponse();
81813590Srekai.gonzalezalberquilla@arm.com    return pioDelay;
81913590Srekai.gonzalezalberquilla@arm.com}
82013590Srekai.gonzalezalberquilla@arm.com
82113590Srekai.gonzalezalberquilla@arm.comvoid
82213590Srekai.gonzalezalberquilla@arm.comNSGigE::devIntrPost(uint32_t interrupts)
8238481Sgblack@eecs.umich.edu{
82413590Srekai.gonzalezalberquilla@arm.com    if (interrupts & ISR_RESERVE)
82513590Srekai.gonzalezalberquilla@arm.com        panic("Cannot set a reserved interrupt");
82613590Srekai.gonzalezalberquilla@arm.com
82713590Srekai.gonzalezalberquilla@arm.com    if (interrupts & ISR_NOIMPL)
82813590Srekai.gonzalezalberquilla@arm.com        warn("interrupt not implemented %#x\n", interrupts);
82913590Srekai.gonzalezalberquilla@arm.com
8303221Sktlim@umich.edu    interrupts &= ISR_IMPL;
8312292SN/A    regs.isr |= interrupts;
8322292SN/A
8332292SN/A    if (interrupts & regs.imr) {
8342292SN/A        if (interrupts & ISR_SWI) {
8352292SN/A            totalSwi++;
8362292SN/A        }
8372292SN/A        if (interrupts & ISR_RXIDLE) {
8382292SN/A            totalRxIdle++;
8392292SN/A        }
8402292SN/A        if (interrupts & ISR_RXOK) {
8412329SN/A            totalRxOk++;
8422292SN/A        }
84313590Srekai.gonzalezalberquilla@arm.com        if (interrupts & ISR_RXDESC) {
84413590Srekai.gonzalezalberquilla@arm.com            totalRxDesc++;
8457720Sgblack@eecs.umich.edu        }
8462292SN/A        if (interrupts & ISR_TXOK) {
84713590Srekai.gonzalezalberquilla@arm.com            totalTxOk++;
84813590Srekai.gonzalezalberquilla@arm.com        }
8492292SN/A        if (interrupts & ISR_TXIDLE) {
85013590Srekai.gonzalezalberquilla@arm.com            totalTxIdle++;
8512292SN/A        }
8522292SN/A        if (interrupts & ISR_TXDESC) {
8532292SN/A            totalTxDesc++;
8542292SN/A        }
8552292SN/A        if (interrupts & ISR_RXORN) {
8562329SN/A            totalRxOrn++;
85713590Srekai.gonzalezalberquilla@arm.com        }
85813590Srekai.gonzalezalberquilla@arm.com    }
85913590Srekai.gonzalezalberquilla@arm.com
8602292SN/A    DPRINTF(EthernetIntr,
8612292SN/A            "interrupt written to ISR: intr=%#x isr=%#x imr=%#x\n",
86213590Srekai.gonzalezalberquilla@arm.com            interrupts, regs.isr, regs.imr);
8632727Sktlim@umich.edu
8642292SN/A    if ((regs.isr & regs.imr)) {
8652292SN/A        Tick when = curTick();
8664032Sktlim@umich.edu        if ((regs.isr & regs.imr & ISR_NODELAY) == 0)
8674032Sktlim@umich.edu            when += intrDelay;
8684032Sktlim@umich.edu        postedInterrupts++;
8694032Sktlim@umich.edu        cpuIntrPost(when);
8702292SN/A    }
87113590Srekai.gonzalezalberquilla@arm.com}
8722329SN/A
87313590Srekai.gonzalezalberquilla@arm.com/* writing this interrupt counting stats inside this means that this function
8742292SN/A   is now limited to being used to clear all interrupts upon the kernel
8752292SN/A   reading isr and servicing.  just telling you in case you were thinking
8762292SN/A   of expanding use.
8777720Sgblack@eecs.umich.edu*/
8782292SN/Avoid
87913590Srekai.gonzalezalberquilla@arm.comNSGigE::devIntrClear(uint32_t interrupts)
88013590Srekai.gonzalezalberquilla@arm.com{
8812292SN/A    if (interrupts & ISR_RESERVE)
8822329SN/A        panic("Cannot clear a reserved interrupt");
8832329SN/A
8842292SN/A    if (regs.isr & regs.imr & ISR_SWI) {
88513590Srekai.gonzalezalberquilla@arm.com        postedSwi++;
8862292SN/A    }
8872292SN/A    if (regs.isr & regs.imr & ISR_RXIDLE) {
8882292SN/A        postedRxIdle++;
8892292SN/A    }
8902292SN/A    if (regs.isr & regs.imr & ISR_RXOK) {
8912329SN/A        postedRxOk++;
89213590Srekai.gonzalezalberquilla@arm.com    }
8932292SN/A    if (regs.isr & regs.imr & ISR_RXDESC) {
8944032Sktlim@umich.edu            postedRxDesc++;
8954032Sktlim@umich.edu    }
8964032Sktlim@umich.edu    if (regs.isr & regs.imr & ISR_TXOK) {
89713590Srekai.gonzalezalberquilla@arm.com        postedTxOk++;
8982292SN/A    }
8992292SN/A    if (regs.isr & regs.imr & ISR_TXIDLE) {
90013590Srekai.gonzalezalberquilla@arm.com        postedTxIdle++;
9012727Sktlim@umich.edu    }
9022292SN/A    if (regs.isr & regs.imr & ISR_TXDESC) {
9032292SN/A        postedTxDesc++;
9042292SN/A    }
9052292SN/A    if (regs.isr & regs.imr & ISR_RXORN) {
9062292SN/A        postedRxOrn++;
90713590Srekai.gonzalezalberquilla@arm.com    }
9082693Sktlim@umich.edu
9092693Sktlim@umich.edu    interrupts &= ~ISR_NOIMPL;
91013590Srekai.gonzalezalberquilla@arm.com    regs.isr &= ~interrupts;
9112693Sktlim@umich.edu
9122693Sktlim@umich.edu    DPRINTF(EthernetIntr,
9132693Sktlim@umich.edu            "interrupt cleared from ISR: intr=%x isr=%x imr=%x\n",
9142693Sktlim@umich.edu            interrupts, regs.isr, regs.imr);
9152693Sktlim@umich.edu
91613590Srekai.gonzalezalberquilla@arm.com    if (!(regs.isr & regs.imr))
9172693Sktlim@umich.edu        cpuIntrClear();
9182693Sktlim@umich.edu}
91913590Srekai.gonzalezalberquilla@arm.com
9202693Sktlim@umich.eduvoid
9212693Sktlim@umich.eduNSGigE::devIntrChangeMask()
9222693Sktlim@umich.edu{
92313590Srekai.gonzalezalberquilla@arm.com    DPRINTF(EthernetIntr, "interrupt mask changed: isr=%x imr=%x masked=%x\n",
9248887Sgeoffrey.blake@arm.com            regs.isr, regs.imr, regs.isr & regs.imr);
9252693Sktlim@umich.edu
92613590Srekai.gonzalezalberquilla@arm.com    if (regs.isr & regs.imr)
9272693Sktlim@umich.edu        cpuIntrPost(curTick());
9282693Sktlim@umich.edu    else
9292693Sktlim@umich.edu        cpuIntrClear();
9308727Snilay@cs.wisc.edu}
9318727Snilay@cs.wisc.edu
9328727Snilay@cs.wisc.eduvoid
9338727Snilay@cs.wisc.eduNSGigE::cpuIntrPost(Tick when)
93413590Srekai.gonzalezalberquilla@arm.com{
9352693Sktlim@umich.edu    // If the interrupt you want to post is later than an interrupt
9362693Sktlim@umich.edu    // already scheduled, just let it post in the coming one and don't
9372693Sktlim@umich.edu    // schedule another.
9382693Sktlim@umich.edu    // HOWEVER, must be sure that the scheduled intrTick is in the
93913429Srekai.gonzalezalberquilla@arm.com    // future (this was formerly the source of a bug)
9402678Sktlim@umich.edu    /**
9412678Sktlim@umich.edu     * @todo this warning should be removed and the intrTick code should
9422678Sktlim@umich.edu     * be fixed.
9432678Sktlim@umich.edu     */
9442678Sktlim@umich.edu    assert(when >= curTick());
9452678Sktlim@umich.edu    assert(intrTick >= curTick() || intrTick == 0);
9462727Sktlim@umich.edu    if (when > intrTick && intrTick != 0) {
9472678Sktlim@umich.edu        DPRINTF(EthernetIntr, "don't need to schedule event...intrTick=%d\n",
9482678Sktlim@umich.edu                intrTick);
9492678Sktlim@umich.edu        return;
9502678Sktlim@umich.edu    }
9512678Sktlim@umich.edu
9522678Sktlim@umich.edu    intrTick = when;
95310575SMarco.Elver@ARM.com    if (intrTick < curTick()) {
95410575SMarco.Elver@ARM.com        Debug::breakpoint();
95510575SMarco.Elver@ARM.com        intrTick = curTick();
95610575SMarco.Elver@ARM.com    }
95710575SMarco.Elver@ARM.com
95810575SMarco.Elver@ARM.com    DPRINTF(EthernetIntr, "going to schedule an interrupt for intrTick=%d\n",
95910575SMarco.Elver@ARM.com            intrTick);
96010575SMarco.Elver@ARM.com
96110575SMarco.Elver@ARM.com    if (intrEvent)
96210575SMarco.Elver@ARM.com        intrEvent->squash();
96310575SMarco.Elver@ARM.com    intrEvent = new IntrEvent(this, true);
96410575SMarco.Elver@ARM.com    schedule(intrEvent, intrTick);
96510575SMarco.Elver@ARM.com}
96610575SMarco.Elver@ARM.com
9672678Sktlim@umich.eduvoid
9682678Sktlim@umich.eduNSGigE::cpuInterrupt()
9692678Sktlim@umich.edu{
9702678Sktlim@umich.edu    assert(intrTick == curTick());
9712678Sktlim@umich.edu
9722678Sktlim@umich.edu    // Whether or not there's a pending interrupt, we don't care about
9737598Sminkyu.jeong@arm.com    // it anymore
9747598Sminkyu.jeong@arm.com    intrEvent = 0;
9757598Sminkyu.jeong@arm.com    intrTick = 0;
9762678Sktlim@umich.edu
9772678Sktlim@umich.edu    // Don't send an interrupt if there's already one
9782678Sktlim@umich.edu    if (cpuPendingIntr) {
9792678Sktlim@umich.edu        DPRINTF(EthernetIntr,
98013590Srekai.gonzalezalberquilla@arm.com                "would send an interrupt now, but there's already pending\n");
9812292SN/A    } else {
98213590Srekai.gonzalezalberquilla@arm.com        // Send interrupt
98313590Srekai.gonzalezalberquilla@arm.com        cpuPendingIntr = true;
9842292SN/A
9852292SN/A        DPRINTF(EthernetIntr, "posting interrupt\n");
9862292SN/A        intrPost();
9872292SN/A    }
9883126Sktlim@umich.edu}
9892292SN/A
9902292SN/Avoid
99113590Srekai.gonzalezalberquilla@arm.comNSGigE::cpuIntrClear()
99213590Srekai.gonzalezalberquilla@arm.com{
99313590Srekai.gonzalezalberquilla@arm.com    if (!cpuPendingIntr)
99413590Srekai.gonzalezalberquilla@arm.com        return;
9952292SN/A
99613590Srekai.gonzalezalberquilla@arm.com    if (intrEvent) {
99713590Srekai.gonzalezalberquilla@arm.com        intrEvent->squash();
9982292SN/A        intrEvent = 0;
99913590Srekai.gonzalezalberquilla@arm.com    }
100013590Srekai.gonzalezalberquilla@arm.com
10012292SN/A    intrTick = 0;
10022292SN/A
10032292SN/A    cpuPendingIntr = false;
10042292SN/A
10052329SN/A    DPRINTF(EthernetIntr, "clearing interrupt\n");
10062329SN/A    intrClear();
100713590Srekai.gonzalezalberquilla@arm.com}
10082292SN/A
10099527SMatt.Horsnell@arm.combool
10109527SMatt.Horsnell@arm.comNSGigE::cpuIntrPending() const
101113734SAndrea.Mondelli@ucf.edu{ return cpuPendingIntr; }
101213734SAndrea.Mondelli@ucf.edu
10139527SMatt.Horsnell@arm.comvoid
10149527SMatt.Horsnell@arm.comNSGigE::txReset()
10159527SMatt.Horsnell@arm.com{
10162292SN/A
101713590Srekai.gonzalezalberquilla@arm.com    DPRINTF(Ethernet, "transmit reset\n");
10182292SN/A
10192292SN/A    CTDD = false;
10202292SN/A    txEnable = false;;
10212292SN/A    txFragPtr = 0;
10222292SN/A    assert(txDescCnt == 0);
102313590Srekai.gonzalezalberquilla@arm.com    txFifo.clear();
10242292SN/A    txState = txIdle;
10252316SN/A    assert(txDmaState == dmaIdle);
102613590Srekai.gonzalezalberquilla@arm.com}
10272329SN/A
10288727Snilay@cs.wisc.eduvoid
10298727Snilay@cs.wisc.eduNSGigE::rxReset()
10308727Snilay@cs.wisc.edu{
10318727Snilay@cs.wisc.edu    DPRINTF(Ethernet, "receive reset\n");
10322329SN/A
10332329SN/A    CRDD = false;
10342329SN/A    assert(rxPktBytes == 0);
103512216Snikos.nikoleris@arm.com    rxEnable = false;
103612216Snikos.nikoleris@arm.com    rxFragPtr = 0;
103712216Snikos.nikoleris@arm.com    assert(rxDescCnt == 0);
103813590Srekai.gonzalezalberquilla@arm.com    assert(rxDmaState == dmaIdle);
103913590Srekai.gonzalezalberquilla@arm.com    rxFifo.clear();
10402316SN/A    rxState = rxIdle;
10412292SN/A}
10422292SN/A
10432292SN/Avoid
10446974Stjones1@inf.ed.ac.ukNSGigE::regsReset()
104513590Srekai.gonzalezalberquilla@arm.com{
10466974Stjones1@inf.ed.ac.uk    memset(&regs, 0, sizeof(regs));
104713590Srekai.gonzalezalberquilla@arm.com    regs.config = (CFGR_LNKSTS | CFGR_TBI_EN | CFGR_MODE_1000);
104813590Srekai.gonzalezalberquilla@arm.com    regs.mear = 0x12;
104913590Srekai.gonzalezalberquilla@arm.com    regs.txcfg = 0x120; // set drain threshold to 1024 bytes and
105013590Srekai.gonzalezalberquilla@arm.com                        // fill threshold to 32 bytes
105113590Srekai.gonzalezalberquilla@arm.com    regs.rxcfg = 0x4;   // set drain threshold to 16 bytes
105213710Sgabor.dozsa@arm.com    regs.srr = 0x0103;  // set the silicon revision to rev B or 0x103
105313710Sgabor.dozsa@arm.com    regs.mibc = MIBC_FRZ;
105413590Srekai.gonzalezalberquilla@arm.com    regs.vdr = 0x81;    // set the vlan tag type to 802.1q
105513590Srekai.gonzalezalberquilla@arm.com    regs.tesr = 0xc000; // TBI capable of both full and half duplex
105613590Srekai.gonzalezalberquilla@arm.com    regs.brar = 0xffffffff;
105713590Srekai.gonzalezalberquilla@arm.com
105813590Srekai.gonzalezalberquilla@arm.com    extstsEnable = false;
105913590Srekai.gonzalezalberquilla@arm.com    acceptBroadcast = false;
10606974Stjones1@inf.ed.ac.uk    acceptMulticast = false;
106113590Srekai.gonzalezalberquilla@arm.com    acceptUnicast = false;
106213590Srekai.gonzalezalberquilla@arm.com    acceptPerfect = false;
106313590Srekai.gonzalezalberquilla@arm.com    acceptArp = false;
106413590Srekai.gonzalezalberquilla@arm.com}
106513590Srekai.gonzalezalberquilla@arm.com
106613710Sgabor.dozsa@arm.combool
106713590Srekai.gonzalezalberquilla@arm.comNSGigE::doRxDmaRead()
106813590Srekai.gonzalezalberquilla@arm.com{
106913590Srekai.gonzalezalberquilla@arm.com    assert(rxDmaState == dmaIdle || rxDmaState == dmaReadWaiting);
107013590Srekai.gonzalezalberquilla@arm.com    rxDmaState = dmaReading;
107113590Srekai.gonzalezalberquilla@arm.com
107213590Srekai.gonzalezalberquilla@arm.com    if (dmaPending() || getState() != Running)
107313590Srekai.gonzalezalberquilla@arm.com        rxDmaState = dmaReadWaiting;
107413590Srekai.gonzalezalberquilla@arm.com    else
107513590Srekai.gonzalezalberquilla@arm.com        dmaRead(rxDmaAddr, rxDmaLen, &rxDmaReadEvent, (uint8_t*)rxDmaData);
107613590Srekai.gonzalezalberquilla@arm.com
107713590Srekai.gonzalezalberquilla@arm.com    return true;
107813590Srekai.gonzalezalberquilla@arm.com}
107913590Srekai.gonzalezalberquilla@arm.com
108013590Srekai.gonzalezalberquilla@arm.comvoid
10816974Stjones1@inf.ed.ac.ukNSGigE::rxDmaReadDone()
10826974Stjones1@inf.ed.ac.uk{
10836974Stjones1@inf.ed.ac.uk    assert(rxDmaState == dmaReading);
10842693Sktlim@umich.edu    rxDmaState = dmaIdle;
10852693Sktlim@umich.edu
10862693Sktlim@umich.edu    DPRINTF(EthernetDMA, "rx dma read  paddr=%#x len=%d\n",
10872698Sktlim@umich.edu            rxDmaAddr, rxDmaLen);
108813590Srekai.gonzalezalberquilla@arm.com    DDUMP(EthernetDMA, rxDmaData, rxDmaLen);
108913590Srekai.gonzalezalberquilla@arm.com
10902693Sktlim@umich.edu    // If the transmit state machine has a pending DMA, let it go first
10912693Sktlim@umich.edu    if (txDmaState == dmaReadWaiting || txDmaState == dmaWriteWaiting)
10922693Sktlim@umich.edu        txKick();
10932693Sktlim@umich.edu
10942329SN/A    rxKick();
10959440SAndreas.Sandberg@ARM.com}
10962329SN/A
10972329SN/Abool
10982329SN/ANSGigE::doRxDmaWrite()
10992329SN/A{
11002329SN/A    assert(rxDmaState == dmaIdle || rxDmaState == dmaWriteWaiting);
110113590Srekai.gonzalezalberquilla@arm.com    rxDmaState = dmaWriting;
110213590Srekai.gonzalezalberquilla@arm.com
110313831SAndrea.Mondelli@ucf.edu    if (dmaPending() || getState() != Running)
11042329SN/A        rxDmaState = dmaWriteWaiting;
11059440SAndreas.Sandberg@ARM.com    else
11062329SN/A        dmaWrite(rxDmaAddr, rxDmaLen, &rxDmaWriteEvent, (uint8_t*)rxDmaData);
11072329SN/A    return true;
11082329SN/A}
11092329SN/A
111013590Srekai.gonzalezalberquilla@arm.comvoid
111113590Srekai.gonzalezalberquilla@arm.comNSGigE::rxDmaWriteDone()
111213831SAndrea.Mondelli@ucf.edu{
11132329SN/A    assert(rxDmaState == dmaWriting);
11142329SN/A    rxDmaState = dmaIdle;
11152329SN/A
11162329SN/A    DPRINTF(EthernetDMA, "rx dma write paddr=%#x len=%d\n",
11179944Smatt.horsnell@ARM.com            rxDmaAddr, rxDmaLen);
111813590Srekai.gonzalezalberquilla@arm.com    DDUMP(EthernetDMA, rxDmaData, rxDmaLen);
111913590Srekai.gonzalezalberquilla@arm.com
112013590Srekai.gonzalezalberquilla@arm.com    // If the transmit state machine has a pending DMA, let it go first
112113590Srekai.gonzalezalberquilla@arm.com    if (txDmaState == dmaReadWaiting || txDmaState == dmaWriteWaiting)
112213590Srekai.gonzalezalberquilla@arm.com        txKick();
112313590Srekai.gonzalezalberquilla@arm.com
112413590Srekai.gonzalezalberquilla@arm.com    rxKick();
11259944Smatt.horsnell@ARM.com}
1126
1127void
1128NSGigE::rxKick()
1129{
1130    bool is64bit = (bool)(regs.config & CFGR_M64ADDR);
1131
1132    DPRINTF(EthernetSM,
1133            "receive kick rxState=%s (rxBuf.size=%d) %d-bit\n",
1134            NsRxStateStrings[rxState], rxFifo.size(), is64bit ? 64 : 32);
1135
1136    Addr link, bufptr;
1137    uint32_t &cmdsts = is64bit ? rxDesc64.cmdsts : rxDesc32.cmdsts;
1138    uint32_t &extsts = is64bit ? rxDesc64.extsts : rxDesc32.extsts;
1139
1140  next:
1141    if (clock) {
1142        if (rxKickTick > curTick()) {
1143            DPRINTF(EthernetSM, "receive kick exiting, can't run till %d\n",
1144                    rxKickTick);
1145
1146            goto exit;
1147        }
1148
1149        // Go to the next state machine clock tick.
1150        rxKickTick = curTick() + clockPeriod();
1151    }
1152
1153    switch(rxDmaState) {
1154      case dmaReadWaiting:
1155        if (doRxDmaRead())
1156            goto exit;
1157        break;
1158      case dmaWriteWaiting:
1159        if (doRxDmaWrite())
1160            goto exit;
1161        break;
1162      default:
1163        break;
1164    }
1165
1166    link = is64bit ? (Addr)rxDesc64.link : (Addr)rxDesc32.link;
1167    bufptr = is64bit ? (Addr)rxDesc64.bufptr : (Addr)rxDesc32.bufptr;
1168
1169    // see state machine from spec for details
1170    // the way this works is, if you finish work on one state and can
1171    // go directly to another, you do that through jumping to the
1172    // label "next".  however, if you have intermediate work, like DMA
1173    // so that you can't go to the next state yet, you go to exit and
1174    // exit the loop.  however, when the DMA is done it will trigger
1175    // an event and come back to this loop.
1176    switch (rxState) {
1177      case rxIdle:
1178        if (!rxEnable) {
1179            DPRINTF(EthernetSM, "Receive Disabled! Nothing to do.\n");
1180            goto exit;
1181        }
1182
1183        if (CRDD) {
1184            rxState = rxDescRefr;
1185
1186            rxDmaAddr = regs.rxdp & 0x3fffffff;
1187            rxDmaData =
1188                is64bit ? (void *)&rxDesc64.link : (void *)&rxDesc32.link;
1189            rxDmaLen = is64bit ? sizeof(rxDesc64.link) : sizeof(rxDesc32.link);
1190            rxDmaFree = dmaDescFree;
1191
1192            descDmaReads++;
1193            descDmaRdBytes += rxDmaLen;
1194
1195            if (doRxDmaRead())
1196                goto exit;
1197        } else {
1198            rxState = rxDescRead;
1199
1200            rxDmaAddr = regs.rxdp & 0x3fffffff;
1201            rxDmaData = is64bit ? (void *)&rxDesc64 : (void *)&rxDesc32;
1202            rxDmaLen = is64bit ? sizeof(rxDesc64) : sizeof(rxDesc32);
1203            rxDmaFree = dmaDescFree;
1204
1205            descDmaReads++;
1206            descDmaRdBytes += rxDmaLen;
1207
1208            if (doRxDmaRead())
1209                goto exit;
1210        }
1211        break;
1212
1213      case rxDescRefr:
1214        if (rxDmaState != dmaIdle)
1215            goto exit;
1216
1217        rxState = rxAdvance;
1218        break;
1219
1220     case rxDescRead:
1221        if (rxDmaState != dmaIdle)
1222            goto exit;
1223
1224        DPRINTF(EthernetDesc, "rxDesc: addr=%08x read descriptor\n",
1225                regs.rxdp & 0x3fffffff);
1226        DPRINTF(EthernetDesc,
1227                "rxDesc: link=%#x bufptr=%#x cmdsts=%08x extsts=%08x\n",
1228                link, bufptr, cmdsts, extsts);
1229
1230        if (cmdsts & CMDSTS_OWN) {
1231            devIntrPost(ISR_RXIDLE);
1232            rxState = rxIdle;
1233            goto exit;
1234        } else {
1235            rxState = rxFifoBlock;
1236            rxFragPtr = bufptr;
1237            rxDescCnt = cmdsts & CMDSTS_LEN_MASK;
1238        }
1239        break;
1240
1241      case rxFifoBlock:
1242        if (!rxPacket) {
1243            /**
1244             * @todo in reality, we should be able to start processing
1245             * the packet as it arrives, and not have to wait for the
1246             * full packet ot be in the receive fifo.
1247             */
1248            if (rxFifo.empty())
1249                goto exit;
1250
1251            DPRINTF(EthernetSM, "****processing receive of new packet****\n");
1252
1253            // If we don't have a packet, grab a new one from the fifo.
1254            rxPacket = rxFifo.front();
1255            rxPktBytes = rxPacket->length;
1256            rxPacketBufPtr = rxPacket->data;
1257
1258#if TRACING_ON
1259            if (DTRACE(Ethernet)) {
1260                IpPtr ip(rxPacket);
1261                if (ip) {
1262                    DPRINTF(Ethernet, "ID is %d\n", ip->id());
1263                    TcpPtr tcp(ip);
1264                    if (tcp) {
1265                        DPRINTF(Ethernet,
1266                                "Src Port=%d, Dest Port=%d, Seq=%d, Ack=%d\n",
1267                                tcp->sport(), tcp->dport(), tcp->seq(),
1268                                tcp->ack());
1269                    }
1270                }
1271            }
1272#endif
1273
1274            // sanity check - i think the driver behaves like this
1275            assert(rxDescCnt >= rxPktBytes);
1276            rxFifo.pop();
1277        }
1278
1279
1280        // dont' need the && rxDescCnt > 0 if driver sanity check
1281        // above holds
1282        if (rxPktBytes > 0) {
1283            rxState = rxFragWrite;
1284            // don't need min<>(rxPktBytes,rxDescCnt) if above sanity
1285            // check holds
1286            rxXferLen = rxPktBytes;
1287
1288            rxDmaAddr = rxFragPtr & 0x3fffffff;
1289            rxDmaData = rxPacketBufPtr;
1290            rxDmaLen = rxXferLen;
1291            rxDmaFree = dmaDataFree;
1292
1293            if (doRxDmaWrite())
1294                goto exit;
1295
1296        } else {
1297            rxState = rxDescWrite;
1298
1299            //if (rxPktBytes == 0) {  /* packet is done */
1300            assert(rxPktBytes == 0);
1301            DPRINTF(EthernetSM, "done with receiving packet\n");
1302
1303            cmdsts |= CMDSTS_OWN;
1304            cmdsts &= ~CMDSTS_MORE;
1305            cmdsts |= CMDSTS_OK;
1306            cmdsts &= 0xffff0000;
1307            cmdsts += rxPacket->length;   //i.e. set CMDSTS_SIZE
1308
1309#if 0
1310            /*
1311             * all the driver uses these are for its own stats keeping
1312             * which we don't care about, aren't necessary for
1313             * functionality and doing this would just slow us down.
1314             * if they end up using this in a later version for
1315             * functional purposes, just undef
1316             */
1317            if (rxFilterEnable) {
1318                cmdsts &= ~CMDSTS_DEST_MASK;
1319                const EthAddr &dst = rxFifoFront()->dst();
1320                if (dst->unicast())
1321                    cmdsts |= CMDSTS_DEST_SELF;
1322                if (dst->multicast())
1323                    cmdsts |= CMDSTS_DEST_MULTI;
1324                if (dst->broadcast())
1325                    cmdsts |= CMDSTS_DEST_MASK;
1326            }
1327#endif
1328
1329            IpPtr ip(rxPacket);
1330            if (extstsEnable && ip) {
1331                extsts |= EXTSTS_IPPKT;
1332                rxIpChecksums++;
1333                if (cksum(ip) != 0) {
1334                    DPRINTF(EthernetCksum, "Rx IP Checksum Error\n");
1335                    extsts |= EXTSTS_IPERR;
1336                }
1337                TcpPtr tcp(ip);
1338                UdpPtr udp(ip);
1339                if (tcp) {
1340                    extsts |= EXTSTS_TCPPKT;
1341                    rxTcpChecksums++;
1342                    if (cksum(tcp) != 0) {
1343                        DPRINTF(EthernetCksum, "Rx TCP Checksum Error\n");
1344                        extsts |= EXTSTS_TCPERR;
1345
1346                    }
1347                } else if (udp) {
1348                    extsts |= EXTSTS_UDPPKT;
1349                    rxUdpChecksums++;
1350                    if (cksum(udp) != 0) {
1351                        DPRINTF(EthernetCksum, "Rx UDP Checksum Error\n");
1352                        extsts |= EXTSTS_UDPERR;
1353                    }
1354                }
1355            }
1356            rxPacket = 0;
1357
1358            /*
1359             * the driver seems to always receive into desc buffers
1360             * of size 1514, so you never have a pkt that is split
1361             * into multiple descriptors on the receive side, so
1362             * i don't implement that case, hence the assert above.
1363             */
1364
1365            DPRINTF(EthernetDesc,
1366                    "rxDesc: addr=%08x writeback cmdsts extsts\n",
1367                    regs.rxdp & 0x3fffffff);
1368            DPRINTF(EthernetDesc,
1369                    "rxDesc: link=%#x bufptr=%#x cmdsts=%08x extsts=%08x\n",
1370                    link, bufptr, cmdsts, extsts);
1371
1372            rxDmaAddr = regs.rxdp & 0x3fffffff;
1373            rxDmaData = &cmdsts;
1374            if (is64bit) {
1375                rxDmaAddr += offsetof(ns_desc64, cmdsts);
1376                rxDmaLen = sizeof(rxDesc64.cmdsts) + sizeof(rxDesc64.extsts);
1377            } else {
1378                rxDmaAddr += offsetof(ns_desc32, cmdsts);
1379                rxDmaLen = sizeof(rxDesc32.cmdsts) + sizeof(rxDesc32.extsts);
1380            }
1381            rxDmaFree = dmaDescFree;
1382
1383            descDmaWrites++;
1384            descDmaWrBytes += rxDmaLen;
1385
1386            if (doRxDmaWrite())
1387                goto exit;
1388        }
1389        break;
1390
1391      case rxFragWrite:
1392        if (rxDmaState != dmaIdle)
1393            goto exit;
1394
1395        rxPacketBufPtr += rxXferLen;
1396        rxFragPtr += rxXferLen;
1397        rxPktBytes -= rxXferLen;
1398
1399        rxState = rxFifoBlock;
1400        break;
1401
1402      case rxDescWrite:
1403        if (rxDmaState != dmaIdle)
1404            goto exit;
1405
1406        assert(cmdsts & CMDSTS_OWN);
1407
1408        assert(rxPacket == 0);
1409        devIntrPost(ISR_RXOK);
1410
1411        if (cmdsts & CMDSTS_INTR)
1412            devIntrPost(ISR_RXDESC);
1413
1414        if (!rxEnable) {
1415            DPRINTF(EthernetSM, "Halting the RX state machine\n");
1416            rxState = rxIdle;
1417            goto exit;
1418        } else
1419            rxState = rxAdvance;
1420        break;
1421
1422      case rxAdvance:
1423        if (link == 0) {
1424            devIntrPost(ISR_RXIDLE);
1425            rxState = rxIdle;
1426            CRDD = true;
1427            goto exit;
1428        } else {
1429            if (rxDmaState != dmaIdle)
1430                goto exit;
1431            rxState = rxDescRead;
1432            regs.rxdp = link;
1433            CRDD = false;
1434
1435            rxDmaAddr = regs.rxdp & 0x3fffffff;
1436            rxDmaData = is64bit ? (void *)&rxDesc64 : (void *)&rxDesc32;
1437            rxDmaLen = is64bit ? sizeof(rxDesc64) : sizeof(rxDesc32);
1438            rxDmaFree = dmaDescFree;
1439
1440            if (doRxDmaRead())
1441                goto exit;
1442        }
1443        break;
1444
1445      default:
1446        panic("Invalid rxState!");
1447    }
1448
1449    DPRINTF(EthernetSM, "entering next rxState=%s\n",
1450            NsRxStateStrings[rxState]);
1451    goto next;
1452
1453  exit:
1454    /**
1455     * @todo do we want to schedule a future kick?
1456     */
1457    DPRINTF(EthernetSM, "rx state machine exited rxState=%s\n",
1458            NsRxStateStrings[rxState]);
1459
1460    if (clock && !rxKickEvent.scheduled())
1461        schedule(rxKickEvent, rxKickTick);
1462}
1463
1464void
1465NSGigE::transmit()
1466{
1467    if (txFifo.empty()) {
1468        DPRINTF(Ethernet, "nothing to transmit\n");
1469        return;
1470    }
1471
1472    DPRINTF(Ethernet, "Attempt Pkt Transmit: txFifo length=%d\n",
1473            txFifo.size());
1474    if (interface->sendPacket(txFifo.front())) {
1475#if TRACING_ON
1476        if (DTRACE(Ethernet)) {
1477            IpPtr ip(txFifo.front());
1478            if (ip) {
1479                DPRINTF(Ethernet, "ID is %d\n", ip->id());
1480                TcpPtr tcp(ip);
1481                if (tcp) {
1482                    DPRINTF(Ethernet,
1483                            "Src Port=%d, Dest Port=%d, Seq=%d, Ack=%d\n",
1484                            tcp->sport(), tcp->dport(), tcp->seq(),
1485                            tcp->ack());
1486                }
1487            }
1488        }
1489#endif
1490
1491        DDUMP(EthernetData, txFifo.front()->data, txFifo.front()->length);
1492        txBytes += txFifo.front()->length;
1493        txPackets++;
1494
1495        DPRINTF(Ethernet, "Successful Xmit! now txFifoAvail is %d\n",
1496                txFifo.avail());
1497        txFifo.pop();
1498
1499        /*
1500         * normally do a writeback of the descriptor here, and ONLY
1501         * after that is done, send this interrupt.  but since our
1502         * stuff never actually fails, just do this interrupt here,
1503         * otherwise the code has to stray from this nice format.
1504         * besides, it's functionally the same.
1505         */
1506        devIntrPost(ISR_TXOK);
1507    }
1508
1509   if (!txFifo.empty() && !txEvent.scheduled()) {
1510       DPRINTF(Ethernet, "reschedule transmit\n");
1511       schedule(txEvent, curTick() + retryTime);
1512   }
1513}
1514
1515bool
1516NSGigE::doTxDmaRead()
1517{
1518    assert(txDmaState == dmaIdle || txDmaState == dmaReadWaiting);
1519    txDmaState = dmaReading;
1520
1521    if (dmaPending() || getState() != Running)
1522        txDmaState = dmaReadWaiting;
1523    else
1524        dmaRead(txDmaAddr, txDmaLen, &txDmaReadEvent, (uint8_t*)txDmaData);
1525
1526    return true;
1527}
1528
1529void
1530NSGigE::txDmaReadDone()
1531{
1532    assert(txDmaState == dmaReading);
1533    txDmaState = dmaIdle;
1534
1535    DPRINTF(EthernetDMA, "tx dma read  paddr=%#x len=%d\n",
1536            txDmaAddr, txDmaLen);
1537    DDUMP(EthernetDMA, txDmaData, txDmaLen);
1538
1539    // If the receive state machine  has a pending DMA, let it go first
1540    if (rxDmaState == dmaReadWaiting || rxDmaState == dmaWriteWaiting)
1541        rxKick();
1542
1543    txKick();
1544}
1545
1546bool
1547NSGigE::doTxDmaWrite()
1548{
1549    assert(txDmaState == dmaIdle || txDmaState == dmaWriteWaiting);
1550    txDmaState = dmaWriting;
1551
1552    if (dmaPending() || getState() != Running)
1553        txDmaState = dmaWriteWaiting;
1554    else
1555        dmaWrite(txDmaAddr, txDmaLen, &txDmaWriteEvent, (uint8_t*)txDmaData);
1556    return true;
1557}
1558
1559void
1560NSGigE::txDmaWriteDone()
1561{
1562    assert(txDmaState == dmaWriting);
1563    txDmaState = dmaIdle;
1564
1565    DPRINTF(EthernetDMA, "tx dma write paddr=%#x len=%d\n",
1566            txDmaAddr, txDmaLen);
1567    DDUMP(EthernetDMA, txDmaData, txDmaLen);
1568
1569    // If the receive state machine  has a pending DMA, let it go first
1570    if (rxDmaState == dmaReadWaiting || rxDmaState == dmaWriteWaiting)
1571        rxKick();
1572
1573    txKick();
1574}
1575
1576void
1577NSGigE::txKick()
1578{
1579    bool is64bit = (bool)(regs.config & CFGR_M64ADDR);
1580
1581    DPRINTF(EthernetSM, "transmit kick txState=%s %d-bit\n",
1582            NsTxStateStrings[txState], is64bit ? 64 : 32);
1583
1584    Addr link, bufptr;
1585    uint32_t &cmdsts = is64bit ? txDesc64.cmdsts : txDesc32.cmdsts;
1586    uint32_t &extsts = is64bit ? txDesc64.extsts : txDesc32.extsts;
1587
1588  next:
1589    if (clock) {
1590        if (txKickTick > curTick()) {
1591            DPRINTF(EthernetSM, "transmit kick exiting, can't run till %d\n",
1592                    txKickTick);
1593            goto exit;
1594        }
1595
1596        // Go to the next state machine clock tick.
1597        txKickTick = curTick() + clockPeriod();
1598    }
1599
1600    switch(txDmaState) {
1601      case dmaReadWaiting:
1602        if (doTxDmaRead())
1603            goto exit;
1604        break;
1605      case dmaWriteWaiting:
1606        if (doTxDmaWrite())
1607            goto exit;
1608        break;
1609      default:
1610        break;
1611    }
1612
1613    link = is64bit ? (Addr)txDesc64.link : (Addr)txDesc32.link;
1614    bufptr = is64bit ? (Addr)txDesc64.bufptr : (Addr)txDesc32.bufptr;
1615    switch (txState) {
1616      case txIdle:
1617        if (!txEnable) {
1618            DPRINTF(EthernetSM, "Transmit disabled.  Nothing to do.\n");
1619            goto exit;
1620        }
1621
1622        if (CTDD) {
1623            txState = txDescRefr;
1624
1625            txDmaAddr = regs.txdp & 0x3fffffff;
1626            txDmaData =
1627                is64bit ? (void *)&txDesc64.link : (void *)&txDesc32.link;
1628            txDmaLen = is64bit ? sizeof(txDesc64.link) : sizeof(txDesc32.link);
1629            txDmaFree = dmaDescFree;
1630
1631            descDmaReads++;
1632            descDmaRdBytes += txDmaLen;
1633
1634            if (doTxDmaRead())
1635                goto exit;
1636
1637        } else {
1638            txState = txDescRead;
1639
1640            txDmaAddr = regs.txdp & 0x3fffffff;
1641            txDmaData = is64bit ? (void *)&txDesc64 : (void *)&txDesc32;
1642            txDmaLen = is64bit ? sizeof(txDesc64) : sizeof(txDesc32);
1643            txDmaFree = dmaDescFree;
1644
1645            descDmaReads++;
1646            descDmaRdBytes += txDmaLen;
1647
1648            if (doTxDmaRead())
1649                goto exit;
1650        }
1651        break;
1652
1653      case txDescRefr:
1654        if (txDmaState != dmaIdle)
1655            goto exit;
1656
1657        txState = txAdvance;
1658        break;
1659
1660      case txDescRead:
1661        if (txDmaState != dmaIdle)
1662            goto exit;
1663
1664        DPRINTF(EthernetDesc, "txDesc: addr=%08x read descriptor\n",
1665                regs.txdp & 0x3fffffff);
1666        DPRINTF(EthernetDesc,
1667                "txDesc: link=%#x bufptr=%#x cmdsts=%#08x extsts=%#08x\n",
1668                link, bufptr, cmdsts, extsts);
1669
1670        if (cmdsts & CMDSTS_OWN) {
1671            txState = txFifoBlock;
1672            txFragPtr = bufptr;
1673            txDescCnt = cmdsts & CMDSTS_LEN_MASK;
1674        } else {
1675            devIntrPost(ISR_TXIDLE);
1676            txState = txIdle;
1677            goto exit;
1678        }
1679        break;
1680
1681      case txFifoBlock:
1682        if (!txPacket) {
1683            DPRINTF(EthernetSM, "****starting the tx of a new packet****\n");
1684            txPacket = new EthPacketData(16384);
1685            txPacketBufPtr = txPacket->data;
1686        }
1687
1688        if (txDescCnt == 0) {
1689            DPRINTF(EthernetSM, "the txDescCnt == 0, done with descriptor\n");
1690            if (cmdsts & CMDSTS_MORE) {
1691                DPRINTF(EthernetSM, "there are more descriptors to come\n");
1692                txState = txDescWrite;
1693
1694                cmdsts &= ~CMDSTS_OWN;
1695
1696                txDmaAddr = regs.txdp & 0x3fffffff;
1697                txDmaData = &cmdsts;
1698                if (is64bit) {
1699                    txDmaAddr += offsetof(ns_desc64, cmdsts);
1700                    txDmaLen = sizeof(txDesc64.cmdsts);
1701                } else {
1702                    txDmaAddr += offsetof(ns_desc32, cmdsts);
1703                    txDmaLen = sizeof(txDesc32.cmdsts);
1704                }
1705                txDmaFree = dmaDescFree;
1706
1707                if (doTxDmaWrite())
1708                    goto exit;
1709
1710            } else { /* this packet is totally done */
1711                DPRINTF(EthernetSM, "This packet is done, let's wrap it up\n");
1712                /* deal with the the packet that just finished */
1713                if ((regs.vtcr & VTCR_PPCHK) && extstsEnable) {
1714                    IpPtr ip(txPacket);
1715                    if (extsts & EXTSTS_UDPPKT) {
1716                        UdpPtr udp(ip);
1717                        if (udp) {
1718                            udp->sum(0);
1719                            udp->sum(cksum(udp));
1720                            txUdpChecksums++;
1721                        } else {
1722                            Debug::breakpoint();
1723                            warn_once("UDPPKT set, but not UDP!\n");
1724                        }
1725                    } else if (extsts & EXTSTS_TCPPKT) {
1726                        TcpPtr tcp(ip);
1727                        if (tcp) {
1728                            tcp->sum(0);
1729                            tcp->sum(cksum(tcp));
1730                            txTcpChecksums++;
1731                        } else {
1732                            Debug::breakpoint();
1733                            warn_once("TCPPKT set, but not UDP!\n");
1734                        }
1735                    }
1736                    if (extsts & EXTSTS_IPPKT) {
1737                        if (ip) {
1738                            ip->sum(0);
1739                            ip->sum(cksum(ip));
1740                            txIpChecksums++;
1741                        } else {
1742                            Debug::breakpoint();
1743                            warn_once("IPPKT set, but not UDP!\n");
1744                        }
1745                    }
1746                }
1747
1748                txPacket->length = txPacketBufPtr - txPacket->data;
1749                // this is just because the receive can't handle a
1750                // packet bigger want to make sure
1751                if (txPacket->length > 1514)
1752                    panic("transmit packet too large, %s > 1514\n",
1753                          txPacket->length);
1754
1755#ifndef NDEBUG
1756                bool success =
1757#endif
1758                    txFifo.push(txPacket);
1759                assert(success);
1760
1761                /*
1762                 * this following section is not tqo spec, but
1763                 * functionally shouldn't be any different.  normally,
1764                 * the chip will wait til the transmit has occurred
1765                 * before writing back the descriptor because it has
1766                 * to wait to see that it was successfully transmitted
1767                 * to decide whether to set CMDSTS_OK or not.
1768                 * however, in the simulator since it is always
1769                 * successfully transmitted, and writing it exactly to
1770                 * spec would complicate the code, we just do it here
1771                 */
1772
1773                cmdsts &= ~CMDSTS_OWN;
1774                cmdsts |= CMDSTS_OK;
1775
1776                DPRINTF(EthernetDesc,
1777                        "txDesc writeback: cmdsts=%08x extsts=%08x\n",
1778                        cmdsts, extsts);
1779
1780                txDmaFree = dmaDescFree;
1781                txDmaAddr = regs.txdp & 0x3fffffff;
1782                txDmaData = &cmdsts;
1783                if (is64bit) {
1784                    txDmaAddr += offsetof(ns_desc64, cmdsts);
1785                    txDmaLen =
1786                        sizeof(txDesc64.cmdsts) + sizeof(txDesc64.extsts);
1787                } else {
1788                    txDmaAddr += offsetof(ns_desc32, cmdsts);
1789                    txDmaLen =
1790                        sizeof(txDesc32.cmdsts) + sizeof(txDesc32.extsts);
1791                }
1792
1793                descDmaWrites++;
1794                descDmaWrBytes += txDmaLen;
1795
1796                transmit();
1797                txPacket = 0;
1798
1799                if (!txEnable) {
1800                    DPRINTF(EthernetSM, "halting TX state machine\n");
1801                    txState = txIdle;
1802                    goto exit;
1803                } else
1804                    txState = txAdvance;
1805
1806                if (doTxDmaWrite())
1807                    goto exit;
1808            }
1809        } else {
1810            DPRINTF(EthernetSM, "this descriptor isn't done yet\n");
1811            if (!txFifo.full()) {
1812                txState = txFragRead;
1813
1814                /*
1815                 * The number of bytes transferred is either whatever
1816                 * is left in the descriptor (txDescCnt), or if there
1817                 * is not enough room in the fifo, just whatever room
1818                 * is left in the fifo
1819                 */
1820                txXferLen = min<uint32_t>(txDescCnt, txFifo.avail());
1821
1822                txDmaAddr = txFragPtr & 0x3fffffff;
1823                txDmaData = txPacketBufPtr;
1824                txDmaLen = txXferLen;
1825                txDmaFree = dmaDataFree;
1826
1827                if (doTxDmaRead())
1828                    goto exit;
1829            } else {
1830                txState = txFifoBlock;
1831                transmit();
1832
1833                goto exit;
1834            }
1835
1836        }
1837        break;
1838
1839      case txFragRead:
1840        if (txDmaState != dmaIdle)
1841            goto exit;
1842
1843        txPacketBufPtr += txXferLen;
1844        txFragPtr += txXferLen;
1845        txDescCnt -= txXferLen;
1846        txFifo.reserve(txXferLen);
1847
1848        txState = txFifoBlock;
1849        break;
1850
1851      case txDescWrite:
1852        if (txDmaState != dmaIdle)
1853            goto exit;
1854
1855        if (cmdsts & CMDSTS_INTR)
1856            devIntrPost(ISR_TXDESC);
1857
1858        if (!txEnable) {
1859            DPRINTF(EthernetSM, "halting TX state machine\n");
1860            txState = txIdle;
1861            goto exit;
1862        } else
1863            txState = txAdvance;
1864        break;
1865
1866      case txAdvance:
1867        if (link == 0) {
1868            devIntrPost(ISR_TXIDLE);
1869            txState = txIdle;
1870            goto exit;
1871        } else {
1872            if (txDmaState != dmaIdle)
1873                goto exit;
1874            txState = txDescRead;
1875            regs.txdp = link;
1876            CTDD = false;
1877
1878            txDmaAddr = link & 0x3fffffff;
1879            txDmaData = is64bit ? (void *)&txDesc64 : (void *)&txDesc32;
1880            txDmaLen = is64bit ? sizeof(txDesc64) : sizeof(txDesc32);
1881            txDmaFree = dmaDescFree;
1882
1883            if (doTxDmaRead())
1884                goto exit;
1885        }
1886        break;
1887
1888      default:
1889        panic("invalid state");
1890    }
1891
1892    DPRINTF(EthernetSM, "entering next txState=%s\n",
1893            NsTxStateStrings[txState]);
1894    goto next;
1895
1896  exit:
1897    /**
1898     * @todo do we want to schedule a future kick?
1899     */
1900    DPRINTF(EthernetSM, "tx state machine exited txState=%s\n",
1901            NsTxStateStrings[txState]);
1902
1903    if (clock && !txKickEvent.scheduled())
1904        schedule(txKickEvent, txKickTick);
1905}
1906
1907/**
1908 * Advance the EEPROM state machine
1909 * Called on rising edge of EEPROM clock bit in MEAR
1910 */
1911void
1912NSGigE::eepromKick()
1913{
1914    switch (eepromState) {
1915
1916      case eepromStart:
1917
1918        // Wait for start bit
1919        if (regs.mear & MEAR_EEDI) {
1920            // Set up to get 2 opcode bits
1921            eepromState = eepromGetOpcode;
1922            eepromBitsToRx = 2;
1923            eepromOpcode = 0;
1924        }
1925        break;
1926
1927      case eepromGetOpcode:
1928        eepromOpcode <<= 1;
1929        eepromOpcode += (regs.mear & MEAR_EEDI) ? 1 : 0;
1930        --eepromBitsToRx;
1931
1932        // Done getting opcode
1933        if (eepromBitsToRx == 0) {
1934            if (eepromOpcode != EEPROM_READ)
1935                panic("only EEPROM reads are implemented!");
1936
1937            // Set up to get address
1938            eepromState = eepromGetAddress;
1939            eepromBitsToRx = 6;
1940            eepromAddress = 0;
1941        }
1942        break;
1943
1944      case eepromGetAddress:
1945        eepromAddress <<= 1;
1946        eepromAddress += (regs.mear & MEAR_EEDI) ? 1 : 0;
1947        --eepromBitsToRx;
1948
1949        // Done getting address
1950        if (eepromBitsToRx == 0) {
1951
1952            if (eepromAddress >= EEPROM_SIZE)
1953                panic("EEPROM read access out of range!");
1954
1955            switch (eepromAddress) {
1956
1957              case EEPROM_PMATCH2_ADDR:
1958                eepromData = rom.perfectMatch[5];
1959                eepromData <<= 8;
1960                eepromData += rom.perfectMatch[4];
1961                break;
1962
1963              case EEPROM_PMATCH1_ADDR:
1964                eepromData = rom.perfectMatch[3];
1965                eepromData <<= 8;
1966                eepromData += rom.perfectMatch[2];
1967                break;
1968
1969              case EEPROM_PMATCH0_ADDR:
1970                eepromData = rom.perfectMatch[1];
1971                eepromData <<= 8;
1972                eepromData += rom.perfectMatch[0];
1973                break;
1974
1975              default:
1976                panic("FreeBSD driver only uses EEPROM to read PMATCH!");
1977            }
1978            // Set up to read data
1979            eepromState = eepromRead;
1980            eepromBitsToRx = 16;
1981
1982            // Clear data in bit
1983            regs.mear &= ~MEAR_EEDI;
1984        }
1985        break;
1986
1987      case eepromRead:
1988        // Clear Data Out bit
1989        regs.mear &= ~MEAR_EEDO;
1990        // Set bit to value of current EEPROM bit
1991        regs.mear |= (eepromData & 0x8000) ? MEAR_EEDO : 0x0;
1992
1993        eepromData <<= 1;
1994        --eepromBitsToRx;
1995
1996        // All done
1997        if (eepromBitsToRx == 0) {
1998            eepromState = eepromStart;
1999        }
2000        break;
2001
2002      default:
2003        panic("invalid EEPROM state");
2004    }
2005
2006}
2007
2008void
2009NSGigE::transferDone()
2010{
2011    if (txFifo.empty()) {
2012        DPRINTF(Ethernet, "transfer complete: txFifo empty...nothing to do\n");
2013        return;
2014    }
2015
2016    DPRINTF(Ethernet, "transfer complete: data in txFifo...schedule xmit\n");
2017
2018    reschedule(txEvent, curTick() + clockPeriod(), true);
2019}
2020
2021bool
2022NSGigE::rxFilter(const EthPacketPtr &packet)
2023{
2024    EthPtr eth = packet;
2025    bool drop = true;
2026    string type;
2027
2028    const EthAddr &dst = eth->dst();
2029    if (dst.unicast()) {
2030        // If we're accepting all unicast addresses
2031        if (acceptUnicast)
2032            drop = false;
2033
2034        // If we make a perfect match
2035        if (acceptPerfect && dst == rom.perfectMatch)
2036            drop = false;
2037
2038        if (acceptArp && eth->type() == ETH_TYPE_ARP)
2039            drop = false;
2040
2041    } else if (dst.broadcast()) {
2042        // if we're accepting broadcasts
2043        if (acceptBroadcast)
2044            drop = false;
2045
2046    } else if (dst.multicast()) {
2047        // if we're accepting all multicasts
2048        if (acceptMulticast)
2049            drop = false;
2050
2051        // Multicast hashing faked - all packets accepted
2052        if (multicastHashEnable)
2053            drop = false;
2054    }
2055
2056    if (drop) {
2057        DPRINTF(Ethernet, "rxFilter drop\n");
2058        DDUMP(EthernetData, packet->data, packet->length);
2059    }
2060
2061    return drop;
2062}
2063
2064bool
2065NSGigE::recvPacket(EthPacketPtr packet)
2066{
2067    rxBytes += packet->length;
2068    rxPackets++;
2069
2070    DPRINTF(Ethernet, "Receiving packet from wire, rxFifoAvail=%d\n",
2071            rxFifo.avail());
2072
2073    if (!rxEnable) {
2074        DPRINTF(Ethernet, "receive disabled...packet dropped\n");
2075        return true;
2076    }
2077
2078    if (!rxFilterEnable) {
2079        DPRINTF(Ethernet,
2080            "receive packet filtering disabled . . . packet dropped\n");
2081        return true;
2082    }
2083
2084    if (rxFilter(packet)) {
2085        DPRINTF(Ethernet, "packet filtered...dropped\n");
2086        return true;
2087    }
2088
2089    if (rxFifo.avail() < packet->length) {
2090#if TRACING_ON
2091        IpPtr ip(packet);
2092        TcpPtr tcp(ip);
2093        if (ip) {
2094            DPRINTF(Ethernet,
2095                    "packet won't fit in receive buffer...pkt ID %d dropped\n",
2096                    ip->id());
2097            if (tcp) {
2098                DPRINTF(Ethernet, "Seq=%d\n", tcp->seq());
2099            }
2100        }
2101#endif
2102        droppedPackets++;
2103        devIntrPost(ISR_RXORN);
2104        return false;
2105    }
2106
2107    rxFifo.push(packet);
2108
2109    rxKick();
2110    return true;
2111}
2112
2113
2114void
2115NSGigE::resume()
2116{
2117    SimObject::resume();
2118
2119    // During drain we could have left the state machines in a waiting state and
2120    // they wouldn't get out until some other event occured to kick them.
2121    // This way they'll get out immediately
2122    txKick();
2123    rxKick();
2124}
2125
2126
2127//=====================================================================
2128//
2129//
2130void
2131NSGigE::serialize(ostream &os)
2132{
2133    // Serialize the PciDev base class
2134    PciDev::serialize(os);
2135
2136    /*
2137     * Finalize any DMA events now.
2138     */
2139    // @todo will mem system save pending dma?
2140
2141    /*
2142     * Serialize the device registers
2143     */
2144    SERIALIZE_SCALAR(regs.command);
2145    SERIALIZE_SCALAR(regs.config);
2146    SERIALIZE_SCALAR(regs.mear);
2147    SERIALIZE_SCALAR(regs.ptscr);
2148    SERIALIZE_SCALAR(regs.isr);
2149    SERIALIZE_SCALAR(regs.imr);
2150    SERIALIZE_SCALAR(regs.ier);
2151    SERIALIZE_SCALAR(regs.ihr);
2152    SERIALIZE_SCALAR(regs.txdp);
2153    SERIALIZE_SCALAR(regs.txdp_hi);
2154    SERIALIZE_SCALAR(regs.txcfg);
2155    SERIALIZE_SCALAR(regs.gpior);
2156    SERIALIZE_SCALAR(regs.rxdp);
2157    SERIALIZE_SCALAR(regs.rxdp_hi);
2158    SERIALIZE_SCALAR(regs.rxcfg);
2159    SERIALIZE_SCALAR(regs.pqcr);
2160    SERIALIZE_SCALAR(regs.wcsr);
2161    SERIALIZE_SCALAR(regs.pcr);
2162    SERIALIZE_SCALAR(regs.rfcr);
2163    SERIALIZE_SCALAR(regs.rfdr);
2164    SERIALIZE_SCALAR(regs.brar);
2165    SERIALIZE_SCALAR(regs.brdr);
2166    SERIALIZE_SCALAR(regs.srr);
2167    SERIALIZE_SCALAR(regs.mibc);
2168    SERIALIZE_SCALAR(regs.vrcr);
2169    SERIALIZE_SCALAR(regs.vtcr);
2170    SERIALIZE_SCALAR(regs.vdr);
2171    SERIALIZE_SCALAR(regs.ccsr);
2172    SERIALIZE_SCALAR(regs.tbicr);
2173    SERIALIZE_SCALAR(regs.tbisr);
2174    SERIALIZE_SCALAR(regs.tanar);
2175    SERIALIZE_SCALAR(regs.tanlpar);
2176    SERIALIZE_SCALAR(regs.taner);
2177    SERIALIZE_SCALAR(regs.tesr);
2178
2179    SERIALIZE_ARRAY(rom.perfectMatch, ETH_ADDR_LEN);
2180    SERIALIZE_ARRAY(rom.filterHash, FHASH_SIZE);
2181
2182    SERIALIZE_SCALAR(ioEnable);
2183
2184    /*
2185     * Serialize the data Fifos
2186     */
2187    rxFifo.serialize("rxFifo", os);
2188    txFifo.serialize("txFifo", os);
2189
2190    /*
2191     * Serialize the various helper variables
2192     */
2193    bool txPacketExists = txPacket;
2194    SERIALIZE_SCALAR(txPacketExists);
2195    if (txPacketExists) {
2196        txPacket->length = txPacketBufPtr - txPacket->data;
2197        txPacket->serialize("txPacket", os);
2198        uint32_t txPktBufPtr = (uint32_t) (txPacketBufPtr - txPacket->data);
2199        SERIALIZE_SCALAR(txPktBufPtr);
2200    }
2201
2202    bool rxPacketExists = rxPacket;
2203    SERIALIZE_SCALAR(rxPacketExists);
2204    if (rxPacketExists) {
2205        rxPacket->serialize("rxPacket", os);
2206        uint32_t rxPktBufPtr = (uint32_t) (rxPacketBufPtr - rxPacket->data);
2207        SERIALIZE_SCALAR(rxPktBufPtr);
2208    }
2209
2210    SERIALIZE_SCALAR(txXferLen);
2211    SERIALIZE_SCALAR(rxXferLen);
2212
2213    /*
2214     * Serialize Cached Descriptors
2215     */
2216    SERIALIZE_SCALAR(rxDesc64.link);
2217    SERIALIZE_SCALAR(rxDesc64.bufptr);
2218    SERIALIZE_SCALAR(rxDesc64.cmdsts);
2219    SERIALIZE_SCALAR(rxDesc64.extsts);
2220    SERIALIZE_SCALAR(txDesc64.link);
2221    SERIALIZE_SCALAR(txDesc64.bufptr);
2222    SERIALIZE_SCALAR(txDesc64.cmdsts);
2223    SERIALIZE_SCALAR(txDesc64.extsts);
2224    SERIALIZE_SCALAR(rxDesc32.link);
2225    SERIALIZE_SCALAR(rxDesc32.bufptr);
2226    SERIALIZE_SCALAR(rxDesc32.cmdsts);
2227    SERIALIZE_SCALAR(rxDesc32.extsts);
2228    SERIALIZE_SCALAR(txDesc32.link);
2229    SERIALIZE_SCALAR(txDesc32.bufptr);
2230    SERIALIZE_SCALAR(txDesc32.cmdsts);
2231    SERIALIZE_SCALAR(txDesc32.extsts);
2232    SERIALIZE_SCALAR(extstsEnable);
2233
2234    /*
2235     * Serialize tx state machine
2236     */
2237    int txState = this->txState;
2238    SERIALIZE_SCALAR(txState);
2239    SERIALIZE_SCALAR(txEnable);
2240    SERIALIZE_SCALAR(CTDD);
2241    SERIALIZE_SCALAR(txFragPtr);
2242    SERIALIZE_SCALAR(txDescCnt);
2243    int txDmaState = this->txDmaState;
2244    SERIALIZE_SCALAR(txDmaState);
2245    SERIALIZE_SCALAR(txKickTick);
2246
2247    /*
2248     * Serialize rx state machine
2249     */
2250    int rxState = this->rxState;
2251    SERIALIZE_SCALAR(rxState);
2252    SERIALIZE_SCALAR(rxEnable);
2253    SERIALIZE_SCALAR(CRDD);
2254    SERIALIZE_SCALAR(rxPktBytes);
2255    SERIALIZE_SCALAR(rxFragPtr);
2256    SERIALIZE_SCALAR(rxDescCnt);
2257    int rxDmaState = this->rxDmaState;
2258    SERIALIZE_SCALAR(rxDmaState);
2259    SERIALIZE_SCALAR(rxKickTick);
2260
2261    /*
2262     * Serialize EEPROM state machine
2263     */
2264    int eepromState = this->eepromState;
2265    SERIALIZE_SCALAR(eepromState);
2266    SERIALIZE_SCALAR(eepromClk);
2267    SERIALIZE_SCALAR(eepromBitsToRx);
2268    SERIALIZE_SCALAR(eepromOpcode);
2269    SERIALIZE_SCALAR(eepromAddress);
2270    SERIALIZE_SCALAR(eepromData);
2271
2272    /*
2273     * If there's a pending transmit, store the time so we can
2274     * reschedule it later
2275     */
2276    Tick transmitTick = txEvent.scheduled() ? txEvent.when() - curTick() : 0;
2277    SERIALIZE_SCALAR(transmitTick);
2278
2279    /*
2280     * receive address filter settings
2281     */
2282    SERIALIZE_SCALAR(rxFilterEnable);
2283    SERIALIZE_SCALAR(acceptBroadcast);
2284    SERIALIZE_SCALAR(acceptMulticast);
2285    SERIALIZE_SCALAR(acceptUnicast);
2286    SERIALIZE_SCALAR(acceptPerfect);
2287    SERIALIZE_SCALAR(acceptArp);
2288    SERIALIZE_SCALAR(multicastHashEnable);
2289
2290    /*
2291     * Keep track of pending interrupt status.
2292     */
2293    SERIALIZE_SCALAR(intrTick);
2294    SERIALIZE_SCALAR(cpuPendingIntr);
2295    Tick intrEventTick = 0;
2296    if (intrEvent)
2297        intrEventTick = intrEvent->when();
2298    SERIALIZE_SCALAR(intrEventTick);
2299
2300}
2301
2302void
2303NSGigE::unserialize(Checkpoint *cp, const std::string &section)
2304{
2305    // Unserialize the PciDev base class
2306    PciDev::unserialize(cp, section);
2307
2308    UNSERIALIZE_SCALAR(regs.command);
2309    UNSERIALIZE_SCALAR(regs.config);
2310    UNSERIALIZE_SCALAR(regs.mear);
2311    UNSERIALIZE_SCALAR(regs.ptscr);
2312    UNSERIALIZE_SCALAR(regs.isr);
2313    UNSERIALIZE_SCALAR(regs.imr);
2314    UNSERIALIZE_SCALAR(regs.ier);
2315    UNSERIALIZE_SCALAR(regs.ihr);
2316    UNSERIALIZE_SCALAR(regs.txdp);
2317    UNSERIALIZE_SCALAR(regs.txdp_hi);
2318    UNSERIALIZE_SCALAR(regs.txcfg);
2319    UNSERIALIZE_SCALAR(regs.gpior);
2320    UNSERIALIZE_SCALAR(regs.rxdp);
2321    UNSERIALIZE_SCALAR(regs.rxdp_hi);
2322    UNSERIALIZE_SCALAR(regs.rxcfg);
2323    UNSERIALIZE_SCALAR(regs.pqcr);
2324    UNSERIALIZE_SCALAR(regs.wcsr);
2325    UNSERIALIZE_SCALAR(regs.pcr);
2326    UNSERIALIZE_SCALAR(regs.rfcr);
2327    UNSERIALIZE_SCALAR(regs.rfdr);
2328    UNSERIALIZE_SCALAR(regs.brar);
2329    UNSERIALIZE_SCALAR(regs.brdr);
2330    UNSERIALIZE_SCALAR(regs.srr);
2331    UNSERIALIZE_SCALAR(regs.mibc);
2332    UNSERIALIZE_SCALAR(regs.vrcr);
2333    UNSERIALIZE_SCALAR(regs.vtcr);
2334    UNSERIALIZE_SCALAR(regs.vdr);
2335    UNSERIALIZE_SCALAR(regs.ccsr);
2336    UNSERIALIZE_SCALAR(regs.tbicr);
2337    UNSERIALIZE_SCALAR(regs.tbisr);
2338    UNSERIALIZE_SCALAR(regs.tanar);
2339    UNSERIALIZE_SCALAR(regs.tanlpar);
2340    UNSERIALIZE_SCALAR(regs.taner);
2341    UNSERIALIZE_SCALAR(regs.tesr);
2342
2343    UNSERIALIZE_ARRAY(rom.perfectMatch, ETH_ADDR_LEN);
2344    UNSERIALIZE_ARRAY(rom.filterHash, FHASH_SIZE);
2345
2346    UNSERIALIZE_SCALAR(ioEnable);
2347
2348    /*
2349     * unserialize the data fifos
2350     */
2351    rxFifo.unserialize("rxFifo", cp, section);
2352    txFifo.unserialize("txFifo", cp, section);
2353
2354    /*
2355     * unserialize the various helper variables
2356     */
2357    bool txPacketExists;
2358    UNSERIALIZE_SCALAR(txPacketExists);
2359    if (txPacketExists) {
2360        txPacket = new EthPacketData(16384);
2361        txPacket->unserialize("txPacket", cp, section);
2362        uint32_t txPktBufPtr;
2363        UNSERIALIZE_SCALAR(txPktBufPtr);
2364        txPacketBufPtr = (uint8_t *) txPacket->data + txPktBufPtr;
2365    } else
2366        txPacket = 0;
2367
2368    bool rxPacketExists;
2369    UNSERIALIZE_SCALAR(rxPacketExists);
2370    rxPacket = 0;
2371    if (rxPacketExists) {
2372        rxPacket = new EthPacketData(16384);
2373        rxPacket->unserialize("rxPacket", cp, section);
2374        uint32_t rxPktBufPtr;
2375        UNSERIALIZE_SCALAR(rxPktBufPtr);
2376        rxPacketBufPtr = (uint8_t *) rxPacket->data + rxPktBufPtr;
2377    } else
2378        rxPacket = 0;
2379
2380    UNSERIALIZE_SCALAR(txXferLen);
2381    UNSERIALIZE_SCALAR(rxXferLen);
2382
2383    /*
2384     * Unserialize Cached Descriptors
2385     */
2386    UNSERIALIZE_SCALAR(rxDesc64.link);
2387    UNSERIALIZE_SCALAR(rxDesc64.bufptr);
2388    UNSERIALIZE_SCALAR(rxDesc64.cmdsts);
2389    UNSERIALIZE_SCALAR(rxDesc64.extsts);
2390    UNSERIALIZE_SCALAR(txDesc64.link);
2391    UNSERIALIZE_SCALAR(txDesc64.bufptr);
2392    UNSERIALIZE_SCALAR(txDesc64.cmdsts);
2393    UNSERIALIZE_SCALAR(txDesc64.extsts);
2394    UNSERIALIZE_SCALAR(rxDesc32.link);
2395    UNSERIALIZE_SCALAR(rxDesc32.bufptr);
2396    UNSERIALIZE_SCALAR(rxDesc32.cmdsts);
2397    UNSERIALIZE_SCALAR(rxDesc32.extsts);
2398    UNSERIALIZE_SCALAR(txDesc32.link);
2399    UNSERIALIZE_SCALAR(txDesc32.bufptr);
2400    UNSERIALIZE_SCALAR(txDesc32.cmdsts);
2401    UNSERIALIZE_SCALAR(txDesc32.extsts);
2402    UNSERIALIZE_SCALAR(extstsEnable);
2403
2404    /*
2405     * unserialize tx state machine
2406     */
2407    int txState;
2408    UNSERIALIZE_SCALAR(txState);
2409    this->txState = (TxState) txState;
2410    UNSERIALIZE_SCALAR(txEnable);
2411    UNSERIALIZE_SCALAR(CTDD);
2412    UNSERIALIZE_SCALAR(txFragPtr);
2413    UNSERIALIZE_SCALAR(txDescCnt);
2414    int txDmaState;
2415    UNSERIALIZE_SCALAR(txDmaState);
2416    this->txDmaState = (DmaState) txDmaState;
2417    UNSERIALIZE_SCALAR(txKickTick);
2418    if (txKickTick)
2419        schedule(txKickEvent, txKickTick);
2420
2421    /*
2422     * unserialize rx state machine
2423     */
2424    int rxState;
2425    UNSERIALIZE_SCALAR(rxState);
2426    this->rxState = (RxState) rxState;
2427    UNSERIALIZE_SCALAR(rxEnable);
2428    UNSERIALIZE_SCALAR(CRDD);
2429    UNSERIALIZE_SCALAR(rxPktBytes);
2430    UNSERIALIZE_SCALAR(rxFragPtr);
2431    UNSERIALIZE_SCALAR(rxDescCnt);
2432    int rxDmaState;
2433    UNSERIALIZE_SCALAR(rxDmaState);
2434    this->rxDmaState = (DmaState) rxDmaState;
2435    UNSERIALIZE_SCALAR(rxKickTick);
2436    if (rxKickTick)
2437        schedule(rxKickEvent, rxKickTick);
2438
2439    /*
2440     * Unserialize EEPROM state machine
2441     */
2442    int eepromState;
2443    UNSERIALIZE_SCALAR(eepromState);
2444    this->eepromState = (EEPROMState) eepromState;
2445    UNSERIALIZE_SCALAR(eepromClk);
2446    UNSERIALIZE_SCALAR(eepromBitsToRx);
2447    UNSERIALIZE_SCALAR(eepromOpcode);
2448    UNSERIALIZE_SCALAR(eepromAddress);
2449    UNSERIALIZE_SCALAR(eepromData);
2450
2451    /*
2452     * If there's a pending transmit, reschedule it now
2453     */
2454    Tick transmitTick;
2455    UNSERIALIZE_SCALAR(transmitTick);
2456    if (transmitTick)
2457        schedule(txEvent, curTick() + transmitTick);
2458
2459    /*
2460     * unserialize receive address filter settings
2461     */
2462    UNSERIALIZE_SCALAR(rxFilterEnable);
2463    UNSERIALIZE_SCALAR(acceptBroadcast);
2464    UNSERIALIZE_SCALAR(acceptMulticast);
2465    UNSERIALIZE_SCALAR(acceptUnicast);
2466    UNSERIALIZE_SCALAR(acceptPerfect);
2467    UNSERIALIZE_SCALAR(acceptArp);
2468    UNSERIALIZE_SCALAR(multicastHashEnable);
2469
2470    /*
2471     * Keep track of pending interrupt status.
2472     */
2473    UNSERIALIZE_SCALAR(intrTick);
2474    UNSERIALIZE_SCALAR(cpuPendingIntr);
2475    Tick intrEventTick;
2476    UNSERIALIZE_SCALAR(intrEventTick);
2477    if (intrEventTick) {
2478        intrEvent = new IntrEvent(this, true);
2479        schedule(intrEvent, intrEventTick);
2480    }
2481}
2482
2483NSGigE *
2484NSGigEParams::create()
2485{
2486    return new NSGigE(this);
2487}
2488