ns_gige.cc revision 9086
16657Snate@binkert.org/*
26657Snate@binkert.org * Copyright (c) 2004-2005 The Regents of The University of Michigan
36657Snate@binkert.org * All rights reserved.
46657Snate@binkert.org *
56657Snate@binkert.org * Redistribution and use in source and binary forms, with or without
66657Snate@binkert.org * modification, are permitted provided that the following conditions are
76657Snate@binkert.org * met: redistributions of source code must retain the above copyright
86657Snate@binkert.org * notice, this list of conditions and the following disclaimer;
96657Snate@binkert.org * redistributions in binary form must reproduce the above copyright
106657Snate@binkert.org * notice, this list of conditions and the following disclaimer in the
116657Snate@binkert.org * documentation and/or other materials provided with the distribution;
126657Snate@binkert.org * neither the name of the copyright holders nor the names of its
136657Snate@binkert.org * contributors may be used to endorse or promote products derived from
146657Snate@binkert.org * this software without specific prior written permission.
156657Snate@binkert.org *
166657Snate@binkert.org * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
176657Snate@binkert.org * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
186657Snate@binkert.org * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
196657Snate@binkert.org * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
206657Snate@binkert.org * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
216657Snate@binkert.org * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
226657Snate@binkert.org * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
236657Snate@binkert.org * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
246657Snate@binkert.org * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
256657Snate@binkert.org * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
266657Snate@binkert.org * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
276657Snate@binkert.org *
286999Snate@binkert.org * Authors: Nathan Binkert
296657Snate@binkert.org *          Lisa Hsu
306657Snate@binkert.org */
316657Snate@binkert.org
329302Snilay@cs.wisc.edu/** @file
336657Snate@binkert.org * Device module for modelling the National Semiconductor
346657Snate@binkert.org * DP83820 ethernet controller.  Does not support priority queueing
356657Snate@binkert.org */
366657Snate@binkert.org#include <deque>
376657Snate@binkert.org#include <string>
386657Snate@binkert.org
396657Snate@binkert.org#include "base/debug.hh"
406657Snate@binkert.org#include "base/inet.hh"
416657Snate@binkert.org#include "base/types.hh"
426657Snate@binkert.org#include "config/the_isa.hh"
436657Snate@binkert.org#include "cpu/thread_context.hh"
446657Snate@binkert.org#include "debug/EthernetAll.hh"
456657Snate@binkert.org#include "dev/etherlink.hh"
466657Snate@binkert.org#include "dev/ns_gige.hh"
476657Snate@binkert.org#include "dev/pciconfigall.hh"
486657Snate@binkert.org#include "mem/packet.hh"
496657Snate@binkert.org#include "mem/packet_access.hh"
506657Snate@binkert.org#include "params/NSGigE.hh"
516657Snate@binkert.org#include "sim/system.hh"
526657Snate@binkert.org
536657Snate@binkert.org// clang complains about std::set being overloaded with Packet::set if
546657Snate@binkert.org// we open up the entire namespace std
556882SBrad.Beckmann@amd.comusing std::min;
566657Snate@binkert.orgusing std::ostream;
576657Snate@binkert.orgusing std::string;
586657Snate@binkert.org
596657Snate@binkert.orgconst char *NsRxStateStrings[] =
606657Snate@binkert.org{
616657Snate@binkert.org    "rxIdle",
626657Snate@binkert.org    "rxDescRefr",
636657Snate@binkert.org    "rxDescRead",
646657Snate@binkert.org    "rxFifoBlock",
656657Snate@binkert.org    "rxFragWrite",
666657Snate@binkert.org    "rxDescWrite",
676657Snate@binkert.org    "rxAdvance"
686657Snate@binkert.org};
696657Snate@binkert.org
706657Snate@binkert.orgconst char *NsTxStateStrings[] =
716657Snate@binkert.org{
726657Snate@binkert.org    "txIdle",
736657Snate@binkert.org    "txDescRefr",
746657Snate@binkert.org    "txDescRead",
7510228Snilay@cs.wisc.edu    "txFifoBlock",
766657Snate@binkert.org    "txFragRead",
776657Snate@binkert.org    "txDescWrite",
7810228Snilay@cs.wisc.edu    "txAdvance"
796657Snate@binkert.org};
806657Snate@binkert.org
816657Snate@binkert.orgconst char *NsDmaState[] =
826657Snate@binkert.org{
836657Snate@binkert.org    "dmaIdle",
846657Snate@binkert.org    "dmaReading",
856657Snate@binkert.org    "dmaWriting",
866657Snate@binkert.org    "dmaReadWaiting",
876657Snate@binkert.org    "dmaWriteWaiting"
886657Snate@binkert.org};
896657Snate@binkert.org
906657Snate@binkert.orgusing namespace Net;
916657Snate@binkert.orgusing namespace TheISA;
926657Snate@binkert.org
936657Snate@binkert.org///////////////////////////////////////////////////////////////////////
946657Snate@binkert.org//
958086SBrad.Beckmann@amd.com// NSGigE PCI Device
968086SBrad.Beckmann@amd.com//
978086SBrad.Beckmann@amd.comNSGigE::NSGigE(Params *p)
986657Snate@binkert.org    : EtherDevice(p), ioEnable(false),
996657Snate@binkert.org      txFifo(p->tx_fifo_size), rxFifo(p->rx_fifo_size),
1006657Snate@binkert.org      txPacket(0), rxPacket(0), txPacketBufPtr(NULL), rxPacketBufPtr(NULL),
1016657Snate@binkert.org      txXferLen(0), rxXferLen(0), rxDmaFree(false), txDmaFree(false),
1029298Snilay@cs.wisc.edu      clock(p->clock),
1036657Snate@binkert.org      txState(txIdle), txEnable(false), CTDD(false), txHalt(false),
1046657Snate@binkert.org      txFragPtr(0), txDescCnt(0), txDmaState(dmaIdle), rxState(rxIdle),
1056657Snate@binkert.org      rxEnable(false), CRDD(false), rxPktBytes(0), rxHalt(false),
1066657Snate@binkert.org      rxFragPtr(0), rxDescCnt(0), rxDmaState(dmaIdle), extstsEnable(false),
1076657Snate@binkert.org      eepromState(eepromStart), eepromClk(false), eepromBitsToRx(0),
1086657Snate@binkert.org      eepromOpcode(0), eepromAddress(0), eepromData(0),
1096657Snate@binkert.org      dmaReadDelay(p->dma_read_delay), dmaWriteDelay(p->dma_write_delay),
1106657Snate@binkert.org      dmaReadFactor(p->dma_read_factor), dmaWriteFactor(p->dma_write_factor),
1116657Snate@binkert.org      rxDmaData(NULL), rxDmaAddr(0), rxDmaLen(0),
1126657Snate@binkert.org      txDmaData(NULL), txDmaAddr(0), txDmaLen(0),
1136657Snate@binkert.org      rxDmaReadEvent(this), rxDmaWriteEvent(this),
1146657Snate@binkert.org      txDmaReadEvent(this), txDmaWriteEvent(this),
1156657Snate@binkert.org      dmaDescFree(p->dma_desc_free), dmaDataFree(p->dma_data_free),
1166657Snate@binkert.org      txDelay(p->tx_delay), rxDelay(p->rx_delay),
1176657Snate@binkert.org      rxKickTick(0), rxKickEvent(this), txKickTick(0), txKickEvent(this),
1186657Snate@binkert.org      txEvent(this), rxFilterEnable(p->rx_filter),
1196657Snate@binkert.org      acceptBroadcast(false), acceptMulticast(false), acceptUnicast(false),
1206657Snate@binkert.org      acceptPerfect(false), acceptArp(false), multicastHashEnable(false),
1216657Snate@binkert.org      intrDelay(p->intr_delay), intrTick(0), cpuPendingIntr(false),
1226657Snate@binkert.org      intrEvent(0), interface(0)
1236657Snate@binkert.org{
1246657Snate@binkert.org
1256657Snate@binkert.org
1266657Snate@binkert.org    interface = new NSGigEInt(name() + ".int0", this);
1276657Snate@binkert.org
1286657Snate@binkert.org    regsReset();
1296657Snate@binkert.org    memcpy(&rom.perfectMatch, p->hardware_address.bytes(), ETH_ADDR_LEN);
1306657Snate@binkert.org
1316657Snate@binkert.org    memset(&rxDesc32, 0, sizeof(rxDesc32));
1326657Snate@binkert.org    memset(&txDesc32, 0, sizeof(txDesc32));
1336657Snate@binkert.org    memset(&rxDesc64, 0, sizeof(rxDesc64));
1346657Snate@binkert.org    memset(&txDesc64, 0, sizeof(txDesc64));
1356657Snate@binkert.org}
1366657Snate@binkert.org
1376657Snate@binkert.orgNSGigE::~NSGigE()
1386657Snate@binkert.org{
1399298Snilay@cs.wisc.edu    delete interface;
1406657Snate@binkert.org}
1416657Snate@binkert.org
1426657Snate@binkert.org/**
1436657Snate@binkert.org * This is to write to the PCI general configuration registers
1446657Snate@binkert.org */
1456657Snate@binkert.orgTick
1469302Snilay@cs.wisc.eduNSGigE::writeConfig(PacketPtr pkt)
1479302Snilay@cs.wisc.edu{
1489302Snilay@cs.wisc.edu    int offset = pkt->getAddr() & PCI_CONFIG_SIZE;
1496657Snate@binkert.org    if (offset < PCI_DEVICE_SPECIFIC)
1506657Snate@binkert.org        PciDev::writeConfig(pkt);
1516657Snate@binkert.org    else
1526657Snate@binkert.org        panic("Device specific PCI config space not implemented!\n");
1536657Snate@binkert.org
1546657Snate@binkert.org    switch (offset) {
1556657Snate@binkert.org        // seems to work fine without all these PCI settings, but i
1566657Snate@binkert.org        // put in the IO to double check, an assertion will fail if we
1576882SBrad.Beckmann@amd.com        // need to properly implement it
1586882SBrad.Beckmann@amd.com      case PCI_COMMAND:
1596882SBrad.Beckmann@amd.com        if (config.data[offset] & PCI_CMD_IOSE)
1608086SBrad.Beckmann@amd.com            ioEnable = true;
1618086SBrad.Beckmann@amd.com        else
1628086SBrad.Beckmann@amd.com            ioEnable = false;
1639298Snilay@cs.wisc.edu        break;
1646657Snate@binkert.org    }
1656657Snate@binkert.org
1666657Snate@binkert.org    return configDelay;
1676657Snate@binkert.org}
1686657Snate@binkert.org
1696657Snate@binkert.orgEtherInt*
1706657Snate@binkert.orgNSGigE::getEthPort(const std::string &if_name, int idx)
1719298Snilay@cs.wisc.edu{
1729298Snilay@cs.wisc.edu    if (if_name == "interface") {
1739298Snilay@cs.wisc.edu       if (interface->getPeer())
1749298Snilay@cs.wisc.edu           panic("interface already connected to\n");
1759298Snilay@cs.wisc.edu       return interface;
1769298Snilay@cs.wisc.edu    }
1779298Snilay@cs.wisc.edu    return NULL;
1789298Snilay@cs.wisc.edu}
1799298Snilay@cs.wisc.edu
1809298Snilay@cs.wisc.edu/**
1819298Snilay@cs.wisc.edu * This reads the device registers, which are detailed in the NS83820
1829298Snilay@cs.wisc.edu * spec sheet
1836657Snate@binkert.org */
1846657Snate@binkert.orgTick
1856657Snate@binkert.orgNSGigE::read(PacketPtr pkt)
1866657Snate@binkert.org{
1876657Snate@binkert.org    assert(ioEnable);
1886657Snate@binkert.org
1896657Snate@binkert.org    pkt->allocate();
1906657Snate@binkert.org
1916657Snate@binkert.org    //The mask is to give you only the offset into the device register file
1926657Snate@binkert.org    Addr daddr = pkt->getAddr() & 0xfff;
1936657Snate@binkert.org    DPRINTF(EthernetPIO, "read  da=%#x pa=%#x size=%d\n",
1949219Spower.jg@gmail.com            daddr, pkt->getAddr(), pkt->getSize());
1956657Snate@binkert.org
1966657Snate@binkert.org
1976657Snate@binkert.org    // there are some reserved registers, you can see ns_gige_reg.h and
1986657Snate@binkert.org    // the spec sheet for details
1996657Snate@binkert.org    if (daddr > LAST && daddr <=  RESERVED) {
2006657Snate@binkert.org        panic("Accessing reserved register");
2016657Snate@binkert.org    } else if (daddr > RESERVED && daddr <= 0x3FC) {
2026657Snate@binkert.org        return readConfig(pkt);
2036657Snate@binkert.org    } else if (daddr >= MIB_START && daddr <= MIB_END) {
2046657Snate@binkert.org        // don't implement all the MIB's.  hopefully the kernel
2056657Snate@binkert.org        // doesn't actually DEPEND upon their values
2066657Snate@binkert.org        // MIB are just hardware stats keepers
2076999Snate@binkert.org        pkt->set<uint32_t>(0);
2086657Snate@binkert.org        pkt->makeAtomicResponse();
2096657Snate@binkert.org        return pioDelay;
2106657Snate@binkert.org    } else if (daddr > 0x3FC)
2116657Snate@binkert.org        panic("Something is messed up!\n");
2126657Snate@binkert.org
2136657Snate@binkert.org    assert(pkt->getSize() == sizeof(uint32_t));
2146657Snate@binkert.org        uint32_t &reg = *pkt->getPtr<uint32_t>();
2157007Snate@binkert.org        uint16_t rfaddr;
2167007Snate@binkert.org
2176657Snate@binkert.org        switch (daddr) {
2187002Snate@binkert.org          case CR:
2197002Snate@binkert.org            reg = regs.command;
2209466Snilay@cs.wisc.edu            //these are supposed to be cleared on a read
2216657Snate@binkert.org            reg &= ~(CR_RXD | CR_TXD | CR_TXR | CR_RXR);
2226657Snate@binkert.org            break;
2236657Snate@binkert.org
2246657Snate@binkert.org          case CFGR:
2256657Snate@binkert.org            reg = regs.config;
2266657Snate@binkert.org            break;
2276657Snate@binkert.org
2286657Snate@binkert.org          case MEAR:
2296657Snate@binkert.org            reg = regs.mear;
2306657Snate@binkert.org            break;
2316657Snate@binkert.org
2326657Snate@binkert.org          case PTSCR:
2337007Snate@binkert.org            reg = regs.ptscr;
2347007Snate@binkert.org            break;
2356657Snate@binkert.org
2369466Snilay@cs.wisc.edu          case ISR:
2376657Snate@binkert.org            reg = regs.isr;
2386657Snate@binkert.org            devIntrClear(ISR_ALL);
2399466Snilay@cs.wisc.edu            break;
2409508Snilay@cs.wisc.edu
2419466Snilay@cs.wisc.edu          case IMR:
2429466Snilay@cs.wisc.edu            reg = regs.imr;
2439466Snilay@cs.wisc.edu            break;
2446657Snate@binkert.org
2456657Snate@binkert.org          case IER:
2466657Snate@binkert.org            reg = regs.ier;
2476657Snate@binkert.org            break;
2486657Snate@binkert.org
2496657Snate@binkert.org          case IHR:
2506657Snate@binkert.org            reg = regs.ihr;
2516657Snate@binkert.org            break;
2526657Snate@binkert.org
2536657Snate@binkert.org          case TXDP:
2546657Snate@binkert.org            reg = regs.txdp;
2556657Snate@binkert.org            break;
2566657Snate@binkert.org
2576657Snate@binkert.org          case TXDP_HI:
2586657Snate@binkert.org            reg = regs.txdp_hi;
2596657Snate@binkert.org            break;
2606657Snate@binkert.org
2617453Snate@binkert.org          case TX_CFG:
2627453Snate@binkert.org            reg = regs.txcfg;
2637453Snate@binkert.org            break;
2647453Snate@binkert.org
2657453Snate@binkert.org          case GPIOR:
2667453Snate@binkert.org            reg = regs.gpior;
2677453Snate@binkert.org            break;
2687453Snate@binkert.org
2697453Snate@binkert.org          case RXDP:
2707453Snate@binkert.org            reg = regs.rxdp;
2717453Snate@binkert.org            break;
2727453Snate@binkert.org
2737453Snate@binkert.org          case RXDP_HI:
2747453Snate@binkert.org            reg = regs.rxdp_hi;
2757453Snate@binkert.org            break;
2767453Snate@binkert.org
2777453Snate@binkert.org          case RX_CFG:
2786657Snate@binkert.org            reg = regs.rxcfg;
2796657Snate@binkert.org            break;
2806657Snate@binkert.org
2816657Snate@binkert.org          case PQCR:
2829466Snilay@cs.wisc.edu            reg = regs.pqcr;
2836657Snate@binkert.org            break;
2849466Snilay@cs.wisc.edu
2859508Snilay@cs.wisc.edu          case WCSR:
2869466Snilay@cs.wisc.edu            reg = regs.wcsr;
2876657Snate@binkert.org            break;
2886657Snate@binkert.org
2896657Snate@binkert.org          case PCR:
2906657Snate@binkert.org            reg = regs.pcr;
2919466Snilay@cs.wisc.edu            break;
2929466Snilay@cs.wisc.edu
2939466Snilay@cs.wisc.edu            // see the spec sheet for how RFCR and RFDR work
2949466Snilay@cs.wisc.edu            // basically, you write to RFCR to tell the machine
2956657Snate@binkert.org            // what you want to do next, then you act upon RFDR,
2966657Snate@binkert.org            // and the device will be prepared b/c of what you
2976657Snate@binkert.org            // wrote to RFCR
2986657Snate@binkert.org          case RFCR:
2996657Snate@binkert.org            reg = regs.rfcr;
3006657Snate@binkert.org            break;
3016657Snate@binkert.org
3026657Snate@binkert.org          case RFDR:
3036657Snate@binkert.org            rfaddr = (uint16_t)(regs.rfcr & RFCR_RFADDR);
3046657Snate@binkert.org            switch (rfaddr) {
3056657Snate@binkert.org              // Read from perfect match ROM octets
3069466Snilay@cs.wisc.edu              case 0x000:
3077453Snate@binkert.org                reg = rom.perfectMatch[1];
3087453Snate@binkert.org                reg = reg << 8;
3097007Snate@binkert.org                reg += rom.perfectMatch[0];
3107007Snate@binkert.org                break;
3117453Snate@binkert.org              case 0x002:
3127007Snate@binkert.org                reg = rom.perfectMatch[3] << 8;
3136657Snate@binkert.org                reg += rom.perfectMatch[2];
3146657Snate@binkert.org                break;
3156657Snate@binkert.org              case 0x004:
3166657Snate@binkert.org                reg = rom.perfectMatch[5] << 8;
3176657Snate@binkert.org                reg += rom.perfectMatch[4];
3186657Snate@binkert.org                break;
3196657Snate@binkert.org              default:
3206657Snate@binkert.org                // Read filter hash table
3216657Snate@binkert.org                if (rfaddr >= FHASH_ADDR &&
3226657Snate@binkert.org                    rfaddr < FHASH_ADDR + FHASH_SIZE) {
3237007Snate@binkert.org
3247007Snate@binkert.org                    // Only word-aligned reads supported
3257007Snate@binkert.org                    if (rfaddr % 2)
3267007Snate@binkert.org                        panic("unaligned read from filter hash table!");
3277007Snate@binkert.org
3286657Snate@binkert.org                    reg = rom.filterHash[rfaddr - FHASH_ADDR + 1] << 8;
3296657Snate@binkert.org                    reg += rom.filterHash[rfaddr - FHASH_ADDR];
3306657Snate@binkert.org                    break;
3316657Snate@binkert.org                }
3326657Snate@binkert.org
3336657Snate@binkert.org                panic("reading RFDR for something other than pattern"
3346657Snate@binkert.org                      " matching or hashing! %#x\n", rfaddr);
3356657Snate@binkert.org            }
3366657Snate@binkert.org            break;
3377007Snate@binkert.org
3387007Snate@binkert.org          case SRR:
3397007Snate@binkert.org            reg = regs.srr;
3407007Snate@binkert.org            break;
3417007Snate@binkert.org
3426657Snate@binkert.org          case MIBC:
3436657Snate@binkert.org            reg = regs.mibc;
3446657Snate@binkert.org            reg &= ~(MIBC_MIBS | MIBC_ACLR);
3456657Snate@binkert.org            break;
3466657Snate@binkert.org
3476657Snate@binkert.org          case VRCR:
3486657Snate@binkert.org            reg = regs.vrcr;
3497007Snate@binkert.org            break;
3507007Snate@binkert.org
3517007Snate@binkert.org          case VTCR:
3527007Snate@binkert.org            reg = regs.vtcr;
3537007Snate@binkert.org            break;
3546657Snate@binkert.org
3556657Snate@binkert.org          case VDR:
3567002Snate@binkert.org            reg = regs.vdr;
3576657Snate@binkert.org            break;
3586657Snate@binkert.org
3596657Snate@binkert.org          case CCSR:
3606657Snate@binkert.org            reg = regs.ccsr;
3616657Snate@binkert.org            break;
3626657Snate@binkert.org
3636657Snate@binkert.org          case TBICR:
3646657Snate@binkert.org            reg = regs.tbicr;
3656657Snate@binkert.org            break;
3666657Snate@binkert.org
3676657Snate@binkert.org          case TBISR:
3686657Snate@binkert.org            reg = regs.tbisr;
3696657Snate@binkert.org            break;
3706657Snate@binkert.org
3716657Snate@binkert.org          case TANAR:
3726657Snate@binkert.org            reg = regs.tanar;
3736657Snate@binkert.org            break;
3746657Snate@binkert.org
3756657Snate@binkert.org          case TANLPAR:
3766657Snate@binkert.org            reg = regs.tanlpar;
3776657Snate@binkert.org            break;
3787007Snate@binkert.org
3796657Snate@binkert.org          case TANER:
3807007Snate@binkert.org            reg = regs.taner;
3816657Snate@binkert.org            break;
3829298Snilay@cs.wisc.edu
3839298Snilay@cs.wisc.edu          case TESR:
3849298Snilay@cs.wisc.edu            reg = regs.tesr;
3859298Snilay@cs.wisc.edu            break;
3869298Snilay@cs.wisc.edu
3879298Snilay@cs.wisc.edu          case M5REG:
3886657Snate@binkert.org            reg = 0;
3896657Snate@binkert.org            if (params()->rx_thread)
3906657Snate@binkert.org                reg |= M5REG_RX_THREAD;
3916657Snate@binkert.org            if (params()->tx_thread)
3927055Snate@binkert.org                reg |= M5REG_TX_THREAD;
3937007Snate@binkert.org            if (params()->rss)
3946657Snate@binkert.org                reg |= M5REG_RSS;
3956657Snate@binkert.org            break;
3967002Snate@binkert.org
3976657Snate@binkert.org          default:
3986657Snate@binkert.org            panic("reading unimplemented register: addr=%#x", daddr);
3996657Snate@binkert.org        }
4007007Snate@binkert.org
4016657Snate@binkert.org        DPRINTF(EthernetPIO, "read from %#x: data=%d data=%#x\n",
4026657Snate@binkert.org                daddr, reg, reg);
4036657Snate@binkert.org
4046657Snate@binkert.org    pkt->makeAtomicResponse();
4056657Snate@binkert.org    return pioDelay;
4066999Snate@binkert.org}
4076657Snate@binkert.org
4086657Snate@binkert.orgTick
4096657Snate@binkert.orgNSGigE::write(PacketPtr pkt)
4106657Snate@binkert.org{
4116657Snate@binkert.org    assert(ioEnable);
4126657Snate@binkert.org
4136657Snate@binkert.org    Addr daddr = pkt->getAddr() & 0xfff;
4147002Snate@binkert.org    DPRINTF(EthernetPIO, "write da=%#x pa=%#x size=%d\n",
4157002Snate@binkert.org            daddr, pkt->getAddr(), pkt->getSize());
4166657Snate@binkert.org
4179499Snilay@cs.wisc.edu    if (daddr > LAST && daddr <=  RESERVED) {
4189499Snilay@cs.wisc.edu        panic("Accessing reserved register");
4197002Snate@binkert.org    } else if (daddr > RESERVED && daddr <= 0x3FC) {
4207002Snate@binkert.org        return writeConfig(pkt);
4216657Snate@binkert.org    } else if (daddr > 0x3FC)
4226657Snate@binkert.org        panic("Something is messed up!\n");
4236657Snate@binkert.org
4246657Snate@binkert.org    if (pkt->getSize() == sizeof(uint32_t)) {
4257007Snate@binkert.org        uint32_t reg = pkt->get<uint32_t>();
4267007Snate@binkert.org        uint16_t rfaddr;
4276657Snate@binkert.org
4286657Snate@binkert.org        DPRINTF(EthernetPIO, "write data=%d data=%#x\n", reg, reg);
4296657Snate@binkert.org
4306657Snate@binkert.org        switch (daddr) {
4316657Snate@binkert.org          case CR:
4326657Snate@binkert.org            regs.command = reg;
4336657Snate@binkert.org            if (reg & CR_TXD) {
4346657Snate@binkert.org                txEnable = false;
4356657Snate@binkert.org            } else if (reg & CR_TXE) {
4366657Snate@binkert.org                txEnable = true;
4379206Snilay@cs.wisc.edu
4386657Snate@binkert.org                // the kernel is enabling the transmit machine
4396657Snate@binkert.org                if (txState == txIdle)
4406657Snate@binkert.org                    txKick();
4416657Snate@binkert.org            }
4426657Snate@binkert.org
4436657Snate@binkert.org            if (reg & CR_RXD) {
4446657Snate@binkert.org                rxEnable = false;
4459298Snilay@cs.wisc.edu            } else if (reg & CR_RXE) {
4469298Snilay@cs.wisc.edu                rxEnable = true;
4479298Snilay@cs.wisc.edu
4489298Snilay@cs.wisc.edu                if (rxState == rxIdle)
4496657Snate@binkert.org                    rxKick();
4506657Snate@binkert.org            }
4516657Snate@binkert.org
4526999Snate@binkert.org            if (reg & CR_TXR)
4536657Snate@binkert.org                txReset();
4546657Snate@binkert.org
4556657Snate@binkert.org            if (reg & CR_RXR)
4566657Snate@binkert.org                rxReset();
4576657Snate@binkert.org
4587007Snate@binkert.org            if (reg & CR_SWI)
4597007Snate@binkert.org                devIntrPost(ISR_SWI);
4607007Snate@binkert.org
4616657Snate@binkert.org            if (reg & CR_RST) {
4627002Snate@binkert.org                txReset();
4637002Snate@binkert.org                rxReset();
4647002Snate@binkert.org
4658086SBrad.Beckmann@amd.com                regsReset();
4668086SBrad.Beckmann@amd.com            }
4678086SBrad.Beckmann@amd.com            break;
4688086SBrad.Beckmann@amd.com
4698602Snilay@cs.wisc.edu          case CFGR:
4708602Snilay@cs.wisc.edu            if (reg & CFGR_LNKSTS ||
4718602Snilay@cs.wisc.edu                reg & CFGR_SPDSTS ||
4728602Snilay@cs.wisc.edu                reg & CFGR_DUPSTS ||
4738602Snilay@cs.wisc.edu                reg & CFGR_RESERVED ||
4748086SBrad.Beckmann@amd.com                reg & CFGR_T64ADDR ||
4756657Snate@binkert.org                reg & CFGR_PCI64_DET) {
4767007Snate@binkert.org                // First clear all writable bits
4776657Snate@binkert.org                regs.config &= CFGR_LNKSTS | CFGR_SPDSTS | CFGR_DUPSTS |
4786657Snate@binkert.org                    CFGR_RESERVED | CFGR_T64ADDR |
4796657Snate@binkert.org                    CFGR_PCI64_DET;
4806657Snate@binkert.org                // Now set the appropriate writable bits
4816657Snate@binkert.org                regs.config |= reg & ~(CFGR_LNKSTS | CFGR_SPDSTS | CFGR_DUPSTS |
4826657Snate@binkert.org                                       CFGR_RESERVED | CFGR_T64ADDR |
4836657Snate@binkert.org                                       CFGR_PCI64_DET);
4846657Snate@binkert.org            }
4856657Snate@binkert.org
4866657Snate@binkert.org// all these #if 0's are because i don't THINK the kernel needs to
4876657Snate@binkert.org// have these implemented. if there is a problem relating to one of
4886862Sdrh5@cs.wisc.edu// these, you may need to add functionality in.
4896862Sdrh5@cs.wisc.edu
4906862Sdrh5@cs.wisc.edu// grouped together and #if 0'ed to avoid empty if body and make clang happy
4916862Sdrh5@cs.wisc.edu#if 0
4926657Snate@binkert.org            if (reg & CFGR_TBI_EN) ;
4936657Snate@binkert.org            if (reg & CFGR_MODE_1000) ;
4946657Snate@binkert.org
4956657Snate@binkert.org            if (reg & CFGR_PINT_DUPSTS ||
4966657Snate@binkert.org                reg & CFGR_PINT_LNKSTS ||
4977007Snate@binkert.org                reg & CFGR_PINT_SPDSTS)
4987007Snate@binkert.org                ;
4997002Snate@binkert.org
5007007Snate@binkert.org            if (reg & CFGR_TMRTEST) ;
5017007Snate@binkert.org            if (reg & CFGR_MRM_DIS) ;
5027002Snate@binkert.org            if (reg & CFGR_MWI_DIS) ;
5037007Snate@binkert.org
5047007Snate@binkert.org            if (reg & CFGR_DATA64_EN) ;
5056657Snate@binkert.org            if (reg & CFGR_M64ADDR) ;
5066657Snate@binkert.org            if (reg & CFGR_PHY_RST) ;
5076657Snate@binkert.org            if (reg & CFGR_PHY_DIS) ;
5086657Snate@binkert.org
5096657Snate@binkert.org            if (reg & CFGR_REQALG) ;
5106657Snate@binkert.org            if (reg & CFGR_SB) ;
5116657Snate@binkert.org            if (reg & CFGR_POW) ;
5126657Snate@binkert.org            if (reg & CFGR_EXD) ;
5136657Snate@binkert.org            if (reg & CFGR_PESEL) ;
5146657Snate@binkert.org            if (reg & CFGR_BROM_DIS) ;
5156657Snate@binkert.org            if (reg & CFGR_EXT_125) ;
5166657Snate@binkert.org            if (reg & CFGR_BEM) ;
5176657Snate@binkert.org
5188602Snilay@cs.wisc.edu            if (reg & CFGR_T64ADDR) ;
5198602Snilay@cs.wisc.edu            // panic("CFGR_T64ADDR is read only register!\n");
5208602Snilay@cs.wisc.edu#endif
5218602Snilay@cs.wisc.edu            if (reg & CFGR_AUTO_1000)
5228602Snilay@cs.wisc.edu                panic("CFGR_AUTO_1000 not implemented!\n");
5238602Snilay@cs.wisc.edu
5248602Snilay@cs.wisc.edu            if (reg & CFGR_PCI64_DET)
5258602Snilay@cs.wisc.edu                panic("CFGR_PCI64_DET is read only register!\n");
5268602Snilay@cs.wisc.edu
5278086SBrad.Beckmann@amd.com            if (reg & CFGR_EXTSTS_EN)
5288086SBrad.Beckmann@amd.com                extstsEnable = true;
5298086SBrad.Beckmann@amd.com            else
5308086SBrad.Beckmann@amd.com                extstsEnable = false;
5318086SBrad.Beckmann@amd.com            break;
5328086SBrad.Beckmann@amd.com
5338086SBrad.Beckmann@amd.com          case MEAR:
5348086SBrad.Beckmann@amd.com            // Clear writable bits
5356657Snate@binkert.org            regs.mear &= MEAR_EEDO;
5366657Snate@binkert.org            // Set appropriate writable bits
5377002Snate@binkert.org            regs.mear |= reg & ~MEAR_EEDO;
5386657Snate@binkert.org
5397007Snate@binkert.org            // FreeBSD uses the EEPROM to read PMATCH (for the MAC address)
5406657Snate@binkert.org            // even though it could get it through RFDR
5416657Snate@binkert.org            if (reg & MEAR_EESEL) {
5426657Snate@binkert.org                // Rising edge of clock
5436657Snate@binkert.org                if (reg & MEAR_EECLK && !eepromClk)
5446657Snate@binkert.org                    eepromKick();
5456999Snate@binkert.org            }
5466657Snate@binkert.org            else {
5476657Snate@binkert.org                eepromState = eepromStart;
5486657Snate@binkert.org                regs.mear &= ~MEAR_EEDI;
5496657Snate@binkert.org            }
5506657Snate@binkert.org
5516657Snate@binkert.org            eepromClk = reg & MEAR_EECLK;
5527832Snate@binkert.org
5537002Snate@binkert.org            // since phy is completely faked, MEAR_MD* don't matter
5547002Snate@binkert.org
5557002Snate@binkert.org// grouped together and #if 0'ed to avoid empty if body and make clang happy
5567805Snilay@cs.wisc.edu#if 0
5576657Snate@binkert.org            if (reg & MEAR_MDIO) ;
5586657Snate@binkert.org            if (reg & MEAR_MDDIR) ;
5597002Snate@binkert.org            if (reg & MEAR_MDC) ;
5607002Snate@binkert.org#endif
5616657Snate@binkert.org            break;
5626657Snate@binkert.org
5638086SBrad.Beckmann@amd.com          case PTSCR:
5648086SBrad.Beckmann@amd.com            regs.ptscr = reg & ~(PTSCR_RBIST_RDONLY);
5658086SBrad.Beckmann@amd.com            // these control BISTs for various parts of chip - we
5668086SBrad.Beckmann@amd.com            // don't care or do just fake that the BIST is done
5678086SBrad.Beckmann@amd.com            if (reg & PTSCR_RBIST_EN)
5688086SBrad.Beckmann@amd.com                regs.ptscr |= PTSCR_RBIST_DONE;
5698086SBrad.Beckmann@amd.com            if (reg & PTSCR_EEBIST_EN)
5708086SBrad.Beckmann@amd.com                regs.ptscr &= ~PTSCR_EEBIST_EN;
5718086SBrad.Beckmann@amd.com            if (reg & PTSCR_EELOAD_EN)
5728086SBrad.Beckmann@amd.com                regs.ptscr &= ~PTSCR_EELOAD_EN;
5738086SBrad.Beckmann@amd.com            break;
5748086SBrad.Beckmann@amd.com
5758086SBrad.Beckmann@amd.com          case ISR: /* writing to the ISR has no effect */
5768086SBrad.Beckmann@amd.com            panic("ISR is a read only register!\n");
5778086SBrad.Beckmann@amd.com
5788086SBrad.Beckmann@amd.com          case IMR:
5798086SBrad.Beckmann@amd.com            regs.imr = reg;
5808086SBrad.Beckmann@amd.com            devIntrChangeMask();
5818086SBrad.Beckmann@amd.com            break;
5828086SBrad.Beckmann@amd.com
5838086SBrad.Beckmann@amd.com          case IER:
5846657Snate@binkert.org            regs.ier = reg;
5856657Snate@binkert.org            break;
5869773Snilay@cs.wisc.edu
5879773Snilay@cs.wisc.edu          case IHR:
5888602Snilay@cs.wisc.edu            regs.ihr = reg;
5896657Snate@binkert.org            /* not going to implement real interrupt holdoff */
5906657Snate@binkert.org            break;
5917007Snate@binkert.org
5927007Snate@binkert.org          case TXDP:
5937007Snate@binkert.org            regs.txdp = (reg & 0xFFFFFFFC);
5946657Snate@binkert.org            assert(txState == txIdle);
5956657Snate@binkert.org            CTDD = false;
5966657Snate@binkert.org            break;
5976657Snate@binkert.org
5986657Snate@binkert.org          case TXDP_HI:
5996657Snate@binkert.org            regs.txdp_hi = reg;
6007007Snate@binkert.org            break;
6017007Snate@binkert.org
6027007Snate@binkert.org          case TX_CFG:
6036657Snate@binkert.org            regs.txcfg = reg;
6046657Snate@binkert.org#if 0
6056657Snate@binkert.org            if (reg & TX_CFG_CSI) ;
6066657Snate@binkert.org            if (reg & TX_CFG_HBI) ;
6076657Snate@binkert.org            if (reg & TX_CFG_MLB) ;
6086657Snate@binkert.org            if (reg & TX_CFG_ATP) ;
6096657Snate@binkert.org            if (reg & TX_CFG_ECRETRY) {
6106657Snate@binkert.org                /*
6116657Snate@binkert.org                 * this could easily be implemented, but considering
6126657Snate@binkert.org                 * the network is just a fake pipe, wouldn't make
6136657Snate@binkert.org                 * sense to do this
6146657Snate@binkert.org                 */
6156657Snate@binkert.org            }
6166657Snate@binkert.org
6177805Snilay@cs.wisc.edu            if (reg & TX_CFG_BRST_DIS) ;
6186657Snate@binkert.org#endif
6196657Snate@binkert.org
6206657Snate@binkert.org#if 0
6217007Snate@binkert.org            /* we handle our own DMA, ignore the kernel's exhortations */
6227007Snate@binkert.org            if (reg & TX_CFG_MXDMA) ;
6237007Snate@binkert.org#endif
6246657Snate@binkert.org
6256657Snate@binkert.org            // also, we currently don't care about fill/drain
6266657Snate@binkert.org            // thresholds though this may change in the future with
6276657Snate@binkert.org            // more realistic networks or a driver which changes it
6287007Snate@binkert.org            // according to feedback
6296657Snate@binkert.org
6306657Snate@binkert.org            break;
6316657Snate@binkert.org
6326657Snate@binkert.org          case GPIOR:
6337007Snate@binkert.org            // Only write writable bits
6346657Snate@binkert.org            regs.gpior &= GPIOR_UNUSED | GPIOR_GP5_IN | GPIOR_GP4_IN
6356657Snate@binkert.org                        | GPIOR_GP3_IN | GPIOR_GP2_IN | GPIOR_GP1_IN;
6366657Snate@binkert.org            regs.gpior |= reg & ~(GPIOR_UNUSED | GPIOR_GP5_IN | GPIOR_GP4_IN
6376657Snate@binkert.org                                | GPIOR_GP3_IN | GPIOR_GP2_IN | GPIOR_GP1_IN);
6387805Snilay@cs.wisc.edu            /* these just control general purpose i/o pins, don't matter */
6396657Snate@binkert.org            break;
6406657Snate@binkert.org
6416657Snate@binkert.org          case RXDP:
6427007Snate@binkert.org            regs.rxdp = reg;
6437007Snate@binkert.org            CRDD = false;
6447007Snate@binkert.org            break;
6457007Snate@binkert.org
6466657Snate@binkert.org          case RXDP_HI:
6476657Snate@binkert.org            regs.rxdp_hi = reg;
6486657Snate@binkert.org            break;
6496657Snate@binkert.org
6506657Snate@binkert.org          case RX_CFG:
6516657Snate@binkert.org            regs.rxcfg = reg;
6526657Snate@binkert.org#if 0
6536657Snate@binkert.org            if (reg & RX_CFG_AEP) ;
6546657Snate@binkert.org            if (reg & RX_CFG_ARP) ;
6557007Snate@binkert.org            if (reg & RX_CFG_STRIPCRC) ;
6567007Snate@binkert.org            if (reg & RX_CFG_RX_RD) ;
6576657Snate@binkert.org            if (reg & RX_CFG_ALP) ;
6586657Snate@binkert.org            if (reg & RX_CFG_AIRL) ;
6596657Snate@binkert.org
6606657Snate@binkert.org            /* we handle our own DMA, ignore what kernel says about it */
6617007Snate@binkert.org            if (reg & RX_CFG_MXDMA) ;
6627007Snate@binkert.org
6636657Snate@binkert.org            //also, we currently don't care about fill/drain thresholds
6646657Snate@binkert.org            //though this may change in the future with more realistic
6656657Snate@binkert.org            //networks or a driver which changes it according to feedback
6666657Snate@binkert.org            if (reg & (RX_CFG_DRTH | RX_CFG_DRTH0)) ;
6676657Snate@binkert.org#endif
6686657Snate@binkert.org            break;
6696657Snate@binkert.org
6706657Snate@binkert.org          case PQCR:
6716657Snate@binkert.org            /* there is no priority queueing used in the linux 2.6 driver */
6726657Snate@binkert.org            regs.pqcr = reg;
6736657Snate@binkert.org            break;
6746657Snate@binkert.org
6756657Snate@binkert.org          case WCSR:
6766657Snate@binkert.org            /* not going to implement wake on LAN */
6776657Snate@binkert.org            regs.wcsr = reg;
6786657Snate@binkert.org            break;
6796657Snate@binkert.org
6807805Snilay@cs.wisc.edu          case PCR:
6816657Snate@binkert.org            /* not going to implement pause control */
6826657Snate@binkert.org            regs.pcr = reg;
6836657Snate@binkert.org            break;
6846657Snate@binkert.org
6856657Snate@binkert.org          case RFCR:
6867007Snate@binkert.org            regs.rfcr = reg;
6876657Snate@binkert.org
6887007Snate@binkert.org            rxFilterEnable = (reg & RFCR_RFEN) ? true : false;
6897007Snate@binkert.org            acceptBroadcast = (reg & RFCR_AAB) ? true : false;
6906657Snate@binkert.org            acceptMulticast = (reg & RFCR_AAM) ? true : false;
6916657Snate@binkert.org            acceptUnicast = (reg & RFCR_AAU) ? true : false;
6926657Snate@binkert.org            acceptPerfect = (reg & RFCR_APM) ? true : false;
6936657Snate@binkert.org            acceptArp = (reg & RFCR_AARP) ? true : false;
6946657Snate@binkert.org            multicastHashEnable = (reg & RFCR_MHEN) ? true : false;
6956657Snate@binkert.org
6966657Snate@binkert.org#if 0
6976657Snate@binkert.org            if (reg & RFCR_APAT)
6986657Snate@binkert.org                panic("RFCR_APAT not implemented!\n");
6996657Snate@binkert.org#endif
7006657Snate@binkert.org            if (reg & RFCR_UHEN)
7016657Snate@binkert.org                panic("Unicast hash filtering not used by drivers!\n");
7026657Snate@binkert.org
7036657Snate@binkert.org            if (reg & RFCR_ULM)
7047805Snilay@cs.wisc.edu                panic("RFCR_ULM not implemented!\n");
7056657Snate@binkert.org
7066657Snate@binkert.org            break;
7076657Snate@binkert.org
7086657Snate@binkert.org          case RFDR:
7096657Snate@binkert.org            rfaddr = (uint16_t)(regs.rfcr & RFCR_RFADDR);
7106657Snate@binkert.org            switch (rfaddr) {
7116657Snate@binkert.org              case 0x000:
7126657Snate@binkert.org                rom.perfectMatch[0] = (uint8_t)reg;
7137007Snate@binkert.org                rom.perfectMatch[1] = (uint8_t)(reg >> 8);
7147007Snate@binkert.org                break;
7156657Snate@binkert.org              case 0x002:
7166657Snate@binkert.org                rom.perfectMatch[2] = (uint8_t)reg;
7176657Snate@binkert.org                rom.perfectMatch[3] = (uint8_t)(reg >> 8);
7186657Snate@binkert.org                break;
7196657Snate@binkert.org              case 0x004:
7206657Snate@binkert.org                rom.perfectMatch[4] = (uint8_t)reg;
7216657Snate@binkert.org                rom.perfectMatch[5] = (uint8_t)(reg >> 8);
7226657Snate@binkert.org                break;
7236657Snate@binkert.org              default:
7249773Snilay@cs.wisc.edu
7259773Snilay@cs.wisc.edu                if (rfaddr >= FHASH_ADDR &&
7269773Snilay@cs.wisc.edu                    rfaddr < FHASH_ADDR + FHASH_SIZE) {
7279773Snilay@cs.wisc.edu
7289773Snilay@cs.wisc.edu                    // Only word-aligned writes supported
7296657Snate@binkert.org                    if (rfaddr % 2)
7306657Snate@binkert.org                        panic("unaligned write to filter hash table!");
7316657Snate@binkert.org
7326657Snate@binkert.org                    rom.filterHash[rfaddr - FHASH_ADDR] = (uint8_t)reg;
7336657Snate@binkert.org                    rom.filterHash[rfaddr - FHASH_ADDR + 1]
7346657Snate@binkert.org                        = (uint8_t)(reg >> 8);
7357805Snilay@cs.wisc.edu                    break;
7366657Snate@binkert.org                }
7376657Snate@binkert.org                panic("writing RFDR for something other than pattern matching\
7386657Snate@binkert.org                    or hashing! %#x\n", rfaddr);
7396657Snate@binkert.org            }
7406657Snate@binkert.org
7416657Snate@binkert.org          case BRAR:
7426657Snate@binkert.org            regs.brar = reg;
7436657Snate@binkert.org            break;
7447007Snate@binkert.org
7457007Snate@binkert.org          case BRDR:
7466657Snate@binkert.org            panic("the driver never uses BRDR, something is wrong!\n");
7476657Snate@binkert.org
7486657Snate@binkert.org          case SRR:
7496657Snate@binkert.org            panic("SRR is read only register!\n");
7506657Snate@binkert.org
7516657Snate@binkert.org          case MIBC:
7529773Snilay@cs.wisc.edu            panic("the driver never uses MIBC, something is wrong!\n");
7539773Snilay@cs.wisc.edu
7549773Snilay@cs.wisc.edu          case VRCR:
7559773Snilay@cs.wisc.edu            regs.vrcr = reg;
7569773Snilay@cs.wisc.edu            break;
7576657Snate@binkert.org
7586657Snate@binkert.org          case VTCR:
7596657Snate@binkert.org            regs.vtcr = reg;
7606657Snate@binkert.org            break;
7616657Snate@binkert.org
7627805Snilay@cs.wisc.edu          case VDR:
7636657Snate@binkert.org            panic("the driver never uses VDR, something is wrong!\n");
7646657Snate@binkert.org
7656657Snate@binkert.org          case CCSR:
7666657Snate@binkert.org            /* not going to implement clockrun stuff */
7678602Snilay@cs.wisc.edu            regs.ccsr = reg;
7688602Snilay@cs.wisc.edu            break;
7698602Snilay@cs.wisc.edu
7708602Snilay@cs.wisc.edu          case TBICR:
7718602Snilay@cs.wisc.edu            regs.tbicr = reg;
7728602Snilay@cs.wisc.edu            if (reg & TBICR_MR_LOOPBACK)
7738602Snilay@cs.wisc.edu                panic("TBICR_MR_LOOPBACK never used, something wrong!\n");
7748602Snilay@cs.wisc.edu
7758602Snilay@cs.wisc.edu            if (reg & TBICR_MR_AN_ENABLE) {
7768602Snilay@cs.wisc.edu                regs.tanlpar = regs.tanar;
7778602Snilay@cs.wisc.edu                regs.tbisr |= (TBISR_MR_AN_COMPLETE | TBISR_MR_LINK_STATUS);
7788602Snilay@cs.wisc.edu            }
7798602Snilay@cs.wisc.edu
7808602Snilay@cs.wisc.edu#if 0
7818602Snilay@cs.wisc.edu            if (reg & TBICR_MR_RESTART_AN) ;
7828602Snilay@cs.wisc.edu#endif
7838602Snilay@cs.wisc.edu
7848602Snilay@cs.wisc.edu            break;
7858602Snilay@cs.wisc.edu
7868602Snilay@cs.wisc.edu          case TBISR:
7878602Snilay@cs.wisc.edu            panic("TBISR is read only register!\n");
7886657Snate@binkert.org
7896657Snate@binkert.org          case TANAR:
7906657Snate@binkert.org            // Only write the writable bits
7916657Snate@binkert.org            regs.tanar &= TANAR_RF1 | TANAR_RF2 | TANAR_UNUSED;
792            regs.tanar |= reg & ~(TANAR_RF1 | TANAR_RF2 | TANAR_UNUSED);
793
794            // Pause capability unimplemented
795#if 0
796            if (reg & TANAR_PS2) ;
797            if (reg & TANAR_PS1) ;
798#endif
799
800            break;
801
802          case TANLPAR:
803            panic("this should only be written to by the fake phy!\n");
804
805          case TANER:
806            panic("TANER is read only register!\n");
807
808          case TESR:
809            regs.tesr = reg;
810            break;
811
812          default:
813            panic("invalid register access daddr=%#x", daddr);
814        }
815    } else {
816        panic("Invalid Request Size");
817    }
818    pkt->makeAtomicResponse();
819    return pioDelay;
820}
821
822void
823NSGigE::devIntrPost(uint32_t interrupts)
824{
825    if (interrupts & ISR_RESERVE)
826        panic("Cannot set a reserved interrupt");
827
828    if (interrupts & ISR_NOIMPL)
829        warn("interrupt not implemented %#x\n", interrupts);
830
831    interrupts &= ISR_IMPL;
832    regs.isr |= interrupts;
833
834    if (interrupts & regs.imr) {
835        if (interrupts & ISR_SWI) {
836            totalSwi++;
837        }
838        if (interrupts & ISR_RXIDLE) {
839            totalRxIdle++;
840        }
841        if (interrupts & ISR_RXOK) {
842            totalRxOk++;
843        }
844        if (interrupts & ISR_RXDESC) {
845            totalRxDesc++;
846        }
847        if (interrupts & ISR_TXOK) {
848            totalTxOk++;
849        }
850        if (interrupts & ISR_TXIDLE) {
851            totalTxIdle++;
852        }
853        if (interrupts & ISR_TXDESC) {
854            totalTxDesc++;
855        }
856        if (interrupts & ISR_RXORN) {
857            totalRxOrn++;
858        }
859    }
860
861    DPRINTF(EthernetIntr,
862            "interrupt written to ISR: intr=%#x isr=%#x imr=%#x\n",
863            interrupts, regs.isr, regs.imr);
864
865    if ((regs.isr & regs.imr)) {
866        Tick when = curTick();
867        if ((regs.isr & regs.imr & ISR_NODELAY) == 0)
868            when += intrDelay;
869        postedInterrupts++;
870        cpuIntrPost(when);
871    }
872}
873
874/* writing this interrupt counting stats inside this means that this function
875   is now limited to being used to clear all interrupts upon the kernel
876   reading isr and servicing.  just telling you in case you were thinking
877   of expanding use.
878*/
879void
880NSGigE::devIntrClear(uint32_t interrupts)
881{
882    if (interrupts & ISR_RESERVE)
883        panic("Cannot clear a reserved interrupt");
884
885    if (regs.isr & regs.imr & ISR_SWI) {
886        postedSwi++;
887    }
888    if (regs.isr & regs.imr & ISR_RXIDLE) {
889        postedRxIdle++;
890    }
891    if (regs.isr & regs.imr & ISR_RXOK) {
892        postedRxOk++;
893    }
894    if (regs.isr & regs.imr & ISR_RXDESC) {
895            postedRxDesc++;
896    }
897    if (regs.isr & regs.imr & ISR_TXOK) {
898        postedTxOk++;
899    }
900    if (regs.isr & regs.imr & ISR_TXIDLE) {
901        postedTxIdle++;
902    }
903    if (regs.isr & regs.imr & ISR_TXDESC) {
904        postedTxDesc++;
905    }
906    if (regs.isr & regs.imr & ISR_RXORN) {
907        postedRxOrn++;
908    }
909
910    interrupts &= ~ISR_NOIMPL;
911    regs.isr &= ~interrupts;
912
913    DPRINTF(EthernetIntr,
914            "interrupt cleared from ISR: intr=%x isr=%x imr=%x\n",
915            interrupts, regs.isr, regs.imr);
916
917    if (!(regs.isr & regs.imr))
918        cpuIntrClear();
919}
920
921void
922NSGigE::devIntrChangeMask()
923{
924    DPRINTF(EthernetIntr, "interrupt mask changed: isr=%x imr=%x masked=%x\n",
925            regs.isr, regs.imr, regs.isr & regs.imr);
926
927    if (regs.isr & regs.imr)
928        cpuIntrPost(curTick());
929    else
930        cpuIntrClear();
931}
932
933void
934NSGigE::cpuIntrPost(Tick when)
935{
936    // If the interrupt you want to post is later than an interrupt
937    // already scheduled, just let it post in the coming one and don't
938    // schedule another.
939    // HOWEVER, must be sure that the scheduled intrTick is in the
940    // future (this was formerly the source of a bug)
941    /**
942     * @todo this warning should be removed and the intrTick code should
943     * be fixed.
944     */
945    assert(when >= curTick());
946    assert(intrTick >= curTick() || intrTick == 0);
947    if (when > intrTick && intrTick != 0) {
948        DPRINTF(EthernetIntr, "don't need to schedule event...intrTick=%d\n",
949                intrTick);
950        return;
951    }
952
953    intrTick = when;
954    if (intrTick < curTick()) {
955        Debug::breakpoint();
956        intrTick = curTick();
957    }
958
959    DPRINTF(EthernetIntr, "going to schedule an interrupt for intrTick=%d\n",
960            intrTick);
961
962    if (intrEvent)
963        intrEvent->squash();
964    intrEvent = new IntrEvent(this, true);
965    schedule(intrEvent, intrTick);
966}
967
968void
969NSGigE::cpuInterrupt()
970{
971    assert(intrTick == curTick());
972
973    // Whether or not there's a pending interrupt, we don't care about
974    // it anymore
975    intrEvent = 0;
976    intrTick = 0;
977
978    // Don't send an interrupt if there's already one
979    if (cpuPendingIntr) {
980        DPRINTF(EthernetIntr,
981                "would send an interrupt now, but there's already pending\n");
982    } else {
983        // Send interrupt
984        cpuPendingIntr = true;
985
986        DPRINTF(EthernetIntr, "posting interrupt\n");
987        intrPost();
988    }
989}
990
991void
992NSGigE::cpuIntrClear()
993{
994    if (!cpuPendingIntr)
995        return;
996
997    if (intrEvent) {
998        intrEvent->squash();
999        intrEvent = 0;
1000    }
1001
1002    intrTick = 0;
1003
1004    cpuPendingIntr = false;
1005
1006    DPRINTF(EthernetIntr, "clearing interrupt\n");
1007    intrClear();
1008}
1009
1010bool
1011NSGigE::cpuIntrPending() const
1012{ return cpuPendingIntr; }
1013
1014void
1015NSGigE::txReset()
1016{
1017
1018    DPRINTF(Ethernet, "transmit reset\n");
1019
1020    CTDD = false;
1021    txEnable = false;;
1022    txFragPtr = 0;
1023    assert(txDescCnt == 0);
1024    txFifo.clear();
1025    txState = txIdle;
1026    assert(txDmaState == dmaIdle);
1027}
1028
1029void
1030NSGigE::rxReset()
1031{
1032    DPRINTF(Ethernet, "receive reset\n");
1033
1034    CRDD = false;
1035    assert(rxPktBytes == 0);
1036    rxEnable = false;
1037    rxFragPtr = 0;
1038    assert(rxDescCnt == 0);
1039    assert(rxDmaState == dmaIdle);
1040    rxFifo.clear();
1041    rxState = rxIdle;
1042}
1043
1044void
1045NSGigE::regsReset()
1046{
1047    memset(&regs, 0, sizeof(regs));
1048    regs.config = (CFGR_LNKSTS | CFGR_TBI_EN | CFGR_MODE_1000);
1049    regs.mear = 0x12;
1050    regs.txcfg = 0x120; // set drain threshold to 1024 bytes and
1051                        // fill threshold to 32 bytes
1052    regs.rxcfg = 0x4;   // set drain threshold to 16 bytes
1053    regs.srr = 0x0103;  // set the silicon revision to rev B or 0x103
1054    regs.mibc = MIBC_FRZ;
1055    regs.vdr = 0x81;    // set the vlan tag type to 802.1q
1056    regs.tesr = 0xc000; // TBI capable of both full and half duplex
1057    regs.brar = 0xffffffff;
1058
1059    extstsEnable = false;
1060    acceptBroadcast = false;
1061    acceptMulticast = false;
1062    acceptUnicast = false;
1063    acceptPerfect = false;
1064    acceptArp = false;
1065}
1066
1067bool
1068NSGigE::doRxDmaRead()
1069{
1070    assert(rxDmaState == dmaIdle || rxDmaState == dmaReadWaiting);
1071    rxDmaState = dmaReading;
1072
1073    if (dmaPending() || getState() != Running)
1074        rxDmaState = dmaReadWaiting;
1075    else
1076        dmaRead(rxDmaAddr, rxDmaLen, &rxDmaReadEvent, (uint8_t*)rxDmaData);
1077
1078    return true;
1079}
1080
1081void
1082NSGigE::rxDmaReadDone()
1083{
1084    assert(rxDmaState == dmaReading);
1085    rxDmaState = dmaIdle;
1086
1087    DPRINTF(EthernetDMA, "rx dma read  paddr=%#x len=%d\n",
1088            rxDmaAddr, rxDmaLen);
1089    DDUMP(EthernetDMA, rxDmaData, rxDmaLen);
1090
1091    // If the transmit state machine has a pending DMA, let it go first
1092    if (txDmaState == dmaReadWaiting || txDmaState == dmaWriteWaiting)
1093        txKick();
1094
1095    rxKick();
1096}
1097
1098bool
1099NSGigE::doRxDmaWrite()
1100{
1101    assert(rxDmaState == dmaIdle || rxDmaState == dmaWriteWaiting);
1102    rxDmaState = dmaWriting;
1103
1104    if (dmaPending() || getState() != Running)
1105        rxDmaState = dmaWriteWaiting;
1106    else
1107        dmaWrite(rxDmaAddr, rxDmaLen, &rxDmaWriteEvent, (uint8_t*)rxDmaData);
1108    return true;
1109}
1110
1111void
1112NSGigE::rxDmaWriteDone()
1113{
1114    assert(rxDmaState == dmaWriting);
1115    rxDmaState = dmaIdle;
1116
1117    DPRINTF(EthernetDMA, "rx dma write paddr=%#x len=%d\n",
1118            rxDmaAddr, rxDmaLen);
1119    DDUMP(EthernetDMA, rxDmaData, rxDmaLen);
1120
1121    // If the transmit state machine has a pending DMA, let it go first
1122    if (txDmaState == dmaReadWaiting || txDmaState == dmaWriteWaiting)
1123        txKick();
1124
1125    rxKick();
1126}
1127
1128void
1129NSGigE::rxKick()
1130{
1131    bool is64bit = (bool)(regs.config & CFGR_M64ADDR);
1132
1133    DPRINTF(EthernetSM,
1134            "receive kick rxState=%s (rxBuf.size=%d) %d-bit\n",
1135            NsRxStateStrings[rxState], rxFifo.size(), is64bit ? 64 : 32);
1136
1137    Addr link, bufptr;
1138    uint32_t &cmdsts = is64bit ? rxDesc64.cmdsts : rxDesc32.cmdsts;
1139    uint32_t &extsts = is64bit ? rxDesc64.extsts : rxDesc32.extsts;
1140
1141  next:
1142    if (clock) {
1143        if (rxKickTick > curTick()) {
1144            DPRINTF(EthernetSM, "receive kick exiting, can't run till %d\n",
1145                    rxKickTick);
1146
1147            goto exit;
1148        }
1149
1150        // Go to the next state machine clock tick.
1151        rxKickTick = curTick() + ticks(1);
1152    }
1153
1154    switch(rxDmaState) {
1155      case dmaReadWaiting:
1156        if (doRxDmaRead())
1157            goto exit;
1158        break;
1159      case dmaWriteWaiting:
1160        if (doRxDmaWrite())
1161            goto exit;
1162        break;
1163      default:
1164        break;
1165    }
1166
1167    link = is64bit ? (Addr)rxDesc64.link : (Addr)rxDesc32.link;
1168    bufptr = is64bit ? (Addr)rxDesc64.bufptr : (Addr)rxDesc32.bufptr;
1169
1170    // see state machine from spec for details
1171    // the way this works is, if you finish work on one state and can
1172    // go directly to another, you do that through jumping to the
1173    // label "next".  however, if you have intermediate work, like DMA
1174    // so that you can't go to the next state yet, you go to exit and
1175    // exit the loop.  however, when the DMA is done it will trigger
1176    // an event and come back to this loop.
1177    switch (rxState) {
1178      case rxIdle:
1179        if (!rxEnable) {
1180            DPRINTF(EthernetSM, "Receive Disabled! Nothing to do.\n");
1181            goto exit;
1182        }
1183
1184        if (CRDD) {
1185            rxState = rxDescRefr;
1186
1187            rxDmaAddr = regs.rxdp & 0x3fffffff;
1188            rxDmaData =
1189                is64bit ? (void *)&rxDesc64.link : (void *)&rxDesc32.link;
1190            rxDmaLen = is64bit ? sizeof(rxDesc64.link) : sizeof(rxDesc32.link);
1191            rxDmaFree = dmaDescFree;
1192
1193            descDmaReads++;
1194            descDmaRdBytes += rxDmaLen;
1195
1196            if (doRxDmaRead())
1197                goto exit;
1198        } else {
1199            rxState = rxDescRead;
1200
1201            rxDmaAddr = regs.rxdp & 0x3fffffff;
1202            rxDmaData = is64bit ? (void *)&rxDesc64 : (void *)&rxDesc32;
1203            rxDmaLen = is64bit ? sizeof(rxDesc64) : sizeof(rxDesc32);
1204            rxDmaFree = dmaDescFree;
1205
1206            descDmaReads++;
1207            descDmaRdBytes += rxDmaLen;
1208
1209            if (doRxDmaRead())
1210                goto exit;
1211        }
1212        break;
1213
1214      case rxDescRefr:
1215        if (rxDmaState != dmaIdle)
1216            goto exit;
1217
1218        rxState = rxAdvance;
1219        break;
1220
1221     case rxDescRead:
1222        if (rxDmaState != dmaIdle)
1223            goto exit;
1224
1225        DPRINTF(EthernetDesc, "rxDesc: addr=%08x read descriptor\n",
1226                regs.rxdp & 0x3fffffff);
1227        DPRINTF(EthernetDesc,
1228                "rxDesc: link=%#x bufptr=%#x cmdsts=%08x extsts=%08x\n",
1229                link, bufptr, cmdsts, extsts);
1230
1231        if (cmdsts & CMDSTS_OWN) {
1232            devIntrPost(ISR_RXIDLE);
1233            rxState = rxIdle;
1234            goto exit;
1235        } else {
1236            rxState = rxFifoBlock;
1237            rxFragPtr = bufptr;
1238            rxDescCnt = cmdsts & CMDSTS_LEN_MASK;
1239        }
1240        break;
1241
1242      case rxFifoBlock:
1243        if (!rxPacket) {
1244            /**
1245             * @todo in reality, we should be able to start processing
1246             * the packet as it arrives, and not have to wait for the
1247             * full packet ot be in the receive fifo.
1248             */
1249            if (rxFifo.empty())
1250                goto exit;
1251
1252            DPRINTF(EthernetSM, "****processing receive of new packet****\n");
1253
1254            // If we don't have a packet, grab a new one from the fifo.
1255            rxPacket = rxFifo.front();
1256            rxPktBytes = rxPacket->length;
1257            rxPacketBufPtr = rxPacket->data;
1258
1259#if TRACING_ON
1260            if (DTRACE(Ethernet)) {
1261                IpPtr ip(rxPacket);
1262                if (ip) {
1263                    DPRINTF(Ethernet, "ID is %d\n", ip->id());
1264                    TcpPtr tcp(ip);
1265                    if (tcp) {
1266                        DPRINTF(Ethernet,
1267                                "Src Port=%d, Dest Port=%d, Seq=%d, Ack=%d\n",
1268                                tcp->sport(), tcp->dport(), tcp->seq(),
1269                                tcp->ack());
1270                    }
1271                }
1272            }
1273#endif
1274
1275            // sanity check - i think the driver behaves like this
1276            assert(rxDescCnt >= rxPktBytes);
1277            rxFifo.pop();
1278        }
1279
1280
1281        // dont' need the && rxDescCnt > 0 if driver sanity check
1282        // above holds
1283        if (rxPktBytes > 0) {
1284            rxState = rxFragWrite;
1285            // don't need min<>(rxPktBytes,rxDescCnt) if above sanity
1286            // check holds
1287            rxXferLen = rxPktBytes;
1288
1289            rxDmaAddr = rxFragPtr & 0x3fffffff;
1290            rxDmaData = rxPacketBufPtr;
1291            rxDmaLen = rxXferLen;
1292            rxDmaFree = dmaDataFree;
1293
1294            if (doRxDmaWrite())
1295                goto exit;
1296
1297        } else {
1298            rxState = rxDescWrite;
1299
1300            //if (rxPktBytes == 0) {  /* packet is done */
1301            assert(rxPktBytes == 0);
1302            DPRINTF(EthernetSM, "done with receiving packet\n");
1303
1304            cmdsts |= CMDSTS_OWN;
1305            cmdsts &= ~CMDSTS_MORE;
1306            cmdsts |= CMDSTS_OK;
1307            cmdsts &= 0xffff0000;
1308            cmdsts += rxPacket->length;   //i.e. set CMDSTS_SIZE
1309
1310#if 0
1311            /*
1312             * all the driver uses these are for its own stats keeping
1313             * which we don't care about, aren't necessary for
1314             * functionality and doing this would just slow us down.
1315             * if they end up using this in a later version for
1316             * functional purposes, just undef
1317             */
1318            if (rxFilterEnable) {
1319                cmdsts &= ~CMDSTS_DEST_MASK;
1320                const EthAddr &dst = rxFifoFront()->dst();
1321                if (dst->unicast())
1322                    cmdsts |= CMDSTS_DEST_SELF;
1323                if (dst->multicast())
1324                    cmdsts |= CMDSTS_DEST_MULTI;
1325                if (dst->broadcast())
1326                    cmdsts |= CMDSTS_DEST_MASK;
1327            }
1328#endif
1329
1330            IpPtr ip(rxPacket);
1331            if (extstsEnable && ip) {
1332                extsts |= EXTSTS_IPPKT;
1333                rxIpChecksums++;
1334                if (cksum(ip) != 0) {
1335                    DPRINTF(EthernetCksum, "Rx IP Checksum Error\n");
1336                    extsts |= EXTSTS_IPERR;
1337                }
1338                TcpPtr tcp(ip);
1339                UdpPtr udp(ip);
1340                if (tcp) {
1341                    extsts |= EXTSTS_TCPPKT;
1342                    rxTcpChecksums++;
1343                    if (cksum(tcp) != 0) {
1344                        DPRINTF(EthernetCksum, "Rx TCP Checksum Error\n");
1345                        extsts |= EXTSTS_TCPERR;
1346
1347                    }
1348                } else if (udp) {
1349                    extsts |= EXTSTS_UDPPKT;
1350                    rxUdpChecksums++;
1351                    if (cksum(udp) != 0) {
1352                        DPRINTF(EthernetCksum, "Rx UDP Checksum Error\n");
1353                        extsts |= EXTSTS_UDPERR;
1354                    }
1355                }
1356            }
1357            rxPacket = 0;
1358
1359            /*
1360             * the driver seems to always receive into desc buffers
1361             * of size 1514, so you never have a pkt that is split
1362             * into multiple descriptors on the receive side, so
1363             * i don't implement that case, hence the assert above.
1364             */
1365
1366            DPRINTF(EthernetDesc,
1367                    "rxDesc: addr=%08x writeback cmdsts extsts\n",
1368                    regs.rxdp & 0x3fffffff);
1369            DPRINTF(EthernetDesc,
1370                    "rxDesc: link=%#x bufptr=%#x cmdsts=%08x extsts=%08x\n",
1371                    link, bufptr, cmdsts, extsts);
1372
1373            rxDmaAddr = regs.rxdp & 0x3fffffff;
1374            rxDmaData = &cmdsts;
1375            if (is64bit) {
1376                rxDmaAddr += offsetof(ns_desc64, cmdsts);
1377                rxDmaLen = sizeof(rxDesc64.cmdsts) + sizeof(rxDesc64.extsts);
1378            } else {
1379                rxDmaAddr += offsetof(ns_desc32, cmdsts);
1380                rxDmaLen = sizeof(rxDesc32.cmdsts) + sizeof(rxDesc32.extsts);
1381            }
1382            rxDmaFree = dmaDescFree;
1383
1384            descDmaWrites++;
1385            descDmaWrBytes += rxDmaLen;
1386
1387            if (doRxDmaWrite())
1388                goto exit;
1389        }
1390        break;
1391
1392      case rxFragWrite:
1393        if (rxDmaState != dmaIdle)
1394            goto exit;
1395
1396        rxPacketBufPtr += rxXferLen;
1397        rxFragPtr += rxXferLen;
1398        rxPktBytes -= rxXferLen;
1399
1400        rxState = rxFifoBlock;
1401        break;
1402
1403      case rxDescWrite:
1404        if (rxDmaState != dmaIdle)
1405            goto exit;
1406
1407        assert(cmdsts & CMDSTS_OWN);
1408
1409        assert(rxPacket == 0);
1410        devIntrPost(ISR_RXOK);
1411
1412        if (cmdsts & CMDSTS_INTR)
1413            devIntrPost(ISR_RXDESC);
1414
1415        if (!rxEnable) {
1416            DPRINTF(EthernetSM, "Halting the RX state machine\n");
1417            rxState = rxIdle;
1418            goto exit;
1419        } else
1420            rxState = rxAdvance;
1421        break;
1422
1423      case rxAdvance:
1424        if (link == 0) {
1425            devIntrPost(ISR_RXIDLE);
1426            rxState = rxIdle;
1427            CRDD = true;
1428            goto exit;
1429        } else {
1430            if (rxDmaState != dmaIdle)
1431                goto exit;
1432            rxState = rxDescRead;
1433            regs.rxdp = link;
1434            CRDD = false;
1435
1436            rxDmaAddr = regs.rxdp & 0x3fffffff;
1437            rxDmaData = is64bit ? (void *)&rxDesc64 : (void *)&rxDesc32;
1438            rxDmaLen = is64bit ? sizeof(rxDesc64) : sizeof(rxDesc32);
1439            rxDmaFree = dmaDescFree;
1440
1441            if (doRxDmaRead())
1442                goto exit;
1443        }
1444        break;
1445
1446      default:
1447        panic("Invalid rxState!");
1448    }
1449
1450    DPRINTF(EthernetSM, "entering next rxState=%s\n",
1451            NsRxStateStrings[rxState]);
1452    goto next;
1453
1454  exit:
1455    /**
1456     * @todo do we want to schedule a future kick?
1457     */
1458    DPRINTF(EthernetSM, "rx state machine exited rxState=%s\n",
1459            NsRxStateStrings[rxState]);
1460
1461    if (clock && !rxKickEvent.scheduled())
1462        schedule(rxKickEvent, rxKickTick);
1463}
1464
1465void
1466NSGigE::transmit()
1467{
1468    if (txFifo.empty()) {
1469        DPRINTF(Ethernet, "nothing to transmit\n");
1470        return;
1471    }
1472
1473    DPRINTF(Ethernet, "Attempt Pkt Transmit: txFifo length=%d\n",
1474            txFifo.size());
1475    if (interface->sendPacket(txFifo.front())) {
1476#if TRACING_ON
1477        if (DTRACE(Ethernet)) {
1478            IpPtr ip(txFifo.front());
1479            if (ip) {
1480                DPRINTF(Ethernet, "ID is %d\n", ip->id());
1481                TcpPtr tcp(ip);
1482                if (tcp) {
1483                    DPRINTF(Ethernet,
1484                            "Src Port=%d, Dest Port=%d, Seq=%d, Ack=%d\n",
1485                            tcp->sport(), tcp->dport(), tcp->seq(),
1486                            tcp->ack());
1487                }
1488            }
1489        }
1490#endif
1491
1492        DDUMP(EthernetData, txFifo.front()->data, txFifo.front()->length);
1493        txBytes += txFifo.front()->length;
1494        txPackets++;
1495
1496        DPRINTF(Ethernet, "Successful Xmit! now txFifoAvail is %d\n",
1497                txFifo.avail());
1498        txFifo.pop();
1499
1500        /*
1501         * normally do a writeback of the descriptor here, and ONLY
1502         * after that is done, send this interrupt.  but since our
1503         * stuff never actually fails, just do this interrupt here,
1504         * otherwise the code has to stray from this nice format.
1505         * besides, it's functionally the same.
1506         */
1507        devIntrPost(ISR_TXOK);
1508    }
1509
1510   if (!txFifo.empty() && !txEvent.scheduled()) {
1511       DPRINTF(Ethernet, "reschedule transmit\n");
1512       schedule(txEvent, curTick() + retryTime);
1513   }
1514}
1515
1516bool
1517NSGigE::doTxDmaRead()
1518{
1519    assert(txDmaState == dmaIdle || txDmaState == dmaReadWaiting);
1520    txDmaState = dmaReading;
1521
1522    if (dmaPending() || getState() != Running)
1523        txDmaState = dmaReadWaiting;
1524    else
1525        dmaRead(txDmaAddr, txDmaLen, &txDmaReadEvent, (uint8_t*)txDmaData);
1526
1527    return true;
1528}
1529
1530void
1531NSGigE::txDmaReadDone()
1532{
1533    assert(txDmaState == dmaReading);
1534    txDmaState = dmaIdle;
1535
1536    DPRINTF(EthernetDMA, "tx dma read  paddr=%#x len=%d\n",
1537            txDmaAddr, txDmaLen);
1538    DDUMP(EthernetDMA, txDmaData, txDmaLen);
1539
1540    // If the receive state machine  has a pending DMA, let it go first
1541    if (rxDmaState == dmaReadWaiting || rxDmaState == dmaWriteWaiting)
1542        rxKick();
1543
1544    txKick();
1545}
1546
1547bool
1548NSGigE::doTxDmaWrite()
1549{
1550    assert(txDmaState == dmaIdle || txDmaState == dmaWriteWaiting);
1551    txDmaState = dmaWriting;
1552
1553    if (dmaPending() || getState() != Running)
1554        txDmaState = dmaWriteWaiting;
1555    else
1556        dmaWrite(txDmaAddr, txDmaLen, &txDmaWriteEvent, (uint8_t*)txDmaData);
1557    return true;
1558}
1559
1560void
1561NSGigE::txDmaWriteDone()
1562{
1563    assert(txDmaState == dmaWriting);
1564    txDmaState = dmaIdle;
1565
1566    DPRINTF(EthernetDMA, "tx dma write paddr=%#x len=%d\n",
1567            txDmaAddr, txDmaLen);
1568    DDUMP(EthernetDMA, txDmaData, txDmaLen);
1569
1570    // If the receive state machine  has a pending DMA, let it go first
1571    if (rxDmaState == dmaReadWaiting || rxDmaState == dmaWriteWaiting)
1572        rxKick();
1573
1574    txKick();
1575}
1576
1577void
1578NSGigE::txKick()
1579{
1580    bool is64bit = (bool)(regs.config & CFGR_M64ADDR);
1581
1582    DPRINTF(EthernetSM, "transmit kick txState=%s %d-bit\n",
1583            NsTxStateStrings[txState], is64bit ? 64 : 32);
1584
1585    Addr link, bufptr;
1586    uint32_t &cmdsts = is64bit ? txDesc64.cmdsts : txDesc32.cmdsts;
1587    uint32_t &extsts = is64bit ? txDesc64.extsts : txDesc32.extsts;
1588
1589  next:
1590    if (clock) {
1591        if (txKickTick > curTick()) {
1592            DPRINTF(EthernetSM, "transmit kick exiting, can't run till %d\n",
1593                    txKickTick);
1594            goto exit;
1595        }
1596
1597        // Go to the next state machine clock tick.
1598        txKickTick = curTick() + ticks(1);
1599    }
1600
1601    switch(txDmaState) {
1602      case dmaReadWaiting:
1603        if (doTxDmaRead())
1604            goto exit;
1605        break;
1606      case dmaWriteWaiting:
1607        if (doTxDmaWrite())
1608            goto exit;
1609        break;
1610      default:
1611        break;
1612    }
1613
1614    link = is64bit ? (Addr)txDesc64.link : (Addr)txDesc32.link;
1615    bufptr = is64bit ? (Addr)txDesc64.bufptr : (Addr)txDesc32.bufptr;
1616    switch (txState) {
1617      case txIdle:
1618        if (!txEnable) {
1619            DPRINTF(EthernetSM, "Transmit disabled.  Nothing to do.\n");
1620            goto exit;
1621        }
1622
1623        if (CTDD) {
1624            txState = txDescRefr;
1625
1626            txDmaAddr = regs.txdp & 0x3fffffff;
1627            txDmaData =
1628                is64bit ? (void *)&txDesc64.link : (void *)&txDesc32.link;
1629            txDmaLen = is64bit ? sizeof(txDesc64.link) : sizeof(txDesc32.link);
1630            txDmaFree = dmaDescFree;
1631
1632            descDmaReads++;
1633            descDmaRdBytes += txDmaLen;
1634
1635            if (doTxDmaRead())
1636                goto exit;
1637
1638        } else {
1639            txState = txDescRead;
1640
1641            txDmaAddr = regs.txdp & 0x3fffffff;
1642            txDmaData = is64bit ? (void *)&txDesc64 : (void *)&txDesc32;
1643            txDmaLen = is64bit ? sizeof(txDesc64) : sizeof(txDesc32);
1644            txDmaFree = dmaDescFree;
1645
1646            descDmaReads++;
1647            descDmaRdBytes += txDmaLen;
1648
1649            if (doTxDmaRead())
1650                goto exit;
1651        }
1652        break;
1653
1654      case txDescRefr:
1655        if (txDmaState != dmaIdle)
1656            goto exit;
1657
1658        txState = txAdvance;
1659        break;
1660
1661      case txDescRead:
1662        if (txDmaState != dmaIdle)
1663            goto exit;
1664
1665        DPRINTF(EthernetDesc, "txDesc: addr=%08x read descriptor\n",
1666                regs.txdp & 0x3fffffff);
1667        DPRINTF(EthernetDesc,
1668                "txDesc: link=%#x bufptr=%#x cmdsts=%#08x extsts=%#08x\n",
1669                link, bufptr, cmdsts, extsts);
1670
1671        if (cmdsts & CMDSTS_OWN) {
1672            txState = txFifoBlock;
1673            txFragPtr = bufptr;
1674            txDescCnt = cmdsts & CMDSTS_LEN_MASK;
1675        } else {
1676            devIntrPost(ISR_TXIDLE);
1677            txState = txIdle;
1678            goto exit;
1679        }
1680        break;
1681
1682      case txFifoBlock:
1683        if (!txPacket) {
1684            DPRINTF(EthernetSM, "****starting the tx of a new packet****\n");
1685            txPacket = new EthPacketData(16384);
1686            txPacketBufPtr = txPacket->data;
1687        }
1688
1689        if (txDescCnt == 0) {
1690            DPRINTF(EthernetSM, "the txDescCnt == 0, done with descriptor\n");
1691            if (cmdsts & CMDSTS_MORE) {
1692                DPRINTF(EthernetSM, "there are more descriptors to come\n");
1693                txState = txDescWrite;
1694
1695                cmdsts &= ~CMDSTS_OWN;
1696
1697                txDmaAddr = regs.txdp & 0x3fffffff;
1698                txDmaData = &cmdsts;
1699                if (is64bit) {
1700                    txDmaAddr += offsetof(ns_desc64, cmdsts);
1701                    txDmaLen = sizeof(txDesc64.cmdsts);
1702                } else {
1703                    txDmaAddr += offsetof(ns_desc32, cmdsts);
1704                    txDmaLen = sizeof(txDesc32.cmdsts);
1705                }
1706                txDmaFree = dmaDescFree;
1707
1708                if (doTxDmaWrite())
1709                    goto exit;
1710
1711            } else { /* this packet is totally done */
1712                DPRINTF(EthernetSM, "This packet is done, let's wrap it up\n");
1713                /* deal with the the packet that just finished */
1714                if ((regs.vtcr & VTCR_PPCHK) && extstsEnable) {
1715                    IpPtr ip(txPacket);
1716                    if (extsts & EXTSTS_UDPPKT) {
1717                        UdpPtr udp(ip);
1718                        if (udp) {
1719                            udp->sum(0);
1720                            udp->sum(cksum(udp));
1721                            txUdpChecksums++;
1722                        } else {
1723                            Debug::breakpoint();
1724                            warn_once("UDPPKT set, but not UDP!\n");
1725                        }
1726                    } else if (extsts & EXTSTS_TCPPKT) {
1727                        TcpPtr tcp(ip);
1728                        if (tcp) {
1729                            tcp->sum(0);
1730                            tcp->sum(cksum(tcp));
1731                            txTcpChecksums++;
1732                        } else {
1733                            Debug::breakpoint();
1734                            warn_once("TCPPKT set, but not UDP!\n");
1735                        }
1736                    }
1737                    if (extsts & EXTSTS_IPPKT) {
1738                        if (ip) {
1739                            ip->sum(0);
1740                            ip->sum(cksum(ip));
1741                            txIpChecksums++;
1742                        } else {
1743                            Debug::breakpoint();
1744                            warn_once("IPPKT set, but not UDP!\n");
1745                        }
1746                    }
1747                }
1748
1749                txPacket->length = txPacketBufPtr - txPacket->data;
1750                // this is just because the receive can't handle a
1751                // packet bigger want to make sure
1752                if (txPacket->length > 1514)
1753                    panic("transmit packet too large, %s > 1514\n",
1754                          txPacket->length);
1755
1756#ifndef NDEBUG
1757                bool success =
1758#endif
1759                    txFifo.push(txPacket);
1760                assert(success);
1761
1762                /*
1763                 * this following section is not tqo spec, but
1764                 * functionally shouldn't be any different.  normally,
1765                 * the chip will wait til the transmit has occurred
1766                 * before writing back the descriptor because it has
1767                 * to wait to see that it was successfully transmitted
1768                 * to decide whether to set CMDSTS_OK or not.
1769                 * however, in the simulator since it is always
1770                 * successfully transmitted, and writing it exactly to
1771                 * spec would complicate the code, we just do it here
1772                 */
1773
1774                cmdsts &= ~CMDSTS_OWN;
1775                cmdsts |= CMDSTS_OK;
1776
1777                DPRINTF(EthernetDesc,
1778                        "txDesc writeback: cmdsts=%08x extsts=%08x\n",
1779                        cmdsts, extsts);
1780
1781                txDmaFree = dmaDescFree;
1782                txDmaAddr = regs.txdp & 0x3fffffff;
1783                txDmaData = &cmdsts;
1784                if (is64bit) {
1785                    txDmaAddr += offsetof(ns_desc64, cmdsts);
1786                    txDmaLen =
1787                        sizeof(txDesc64.cmdsts) + sizeof(txDesc64.extsts);
1788                } else {
1789                    txDmaAddr += offsetof(ns_desc32, cmdsts);
1790                    txDmaLen =
1791                        sizeof(txDesc32.cmdsts) + sizeof(txDesc32.extsts);
1792                }
1793
1794                descDmaWrites++;
1795                descDmaWrBytes += txDmaLen;
1796
1797                transmit();
1798                txPacket = 0;
1799
1800                if (!txEnable) {
1801                    DPRINTF(EthernetSM, "halting TX state machine\n");
1802                    txState = txIdle;
1803                    goto exit;
1804                } else
1805                    txState = txAdvance;
1806
1807                if (doTxDmaWrite())
1808                    goto exit;
1809            }
1810        } else {
1811            DPRINTF(EthernetSM, "this descriptor isn't done yet\n");
1812            if (!txFifo.full()) {
1813                txState = txFragRead;
1814
1815                /*
1816                 * The number of bytes transferred is either whatever
1817                 * is left in the descriptor (txDescCnt), or if there
1818                 * is not enough room in the fifo, just whatever room
1819                 * is left in the fifo
1820                 */
1821                txXferLen = min<uint32_t>(txDescCnt, txFifo.avail());
1822
1823                txDmaAddr = txFragPtr & 0x3fffffff;
1824                txDmaData = txPacketBufPtr;
1825                txDmaLen = txXferLen;
1826                txDmaFree = dmaDataFree;
1827
1828                if (doTxDmaRead())
1829                    goto exit;
1830            } else {
1831                txState = txFifoBlock;
1832                transmit();
1833
1834                goto exit;
1835            }
1836
1837        }
1838        break;
1839
1840      case txFragRead:
1841        if (txDmaState != dmaIdle)
1842            goto exit;
1843
1844        txPacketBufPtr += txXferLen;
1845        txFragPtr += txXferLen;
1846        txDescCnt -= txXferLen;
1847        txFifo.reserve(txXferLen);
1848
1849        txState = txFifoBlock;
1850        break;
1851
1852      case txDescWrite:
1853        if (txDmaState != dmaIdle)
1854            goto exit;
1855
1856        if (cmdsts & CMDSTS_INTR)
1857            devIntrPost(ISR_TXDESC);
1858
1859        if (!txEnable) {
1860            DPRINTF(EthernetSM, "halting TX state machine\n");
1861            txState = txIdle;
1862            goto exit;
1863        } else
1864            txState = txAdvance;
1865        break;
1866
1867      case txAdvance:
1868        if (link == 0) {
1869            devIntrPost(ISR_TXIDLE);
1870            txState = txIdle;
1871            goto exit;
1872        } else {
1873            if (txDmaState != dmaIdle)
1874                goto exit;
1875            txState = txDescRead;
1876            regs.txdp = link;
1877            CTDD = false;
1878
1879            txDmaAddr = link & 0x3fffffff;
1880            txDmaData = is64bit ? (void *)&txDesc64 : (void *)&txDesc32;
1881            txDmaLen = is64bit ? sizeof(txDesc64) : sizeof(txDesc32);
1882            txDmaFree = dmaDescFree;
1883
1884            if (doTxDmaRead())
1885                goto exit;
1886        }
1887        break;
1888
1889      default:
1890        panic("invalid state");
1891    }
1892
1893    DPRINTF(EthernetSM, "entering next txState=%s\n",
1894            NsTxStateStrings[txState]);
1895    goto next;
1896
1897  exit:
1898    /**
1899     * @todo do we want to schedule a future kick?
1900     */
1901    DPRINTF(EthernetSM, "tx state machine exited txState=%s\n",
1902            NsTxStateStrings[txState]);
1903
1904    if (clock && !txKickEvent.scheduled())
1905        schedule(txKickEvent, txKickTick);
1906}
1907
1908/**
1909 * Advance the EEPROM state machine
1910 * Called on rising edge of EEPROM clock bit in MEAR
1911 */
1912void
1913NSGigE::eepromKick()
1914{
1915    switch (eepromState) {
1916
1917      case eepromStart:
1918
1919        // Wait for start bit
1920        if (regs.mear & MEAR_EEDI) {
1921            // Set up to get 2 opcode bits
1922            eepromState = eepromGetOpcode;
1923            eepromBitsToRx = 2;
1924            eepromOpcode = 0;
1925        }
1926        break;
1927
1928      case eepromGetOpcode:
1929        eepromOpcode <<= 1;
1930        eepromOpcode += (regs.mear & MEAR_EEDI) ? 1 : 0;
1931        --eepromBitsToRx;
1932
1933        // Done getting opcode
1934        if (eepromBitsToRx == 0) {
1935            if (eepromOpcode != EEPROM_READ)
1936                panic("only EEPROM reads are implemented!");
1937
1938            // Set up to get address
1939            eepromState = eepromGetAddress;
1940            eepromBitsToRx = 6;
1941            eepromAddress = 0;
1942        }
1943        break;
1944
1945      case eepromGetAddress:
1946        eepromAddress <<= 1;
1947        eepromAddress += (regs.mear & MEAR_EEDI) ? 1 : 0;
1948        --eepromBitsToRx;
1949
1950        // Done getting address
1951        if (eepromBitsToRx == 0) {
1952
1953            if (eepromAddress >= EEPROM_SIZE)
1954                panic("EEPROM read access out of range!");
1955
1956            switch (eepromAddress) {
1957
1958              case EEPROM_PMATCH2_ADDR:
1959                eepromData = rom.perfectMatch[5];
1960                eepromData <<= 8;
1961                eepromData += rom.perfectMatch[4];
1962                break;
1963
1964              case EEPROM_PMATCH1_ADDR:
1965                eepromData = rom.perfectMatch[3];
1966                eepromData <<= 8;
1967                eepromData += rom.perfectMatch[2];
1968                break;
1969
1970              case EEPROM_PMATCH0_ADDR:
1971                eepromData = rom.perfectMatch[1];
1972                eepromData <<= 8;
1973                eepromData += rom.perfectMatch[0];
1974                break;
1975
1976              default:
1977                panic("FreeBSD driver only uses EEPROM to read PMATCH!");
1978            }
1979            // Set up to read data
1980            eepromState = eepromRead;
1981            eepromBitsToRx = 16;
1982
1983            // Clear data in bit
1984            regs.mear &= ~MEAR_EEDI;
1985        }
1986        break;
1987
1988      case eepromRead:
1989        // Clear Data Out bit
1990        regs.mear &= ~MEAR_EEDO;
1991        // Set bit to value of current EEPROM bit
1992        regs.mear |= (eepromData & 0x8000) ? MEAR_EEDO : 0x0;
1993
1994        eepromData <<= 1;
1995        --eepromBitsToRx;
1996
1997        // All done
1998        if (eepromBitsToRx == 0) {
1999            eepromState = eepromStart;
2000        }
2001        break;
2002
2003      default:
2004        panic("invalid EEPROM state");
2005    }
2006
2007}
2008
2009void
2010NSGigE::transferDone()
2011{
2012    if (txFifo.empty()) {
2013        DPRINTF(Ethernet, "transfer complete: txFifo empty...nothing to do\n");
2014        return;
2015    }
2016
2017    DPRINTF(Ethernet, "transfer complete: data in txFifo...schedule xmit\n");
2018
2019    reschedule(txEvent, curTick() + ticks(1), true);
2020}
2021
2022bool
2023NSGigE::rxFilter(const EthPacketPtr &packet)
2024{
2025    EthPtr eth = packet;
2026    bool drop = true;
2027    string type;
2028
2029    const EthAddr &dst = eth->dst();
2030    if (dst.unicast()) {
2031        // If we're accepting all unicast addresses
2032        if (acceptUnicast)
2033            drop = false;
2034
2035        // If we make a perfect match
2036        if (acceptPerfect && dst == rom.perfectMatch)
2037            drop = false;
2038
2039        if (acceptArp && eth->type() == ETH_TYPE_ARP)
2040            drop = false;
2041
2042    } else if (dst.broadcast()) {
2043        // if we're accepting broadcasts
2044        if (acceptBroadcast)
2045            drop = false;
2046
2047    } else if (dst.multicast()) {
2048        // if we're accepting all multicasts
2049        if (acceptMulticast)
2050            drop = false;
2051
2052        // Multicast hashing faked - all packets accepted
2053        if (multicastHashEnable)
2054            drop = false;
2055    }
2056
2057    if (drop) {
2058        DPRINTF(Ethernet, "rxFilter drop\n");
2059        DDUMP(EthernetData, packet->data, packet->length);
2060    }
2061
2062    return drop;
2063}
2064
2065bool
2066NSGigE::recvPacket(EthPacketPtr packet)
2067{
2068    rxBytes += packet->length;
2069    rxPackets++;
2070
2071    DPRINTF(Ethernet, "Receiving packet from wire, rxFifoAvail=%d\n",
2072            rxFifo.avail());
2073
2074    if (!rxEnable) {
2075        DPRINTF(Ethernet, "receive disabled...packet dropped\n");
2076        return true;
2077    }
2078
2079    if (!rxFilterEnable) {
2080        DPRINTF(Ethernet,
2081            "receive packet filtering disabled . . . packet dropped\n");
2082        return true;
2083    }
2084
2085    if (rxFilter(packet)) {
2086        DPRINTF(Ethernet, "packet filtered...dropped\n");
2087        return true;
2088    }
2089
2090    if (rxFifo.avail() < packet->length) {
2091#if TRACING_ON
2092        IpPtr ip(packet);
2093        TcpPtr tcp(ip);
2094        if (ip) {
2095            DPRINTF(Ethernet,
2096                    "packet won't fit in receive buffer...pkt ID %d dropped\n",
2097                    ip->id());
2098            if (tcp) {
2099                DPRINTF(Ethernet, "Seq=%d\n", tcp->seq());
2100            }
2101        }
2102#endif
2103        droppedPackets++;
2104        devIntrPost(ISR_RXORN);
2105        return false;
2106    }
2107
2108    rxFifo.push(packet);
2109
2110    rxKick();
2111    return true;
2112}
2113
2114
2115void
2116NSGigE::resume()
2117{
2118    SimObject::resume();
2119
2120    // During drain we could have left the state machines in a waiting state and
2121    // they wouldn't get out until some other event occured to kick them.
2122    // This way they'll get out immediately
2123    txKick();
2124    rxKick();
2125}
2126
2127
2128//=====================================================================
2129//
2130//
2131void
2132NSGigE::serialize(ostream &os)
2133{
2134    // Serialize the PciDev base class
2135    PciDev::serialize(os);
2136
2137    /*
2138     * Finalize any DMA events now.
2139     */
2140    // @todo will mem system save pending dma?
2141
2142    /*
2143     * Serialize the device registers
2144     */
2145    SERIALIZE_SCALAR(regs.command);
2146    SERIALIZE_SCALAR(regs.config);
2147    SERIALIZE_SCALAR(regs.mear);
2148    SERIALIZE_SCALAR(regs.ptscr);
2149    SERIALIZE_SCALAR(regs.isr);
2150    SERIALIZE_SCALAR(regs.imr);
2151    SERIALIZE_SCALAR(regs.ier);
2152    SERIALIZE_SCALAR(regs.ihr);
2153    SERIALIZE_SCALAR(regs.txdp);
2154    SERIALIZE_SCALAR(regs.txdp_hi);
2155    SERIALIZE_SCALAR(regs.txcfg);
2156    SERIALIZE_SCALAR(regs.gpior);
2157    SERIALIZE_SCALAR(regs.rxdp);
2158    SERIALIZE_SCALAR(regs.rxdp_hi);
2159    SERIALIZE_SCALAR(regs.rxcfg);
2160    SERIALIZE_SCALAR(regs.pqcr);
2161    SERIALIZE_SCALAR(regs.wcsr);
2162    SERIALIZE_SCALAR(regs.pcr);
2163    SERIALIZE_SCALAR(regs.rfcr);
2164    SERIALIZE_SCALAR(regs.rfdr);
2165    SERIALIZE_SCALAR(regs.brar);
2166    SERIALIZE_SCALAR(regs.brdr);
2167    SERIALIZE_SCALAR(regs.srr);
2168    SERIALIZE_SCALAR(regs.mibc);
2169    SERIALIZE_SCALAR(regs.vrcr);
2170    SERIALIZE_SCALAR(regs.vtcr);
2171    SERIALIZE_SCALAR(regs.vdr);
2172    SERIALIZE_SCALAR(regs.ccsr);
2173    SERIALIZE_SCALAR(regs.tbicr);
2174    SERIALIZE_SCALAR(regs.tbisr);
2175    SERIALIZE_SCALAR(regs.tanar);
2176    SERIALIZE_SCALAR(regs.tanlpar);
2177    SERIALIZE_SCALAR(regs.taner);
2178    SERIALIZE_SCALAR(regs.tesr);
2179
2180    SERIALIZE_ARRAY(rom.perfectMatch, ETH_ADDR_LEN);
2181    SERIALIZE_ARRAY(rom.filterHash, FHASH_SIZE);
2182
2183    SERIALIZE_SCALAR(ioEnable);
2184
2185    /*
2186     * Serialize the data Fifos
2187     */
2188    rxFifo.serialize("rxFifo", os);
2189    txFifo.serialize("txFifo", os);
2190
2191    /*
2192     * Serialize the various helper variables
2193     */
2194    bool txPacketExists = txPacket;
2195    SERIALIZE_SCALAR(txPacketExists);
2196    if (txPacketExists) {
2197        txPacket->length = txPacketBufPtr - txPacket->data;
2198        txPacket->serialize("txPacket", os);
2199        uint32_t txPktBufPtr = (uint32_t) (txPacketBufPtr - txPacket->data);
2200        SERIALIZE_SCALAR(txPktBufPtr);
2201    }
2202
2203    bool rxPacketExists = rxPacket;
2204    SERIALIZE_SCALAR(rxPacketExists);
2205    if (rxPacketExists) {
2206        rxPacket->serialize("rxPacket", os);
2207        uint32_t rxPktBufPtr = (uint32_t) (rxPacketBufPtr - rxPacket->data);
2208        SERIALIZE_SCALAR(rxPktBufPtr);
2209    }
2210
2211    SERIALIZE_SCALAR(txXferLen);
2212    SERIALIZE_SCALAR(rxXferLen);
2213
2214    /*
2215     * Serialize Cached Descriptors
2216     */
2217    SERIALIZE_SCALAR(rxDesc64.link);
2218    SERIALIZE_SCALAR(rxDesc64.bufptr);
2219    SERIALIZE_SCALAR(rxDesc64.cmdsts);
2220    SERIALIZE_SCALAR(rxDesc64.extsts);
2221    SERIALIZE_SCALAR(txDesc64.link);
2222    SERIALIZE_SCALAR(txDesc64.bufptr);
2223    SERIALIZE_SCALAR(txDesc64.cmdsts);
2224    SERIALIZE_SCALAR(txDesc64.extsts);
2225    SERIALIZE_SCALAR(rxDesc32.link);
2226    SERIALIZE_SCALAR(rxDesc32.bufptr);
2227    SERIALIZE_SCALAR(rxDesc32.cmdsts);
2228    SERIALIZE_SCALAR(rxDesc32.extsts);
2229    SERIALIZE_SCALAR(txDesc32.link);
2230    SERIALIZE_SCALAR(txDesc32.bufptr);
2231    SERIALIZE_SCALAR(txDesc32.cmdsts);
2232    SERIALIZE_SCALAR(txDesc32.extsts);
2233    SERIALIZE_SCALAR(extstsEnable);
2234
2235    /*
2236     * Serialize tx state machine
2237     */
2238    int txState = this->txState;
2239    SERIALIZE_SCALAR(txState);
2240    SERIALIZE_SCALAR(txEnable);
2241    SERIALIZE_SCALAR(CTDD);
2242    SERIALIZE_SCALAR(txFragPtr);
2243    SERIALIZE_SCALAR(txDescCnt);
2244    int txDmaState = this->txDmaState;
2245    SERIALIZE_SCALAR(txDmaState);
2246    SERIALIZE_SCALAR(txKickTick);
2247
2248    /*
2249     * Serialize rx state machine
2250     */
2251    int rxState = this->rxState;
2252    SERIALIZE_SCALAR(rxState);
2253    SERIALIZE_SCALAR(rxEnable);
2254    SERIALIZE_SCALAR(CRDD);
2255    SERIALIZE_SCALAR(rxPktBytes);
2256    SERIALIZE_SCALAR(rxFragPtr);
2257    SERIALIZE_SCALAR(rxDescCnt);
2258    int rxDmaState = this->rxDmaState;
2259    SERIALIZE_SCALAR(rxDmaState);
2260    SERIALIZE_SCALAR(rxKickTick);
2261
2262    /*
2263     * Serialize EEPROM state machine
2264     */
2265    int eepromState = this->eepromState;
2266    SERIALIZE_SCALAR(eepromState);
2267    SERIALIZE_SCALAR(eepromClk);
2268    SERIALIZE_SCALAR(eepromBitsToRx);
2269    SERIALIZE_SCALAR(eepromOpcode);
2270    SERIALIZE_SCALAR(eepromAddress);
2271    SERIALIZE_SCALAR(eepromData);
2272
2273    /*
2274     * If there's a pending transmit, store the time so we can
2275     * reschedule it later
2276     */
2277    Tick transmitTick = txEvent.scheduled() ? txEvent.when() - curTick() : 0;
2278    SERIALIZE_SCALAR(transmitTick);
2279
2280    /*
2281     * receive address filter settings
2282     */
2283    SERIALIZE_SCALAR(rxFilterEnable);
2284    SERIALIZE_SCALAR(acceptBroadcast);
2285    SERIALIZE_SCALAR(acceptMulticast);
2286    SERIALIZE_SCALAR(acceptUnicast);
2287    SERIALIZE_SCALAR(acceptPerfect);
2288    SERIALIZE_SCALAR(acceptArp);
2289    SERIALIZE_SCALAR(multicastHashEnable);
2290
2291    /*
2292     * Keep track of pending interrupt status.
2293     */
2294    SERIALIZE_SCALAR(intrTick);
2295    SERIALIZE_SCALAR(cpuPendingIntr);
2296    Tick intrEventTick = 0;
2297    if (intrEvent)
2298        intrEventTick = intrEvent->when();
2299    SERIALIZE_SCALAR(intrEventTick);
2300
2301}
2302
2303void
2304NSGigE::unserialize(Checkpoint *cp, const std::string &section)
2305{
2306    // Unserialize the PciDev base class
2307    PciDev::unserialize(cp, section);
2308
2309    UNSERIALIZE_SCALAR(regs.command);
2310    UNSERIALIZE_SCALAR(regs.config);
2311    UNSERIALIZE_SCALAR(regs.mear);
2312    UNSERIALIZE_SCALAR(regs.ptscr);
2313    UNSERIALIZE_SCALAR(regs.isr);
2314    UNSERIALIZE_SCALAR(regs.imr);
2315    UNSERIALIZE_SCALAR(regs.ier);
2316    UNSERIALIZE_SCALAR(regs.ihr);
2317    UNSERIALIZE_SCALAR(regs.txdp);
2318    UNSERIALIZE_SCALAR(regs.txdp_hi);
2319    UNSERIALIZE_SCALAR(regs.txcfg);
2320    UNSERIALIZE_SCALAR(regs.gpior);
2321    UNSERIALIZE_SCALAR(regs.rxdp);
2322    UNSERIALIZE_SCALAR(regs.rxdp_hi);
2323    UNSERIALIZE_SCALAR(regs.rxcfg);
2324    UNSERIALIZE_SCALAR(regs.pqcr);
2325    UNSERIALIZE_SCALAR(regs.wcsr);
2326    UNSERIALIZE_SCALAR(regs.pcr);
2327    UNSERIALIZE_SCALAR(regs.rfcr);
2328    UNSERIALIZE_SCALAR(regs.rfdr);
2329    UNSERIALIZE_SCALAR(regs.brar);
2330    UNSERIALIZE_SCALAR(regs.brdr);
2331    UNSERIALIZE_SCALAR(regs.srr);
2332    UNSERIALIZE_SCALAR(regs.mibc);
2333    UNSERIALIZE_SCALAR(regs.vrcr);
2334    UNSERIALIZE_SCALAR(regs.vtcr);
2335    UNSERIALIZE_SCALAR(regs.vdr);
2336    UNSERIALIZE_SCALAR(regs.ccsr);
2337    UNSERIALIZE_SCALAR(regs.tbicr);
2338    UNSERIALIZE_SCALAR(regs.tbisr);
2339    UNSERIALIZE_SCALAR(regs.tanar);
2340    UNSERIALIZE_SCALAR(regs.tanlpar);
2341    UNSERIALIZE_SCALAR(regs.taner);
2342    UNSERIALIZE_SCALAR(regs.tesr);
2343
2344    UNSERIALIZE_ARRAY(rom.perfectMatch, ETH_ADDR_LEN);
2345    UNSERIALIZE_ARRAY(rom.filterHash, FHASH_SIZE);
2346
2347    UNSERIALIZE_SCALAR(ioEnable);
2348
2349    /*
2350     * unserialize the data fifos
2351     */
2352    rxFifo.unserialize("rxFifo", cp, section);
2353    txFifo.unserialize("txFifo", cp, section);
2354
2355    /*
2356     * unserialize the various helper variables
2357     */
2358    bool txPacketExists;
2359    UNSERIALIZE_SCALAR(txPacketExists);
2360    if (txPacketExists) {
2361        txPacket = new EthPacketData(16384);
2362        txPacket->unserialize("txPacket", cp, section);
2363        uint32_t txPktBufPtr;
2364        UNSERIALIZE_SCALAR(txPktBufPtr);
2365        txPacketBufPtr = (uint8_t *) txPacket->data + txPktBufPtr;
2366    } else
2367        txPacket = 0;
2368
2369    bool rxPacketExists;
2370    UNSERIALIZE_SCALAR(rxPacketExists);
2371    rxPacket = 0;
2372    if (rxPacketExists) {
2373        rxPacket = new EthPacketData(16384);
2374        rxPacket->unserialize("rxPacket", cp, section);
2375        uint32_t rxPktBufPtr;
2376        UNSERIALIZE_SCALAR(rxPktBufPtr);
2377        rxPacketBufPtr = (uint8_t *) rxPacket->data + rxPktBufPtr;
2378    } else
2379        rxPacket = 0;
2380
2381    UNSERIALIZE_SCALAR(txXferLen);
2382    UNSERIALIZE_SCALAR(rxXferLen);
2383
2384    /*
2385     * Unserialize Cached Descriptors
2386     */
2387    UNSERIALIZE_SCALAR(rxDesc64.link);
2388    UNSERIALIZE_SCALAR(rxDesc64.bufptr);
2389    UNSERIALIZE_SCALAR(rxDesc64.cmdsts);
2390    UNSERIALIZE_SCALAR(rxDesc64.extsts);
2391    UNSERIALIZE_SCALAR(txDesc64.link);
2392    UNSERIALIZE_SCALAR(txDesc64.bufptr);
2393    UNSERIALIZE_SCALAR(txDesc64.cmdsts);
2394    UNSERIALIZE_SCALAR(txDesc64.extsts);
2395    UNSERIALIZE_SCALAR(rxDesc32.link);
2396    UNSERIALIZE_SCALAR(rxDesc32.bufptr);
2397    UNSERIALIZE_SCALAR(rxDesc32.cmdsts);
2398    UNSERIALIZE_SCALAR(rxDesc32.extsts);
2399    UNSERIALIZE_SCALAR(txDesc32.link);
2400    UNSERIALIZE_SCALAR(txDesc32.bufptr);
2401    UNSERIALIZE_SCALAR(txDesc32.cmdsts);
2402    UNSERIALIZE_SCALAR(txDesc32.extsts);
2403    UNSERIALIZE_SCALAR(extstsEnable);
2404
2405    /*
2406     * unserialize tx state machine
2407     */
2408    int txState;
2409    UNSERIALIZE_SCALAR(txState);
2410    this->txState = (TxState) txState;
2411    UNSERIALIZE_SCALAR(txEnable);
2412    UNSERIALIZE_SCALAR(CTDD);
2413    UNSERIALIZE_SCALAR(txFragPtr);
2414    UNSERIALIZE_SCALAR(txDescCnt);
2415    int txDmaState;
2416    UNSERIALIZE_SCALAR(txDmaState);
2417    this->txDmaState = (DmaState) txDmaState;
2418    UNSERIALIZE_SCALAR(txKickTick);
2419    if (txKickTick)
2420        schedule(txKickEvent, txKickTick);
2421
2422    /*
2423     * unserialize rx state machine
2424     */
2425    int rxState;
2426    UNSERIALIZE_SCALAR(rxState);
2427    this->rxState = (RxState) rxState;
2428    UNSERIALIZE_SCALAR(rxEnable);
2429    UNSERIALIZE_SCALAR(CRDD);
2430    UNSERIALIZE_SCALAR(rxPktBytes);
2431    UNSERIALIZE_SCALAR(rxFragPtr);
2432    UNSERIALIZE_SCALAR(rxDescCnt);
2433    int rxDmaState;
2434    UNSERIALIZE_SCALAR(rxDmaState);
2435    this->rxDmaState = (DmaState) rxDmaState;
2436    UNSERIALIZE_SCALAR(rxKickTick);
2437    if (rxKickTick)
2438        schedule(rxKickEvent, rxKickTick);
2439
2440    /*
2441     * Unserialize EEPROM state machine
2442     */
2443    int eepromState;
2444    UNSERIALIZE_SCALAR(eepromState);
2445    this->eepromState = (EEPROMState) eepromState;
2446    UNSERIALIZE_SCALAR(eepromClk);
2447    UNSERIALIZE_SCALAR(eepromBitsToRx);
2448    UNSERIALIZE_SCALAR(eepromOpcode);
2449    UNSERIALIZE_SCALAR(eepromAddress);
2450    UNSERIALIZE_SCALAR(eepromData);
2451
2452    /*
2453     * If there's a pending transmit, reschedule it now
2454     */
2455    Tick transmitTick;
2456    UNSERIALIZE_SCALAR(transmitTick);
2457    if (transmitTick)
2458        schedule(txEvent, curTick() + transmitTick);
2459
2460    /*
2461     * unserialize receive address filter settings
2462     */
2463    UNSERIALIZE_SCALAR(rxFilterEnable);
2464    UNSERIALIZE_SCALAR(acceptBroadcast);
2465    UNSERIALIZE_SCALAR(acceptMulticast);
2466    UNSERIALIZE_SCALAR(acceptUnicast);
2467    UNSERIALIZE_SCALAR(acceptPerfect);
2468    UNSERIALIZE_SCALAR(acceptArp);
2469    UNSERIALIZE_SCALAR(multicastHashEnable);
2470
2471    /*
2472     * Keep track of pending interrupt status.
2473     */
2474    UNSERIALIZE_SCALAR(intrTick);
2475    UNSERIALIZE_SCALAR(cpuPendingIntr);
2476    Tick intrEventTick;
2477    UNSERIALIZE_SCALAR(intrEventTick);
2478    if (intrEventTick) {
2479        intrEvent = new IntrEvent(this, true);
2480        schedule(intrEvent, intrEventTick);
2481    }
2482}
2483
2484NSGigE *
2485NSGigEParams::create()
2486{
2487    return new NSGigE(this);
2488}
2489