ns_gige.cc revision 6216
15331Sgblack@eecs.umich.edu/*
25331Sgblack@eecs.umich.edu * Copyright (c) 2004-2005 The Regents of The University of Michigan
35331Sgblack@eecs.umich.edu * All rights reserved.
45331Sgblack@eecs.umich.edu *
55331Sgblack@eecs.umich.edu * Redistribution and use in source and binary forms, with or without
65331Sgblack@eecs.umich.edu * modification, are permitted provided that the following conditions are
75331Sgblack@eecs.umich.edu * met: redistributions of source code must retain the above copyright
85331Sgblack@eecs.umich.edu * notice, this list of conditions and the following disclaimer;
95331Sgblack@eecs.umich.edu * redistributions in binary form must reproduce the above copyright
105331Sgblack@eecs.umich.edu * notice, this list of conditions and the following disclaimer in the
115331Sgblack@eecs.umich.edu * documentation and/or other materials provided with the distribution;
125331Sgblack@eecs.umich.edu * neither the name of the copyright holders nor the names of its
135331Sgblack@eecs.umich.edu * contributors may be used to endorse or promote products derived from
145331Sgblack@eecs.umich.edu * this software without specific prior written permission.
155331Sgblack@eecs.umich.edu *
165331Sgblack@eecs.umich.edu * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
175331Sgblack@eecs.umich.edu * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
185331Sgblack@eecs.umich.edu * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
195331Sgblack@eecs.umich.edu * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
205331Sgblack@eecs.umich.edu * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
215331Sgblack@eecs.umich.edu * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
225331Sgblack@eecs.umich.edu * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
235331Sgblack@eecs.umich.edu * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
245331Sgblack@eecs.umich.edu * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
255331Sgblack@eecs.umich.edu * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
265331Sgblack@eecs.umich.edu * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
275331Sgblack@eecs.umich.edu *
285331Sgblack@eecs.umich.edu * Authors: Nathan Binkert
295331Sgblack@eecs.umich.edu *          Lisa Hsu
304276Sgblack@eecs.umich.edu */
314276Sgblack@eecs.umich.edu
324276Sgblack@eecs.umich.edu/** @file
334276Sgblack@eecs.umich.edu * Device module for modelling the National Semiconductor
344276Sgblack@eecs.umich.edu * DP83820 ethernet controller.  Does not support priority queueing
354276Sgblack@eecs.umich.edu */
364276Sgblack@eecs.umich.edu#include <deque>
374276Sgblack@eecs.umich.edu#include <string>
384276Sgblack@eecs.umich.edu
394276Sgblack@eecs.umich.edu#include "base/debug.hh"
404276Sgblack@eecs.umich.edu#include "base/inet.hh"
414276Sgblack@eecs.umich.edu#include "base/types.hh"
424276Sgblack@eecs.umich.edu#include "cpu/thread_context.hh"
434276Sgblack@eecs.umich.edu#include "dev/etherlink.hh"
444276Sgblack@eecs.umich.edu#include "dev/ns_gige.hh"
454276Sgblack@eecs.umich.edu#include "dev/pciconfigall.hh"
464276Sgblack@eecs.umich.edu#include "mem/packet.hh"
474276Sgblack@eecs.umich.edu#include "mem/packet_access.hh"
484276Sgblack@eecs.umich.edu#include "params/NSGigE.hh"
494276Sgblack@eecs.umich.edu#include "sim/system.hh"
504276Sgblack@eecs.umich.edu
514276Sgblack@eecs.umich.educonst char *NsRxStateStrings[] =
524276Sgblack@eecs.umich.edu{
534276Sgblack@eecs.umich.edu    "rxIdle",
544276Sgblack@eecs.umich.edu    "rxDescRefr",
554276Sgblack@eecs.umich.edu    "rxDescRead",
564276Sgblack@eecs.umich.edu    "rxFifoBlock",
574276Sgblack@eecs.umich.edu    "rxFragWrite",
584276Sgblack@eecs.umich.edu    "rxDescWrite",
594276Sgblack@eecs.umich.edu    "rxAdvance"
604276Sgblack@eecs.umich.edu};
614276Sgblack@eecs.umich.edu
624276Sgblack@eecs.umich.educonst char *NsTxStateStrings[] =
634276Sgblack@eecs.umich.edu{
644276Sgblack@eecs.umich.edu    "txIdle",
654276Sgblack@eecs.umich.edu    "txDescRefr",
664276Sgblack@eecs.umich.edu    "txDescRead",
674276Sgblack@eecs.umich.edu    "txFifoBlock",
684276Sgblack@eecs.umich.edu    "txFragRead",
694276Sgblack@eecs.umich.edu    "txDescWrite",
704276Sgblack@eecs.umich.edu    "txAdvance"
714276Sgblack@eecs.umich.edu};
724276Sgblack@eecs.umich.edu
734276Sgblack@eecs.umich.educonst char *NsDmaState[] =
744276Sgblack@eecs.umich.edu{
754276Sgblack@eecs.umich.edu    "dmaIdle",
764276Sgblack@eecs.umich.edu    "dmaReading",
774276Sgblack@eecs.umich.edu    "dmaWriting",
784276Sgblack@eecs.umich.edu    "dmaReadWaiting",
794276Sgblack@eecs.umich.edu    "dmaWriteWaiting"
804276Sgblack@eecs.umich.edu};
814276Sgblack@eecs.umich.edu
824276Sgblack@eecs.umich.eduusing namespace std;
834276Sgblack@eecs.umich.eduusing namespace Net;
844276Sgblack@eecs.umich.eduusing namespace TheISA;
854276Sgblack@eecs.umich.edu
864276Sgblack@eecs.umich.edu///////////////////////////////////////////////////////////////////////
874276Sgblack@eecs.umich.edu//
884276Sgblack@eecs.umich.edu// NSGigE PCI Device
894711Sgblack@eecs.umich.edu//
904276Sgblack@eecs.umich.eduNSGigE::NSGigE(Params *p)
914276Sgblack@eecs.umich.edu    : EtherDevice(p), ioEnable(false),
925238Sgblack@eecs.umich.edu      txFifo(p->tx_fifo_size), rxFifo(p->rx_fifo_size),
935238Sgblack@eecs.umich.edu      txPacket(0), rxPacket(0), txPacketBufPtr(NULL), rxPacketBufPtr(NULL),
945238Sgblack@eecs.umich.edu      txXferLen(0), rxXferLen(0), rxDmaFree(false), txDmaFree(false),
955238Sgblack@eecs.umich.edu      clock(p->clock),
965937Sgblack@eecs.umich.edu      txState(txIdle), txEnable(false), CTDD(false), txHalt(false),
975902Sgblack@eecs.umich.edu      txFragPtr(0), txDescCnt(0), txDmaState(dmaIdle), rxState(rxIdle),
985238Sgblack@eecs.umich.edu      rxEnable(false), CRDD(false), rxPktBytes(0), rxHalt(false),
995238Sgblack@eecs.umich.edu      rxFragPtr(0), rxDescCnt(0), rxDmaState(dmaIdle), extstsEnable(false),
1005238Sgblack@eecs.umich.edu      eepromState(eepromStart), eepromClk(false), eepromBitsToRx(0),
1015238Sgblack@eecs.umich.edu      eepromOpcode(0), eepromAddress(0), eepromData(0),
1025238Sgblack@eecs.umich.edu      dmaReadDelay(p->dma_read_delay), dmaWriteDelay(p->dma_write_delay),
1035238Sgblack@eecs.umich.edu      dmaReadFactor(p->dma_read_factor), dmaWriteFactor(p->dma_write_factor),
1045238Sgblack@eecs.umich.edu      rxDmaData(NULL), rxDmaAddr(0), rxDmaLen(0),
1055238Sgblack@eecs.umich.edu      txDmaData(NULL), txDmaAddr(0), txDmaLen(0),
1065238Sgblack@eecs.umich.edu      rxDmaReadEvent(this), rxDmaWriteEvent(this),
1075238Sgblack@eecs.umich.edu      txDmaReadEvent(this), txDmaWriteEvent(this),
1085238Sgblack@eecs.umich.edu      dmaDescFree(p->dma_desc_free), dmaDataFree(p->dma_data_free),
1095238Sgblack@eecs.umich.edu      txDelay(p->tx_delay), rxDelay(p->rx_delay),
1105238Sgblack@eecs.umich.edu      rxKickTick(0), rxKickEvent(this), txKickTick(0), txKickEvent(this),
1115238Sgblack@eecs.umich.edu      txEvent(this), rxFilterEnable(p->rx_filter),
1125238Sgblack@eecs.umich.edu      acceptBroadcast(false), acceptMulticast(false), acceptUnicast(false),
1135238Sgblack@eecs.umich.edu      acceptPerfect(false), acceptArp(false), multicastHashEnable(false),
1145238Sgblack@eecs.umich.edu      intrDelay(p->intr_delay), intrTick(0), cpuPendingIntr(false),
1155238Sgblack@eecs.umich.edu      intrEvent(0), interface(0)
1165238Sgblack@eecs.umich.edu{
1175238Sgblack@eecs.umich.edu
1185238Sgblack@eecs.umich.edu
1195238Sgblack@eecs.umich.edu    interface = new NSGigEInt(name() + ".int0", this);
1205238Sgblack@eecs.umich.edu
1215238Sgblack@eecs.umich.edu    regsReset();
1225238Sgblack@eecs.umich.edu    memcpy(&rom.perfectMatch, p->hardware_address.bytes(), ETH_ADDR_LEN);
1235238Sgblack@eecs.umich.edu
1245238Sgblack@eecs.umich.edu    memset(&rxDesc32, 0, sizeof(rxDesc32));
1255238Sgblack@eecs.umich.edu    memset(&txDesc32, 0, sizeof(txDesc32));
1265238Sgblack@eecs.umich.edu    memset(&rxDesc64, 0, sizeof(rxDesc64));
1275238Sgblack@eecs.umich.edu    memset(&txDesc64, 0, sizeof(txDesc64));
1286055Sgblack@eecs.umich.edu}
1296054Sgblack@eecs.umich.edu
1305238Sgblack@eecs.umich.eduNSGigE::~NSGigE()
1315683Sgblack@eecs.umich.edu{}
1325238Sgblack@eecs.umich.edu
1335238Sgblack@eecs.umich.edu/**
1345238Sgblack@eecs.umich.edu * This is to write to the PCI general configuration registers
1355238Sgblack@eecs.umich.edu */
1365238Sgblack@eecs.umich.eduTick
1375238Sgblack@eecs.umich.eduNSGigE::writeConfig(PacketPtr pkt)
1385238Sgblack@eecs.umich.edu{
1395238Sgblack@eecs.umich.edu    int offset = pkt->getAddr() & PCI_CONFIG_SIZE;
1405291Sgblack@eecs.umich.edu    if (offset < PCI_DEVICE_SPECIFIC)
1415291Sgblack@eecs.umich.edu        PciDev::writeConfig(pkt);
1425291Sgblack@eecs.umich.edu    else
1435291Sgblack@eecs.umich.edu        panic("Device specific PCI config space not implemented!\n");
1445291Sgblack@eecs.umich.edu
1455291Sgblack@eecs.umich.edu    switch (offset) {
1465291Sgblack@eecs.umich.edu        // seems to work fine without all these PCI settings, but i
1475291Sgblack@eecs.umich.edu        // put in the IO to double check, an assertion will fail if we
1485291Sgblack@eecs.umich.edu        // need to properly implement it
1495292Sgblack@eecs.umich.edu      case PCI_COMMAND:
1505292Sgblack@eecs.umich.edu        if (config.data[offset] & PCI_CMD_IOSE)
1515292Sgblack@eecs.umich.edu            ioEnable = true;
1525292Sgblack@eecs.umich.edu        else
1535292Sgblack@eecs.umich.edu            ioEnable = false;
1545292Sgblack@eecs.umich.edu        break;
1555292Sgblack@eecs.umich.edu    }
1565292Sgblack@eecs.umich.edu
1575292Sgblack@eecs.umich.edu    return configDelay;
1586055Sgblack@eecs.umich.edu}
1596054Sgblack@eecs.umich.edu
1605359Sgblack@eecs.umich.eduEtherInt*
1615238Sgblack@eecs.umich.eduNSGigE::getEthPort(const std::string &if_name, int idx)
1625238Sgblack@eecs.umich.edu{
1635238Sgblack@eecs.umich.edu    if (if_name == "interface") {
1644276Sgblack@eecs.umich.edu       if (interface->getPeer())
1654276Sgblack@eecs.umich.edu           panic("interface already connected to\n");
1665789Sgblack@eecs.umich.edu       return interface;
1675789Sgblack@eecs.umich.edu    }
1685789Sgblack@eecs.umich.edu    return NULL;
1695789Sgblack@eecs.umich.edu}
1705789Sgblack@eecs.umich.edu
1715789Sgblack@eecs.umich.edu/**
1725789Sgblack@eecs.umich.edu * This reads the device registers, which are detailed in the NS83820
1735789Sgblack@eecs.umich.edu * spec sheet
1745789Sgblack@eecs.umich.edu */
1755789Sgblack@eecs.umich.eduTick
1765789Sgblack@eecs.umich.eduNSGigE::read(PacketPtr pkt)
1775789Sgblack@eecs.umich.edu{
1785789Sgblack@eecs.umich.edu    assert(ioEnable);
1795789Sgblack@eecs.umich.edu
1805789Sgblack@eecs.umich.edu    pkt->allocate();
1815789Sgblack@eecs.umich.edu
1825789Sgblack@eecs.umich.edu    //The mask is to give you only the offset into the device register file
1835789Sgblack@eecs.umich.edu    Addr daddr = pkt->getAddr() & 0xfff;
1845789Sgblack@eecs.umich.edu    DPRINTF(EthernetPIO, "read  da=%#x pa=%#x size=%d\n",
1855789Sgblack@eecs.umich.edu            daddr, pkt->getAddr(), pkt->getSize());
1865789Sgblack@eecs.umich.edu
1875789Sgblack@eecs.umich.edu
1885789Sgblack@eecs.umich.edu    // there are some reserved registers, you can see ns_gige_reg.h and
1895789Sgblack@eecs.umich.edu    // the spec sheet for details
1905789Sgblack@eecs.umich.edu    if (daddr > LAST && daddr <=  RESERVED) {
1915789Sgblack@eecs.umich.edu        panic("Accessing reserved register");
1925789Sgblack@eecs.umich.edu    } else if (daddr > RESERVED && daddr <= 0x3FC) {
1935789Sgblack@eecs.umich.edu        return readConfig(pkt);
1945789Sgblack@eecs.umich.edu    } else if (daddr >= MIB_START && daddr <= MIB_END) {
1955789Sgblack@eecs.umich.edu        // don't implement all the MIB's.  hopefully the kernel
1965789Sgblack@eecs.umich.edu        // doesn't actually DEPEND upon their values
1975789Sgblack@eecs.umich.edu        // MIB are just hardware stats keepers
1985789Sgblack@eecs.umich.edu        pkt->set<uint32_t>(0);
1995789Sgblack@eecs.umich.edu        pkt->makeAtomicResponse();
2005789Sgblack@eecs.umich.edu        return pioDelay;
2015789Sgblack@eecs.umich.edu    } else if (daddr > 0x3FC)
2025789Sgblack@eecs.umich.edu        panic("Something is messed up!\n");
2035789Sgblack@eecs.umich.edu
2045789Sgblack@eecs.umich.edu    assert(pkt->getSize() == sizeof(uint32_t));
2055789Sgblack@eecs.umich.edu        uint32_t &reg = *pkt->getPtr<uint32_t>();
2065789Sgblack@eecs.umich.edu        uint16_t rfaddr;
2075789Sgblack@eecs.umich.edu
2085789Sgblack@eecs.umich.edu        switch (daddr) {
2095789Sgblack@eecs.umich.edu          case CR:
2105789Sgblack@eecs.umich.edu            reg = regs.command;
2115789Sgblack@eecs.umich.edu            //these are supposed to be cleared on a read
2125789Sgblack@eecs.umich.edu            reg &= ~(CR_RXD | CR_TXD | CR_TXR | CR_RXR);
2135789Sgblack@eecs.umich.edu            break;
2145789Sgblack@eecs.umich.edu
2155789Sgblack@eecs.umich.edu          case CFGR:
2165789Sgblack@eecs.umich.edu            reg = regs.config;
2175789Sgblack@eecs.umich.edu            break;
2185789Sgblack@eecs.umich.edu
2195789Sgblack@eecs.umich.edu          case MEAR:
2205789Sgblack@eecs.umich.edu            reg = regs.mear;
2215789Sgblack@eecs.umich.edu            break;
2225789Sgblack@eecs.umich.edu
2235789Sgblack@eecs.umich.edu          case PTSCR:
2245789Sgblack@eecs.umich.edu            reg = regs.ptscr;
2255789Sgblack@eecs.umich.edu            break;
2265789Sgblack@eecs.umich.edu
2275789Sgblack@eecs.umich.edu          case ISR:
2285789Sgblack@eecs.umich.edu            reg = regs.isr;
2295789Sgblack@eecs.umich.edu            devIntrClear(ISR_ALL);
2305789Sgblack@eecs.umich.edu            break;
2315789Sgblack@eecs.umich.edu
2325789Sgblack@eecs.umich.edu          case IMR:
2335789Sgblack@eecs.umich.edu            reg = regs.imr;
2345789Sgblack@eecs.umich.edu            break;
2355789Sgblack@eecs.umich.edu
2365789Sgblack@eecs.umich.edu          case IER:
2375789Sgblack@eecs.umich.edu            reg = regs.ier;
2385789Sgblack@eecs.umich.edu            break;
2395789Sgblack@eecs.umich.edu
2405789Sgblack@eecs.umich.edu          case IHR:
2415789Sgblack@eecs.umich.edu            reg = regs.ihr;
2425789Sgblack@eecs.umich.edu            break;
2435789Sgblack@eecs.umich.edu
2445789Sgblack@eecs.umich.edu          case TXDP:
2455789Sgblack@eecs.umich.edu            reg = regs.txdp;
2465789Sgblack@eecs.umich.edu            break;
2475789Sgblack@eecs.umich.edu
2485789Sgblack@eecs.umich.edu          case TXDP_HI:
2495789Sgblack@eecs.umich.edu            reg = regs.txdp_hi;
2505789Sgblack@eecs.umich.edu            break;
2515789Sgblack@eecs.umich.edu
2525789Sgblack@eecs.umich.edu          case TX_CFG:
2535789Sgblack@eecs.umich.edu            reg = regs.txcfg;
2545789Sgblack@eecs.umich.edu            break;
2555789Sgblack@eecs.umich.edu
2564712Sgblack@eecs.umich.edu          case GPIOR:
2575907Sgblack@eecs.umich.edu            reg = regs.gpior;
2585907Sgblack@eecs.umich.edu            break;
2595907Sgblack@eecs.umich.edu
2605907Sgblack@eecs.umich.edu          case RXDP:
2615907Sgblack@eecs.umich.edu            reg = regs.rxdp;
2625907Sgblack@eecs.umich.edu            break;
2635907Sgblack@eecs.umich.edu
2644712Sgblack@eecs.umich.edu          case RXDP_HI:
2655659Sgblack@eecs.umich.edu            reg = regs.rxdp_hi;
2664712Sgblack@eecs.umich.edu            break;
2675933Sgblack@eecs.umich.edu
2685908Sgblack@eecs.umich.edu          case RX_CFG:
2695908Sgblack@eecs.umich.edu            reg = regs.rxcfg;
2705908Sgblack@eecs.umich.edu            break;
2715908Sgblack@eecs.umich.edu
2725908Sgblack@eecs.umich.edu          case PQCR:
2735908Sgblack@eecs.umich.edu            reg = regs.pqcr;
2745908Sgblack@eecs.umich.edu            break;
2755908Sgblack@eecs.umich.edu
2765908Sgblack@eecs.umich.edu          case WCSR:
2774276Sgblack@eecs.umich.edu            reg = regs.wcsr;
2784276Sgblack@eecs.umich.edu            break;
2794712Sgblack@eecs.umich.edu
2804712Sgblack@eecs.umich.edu          case PCR:
2814730Sgblack@eecs.umich.edu            reg = regs.pcr;
2824760Sgblack@eecs.umich.edu            break;
2834730Sgblack@eecs.umich.edu
2845920Sgblack@eecs.umich.edu            // see the spec sheet for how RFCR and RFDR work
2855422Sgblack@eecs.umich.edu            // basically, you write to RFCR to tell the machine
2865422Sgblack@eecs.umich.edu            // what you want to do next, then you act upon RFDR,
2874276Sgblack@eecs.umich.edu            // and the device will be prepared b/c of what you
2886576Sgblack@eecs.umich.edu            // wrote to RFCR
2896576Sgblack@eecs.umich.edu          case RFCR:
2906576Sgblack@eecs.umich.edu            reg = regs.rfcr;
2916576Sgblack@eecs.umich.edu            break;
2926576Sgblack@eecs.umich.edu
2936576Sgblack@eecs.umich.edu          case RFDR:
2946576Sgblack@eecs.umich.edu            rfaddr = (uint16_t)(regs.rfcr & RFCR_RFADDR);
2956576Sgblack@eecs.umich.edu            switch (rfaddr) {
2966576Sgblack@eecs.umich.edu              // Read from perfect match ROM octets
2976576Sgblack@eecs.umich.edu              case 0x000:
2986576Sgblack@eecs.umich.edu                reg = rom.perfectMatch[1];
2996576Sgblack@eecs.umich.edu                reg = reg << 8;
3006576Sgblack@eecs.umich.edu                reg += rom.perfectMatch[0];
3016576Sgblack@eecs.umich.edu                break;
3026576Sgblack@eecs.umich.edu              case 0x002:
3036576Sgblack@eecs.umich.edu                reg = rom.perfectMatch[3] << 8;
3046576Sgblack@eecs.umich.edu                reg += rom.perfectMatch[2];
3056576Sgblack@eecs.umich.edu                break;
3065020Sgblack@eecs.umich.edu              case 0x004:
3076576Sgblack@eecs.umich.edu                reg = rom.perfectMatch[5] << 8;
3086576Sgblack@eecs.umich.edu                reg += rom.perfectMatch[4];
3096600Sgblack@eecs.umich.edu                break;
3106600Sgblack@eecs.umich.edu              default:
3116576Sgblack@eecs.umich.edu                // Read filter hash table
3126576Sgblack@eecs.umich.edu                if (rfaddr >= FHASH_ADDR &&
3136576Sgblack@eecs.umich.edu                    rfaddr < FHASH_ADDR + FHASH_SIZE) {
3145020Sgblack@eecs.umich.edu
3156576Sgblack@eecs.umich.edu                    // Only word-aligned reads supported
3166576Sgblack@eecs.umich.edu                    if (rfaddr % 2)
3176576Sgblack@eecs.umich.edu                        panic("unaligned read from filter hash table!");
3186576Sgblack@eecs.umich.edu
3196576Sgblack@eecs.umich.edu                    reg = rom.filterHash[rfaddr - FHASH_ADDR + 1] << 8;
3206576Sgblack@eecs.umich.edu                    reg += rom.filterHash[rfaddr - FHASH_ADDR];
3216576Sgblack@eecs.umich.edu                    break;
3226576Sgblack@eecs.umich.edu                }
3236576Sgblack@eecs.umich.edu
3246576Sgblack@eecs.umich.edu                panic("reading RFDR for something other than pattern"
3256576Sgblack@eecs.umich.edu                      " matching or hashing! %#x\n", rfaddr);
3266576Sgblack@eecs.umich.edu            }
3276576Sgblack@eecs.umich.edu            break;
3286576Sgblack@eecs.umich.edu
3296576Sgblack@eecs.umich.edu          case SRR:
3306576Sgblack@eecs.umich.edu            reg = regs.srr;
3316576Sgblack@eecs.umich.edu            break;
3326576Sgblack@eecs.umich.edu
3336576Sgblack@eecs.umich.edu          case MIBC:
3344760Sgblack@eecs.umich.edu            reg = regs.mibc;
3356576Sgblack@eecs.umich.edu            reg &= ~(MIBC_MIBS | MIBC_ACLR);
3366576Sgblack@eecs.umich.edu            break;
3376576Sgblack@eecs.umich.edu
3386576Sgblack@eecs.umich.edu          case VRCR:
3396576Sgblack@eecs.umich.edu            reg = regs.vrcr;
3406576Sgblack@eecs.umich.edu            break;
3416576Sgblack@eecs.umich.edu
3426576Sgblack@eecs.umich.edu          case VTCR:
3436576Sgblack@eecs.umich.edu            reg = regs.vtcr;
3446576Sgblack@eecs.umich.edu            break;
3456576Sgblack@eecs.umich.edu
3466576Sgblack@eecs.umich.edu          case VDR:
3476576Sgblack@eecs.umich.edu            reg = regs.vdr;
3486576Sgblack@eecs.umich.edu            break;
3496576Sgblack@eecs.umich.edu
3506576Sgblack@eecs.umich.edu          case CCSR:
3514760Sgblack@eecs.umich.edu            reg = regs.ccsr;
3526576Sgblack@eecs.umich.edu            break;
3536576Sgblack@eecs.umich.edu
3546576Sgblack@eecs.umich.edu          case TBICR:
3556576Sgblack@eecs.umich.edu            reg = regs.tbicr;
3566576Sgblack@eecs.umich.edu            break;
3576576Sgblack@eecs.umich.edu
3586576Sgblack@eecs.umich.edu          case TBISR:
3596576Sgblack@eecs.umich.edu            reg = regs.tbisr;
3606576Sgblack@eecs.umich.edu            break;
3616576Sgblack@eecs.umich.edu
3626576Sgblack@eecs.umich.edu          case TANAR:
3636576Sgblack@eecs.umich.edu            reg = regs.tanar;
3646576Sgblack@eecs.umich.edu            break;
3656576Sgblack@eecs.umich.edu
3666576Sgblack@eecs.umich.edu          case TANLPAR:
3676576Sgblack@eecs.umich.edu            reg = regs.tanlpar;
3686576Sgblack@eecs.umich.edu            break;
3694760Sgblack@eecs.umich.edu
3704276Sgblack@eecs.umich.edu          case TANER:
3715020Sgblack@eecs.umich.edu            reg = regs.taner;
3725020Sgblack@eecs.umich.edu            break;
3735020Sgblack@eecs.umich.edu
3745031Sgblack@eecs.umich.edu          case TESR:
3755031Sgblack@eecs.umich.edu            reg = regs.tesr;
3765031Sgblack@eecs.umich.edu            break;
3775031Sgblack@eecs.umich.edu
3786563Sgblack@eecs.umich.edu          case M5REG:
3795020Sgblack@eecs.umich.edu            reg = 0;
3806606Sgblack@eecs.umich.edu            if (params()->rx_thread)
3816606Sgblack@eecs.umich.edu                reg |= M5REG_RX_THREAD;
3826602Sgblack@eecs.umich.edu            if (params()->tx_thread)
3836602Sgblack@eecs.umich.edu                reg |= M5REG_TX_THREAD;
3845020Sgblack@eecs.umich.edu            if (params()->rss)
3855020Sgblack@eecs.umich.edu                reg |= M5REG_RSS;
3865020Sgblack@eecs.umich.edu            break;
3876563Sgblack@eecs.umich.edu
3886606Sgblack@eecs.umich.edu          default:
3896606Sgblack@eecs.umich.edu            panic("reading unimplemented register: addr=%#x", daddr);
3905020Sgblack@eecs.umich.edu        }
3915020Sgblack@eecs.umich.edu
3925020Sgblack@eecs.umich.edu        DPRINTF(EthernetPIO, "read from %#x: data=%d data=%#x\n",
3935020Sgblack@eecs.umich.edu                daddr, reg, reg);
3946564Sgblack@eecs.umich.edu
3956564Sgblack@eecs.umich.edu    pkt->makeAtomicResponse();
3966563Sgblack@eecs.umich.edu    return pioDelay;
3975020Sgblack@eecs.umich.edu}
3986606Sgblack@eecs.umich.edu
3996606Sgblack@eecs.umich.eduTick
4005058Sgblack@eecs.umich.eduNSGigE::write(PacketPtr pkt)
4016602Sgblack@eecs.umich.edu{
4025020Sgblack@eecs.umich.edu    assert(ioEnable);
4035020Sgblack@eecs.umich.edu
4045020Sgblack@eecs.umich.edu    Addr daddr = pkt->getAddr() & 0xfff;
4055046Sgblack@eecs.umich.edu    DPRINTF(EthernetPIO, "write da=%#x pa=%#x size=%d\n",
4065046Sgblack@eecs.umich.edu            daddr, pkt->getAddr(), pkt->getSize());
4075046Sgblack@eecs.umich.edu
4085046Sgblack@eecs.umich.edu    if (daddr > LAST && daddr <=  RESERVED) {
4096606Sgblack@eecs.umich.edu        panic("Accessing reserved register");
4105020Sgblack@eecs.umich.edu    } else if (daddr > RESERVED && daddr <= 0x3FC) {
4115020Sgblack@eecs.umich.edu        return writeConfig(pkt);
4125020Sgblack@eecs.umich.edu    } else if (daddr > 0x3FC)
4134276Sgblack@eecs.umich.edu        panic("Something is messed up!\n");
4144276Sgblack@eecs.umich.edu
4155149Sgblack@eecs.umich.edu    if (pkt->getSize() == sizeof(uint32_t)) {
4165409Sgblack@eecs.umich.edu        uint32_t reg = pkt->get<uint32_t>();
4175149Sgblack@eecs.umich.edu        uint16_t rfaddr;
4184712Sgblack@eecs.umich.edu
4195972Sgblack@eecs.umich.edu        DPRINTF(EthernetPIO, "write data=%d data=%#x\n", reg, reg);
4204712Sgblack@eecs.umich.edu
4215972Sgblack@eecs.umich.edu        switch (daddr) {
4225972Sgblack@eecs.umich.edu          case CR:
4235972Sgblack@eecs.umich.edu            regs.command = reg;
4244712Sgblack@eecs.umich.edu            if (reg & CR_TXD) {
4254730Sgblack@eecs.umich.edu                txEnable = false;
4264712Sgblack@eecs.umich.edu            } else if (reg & CR_TXE) {
4274276Sgblack@eecs.umich.edu                txEnable = true;
4284276Sgblack@eecs.umich.edu
4294712Sgblack@eecs.umich.edu                // the kernel is enabling the transmit machine
4304712Sgblack@eecs.umich.edu                if (txState == txIdle)
4314712Sgblack@eecs.umich.edu                    txKick();
4324712Sgblack@eecs.umich.edu            }
4334712Sgblack@eecs.umich.edu
4344712Sgblack@eecs.umich.edu            if (reg & CR_RXD) {
4354712Sgblack@eecs.umich.edu                rxEnable = false;
4364712Sgblack@eecs.umich.edu            } else if (reg & CR_RXE) {
4374276Sgblack@eecs.umich.edu                rxEnable = true;
4384760Sgblack@eecs.umich.edu
4394760Sgblack@eecs.umich.edu                if (rxState == rxIdle)
4404760Sgblack@eecs.umich.edu                    rxKick();
4414760Sgblack@eecs.umich.edu            }
4424760Sgblack@eecs.umich.edu
4434760Sgblack@eecs.umich.edu            if (reg & CR_TXR)
4444760Sgblack@eecs.umich.edu                txReset();
4454760Sgblack@eecs.umich.edu
4464760Sgblack@eecs.umich.edu            if (reg & CR_RXR)
4474760Sgblack@eecs.umich.edu                rxReset();
4484760Sgblack@eecs.umich.edu
4494760Sgblack@eecs.umich.edu            if (reg & CR_SWI)
4504760Sgblack@eecs.umich.edu                devIntrPost(ISR_SWI);
4514760Sgblack@eecs.umich.edu
4524760Sgblack@eecs.umich.edu            if (reg & CR_RST) {
4534760Sgblack@eecs.umich.edu                txReset();
4544760Sgblack@eecs.umich.edu                rxReset();
4554760Sgblack@eecs.umich.edu
4564760Sgblack@eecs.umich.edu                regsReset();
4574760Sgblack@eecs.umich.edu            }
4584760Sgblack@eecs.umich.edu            break;
4596576Sgblack@eecs.umich.edu
4606576Sgblack@eecs.umich.edu          case CFGR:
4616576Sgblack@eecs.umich.edu            if (reg & CFGR_LNKSTS ||
4626593Sgblack@eecs.umich.edu                reg & CFGR_SPDSTS ||
4636576Sgblack@eecs.umich.edu                reg & CFGR_DUPSTS ||
4646576Sgblack@eecs.umich.edu                reg & CFGR_RESERVED ||
4656576Sgblack@eecs.umich.edu                reg & CFGR_T64ADDR ||
4666576Sgblack@eecs.umich.edu                reg & CFGR_PCI64_DET)
4676576Sgblack@eecs.umich.edu
4686576Sgblack@eecs.umich.edu            // First clear all writable bits
4696576Sgblack@eecs.umich.edu            regs.config &= CFGR_LNKSTS | CFGR_SPDSTS | CFGR_DUPSTS |
4706576Sgblack@eecs.umich.edu                                   CFGR_RESERVED | CFGR_T64ADDR |
4716576Sgblack@eecs.umich.edu                                   CFGR_PCI64_DET;
4726576Sgblack@eecs.umich.edu            // Now set the appropriate writable bits
4736576Sgblack@eecs.umich.edu            regs.config |= reg & ~(CFGR_LNKSTS | CFGR_SPDSTS | CFGR_DUPSTS |
4746576Sgblack@eecs.umich.edu                                   CFGR_RESERVED | CFGR_T64ADDR |
4756576Sgblack@eecs.umich.edu                                   CFGR_PCI64_DET);
4766576Sgblack@eecs.umich.edu
4776576Sgblack@eecs.umich.edu// all these #if 0's are because i don't THINK the kernel needs to
4786576Sgblack@eecs.umich.edu// have these implemented. if there is a problem relating to one of
4796576Sgblack@eecs.umich.edu// these, you may need to add functionality in.
4806593Sgblack@eecs.umich.edu            if (reg & CFGR_TBI_EN) ;
4816576Sgblack@eecs.umich.edu            if (reg & CFGR_MODE_1000) ;
4826576Sgblack@eecs.umich.edu
4836576Sgblack@eecs.umich.edu            if (reg & CFGR_AUTO_1000)
4846576Sgblack@eecs.umich.edu                panic("CFGR_AUTO_1000 not implemented!\n");
4856576Sgblack@eecs.umich.edu
4866576Sgblack@eecs.umich.edu            if (reg & CFGR_PINT_DUPSTS ||
4876576Sgblack@eecs.umich.edu                reg & CFGR_PINT_LNKSTS ||
4886576Sgblack@eecs.umich.edu                reg & CFGR_PINT_SPDSTS)
4896576Sgblack@eecs.umich.edu                ;
4905059Sgblack@eecs.umich.edu
4915059Sgblack@eecs.umich.edu            if (reg & CFGR_TMRTEST) ;
4926576Sgblack@eecs.umich.edu            if (reg & CFGR_MRM_DIS) ;
4935059Sgblack@eecs.umich.edu            if (reg & CFGR_MWI_DIS) ;
4945059Sgblack@eecs.umich.edu
4955059Sgblack@eecs.umich.edu            if (reg & CFGR_T64ADDR) ;
4965020Sgblack@eecs.umich.edu            // panic("CFGR_T64ADDR is read only register!\n");
4976576Sgblack@eecs.umich.edu
4986576Sgblack@eecs.umich.edu            if (reg & CFGR_PCI64_DET)
4996576Sgblack@eecs.umich.edu                panic("CFGR_PCI64_DET is read only register!\n");
5006576Sgblack@eecs.umich.edu
5016576Sgblack@eecs.umich.edu            if (reg & CFGR_DATA64_EN) ;
5026576Sgblack@eecs.umich.edu            if (reg & CFGR_M64ADDR) ;
5036576Sgblack@eecs.umich.edu            if (reg & CFGR_PHY_RST) ;
5046576Sgblack@eecs.umich.edu            if (reg & CFGR_PHY_DIS) ;
5056576Sgblack@eecs.umich.edu
5066576Sgblack@eecs.umich.edu            if (reg & CFGR_EXTSTS_EN)
5076576Sgblack@eecs.umich.edu                extstsEnable = true;
5086576Sgblack@eecs.umich.edu            else
5096576Sgblack@eecs.umich.edu                extstsEnable = false;
5106576Sgblack@eecs.umich.edu
5116576Sgblack@eecs.umich.edu            if (reg & CFGR_REQALG) ;
5126576Sgblack@eecs.umich.edu            if (reg & CFGR_SB) ;
5136576Sgblack@eecs.umich.edu            if (reg & CFGR_POW) ;
5146606Sgblack@eecs.umich.edu            if (reg & CFGR_EXD) ;
5156576Sgblack@eecs.umich.edu            if (reg & CFGR_PESEL) ;
5166576Sgblack@eecs.umich.edu            if (reg & CFGR_BROM_DIS) ;
5176576Sgblack@eecs.umich.edu            if (reg & CFGR_EXT_125) ;
5186576Sgblack@eecs.umich.edu            if (reg & CFGR_BEM) ;
5196576Sgblack@eecs.umich.edu            break;
5206576Sgblack@eecs.umich.edu
5216576Sgblack@eecs.umich.edu          case MEAR:
5226576Sgblack@eecs.umich.edu            // Clear writable bits
5236576Sgblack@eecs.umich.edu            regs.mear &= MEAR_EEDO;
5246576Sgblack@eecs.umich.edu            // Set appropriate writable bits
5256606Sgblack@eecs.umich.edu            regs.mear |= reg & ~MEAR_EEDO;
5266576Sgblack@eecs.umich.edu
5276576Sgblack@eecs.umich.edu            // FreeBSD uses the EEPROM to read PMATCH (for the MAC address)
5286576Sgblack@eecs.umich.edu            // even though it could get it through RFDR
5296576Sgblack@eecs.umich.edu            if (reg & MEAR_EESEL) {
5306576Sgblack@eecs.umich.edu                // Rising edge of clock
5316576Sgblack@eecs.umich.edu                if (reg & MEAR_EECLK && !eepromClk)
5326576Sgblack@eecs.umich.edu                    eepromKick();
5336576Sgblack@eecs.umich.edu            }
5346576Sgblack@eecs.umich.edu            else {
5356576Sgblack@eecs.umich.edu                eepromState = eepromStart;
5366576Sgblack@eecs.umich.edu                regs.mear &= ~MEAR_EEDI;
5376576Sgblack@eecs.umich.edu            }
5386576Sgblack@eecs.umich.edu
5396576Sgblack@eecs.umich.edu            eepromClk = reg & MEAR_EECLK;
5406576Sgblack@eecs.umich.edu
5416576Sgblack@eecs.umich.edu            // since phy is completely faked, MEAR_MD* don't matter
5426576Sgblack@eecs.umich.edu            if (reg & MEAR_MDIO) ;
5435020Sgblack@eecs.umich.edu            if (reg & MEAR_MDDIR) ;
5446576Sgblack@eecs.umich.edu            if (reg & MEAR_MDC) ;
5456576Sgblack@eecs.umich.edu            break;
5466576Sgblack@eecs.umich.edu
5476576Sgblack@eecs.umich.edu          case PTSCR:
5486576Sgblack@eecs.umich.edu            regs.ptscr = reg & ~(PTSCR_RBIST_RDONLY);
5496576Sgblack@eecs.umich.edu            // these control BISTs for various parts of chip - we
5506576Sgblack@eecs.umich.edu            // don't care or do just fake that the BIST is done
5516576Sgblack@eecs.umich.edu            if (reg & PTSCR_RBIST_EN)
5526576Sgblack@eecs.umich.edu                regs.ptscr |= PTSCR_RBIST_DONE;
5536576Sgblack@eecs.umich.edu            if (reg & PTSCR_EEBIST_EN)
5546576Sgblack@eecs.umich.edu                regs.ptscr &= ~PTSCR_EEBIST_EN;
5556576Sgblack@eecs.umich.edu            if (reg & PTSCR_EELOAD_EN)
5566576Sgblack@eecs.umich.edu                regs.ptscr &= ~PTSCR_EELOAD_EN;
5576576Sgblack@eecs.umich.edu            break;
5586576Sgblack@eecs.umich.edu
5596576Sgblack@eecs.umich.edu          case ISR: /* writing to the ISR has no effect */
5606576Sgblack@eecs.umich.edu            panic("ISR is a read only register!\n");
5616576Sgblack@eecs.umich.edu
5626576Sgblack@eecs.umich.edu          case IMR:
5636576Sgblack@eecs.umich.edu            regs.imr = reg;
5646576Sgblack@eecs.umich.edu            devIntrChangeMask();
5656576Sgblack@eecs.umich.edu            break;
5666576Sgblack@eecs.umich.edu
5676576Sgblack@eecs.umich.edu          case IER:
5685020Sgblack@eecs.umich.edu            regs.ier = reg;
5696576Sgblack@eecs.umich.edu            break;
5706576Sgblack@eecs.umich.edu
5716576Sgblack@eecs.umich.edu          case IHR:
5726576Sgblack@eecs.umich.edu            regs.ihr = reg;
5736576Sgblack@eecs.umich.edu            /* not going to implement real interrupt holdoff */
5746576Sgblack@eecs.umich.edu            break;
5756576Sgblack@eecs.umich.edu
5766576Sgblack@eecs.umich.edu          case TXDP:
5776576Sgblack@eecs.umich.edu            regs.txdp = (reg & 0xFFFFFFFC);
5786576Sgblack@eecs.umich.edu            assert(txState == txIdle);
5796576Sgblack@eecs.umich.edu            CTDD = false;
5806576Sgblack@eecs.umich.edu            break;
5816576Sgblack@eecs.umich.edu
5826576Sgblack@eecs.umich.edu          case TXDP_HI:
5836576Sgblack@eecs.umich.edu            regs.txdp_hi = reg;
5846576Sgblack@eecs.umich.edu            break;
5856576Sgblack@eecs.umich.edu
5866576Sgblack@eecs.umich.edu          case TX_CFG:
5876576Sgblack@eecs.umich.edu            regs.txcfg = reg;
5886576Sgblack@eecs.umich.edu#if 0
5896576Sgblack@eecs.umich.edu            if (reg & TX_CFG_CSI) ;
5906576Sgblack@eecs.umich.edu            if (reg & TX_CFG_HBI) ;
5916576Sgblack@eecs.umich.edu            if (reg & TX_CFG_MLB) ;
5926576Sgblack@eecs.umich.edu            if (reg & TX_CFG_ATP) ;
5936576Sgblack@eecs.umich.edu            if (reg & TX_CFG_ECRETRY) {
5946576Sgblack@eecs.umich.edu                /*
5956576Sgblack@eecs.umich.edu                 * this could easily be implemented, but considering
5966576Sgblack@eecs.umich.edu                 * the network is just a fake pipe, wouldn't make
5975020Sgblack@eecs.umich.edu                 * sense to do this
5986584Sgblack@eecs.umich.edu                 */
5996584Sgblack@eecs.umich.edu            }
6006584Sgblack@eecs.umich.edu
6016597Sgblack@eecs.umich.edu            if (reg & TX_CFG_BRST_DIS) ;
6026584Sgblack@eecs.umich.edu#endif
6036584Sgblack@eecs.umich.edu
6046584Sgblack@eecs.umich.edu#if 0
6056584Sgblack@eecs.umich.edu            /* we handle our own DMA, ignore the kernel's exhortations */
6066584Sgblack@eecs.umich.edu            if (reg & TX_CFG_MXDMA) ;
6076584Sgblack@eecs.umich.edu#endif
6086584Sgblack@eecs.umich.edu
6096584Sgblack@eecs.umich.edu            // also, we currently don't care about fill/drain
6106584Sgblack@eecs.umich.edu            // thresholds though this may change in the future with
6116584Sgblack@eecs.umich.edu            // more realistic networks or a driver which changes it
6126584Sgblack@eecs.umich.edu            // according to feedback
6136584Sgblack@eecs.umich.edu
6146584Sgblack@eecs.umich.edu            break;
6156584Sgblack@eecs.umich.edu
6166584Sgblack@eecs.umich.edu          case GPIOR:
6175238Sgblack@eecs.umich.edu            // Only write writable bits
6186584Sgblack@eecs.umich.edu            regs.gpior &= GPIOR_UNUSED | GPIOR_GP5_IN | GPIOR_GP4_IN
6196584Sgblack@eecs.umich.edu                        | GPIOR_GP3_IN | GPIOR_GP2_IN | GPIOR_GP1_IN;
6206584Sgblack@eecs.umich.edu            regs.gpior |= reg & ~(GPIOR_UNUSED | GPIOR_GP5_IN | GPIOR_GP4_IN
6216584Sgblack@eecs.umich.edu                                | GPIOR_GP3_IN | GPIOR_GP2_IN | GPIOR_GP1_IN);
6226584Sgblack@eecs.umich.edu            /* these just control general purpose i/o pins, don't matter */
6236584Sgblack@eecs.umich.edu            break;
6246584Sgblack@eecs.umich.edu
6256584Sgblack@eecs.umich.edu          case RXDP:
6266584Sgblack@eecs.umich.edu            regs.rxdp = reg;
6276584Sgblack@eecs.umich.edu            CRDD = false;
6286584Sgblack@eecs.umich.edu            break;
6296584Sgblack@eecs.umich.edu
6306584Sgblack@eecs.umich.edu          case RXDP_HI:
6316584Sgblack@eecs.umich.edu            regs.rxdp_hi = reg;
6326584Sgblack@eecs.umich.edu            break;
6335238Sgblack@eecs.umich.edu
6346584Sgblack@eecs.umich.edu          case RX_CFG:
6356584Sgblack@eecs.umich.edu            regs.rxcfg = reg;
6366584Sgblack@eecs.umich.edu#if 0
6376584Sgblack@eecs.umich.edu            if (reg & RX_CFG_AEP) ;
6386584Sgblack@eecs.umich.edu            if (reg & RX_CFG_ARP) ;
6396584Sgblack@eecs.umich.edu            if (reg & RX_CFG_STRIPCRC) ;
6406584Sgblack@eecs.umich.edu            if (reg & RX_CFG_RX_RD) ;
6416584Sgblack@eecs.umich.edu            if (reg & RX_CFG_ALP) ;
6426584Sgblack@eecs.umich.edu            if (reg & RX_CFG_AIRL) ;
6436584Sgblack@eecs.umich.edu
6446584Sgblack@eecs.umich.edu            /* we handle our own DMA, ignore what kernel says about it */
6456584Sgblack@eecs.umich.edu            if (reg & RX_CFG_MXDMA) ;
6466584Sgblack@eecs.umich.edu
6476584Sgblack@eecs.umich.edu            //also, we currently don't care about fill/drain thresholds
6486584Sgblack@eecs.umich.edu            //though this may change in the future with more realistic
6496584Sgblack@eecs.umich.edu            //networks or a driver which changes it according to feedback
6506584Sgblack@eecs.umich.edu            if (reg & (RX_CFG_DRTH | RX_CFG_DRTH0)) ;
6516584Sgblack@eecs.umich.edu#endif
6526584Sgblack@eecs.umich.edu            break;
6535238Sgblack@eecs.umich.edu
6546584Sgblack@eecs.umich.edu          case PQCR:
6556584Sgblack@eecs.umich.edu            /* there is no priority queueing used in the linux 2.6 driver */
6566584Sgblack@eecs.umich.edu            regs.pqcr = reg;
6576584Sgblack@eecs.umich.edu            break;
6585238Sgblack@eecs.umich.edu
6596584Sgblack@eecs.umich.edu          case WCSR:
6606584Sgblack@eecs.umich.edu            /* not going to implement wake on LAN */
6616597Sgblack@eecs.umich.edu            regs.wcsr = reg;
6626584Sgblack@eecs.umich.edu            break;
6636584Sgblack@eecs.umich.edu
6646584Sgblack@eecs.umich.edu          case PCR:
6656584Sgblack@eecs.umich.edu            /* not going to implement pause control */
6666597Sgblack@eecs.umich.edu            regs.pcr = reg;
6676584Sgblack@eecs.umich.edu            break;
6686584Sgblack@eecs.umich.edu
6696584Sgblack@eecs.umich.edu          case RFCR:
6706584Sgblack@eecs.umich.edu            regs.rfcr = reg;
6716584Sgblack@eecs.umich.edu
6726584Sgblack@eecs.umich.edu            rxFilterEnable = (reg & RFCR_RFEN) ? true : false;
6736584Sgblack@eecs.umich.edu            acceptBroadcast = (reg & RFCR_AAB) ? true : false;
6746584Sgblack@eecs.umich.edu            acceptMulticast = (reg & RFCR_AAM) ? true : false;
6756584Sgblack@eecs.umich.edu            acceptUnicast = (reg & RFCR_AAU) ? true : false;
6766584Sgblack@eecs.umich.edu            acceptPerfect = (reg & RFCR_APM) ? true : false;
6776584Sgblack@eecs.umich.edu            acceptArp = (reg & RFCR_AARP) ? true : false;
6786584Sgblack@eecs.umich.edu            multicastHashEnable = (reg & RFCR_MHEN) ? true : false;
6796584Sgblack@eecs.umich.edu
6806584Sgblack@eecs.umich.edu#if 0
6816584Sgblack@eecs.umich.edu            if (reg & RFCR_APAT)
6825238Sgblack@eecs.umich.edu                panic("RFCR_APAT not implemented!\n");
6836584Sgblack@eecs.umich.edu#endif
6846584Sgblack@eecs.umich.edu            if (reg & RFCR_UHEN)
6856584Sgblack@eecs.umich.edu                panic("Unicast hash filtering not used by drivers!\n");
6866584Sgblack@eecs.umich.edu
6876584Sgblack@eecs.umich.edu            if (reg & RFCR_ULM)
6886584Sgblack@eecs.umich.edu                panic("RFCR_ULM not implemented!\n");
6896584Sgblack@eecs.umich.edu
6906584Sgblack@eecs.umich.edu            break;
6916584Sgblack@eecs.umich.edu
6926584Sgblack@eecs.umich.edu          case RFDR:
6936584Sgblack@eecs.umich.edu            rfaddr = (uint16_t)(regs.rfcr & RFCR_RFADDR);
6946584Sgblack@eecs.umich.edu            switch (rfaddr) {
6956584Sgblack@eecs.umich.edu              case 0x000:
6966584Sgblack@eecs.umich.edu                rom.perfectMatch[0] = (uint8_t)reg;
6976584Sgblack@eecs.umich.edu                rom.perfectMatch[1] = (uint8_t)(reg >> 8);
6985238Sgblack@eecs.umich.edu                break;
6996584Sgblack@eecs.umich.edu              case 0x002:
7006584Sgblack@eecs.umich.edu                rom.perfectMatch[2] = (uint8_t)reg;
7016584Sgblack@eecs.umich.edu                rom.perfectMatch[3] = (uint8_t)(reg >> 8);
7026584Sgblack@eecs.umich.edu                break;
7036584Sgblack@eecs.umich.edu              case 0x004:
7046584Sgblack@eecs.umich.edu                rom.perfectMatch[4] = (uint8_t)reg;
7056584Sgblack@eecs.umich.edu                rom.perfectMatch[5] = (uint8_t)(reg >> 8);
7066584Sgblack@eecs.umich.edu                break;
7076584Sgblack@eecs.umich.edu              default:
7086584Sgblack@eecs.umich.edu
7096584Sgblack@eecs.umich.edu                if (rfaddr >= FHASH_ADDR &&
7106584Sgblack@eecs.umich.edu                    rfaddr < FHASH_ADDR + FHASH_SIZE) {
7116584Sgblack@eecs.umich.edu
7126584Sgblack@eecs.umich.edu                    // Only word-aligned writes supported
7136584Sgblack@eecs.umich.edu                    if (rfaddr % 2)
7146584Sgblack@eecs.umich.edu                        panic("unaligned write to filter hash table!");
7156584Sgblack@eecs.umich.edu
7166584Sgblack@eecs.umich.edu                    rom.filterHash[rfaddr - FHASH_ADDR] = (uint8_t)reg;
7176584Sgblack@eecs.umich.edu                    rom.filterHash[rfaddr - FHASH_ADDR + 1]
7185238Sgblack@eecs.umich.edu                        = (uint8_t)(reg >> 8);
7196584Sgblack@eecs.umich.edu                    break;
7206584Sgblack@eecs.umich.edu                }
7216584Sgblack@eecs.umich.edu                panic("writing RFDR for something other than pattern matching\
7226584Sgblack@eecs.umich.edu                    or hashing! %#x\n", rfaddr);
7235238Sgblack@eecs.umich.edu            }
7246584Sgblack@eecs.umich.edu
7256584Sgblack@eecs.umich.edu          case BRAR:
7266597Sgblack@eecs.umich.edu            regs.brar = reg;
7276584Sgblack@eecs.umich.edu            break;
7285238Sgblack@eecs.umich.edu
7296584Sgblack@eecs.umich.edu          case BRDR:
7305020Sgblack@eecs.umich.edu            panic("the driver never uses BRDR, something is wrong!\n");
7316584Sgblack@eecs.umich.edu
7326584Sgblack@eecs.umich.edu          case SRR:
7336584Sgblack@eecs.umich.edu            panic("SRR is read only register!\n");
7346584Sgblack@eecs.umich.edu
7356584Sgblack@eecs.umich.edu          case MIBC:
7366584Sgblack@eecs.umich.edu            panic("the driver never uses MIBC, something is wrong!\n");
7376584Sgblack@eecs.umich.edu
7386584Sgblack@eecs.umich.edu          case VRCR:
7396584Sgblack@eecs.umich.edu            regs.vrcr = reg;
7406584Sgblack@eecs.umich.edu            break;
7416584Sgblack@eecs.umich.edu
7426584Sgblack@eecs.umich.edu          case VTCR:
7436584Sgblack@eecs.umich.edu            regs.vtcr = reg;
7446584Sgblack@eecs.umich.edu            break;
7456584Sgblack@eecs.umich.edu
7466584Sgblack@eecs.umich.edu          case VDR:
7476584Sgblack@eecs.umich.edu            panic("the driver never uses VDR, something is wrong!\n");
7486584Sgblack@eecs.umich.edu
7496584Sgblack@eecs.umich.edu          case CCSR:
7506584Sgblack@eecs.umich.edu            /* not going to implement clockrun stuff */
7516584Sgblack@eecs.umich.edu            regs.ccsr = reg;
7526584Sgblack@eecs.umich.edu            break;
7536584Sgblack@eecs.umich.edu
7546584Sgblack@eecs.umich.edu          case TBICR:
7556584Sgblack@eecs.umich.edu            regs.tbicr = reg;
7566584Sgblack@eecs.umich.edu            if (reg & TBICR_MR_LOOPBACK)
7576584Sgblack@eecs.umich.edu                panic("TBICR_MR_LOOPBACK never used, something wrong!\n");
7586584Sgblack@eecs.umich.edu
7596584Sgblack@eecs.umich.edu            if (reg & TBICR_MR_AN_ENABLE) {
7606584Sgblack@eecs.umich.edu                regs.tanlpar = regs.tanar;
7615020Sgblack@eecs.umich.edu                regs.tbisr |= (TBISR_MR_AN_COMPLETE | TBISR_MR_LINK_STATUS);
7624727Sgblack@eecs.umich.edu            }
7634727Sgblack@eecs.umich.edu
7644727Sgblack@eecs.umich.edu#if 0
7654727Sgblack@eecs.umich.edu            if (reg & TBICR_MR_RESTART_AN) ;
7664727Sgblack@eecs.umich.edu#endif
7674727Sgblack@eecs.umich.edu
7684727Sgblack@eecs.umich.edu            break;
7694727Sgblack@eecs.umich.edu
7704727Sgblack@eecs.umich.edu          case TBISR:
7714727Sgblack@eecs.umich.edu            panic("TBISR is read only register!\n");
7724727Sgblack@eecs.umich.edu
7734727Sgblack@eecs.umich.edu          case TANAR:
7744727Sgblack@eecs.umich.edu            // Only write the writable bits
7754727Sgblack@eecs.umich.edu            regs.tanar &= TANAR_RF1 | TANAR_RF2 | TANAR_UNUSED;
7764727Sgblack@eecs.umich.edu            regs.tanar |= reg & ~(TANAR_RF1 | TANAR_RF2 | TANAR_UNUSED);
7774727Sgblack@eecs.umich.edu
7784727Sgblack@eecs.umich.edu            // Pause capability unimplemented
7794727Sgblack@eecs.umich.edu#if 0
7804727Sgblack@eecs.umich.edu            if (reg & TANAR_PS2) ;
7814727Sgblack@eecs.umich.edu            if (reg & TANAR_PS1) ;
7824760Sgblack@eecs.umich.edu#endif
7834760Sgblack@eecs.umich.edu
7844760Sgblack@eecs.umich.edu            break;
7854760Sgblack@eecs.umich.edu
7864760Sgblack@eecs.umich.edu          case TANLPAR:
7874760Sgblack@eecs.umich.edu            panic("this should only be written to by the fake phy!\n");
7884760Sgblack@eecs.umich.edu
7894760Sgblack@eecs.umich.edu          case TANER:
7904760Sgblack@eecs.umich.edu            panic("TANER is read only register!\n");
7914760Sgblack@eecs.umich.edu
7924760Sgblack@eecs.umich.edu          case TESR:
7934760Sgblack@eecs.umich.edu            regs.tesr = reg;
7944760Sgblack@eecs.umich.edu            break;
7954760Sgblack@eecs.umich.edu
7964760Sgblack@eecs.umich.edu          default:
7974760Sgblack@eecs.umich.edu            panic("invalid register access daddr=%#x", daddr);
7984760Sgblack@eecs.umich.edu        }
7994760Sgblack@eecs.umich.edu    } else {
8004760Sgblack@eecs.umich.edu        panic("Invalid Request Size");
8014760Sgblack@eecs.umich.edu    }
8024276Sgblack@eecs.umich.edu    pkt->makeAtomicResponse();
8034276Sgblack@eecs.umich.edu    return pioDelay;
8044712Sgblack@eecs.umich.edu}
8054712Sgblack@eecs.umich.edu
8065659Sgblack@eecs.umich.eduvoid
8075659Sgblack@eecs.umich.eduNSGigE::devIntrPost(uint32_t interrupts)
8086052Sgblack@eecs.umich.edu{
8095659Sgblack@eecs.umich.edu    if (interrupts & ISR_RESERVE)
8105659Sgblack@eecs.umich.edu        panic("Cannot set a reserved interrupt");
8115659Sgblack@eecs.umich.edu
8125659Sgblack@eecs.umich.edu    if (interrupts & ISR_NOIMPL)
8135659Sgblack@eecs.umich.edu        warn("interrupt not implemented %#x\n", interrupts);
8145240Sgblack@eecs.umich.edu
8156480Sgblack@eecs.umich.edu    interrupts &= ISR_IMPL;
8166480Sgblack@eecs.umich.edu    regs.isr |= interrupts;
8174712Sgblack@eecs.umich.edu
8184712Sgblack@eecs.umich.edu    if (interrupts & regs.imr) {
8194276Sgblack@eecs.umich.edu        if (interrupts & ISR_SWI) {
8204276Sgblack@eecs.umich.edu            totalSwi++;
8214712Sgblack@eecs.umich.edu        }
8224712Sgblack@eecs.umich.edu        if (interrupts & ISR_RXIDLE) {
8234712Sgblack@eecs.umich.edu            totalRxIdle++;
8245240Sgblack@eecs.umich.edu        }
8255977Sgblack@eecs.umich.edu        if (interrupts & ISR_RXOK) {
8266481Sgblack@eecs.umich.edu            totalRxOk++;
8275238Sgblack@eecs.umich.edu        }
8285967Sgblack@eecs.umich.edu        if (interrupts & ISR_RXDESC) {
8295967Sgblack@eecs.umich.edu            totalRxDesc++;
8305967Sgblack@eecs.umich.edu        }
8316599Sgblack@eecs.umich.edu        if (interrupts & ISR_TXOK) {
8326598Sgblack@eecs.umich.edu            totalTxOk++;
8335967Sgblack@eecs.umich.edu        }
8345967Sgblack@eecs.umich.edu        if (interrupts & ISR_TXIDLE) {
8355967Sgblack@eecs.umich.edu            totalTxIdle++;
8365923Sgblack@eecs.umich.edu        }
8375238Sgblack@eecs.umich.edu        if (interrupts & ISR_TXDESC) {
8385238Sgblack@eecs.umich.edu            totalTxDesc++;
8395967Sgblack@eecs.umich.edu        }
8405967Sgblack@eecs.umich.edu        if (interrupts & ISR_RXORN) {
8415967Sgblack@eecs.umich.edu            totalRxOrn++;
8425967Sgblack@eecs.umich.edu        }
8435967Sgblack@eecs.umich.edu    }
8445967Sgblack@eecs.umich.edu
8455967Sgblack@eecs.umich.edu    DPRINTF(EthernetIntr,
8465967Sgblack@eecs.umich.edu            "interrupt written to ISR: intr=%#x isr=%#x imr=%#x\n",
8475238Sgblack@eecs.umich.edu            interrupts, regs.isr, regs.imr);
8485238Sgblack@eecs.umich.edu
8495238Sgblack@eecs.umich.edu    if ((regs.isr & regs.imr)) {
8504724Sgblack@eecs.umich.edu        Tick when = curTick;
8514276Sgblack@eecs.umich.edu        if ((regs.isr & regs.imr & ISR_NODELAY) == 0)
8526593Sgblack@eecs.umich.edu            when += intrDelay;
8536593Sgblack@eecs.umich.edu        postedInterrupts++;
8546593Sgblack@eecs.umich.edu        cpuIntrPost(when);
8556593Sgblack@eecs.umich.edu    }
8566593Sgblack@eecs.umich.edu}
8576593Sgblack@eecs.umich.edu
8586593Sgblack@eecs.umich.edu/* writing this interrupt counting stats inside this means that this function
8596593Sgblack@eecs.umich.edu   is now limited to being used to clear all interrupts upon the kernel
8606593Sgblack@eecs.umich.edu   reading isr and servicing.  just telling you in case you were thinking
8616593Sgblack@eecs.umich.edu   of expanding use.
8626593Sgblack@eecs.umich.edu*/
8636593Sgblack@eecs.umich.eduvoid
8646593Sgblack@eecs.umich.eduNSGigE::devIntrClear(uint32_t interrupts)
8656593Sgblack@eecs.umich.edu{
8666593Sgblack@eecs.umich.edu    if (interrupts & ISR_RESERVE)
8676593Sgblack@eecs.umich.edu        panic("Cannot clear a reserved interrupt");
8686593Sgblack@eecs.umich.edu
8695240Sgblack@eecs.umich.edu    if (regs.isr & regs.imr & ISR_SWI) {
8705240Sgblack@eecs.umich.edu        postedSwi++;
8715240Sgblack@eecs.umich.edu    }
8725240Sgblack@eecs.umich.edu    if (regs.isr & regs.imr & ISR_RXIDLE) {
8735240Sgblack@eecs.umich.edu        postedRxIdle++;
8745240Sgblack@eecs.umich.edu    }
8755240Sgblack@eecs.umich.edu    if (regs.isr & regs.imr & ISR_RXOK) {
8765240Sgblack@eecs.umich.edu        postedRxOk++;
8775240Sgblack@eecs.umich.edu    }
8785240Sgblack@eecs.umich.edu    if (regs.isr & regs.imr & ISR_RXDESC) {
8795240Sgblack@eecs.umich.edu            postedRxDesc++;
8806593Sgblack@eecs.umich.edu    }
8816593Sgblack@eecs.umich.edu    if (regs.isr & regs.imr & ISR_TXOK) {
8826593Sgblack@eecs.umich.edu        postedTxOk++;
8836593Sgblack@eecs.umich.edu    }
8846593Sgblack@eecs.umich.edu    if (regs.isr & regs.imr & ISR_TXIDLE) {
8856593Sgblack@eecs.umich.edu        postedTxIdle++;
8866593Sgblack@eecs.umich.edu    }
8876593Sgblack@eecs.umich.edu    if (regs.isr & regs.imr & ISR_TXDESC) {
8885238Sgblack@eecs.umich.edu        postedTxDesc++;
8896576Sgblack@eecs.umich.edu    }
8906576Sgblack@eecs.umich.edu    if (regs.isr & regs.imr & ISR_RXORN) {
8916576Sgblack@eecs.umich.edu        postedRxOrn++;
8926576Sgblack@eecs.umich.edu    }
8936576Sgblack@eecs.umich.edu
8946576Sgblack@eecs.umich.edu    interrupts &= ~ISR_NOIMPL;
8956576Sgblack@eecs.umich.edu    regs.isr &= ~interrupts;
8966576Sgblack@eecs.umich.edu
8976576Sgblack@eecs.umich.edu    DPRINTF(EthernetIntr,
8986576Sgblack@eecs.umich.edu            "interrupt cleared from ISR: intr=%x isr=%x imr=%x\n",
8996576Sgblack@eecs.umich.edu            interrupts, regs.isr, regs.imr);
9006576Sgblack@eecs.umich.edu
9016576Sgblack@eecs.umich.edu    if (!(regs.isr & regs.imr))
9025238Sgblack@eecs.umich.edu        cpuIntrClear();
9036576Sgblack@eecs.umich.edu}
9046576Sgblack@eecs.umich.edu
9055238Sgblack@eecs.umich.eduvoid
9066576Sgblack@eecs.umich.eduNSGigE::devIntrChangeMask()
9076576Sgblack@eecs.umich.edu{
9086576Sgblack@eecs.umich.edu    DPRINTF(EthernetIntr, "interrupt mask changed: isr=%x imr=%x masked=%x\n",
9096604Sgblack@eecs.umich.edu            regs.isr, regs.imr, regs.isr & regs.imr);
9106590Sgblack@eecs.umich.edu
9116591Sgblack@eecs.umich.edu    if (regs.isr & regs.imr)
9126591Sgblack@eecs.umich.edu        cpuIntrPost(curTick);
9136597Sgblack@eecs.umich.edu    else
9146576Sgblack@eecs.umich.edu        cpuIntrClear();
9156576Sgblack@eecs.umich.edu}
9166576Sgblack@eecs.umich.edu
9176604Sgblack@eecs.umich.eduvoid
9186576Sgblack@eecs.umich.eduNSGigE::cpuIntrPost(Tick when)
9196576Sgblack@eecs.umich.edu{
9206576Sgblack@eecs.umich.edu    // If the interrupt you want to post is later than an interrupt
9216576Sgblack@eecs.umich.edu    // already scheduled, just let it post in the coming one and don't
9226604Sgblack@eecs.umich.edu    // schedule another.
9236591Sgblack@eecs.umich.edu    // HOWEVER, must be sure that the scheduled intrTick is in the
9246591Sgblack@eecs.umich.edu    // future (this was formerly the source of a bug)
9256597Sgblack@eecs.umich.edu    /**
9266576Sgblack@eecs.umich.edu     * @todo this warning should be removed and the intrTick code should
9276576Sgblack@eecs.umich.edu     * be fixed.
9286576Sgblack@eecs.umich.edu     */
9296576Sgblack@eecs.umich.edu    assert(when >= curTick);
9306604Sgblack@eecs.umich.edu    assert(intrTick >= curTick || intrTick == 0);
9316576Sgblack@eecs.umich.edu    if (when > intrTick && intrTick != 0) {
9326576Sgblack@eecs.umich.edu        DPRINTF(EthernetIntr, "don't need to schedule event...intrTick=%d\n",
9336576Sgblack@eecs.umich.edu                intrTick);
9346576Sgblack@eecs.umich.edu        return;
9355238Sgblack@eecs.umich.edu    }
9366576Sgblack@eecs.umich.edu
9376576Sgblack@eecs.umich.edu    intrTick = when;
9386576Sgblack@eecs.umich.edu    if (intrTick < curTick) {
9396576Sgblack@eecs.umich.edu        debug_break();
9405020Sgblack@eecs.umich.edu        intrTick = curTick;
9416593Sgblack@eecs.umich.edu    }
9426593Sgblack@eecs.umich.edu
9436593Sgblack@eecs.umich.edu    DPRINTF(EthernetIntr, "going to schedule an interrupt for intrTick=%d\n",
9446593Sgblack@eecs.umich.edu            intrTick);
9456593Sgblack@eecs.umich.edu
9466593Sgblack@eecs.umich.edu    if (intrEvent)
9476593Sgblack@eecs.umich.edu        intrEvent->squash();
9486593Sgblack@eecs.umich.edu    intrEvent = new IntrEvent(this, true);
9496593Sgblack@eecs.umich.edu    schedule(intrEvent, intrTick);
9506593Sgblack@eecs.umich.edu}
9516593Sgblack@eecs.umich.edu
9526593Sgblack@eecs.umich.eduvoid
9536593Sgblack@eecs.umich.eduNSGigE::cpuInterrupt()
9546608Sgblack@eecs.umich.edu{
9556593Sgblack@eecs.umich.edu    assert(intrTick == curTick);
9566593Sgblack@eecs.umich.edu
9576593Sgblack@eecs.umich.edu    // Whether or not there's a pending interrupt, we don't care about
9586593Sgblack@eecs.umich.edu    // it anymore
9596593Sgblack@eecs.umich.edu    intrEvent = 0;
9606593Sgblack@eecs.umich.edu    intrTick = 0;
9616593Sgblack@eecs.umich.edu
9626593Sgblack@eecs.umich.edu    // Don't send an interrupt if there's already one
9636593Sgblack@eecs.umich.edu    if (cpuPendingIntr) {
9646593Sgblack@eecs.umich.edu        DPRINTF(EthernetIntr,
9656593Sgblack@eecs.umich.edu                "would send an interrupt now, but there's already pending\n");
9666593Sgblack@eecs.umich.edu    } else {
9676593Sgblack@eecs.umich.edu        // Send interrupt
9686593Sgblack@eecs.umich.edu        cpuPendingIntr = true;
9696593Sgblack@eecs.umich.edu
9706593Sgblack@eecs.umich.edu        DPRINTF(EthernetIntr, "posting interrupt\n");
9716607Sgblack@eecs.umich.edu        intrPost();
9726593Sgblack@eecs.umich.edu    }
9736593Sgblack@eecs.umich.edu}
9746593Sgblack@eecs.umich.edu
9755020Sgblack@eecs.umich.eduvoid
9766576Sgblack@eecs.umich.eduNSGigE::cpuIntrClear()
9776576Sgblack@eecs.umich.edu{
9786576Sgblack@eecs.umich.edu    if (!cpuPendingIntr)
9796580Sgblack@eecs.umich.edu        return;
9806580Sgblack@eecs.umich.edu
9816576Sgblack@eecs.umich.edu    if (intrEvent) {
9826576Sgblack@eecs.umich.edu        intrEvent->squash();
9836576Sgblack@eecs.umich.edu        intrEvent = 0;
9846576Sgblack@eecs.umich.edu    }
9856576Sgblack@eecs.umich.edu
9866576Sgblack@eecs.umich.edu    intrTick = 0;
9876576Sgblack@eecs.umich.edu
9886576Sgblack@eecs.umich.edu    cpuPendingIntr = false;
9896576Sgblack@eecs.umich.edu
9906580Sgblack@eecs.umich.edu    DPRINTF(EthernetIntr, "clearing interrupt\n");
9916580Sgblack@eecs.umich.edu    intrClear();
9926576Sgblack@eecs.umich.edu}
9936576Sgblack@eecs.umich.edu
9946576Sgblack@eecs.umich.edubool
9956576Sgblack@eecs.umich.eduNSGigE::cpuIntrPending() const
9966576Sgblack@eecs.umich.edu{ return cpuPendingIntr; }
9976576Sgblack@eecs.umich.edu
9986576Sgblack@eecs.umich.eduvoid
9996576Sgblack@eecs.umich.eduNSGigE::txReset()
10005020Sgblack@eecs.umich.edu{
10016588Sgblack@eecs.umich.edu
10026588Sgblack@eecs.umich.edu    DPRINTF(Ethernet, "transmit reset\n");
10036588Sgblack@eecs.umich.edu
10046588Sgblack@eecs.umich.edu    CTDD = false;
10056588Sgblack@eecs.umich.edu    txEnable = false;;
10066588Sgblack@eecs.umich.edu    txFragPtr = 0;
10076588Sgblack@eecs.umich.edu    assert(txDescCnt == 0);
10086588Sgblack@eecs.umich.edu    txFifo.clear();
10096588Sgblack@eecs.umich.edu    txState = txIdle;
10106588Sgblack@eecs.umich.edu    assert(txDmaState == dmaIdle);
10116588Sgblack@eecs.umich.edu}
10126588Sgblack@eecs.umich.edu
10136588Sgblack@eecs.umich.eduvoid
10146588Sgblack@eecs.umich.eduNSGigE::rxReset()
10156588Sgblack@eecs.umich.edu{
10166588Sgblack@eecs.umich.edu    DPRINTF(Ethernet, "receive reset\n");
10176588Sgblack@eecs.umich.edu
10186588Sgblack@eecs.umich.edu    CRDD = false;
10196588Sgblack@eecs.umich.edu    assert(rxPktBytes == 0);
10206588Sgblack@eecs.umich.edu    rxEnable = false;
10216588Sgblack@eecs.umich.edu    rxFragPtr = 0;
10226588Sgblack@eecs.umich.edu    assert(rxDescCnt == 0);
10236588Sgblack@eecs.umich.edu    assert(rxDmaState == dmaIdle);
10246588Sgblack@eecs.umich.edu    rxFifo.clear();
10256588Sgblack@eecs.umich.edu    rxState = rxIdle;
10266606Sgblack@eecs.umich.edu}
10276588Sgblack@eecs.umich.edu
10286588Sgblack@eecs.umich.eduvoid
10296588Sgblack@eecs.umich.eduNSGigE::regsReset()
10306588Sgblack@eecs.umich.edu{
10316606Sgblack@eecs.umich.edu    memset(&regs, 0, sizeof(regs));
10326588Sgblack@eecs.umich.edu    regs.config = (CFGR_LNKSTS | CFGR_TBI_EN | CFGR_MODE_1000);
10336588Sgblack@eecs.umich.edu    regs.mear = 0x12;
10346588Sgblack@eecs.umich.edu    regs.txcfg = 0x120; // set drain threshold to 1024 bytes and
10355022Sgblack@eecs.umich.edu                        // fill threshold to 32 bytes
10366576Sgblack@eecs.umich.edu    regs.rxcfg = 0x4;   // set drain threshold to 16 bytes
10376576Sgblack@eecs.umich.edu    regs.srr = 0x0103;  // set the silicon revision to rev B or 0x103
10386576Sgblack@eecs.umich.edu    regs.mibc = MIBC_FRZ;
10396580Sgblack@eecs.umich.edu    regs.vdr = 0x81;    // set the vlan tag type to 802.1q
10406580Sgblack@eecs.umich.edu    regs.tesr = 0xc000; // TBI capable of both full and half duplex
10416576Sgblack@eecs.umich.edu    regs.brar = 0xffffffff;
10426576Sgblack@eecs.umich.edu
10436576Sgblack@eecs.umich.edu    extstsEnable = false;
10446576Sgblack@eecs.umich.edu    acceptBroadcast = false;
10456576Sgblack@eecs.umich.edu    acceptMulticast = false;
10466576Sgblack@eecs.umich.edu    acceptUnicast = false;
10476576Sgblack@eecs.umich.edu    acceptPerfect = false;
10486576Sgblack@eecs.umich.edu    acceptArp = false;
10496576Sgblack@eecs.umich.edu}
10506580Sgblack@eecs.umich.edu
10516580Sgblack@eecs.umich.edubool
10526576Sgblack@eecs.umich.eduNSGigE::doRxDmaRead()
10536576Sgblack@eecs.umich.edu{
10546576Sgblack@eecs.umich.edu    assert(rxDmaState == dmaIdle || rxDmaState == dmaReadWaiting);
10556576Sgblack@eecs.umich.edu    rxDmaState = dmaReading;
10566576Sgblack@eecs.umich.edu
10576576Sgblack@eecs.umich.edu    if (dmaPending() || getState() != Running)
10586576Sgblack@eecs.umich.edu        rxDmaState = dmaReadWaiting;
10596576Sgblack@eecs.umich.edu    else
10605020Sgblack@eecs.umich.edu        dmaRead(rxDmaAddr, rxDmaLen, &rxDmaReadEvent, (uint8_t*)rxDmaData);
10616586Sgblack@eecs.umich.edu
10626586Sgblack@eecs.umich.edu    return true;
10636586Sgblack@eecs.umich.edu}
10646586Sgblack@eecs.umich.edu
10656586Sgblack@eecs.umich.eduvoid
10666586Sgblack@eecs.umich.eduNSGigE::rxDmaReadDone()
10676586Sgblack@eecs.umich.edu{
10686586Sgblack@eecs.umich.edu    assert(rxDmaState == dmaReading);
10696586Sgblack@eecs.umich.edu    rxDmaState = dmaIdle;
10706595Sgblack@eecs.umich.edu
10716586Sgblack@eecs.umich.edu    DPRINTF(EthernetDMA, "rx dma read  paddr=%#x len=%d\n",
10726586Sgblack@eecs.umich.edu            rxDmaAddr, rxDmaLen);
10736586Sgblack@eecs.umich.edu    DDUMP(EthernetDMA, rxDmaData, rxDmaLen);
10746586Sgblack@eecs.umich.edu
10756586Sgblack@eecs.umich.edu    // If the transmit state machine has a pending DMA, let it go first
10766586Sgblack@eecs.umich.edu    if (txDmaState == dmaReadWaiting || txDmaState == dmaWriteWaiting)
10776586Sgblack@eecs.umich.edu        txKick();
10786586Sgblack@eecs.umich.edu
10796586Sgblack@eecs.umich.edu    rxKick();
10806586Sgblack@eecs.umich.edu}
10816595Sgblack@eecs.umich.edu
10826586Sgblack@eecs.umich.edubool
10836586Sgblack@eecs.umich.eduNSGigE::doRxDmaWrite()
10846586Sgblack@eecs.umich.edu{
10856586Sgblack@eecs.umich.edu    assert(rxDmaState == dmaIdle || rxDmaState == dmaWriteWaiting);
10866586Sgblack@eecs.umich.edu    rxDmaState = dmaWriting;
10876586Sgblack@eecs.umich.edu
10886586Sgblack@eecs.umich.edu    if (dmaPending() || getState() != Running)
10896586Sgblack@eecs.umich.edu        rxDmaState = dmaWriteWaiting;
10905022Sgblack@eecs.umich.edu    else
10916576Sgblack@eecs.umich.edu        dmaWrite(rxDmaAddr, rxDmaLen, &rxDmaWriteEvent, (uint8_t*)rxDmaData);
10926576Sgblack@eecs.umich.edu    return true;
10936576Sgblack@eecs.umich.edu}
10946580Sgblack@eecs.umich.edu
10956580Sgblack@eecs.umich.eduvoid
10966580Sgblack@eecs.umich.eduNSGigE::rxDmaWriteDone()
10976580Sgblack@eecs.umich.edu{
10986576Sgblack@eecs.umich.edu    assert(rxDmaState == dmaWriting);
10996576Sgblack@eecs.umich.edu    rxDmaState = dmaIdle;
11006576Sgblack@eecs.umich.edu
11016576Sgblack@eecs.umich.edu    DPRINTF(EthernetDMA, "rx dma write paddr=%#x len=%d\n",
11026576Sgblack@eecs.umich.edu            rxDmaAddr, rxDmaLen);
11036576Sgblack@eecs.umich.edu    DDUMP(EthernetDMA, rxDmaData, rxDmaLen);
11046576Sgblack@eecs.umich.edu
11056580Sgblack@eecs.umich.edu    // If the transmit state machine has a pending DMA, let it go first
11066580Sgblack@eecs.umich.edu    if (txDmaState == dmaReadWaiting || txDmaState == dmaWriteWaiting)
11076580Sgblack@eecs.umich.edu        txKick();
11086580Sgblack@eecs.umich.edu
11096576Sgblack@eecs.umich.edu    rxKick();
11106576Sgblack@eecs.umich.edu}
11116576Sgblack@eecs.umich.edu
11126576Sgblack@eecs.umich.eduvoid
11136576Sgblack@eecs.umich.eduNSGigE::rxKick()
11146576Sgblack@eecs.umich.edu{
11155020Sgblack@eecs.umich.edu    bool is64bit = (bool)(regs.config & CFGR_M64ADDR);
11164276Sgblack@eecs.umich.edu
11174276Sgblack@eecs.umich.edu    DPRINTF(EthernetSM,
11184276Sgblack@eecs.umich.edu            "receive kick rxState=%s (rxBuf.size=%d) %d-bit\n",
11194276Sgblack@eecs.umich.edu            NsRxStateStrings[rxState], rxFifo.size(), is64bit ? 64 : 32);
11204276Sgblack@eecs.umich.edu
11214276Sgblack@eecs.umich.edu    Addr link, bufptr;
11224276Sgblack@eecs.umich.edu    uint32_t &cmdsts = is64bit ? rxDesc64.cmdsts : rxDesc32.cmdsts;
1123    uint32_t &extsts = is64bit ? rxDesc64.extsts : rxDesc32.extsts;
1124
1125  next:
1126    if (clock) {
1127        if (rxKickTick > curTick) {
1128            DPRINTF(EthernetSM, "receive kick exiting, can't run till %d\n",
1129                    rxKickTick);
1130
1131            goto exit;
1132        }
1133
1134        // Go to the next state machine clock tick.
1135        rxKickTick = curTick + ticks(1);
1136    }
1137
1138    switch(rxDmaState) {
1139      case dmaReadWaiting:
1140        if (doRxDmaRead())
1141            goto exit;
1142        break;
1143      case dmaWriteWaiting:
1144        if (doRxDmaWrite())
1145            goto exit;
1146        break;
1147      default:
1148        break;
1149    }
1150
1151    link = is64bit ? (Addr)rxDesc64.link : (Addr)rxDesc32.link;
1152    bufptr = is64bit ? (Addr)rxDesc64.bufptr : (Addr)rxDesc32.bufptr;
1153
1154    // see state machine from spec for details
1155    // the way this works is, if you finish work on one state and can
1156    // go directly to another, you do that through jumping to the
1157    // label "next".  however, if you have intermediate work, like DMA
1158    // so that you can't go to the next state yet, you go to exit and
1159    // exit the loop.  however, when the DMA is done it will trigger
1160    // an event and come back to this loop.
1161    switch (rxState) {
1162      case rxIdle:
1163        if (!rxEnable) {
1164            DPRINTF(EthernetSM, "Receive Disabled! Nothing to do.\n");
1165            goto exit;
1166        }
1167
1168        if (CRDD) {
1169            rxState = rxDescRefr;
1170
1171            rxDmaAddr = regs.rxdp & 0x3fffffff;
1172            rxDmaData =
1173                is64bit ? (void *)&rxDesc64.link : (void *)&rxDesc32.link;
1174            rxDmaLen = is64bit ? sizeof(rxDesc64.link) : sizeof(rxDesc32.link);
1175            rxDmaFree = dmaDescFree;
1176
1177            descDmaReads++;
1178            descDmaRdBytes += rxDmaLen;
1179
1180            if (doRxDmaRead())
1181                goto exit;
1182        } else {
1183            rxState = rxDescRead;
1184
1185            rxDmaAddr = regs.rxdp & 0x3fffffff;
1186            rxDmaData = is64bit ? (void *)&rxDesc64 : (void *)&rxDesc32;
1187            rxDmaLen = is64bit ? sizeof(rxDesc64) : sizeof(rxDesc32);
1188            rxDmaFree = dmaDescFree;
1189
1190            descDmaReads++;
1191            descDmaRdBytes += rxDmaLen;
1192
1193            if (doRxDmaRead())
1194                goto exit;
1195        }
1196        break;
1197
1198      case rxDescRefr:
1199        if (rxDmaState != dmaIdle)
1200            goto exit;
1201
1202        rxState = rxAdvance;
1203        break;
1204
1205     case rxDescRead:
1206        if (rxDmaState != dmaIdle)
1207            goto exit;
1208
1209        DPRINTF(EthernetDesc, "rxDesc: addr=%08x read descriptor\n",
1210                regs.rxdp & 0x3fffffff);
1211        DPRINTF(EthernetDesc,
1212                "rxDesc: link=%#x bufptr=%#x cmdsts=%08x extsts=%08x\n",
1213                link, bufptr, cmdsts, extsts);
1214
1215        if (cmdsts & CMDSTS_OWN) {
1216            devIntrPost(ISR_RXIDLE);
1217            rxState = rxIdle;
1218            goto exit;
1219        } else {
1220            rxState = rxFifoBlock;
1221            rxFragPtr = bufptr;
1222            rxDescCnt = cmdsts & CMDSTS_LEN_MASK;
1223        }
1224        break;
1225
1226      case rxFifoBlock:
1227        if (!rxPacket) {
1228            /**
1229             * @todo in reality, we should be able to start processing
1230             * the packet as it arrives, and not have to wait for the
1231             * full packet ot be in the receive fifo.
1232             */
1233            if (rxFifo.empty())
1234                goto exit;
1235
1236            DPRINTF(EthernetSM, "****processing receive of new packet****\n");
1237
1238            // If we don't have a packet, grab a new one from the fifo.
1239            rxPacket = rxFifo.front();
1240            rxPktBytes = rxPacket->length;
1241            rxPacketBufPtr = rxPacket->data;
1242
1243#if TRACING_ON
1244            if (DTRACE(Ethernet)) {
1245                IpPtr ip(rxPacket);
1246                if (ip) {
1247                    DPRINTF(Ethernet, "ID is %d\n", ip->id());
1248                    TcpPtr tcp(ip);
1249                    if (tcp) {
1250                        DPRINTF(Ethernet,
1251                                "Src Port=%d, Dest Port=%d, Seq=%d, Ack=%d\n",
1252                                tcp->sport(), tcp->dport(), tcp->seq(),
1253                                tcp->ack());
1254                    }
1255                }
1256            }
1257#endif
1258
1259            // sanity check - i think the driver behaves like this
1260            assert(rxDescCnt >= rxPktBytes);
1261            rxFifo.pop();
1262        }
1263
1264
1265        // dont' need the && rxDescCnt > 0 if driver sanity check
1266        // above holds
1267        if (rxPktBytes > 0) {
1268            rxState = rxFragWrite;
1269            // don't need min<>(rxPktBytes,rxDescCnt) if above sanity
1270            // check holds
1271            rxXferLen = rxPktBytes;
1272
1273            rxDmaAddr = rxFragPtr & 0x3fffffff;
1274            rxDmaData = rxPacketBufPtr;
1275            rxDmaLen = rxXferLen;
1276            rxDmaFree = dmaDataFree;
1277
1278            if (doRxDmaWrite())
1279                goto exit;
1280
1281        } else {
1282            rxState = rxDescWrite;
1283
1284            //if (rxPktBytes == 0) {  /* packet is done */
1285            assert(rxPktBytes == 0);
1286            DPRINTF(EthernetSM, "done with receiving packet\n");
1287
1288            cmdsts |= CMDSTS_OWN;
1289            cmdsts &= ~CMDSTS_MORE;
1290            cmdsts |= CMDSTS_OK;
1291            cmdsts &= 0xffff0000;
1292            cmdsts += rxPacket->length;   //i.e. set CMDSTS_SIZE
1293
1294#if 0
1295            /*
1296             * all the driver uses these are for its own stats keeping
1297             * which we don't care about, aren't necessary for
1298             * functionality and doing this would just slow us down.
1299             * if they end up using this in a later version for
1300             * functional purposes, just undef
1301             */
1302            if (rxFilterEnable) {
1303                cmdsts &= ~CMDSTS_DEST_MASK;
1304                const EthAddr &dst = rxFifoFront()->dst();
1305                if (dst->unicast())
1306                    cmdsts |= CMDSTS_DEST_SELF;
1307                if (dst->multicast())
1308                    cmdsts |= CMDSTS_DEST_MULTI;
1309                if (dst->broadcast())
1310                    cmdsts |= CMDSTS_DEST_MASK;
1311            }
1312#endif
1313
1314            IpPtr ip(rxPacket);
1315            if (extstsEnable && ip) {
1316                extsts |= EXTSTS_IPPKT;
1317                rxIpChecksums++;
1318                if (cksum(ip) != 0) {
1319                    DPRINTF(EthernetCksum, "Rx IP Checksum Error\n");
1320                    extsts |= EXTSTS_IPERR;
1321                }
1322                TcpPtr tcp(ip);
1323                UdpPtr udp(ip);
1324                if (tcp) {
1325                    extsts |= EXTSTS_TCPPKT;
1326                    rxTcpChecksums++;
1327                    if (cksum(tcp) != 0) {
1328                        DPRINTF(EthernetCksum, "Rx TCP Checksum Error\n");
1329                        extsts |= EXTSTS_TCPERR;
1330
1331                    }
1332                } else if (udp) {
1333                    extsts |= EXTSTS_UDPPKT;
1334                    rxUdpChecksums++;
1335                    if (cksum(udp) != 0) {
1336                        DPRINTF(EthernetCksum, "Rx UDP Checksum Error\n");
1337                        extsts |= EXTSTS_UDPERR;
1338                    }
1339                }
1340            }
1341            rxPacket = 0;
1342
1343            /*
1344             * the driver seems to always receive into desc buffers
1345             * of size 1514, so you never have a pkt that is split
1346             * into multiple descriptors on the receive side, so
1347             * i don't implement that case, hence the assert above.
1348             */
1349
1350            DPRINTF(EthernetDesc,
1351                    "rxDesc: addr=%08x writeback cmdsts extsts\n",
1352                    regs.rxdp & 0x3fffffff);
1353            DPRINTF(EthernetDesc,
1354                    "rxDesc: link=%#x bufptr=%#x cmdsts=%08x extsts=%08x\n",
1355                    link, bufptr, cmdsts, extsts);
1356
1357            rxDmaAddr = regs.rxdp & 0x3fffffff;
1358            rxDmaData = &cmdsts;
1359            if (is64bit) {
1360                rxDmaAddr += offsetof(ns_desc64, cmdsts);
1361                rxDmaLen = sizeof(rxDesc64.cmdsts) + sizeof(rxDesc64.extsts);
1362            } else {
1363                rxDmaAddr += offsetof(ns_desc32, cmdsts);
1364                rxDmaLen = sizeof(rxDesc32.cmdsts) + sizeof(rxDesc32.extsts);
1365            }
1366            rxDmaFree = dmaDescFree;
1367
1368            descDmaWrites++;
1369            descDmaWrBytes += rxDmaLen;
1370
1371            if (doRxDmaWrite())
1372                goto exit;
1373        }
1374        break;
1375
1376      case rxFragWrite:
1377        if (rxDmaState != dmaIdle)
1378            goto exit;
1379
1380        rxPacketBufPtr += rxXferLen;
1381        rxFragPtr += rxXferLen;
1382        rxPktBytes -= rxXferLen;
1383
1384        rxState = rxFifoBlock;
1385        break;
1386
1387      case rxDescWrite:
1388        if (rxDmaState != dmaIdle)
1389            goto exit;
1390
1391        assert(cmdsts & CMDSTS_OWN);
1392
1393        assert(rxPacket == 0);
1394        devIntrPost(ISR_RXOK);
1395
1396        if (cmdsts & CMDSTS_INTR)
1397            devIntrPost(ISR_RXDESC);
1398
1399        if (!rxEnable) {
1400            DPRINTF(EthernetSM, "Halting the RX state machine\n");
1401            rxState = rxIdle;
1402            goto exit;
1403        } else
1404            rxState = rxAdvance;
1405        break;
1406
1407      case rxAdvance:
1408        if (link == 0) {
1409            devIntrPost(ISR_RXIDLE);
1410            rxState = rxIdle;
1411            CRDD = true;
1412            goto exit;
1413        } else {
1414            if (rxDmaState != dmaIdle)
1415                goto exit;
1416            rxState = rxDescRead;
1417            regs.rxdp = link;
1418            CRDD = false;
1419
1420            rxDmaAddr = regs.rxdp & 0x3fffffff;
1421            rxDmaData = is64bit ? (void *)&rxDesc64 : (void *)&rxDesc32;
1422            rxDmaLen = is64bit ? sizeof(rxDesc64) : sizeof(rxDesc32);
1423            rxDmaFree = dmaDescFree;
1424
1425            if (doRxDmaRead())
1426                goto exit;
1427        }
1428        break;
1429
1430      default:
1431        panic("Invalid rxState!");
1432    }
1433
1434    DPRINTF(EthernetSM, "entering next rxState=%s\n",
1435            NsRxStateStrings[rxState]);
1436    goto next;
1437
1438  exit:
1439    /**
1440     * @todo do we want to schedule a future kick?
1441     */
1442    DPRINTF(EthernetSM, "rx state machine exited rxState=%s\n",
1443            NsRxStateStrings[rxState]);
1444
1445    if (clock && !rxKickEvent.scheduled())
1446        schedule(rxKickEvent, rxKickTick);
1447}
1448
1449void
1450NSGigE::transmit()
1451{
1452    if (txFifo.empty()) {
1453        DPRINTF(Ethernet, "nothing to transmit\n");
1454        return;
1455    }
1456
1457    DPRINTF(Ethernet, "Attempt Pkt Transmit: txFifo length=%d\n",
1458            txFifo.size());
1459    if (interface->sendPacket(txFifo.front())) {
1460#if TRACING_ON
1461        if (DTRACE(Ethernet)) {
1462            IpPtr ip(txFifo.front());
1463            if (ip) {
1464                DPRINTF(Ethernet, "ID is %d\n", ip->id());
1465                TcpPtr tcp(ip);
1466                if (tcp) {
1467                    DPRINTF(Ethernet,
1468                            "Src Port=%d, Dest Port=%d, Seq=%d, Ack=%d\n",
1469                            tcp->sport(), tcp->dport(), tcp->seq(),
1470                            tcp->ack());
1471                }
1472            }
1473        }
1474#endif
1475
1476        DDUMP(EthernetData, txFifo.front()->data, txFifo.front()->length);
1477        txBytes += txFifo.front()->length;
1478        txPackets++;
1479
1480        DPRINTF(Ethernet, "Successful Xmit! now txFifoAvail is %d\n",
1481                txFifo.avail());
1482        txFifo.pop();
1483
1484        /*
1485         * normally do a writeback of the descriptor here, and ONLY
1486         * after that is done, send this interrupt.  but since our
1487         * stuff never actually fails, just do this interrupt here,
1488         * otherwise the code has to stray from this nice format.
1489         * besides, it's functionally the same.
1490         */
1491        devIntrPost(ISR_TXOK);
1492    }
1493
1494   if (!txFifo.empty() && !txEvent.scheduled()) {
1495       DPRINTF(Ethernet, "reschedule transmit\n");
1496       schedule(txEvent, curTick + retryTime);
1497   }
1498}
1499
1500bool
1501NSGigE::doTxDmaRead()
1502{
1503    assert(txDmaState == dmaIdle || txDmaState == dmaReadWaiting);
1504    txDmaState = dmaReading;
1505
1506    if (dmaPending() || getState() != Running)
1507        txDmaState = dmaReadWaiting;
1508    else
1509        dmaRead(txDmaAddr, txDmaLen, &txDmaReadEvent, (uint8_t*)txDmaData);
1510
1511    return true;
1512}
1513
1514void
1515NSGigE::txDmaReadDone()
1516{
1517    assert(txDmaState == dmaReading);
1518    txDmaState = dmaIdle;
1519
1520    DPRINTF(EthernetDMA, "tx dma read  paddr=%#x len=%d\n",
1521            txDmaAddr, txDmaLen);
1522    DDUMP(EthernetDMA, txDmaData, txDmaLen);
1523
1524    // If the receive state machine  has a pending DMA, let it go first
1525    if (rxDmaState == dmaReadWaiting || rxDmaState == dmaWriteWaiting)
1526        rxKick();
1527
1528    txKick();
1529}
1530
1531bool
1532NSGigE::doTxDmaWrite()
1533{
1534    assert(txDmaState == dmaIdle || txDmaState == dmaWriteWaiting);
1535    txDmaState = dmaWriting;
1536
1537    if (dmaPending() || getState() != Running)
1538        txDmaState = dmaWriteWaiting;
1539    else
1540        dmaWrite(txDmaAddr, txDmaLen, &txDmaWriteEvent, (uint8_t*)txDmaData);
1541    return true;
1542}
1543
1544void
1545NSGigE::txDmaWriteDone()
1546{
1547    assert(txDmaState == dmaWriting);
1548    txDmaState = dmaIdle;
1549
1550    DPRINTF(EthernetDMA, "tx dma write paddr=%#x len=%d\n",
1551            txDmaAddr, txDmaLen);
1552    DDUMP(EthernetDMA, txDmaData, txDmaLen);
1553
1554    // If the receive state machine  has a pending DMA, let it go first
1555    if (rxDmaState == dmaReadWaiting || rxDmaState == dmaWriteWaiting)
1556        rxKick();
1557
1558    txKick();
1559}
1560
1561void
1562NSGigE::txKick()
1563{
1564    bool is64bit = (bool)(regs.config & CFGR_M64ADDR);
1565
1566    DPRINTF(EthernetSM, "transmit kick txState=%s %d-bit\n",
1567            NsTxStateStrings[txState], is64bit ? 64 : 32);
1568
1569    Addr link, bufptr;
1570    uint32_t &cmdsts = is64bit ? txDesc64.cmdsts : txDesc32.cmdsts;
1571    uint32_t &extsts = is64bit ? txDesc64.extsts : txDesc32.extsts;
1572
1573  next:
1574    if (clock) {
1575        if (txKickTick > curTick) {
1576            DPRINTF(EthernetSM, "transmit kick exiting, can't run till %d\n",
1577                    txKickTick);
1578            goto exit;
1579        }
1580
1581        // Go to the next state machine clock tick.
1582        txKickTick = curTick + ticks(1);
1583    }
1584
1585    switch(txDmaState) {
1586      case dmaReadWaiting:
1587        if (doTxDmaRead())
1588            goto exit;
1589        break;
1590      case dmaWriteWaiting:
1591        if (doTxDmaWrite())
1592            goto exit;
1593        break;
1594      default:
1595        break;
1596    }
1597
1598    link = is64bit ? (Addr)txDesc64.link : (Addr)txDesc32.link;
1599    bufptr = is64bit ? (Addr)txDesc64.bufptr : (Addr)txDesc32.bufptr;
1600    switch (txState) {
1601      case txIdle:
1602        if (!txEnable) {
1603            DPRINTF(EthernetSM, "Transmit disabled.  Nothing to do.\n");
1604            goto exit;
1605        }
1606
1607        if (CTDD) {
1608            txState = txDescRefr;
1609
1610            txDmaAddr = regs.txdp & 0x3fffffff;
1611            txDmaData =
1612                is64bit ? (void *)&txDesc64.link : (void *)&txDesc32.link;
1613            txDmaLen = is64bit ? sizeof(txDesc64.link) : sizeof(txDesc32.link);
1614            txDmaFree = dmaDescFree;
1615
1616            descDmaReads++;
1617            descDmaRdBytes += txDmaLen;
1618
1619            if (doTxDmaRead())
1620                goto exit;
1621
1622        } else {
1623            txState = txDescRead;
1624
1625            txDmaAddr = regs.txdp & 0x3fffffff;
1626            txDmaData = is64bit ? (void *)&txDesc64 : (void *)&txDesc32;
1627            txDmaLen = is64bit ? sizeof(txDesc64) : sizeof(txDesc32);
1628            txDmaFree = dmaDescFree;
1629
1630            descDmaReads++;
1631            descDmaRdBytes += txDmaLen;
1632
1633            if (doTxDmaRead())
1634                goto exit;
1635        }
1636        break;
1637
1638      case txDescRefr:
1639        if (txDmaState != dmaIdle)
1640            goto exit;
1641
1642        txState = txAdvance;
1643        break;
1644
1645      case txDescRead:
1646        if (txDmaState != dmaIdle)
1647            goto exit;
1648
1649        DPRINTF(EthernetDesc, "txDesc: addr=%08x read descriptor\n",
1650                regs.txdp & 0x3fffffff);
1651        DPRINTF(EthernetDesc,
1652                "txDesc: link=%#x bufptr=%#x cmdsts=%#08x extsts=%#08x\n",
1653                link, bufptr, cmdsts, extsts);
1654
1655        if (cmdsts & CMDSTS_OWN) {
1656            txState = txFifoBlock;
1657            txFragPtr = bufptr;
1658            txDescCnt = cmdsts & CMDSTS_LEN_MASK;
1659        } else {
1660            devIntrPost(ISR_TXIDLE);
1661            txState = txIdle;
1662            goto exit;
1663        }
1664        break;
1665
1666      case txFifoBlock:
1667        if (!txPacket) {
1668            DPRINTF(EthernetSM, "****starting the tx of a new packet****\n");
1669            txPacket = new EthPacketData(16384);
1670            txPacketBufPtr = txPacket->data;
1671        }
1672
1673        if (txDescCnt == 0) {
1674            DPRINTF(EthernetSM, "the txDescCnt == 0, done with descriptor\n");
1675            if (cmdsts & CMDSTS_MORE) {
1676                DPRINTF(EthernetSM, "there are more descriptors to come\n");
1677                txState = txDescWrite;
1678
1679                cmdsts &= ~CMDSTS_OWN;
1680
1681                txDmaAddr = regs.txdp & 0x3fffffff;
1682                txDmaData = &cmdsts;
1683                if (is64bit) {
1684                    txDmaAddr += offsetof(ns_desc64, cmdsts);
1685                    txDmaLen = sizeof(txDesc64.cmdsts);
1686                } else {
1687                    txDmaAddr += offsetof(ns_desc32, cmdsts);
1688                    txDmaLen = sizeof(txDesc32.cmdsts);
1689                }
1690                txDmaFree = dmaDescFree;
1691
1692                if (doTxDmaWrite())
1693                    goto exit;
1694
1695            } else { /* this packet is totally done */
1696                DPRINTF(EthernetSM, "This packet is done, let's wrap it up\n");
1697                /* deal with the the packet that just finished */
1698                if ((regs.vtcr & VTCR_PPCHK) && extstsEnable) {
1699                    IpPtr ip(txPacket);
1700                    if (extsts & EXTSTS_UDPPKT) {
1701                        UdpPtr udp(ip);
1702                        if (udp) {
1703                            udp->sum(0);
1704                            udp->sum(cksum(udp));
1705                            txUdpChecksums++;
1706                        } else {
1707                            debug_break();
1708                            warn_once("UDPPKT set, but not UDP!\n");
1709                        }
1710                    } else if (extsts & EXTSTS_TCPPKT) {
1711                        TcpPtr tcp(ip);
1712                        if (tcp) {
1713                            tcp->sum(0);
1714                            tcp->sum(cksum(tcp));
1715                            txTcpChecksums++;
1716                        } else {
1717                            debug_break();
1718                            warn_once("TCPPKT set, but not UDP!\n");
1719                        }
1720                    }
1721                    if (extsts & EXTSTS_IPPKT) {
1722                        if (ip) {
1723                            ip->sum(0);
1724                            ip->sum(cksum(ip));
1725                            txIpChecksums++;
1726                        } else {
1727                            debug_break();
1728                            warn_once("IPPKT set, but not UDP!\n");
1729                        }
1730                    }
1731                }
1732
1733                txPacket->length = txPacketBufPtr - txPacket->data;
1734                // this is just because the receive can't handle a
1735                // packet bigger want to make sure
1736                if (txPacket->length > 1514)
1737                    panic("transmit packet too large, %s > 1514\n",
1738                          txPacket->length);
1739
1740#ifndef NDEBUG
1741                bool success =
1742#endif
1743                    txFifo.push(txPacket);
1744                assert(success);
1745
1746                /*
1747                 * this following section is not tqo spec, but
1748                 * functionally shouldn't be any different.  normally,
1749                 * the chip will wait til the transmit has occurred
1750                 * before writing back the descriptor because it has
1751                 * to wait to see that it was successfully transmitted
1752                 * to decide whether to set CMDSTS_OK or not.
1753                 * however, in the simulator since it is always
1754                 * successfully transmitted, and writing it exactly to
1755                 * spec would complicate the code, we just do it here
1756                 */
1757
1758                cmdsts &= ~CMDSTS_OWN;
1759                cmdsts |= CMDSTS_OK;
1760
1761                DPRINTF(EthernetDesc,
1762                        "txDesc writeback: cmdsts=%08x extsts=%08x\n",
1763                        cmdsts, extsts);
1764
1765                txDmaFree = dmaDescFree;
1766                txDmaAddr = regs.txdp & 0x3fffffff;
1767                txDmaData = &cmdsts;
1768                if (is64bit) {
1769                    txDmaAddr += offsetof(ns_desc64, cmdsts);
1770                    txDmaLen =
1771                        sizeof(txDesc64.cmdsts) + sizeof(txDesc64.extsts);
1772                } else {
1773                    txDmaAddr += offsetof(ns_desc32, cmdsts);
1774                    txDmaLen =
1775                        sizeof(txDesc32.cmdsts) + sizeof(txDesc32.extsts);
1776                }
1777
1778                descDmaWrites++;
1779                descDmaWrBytes += txDmaLen;
1780
1781                transmit();
1782                txPacket = 0;
1783
1784                if (!txEnable) {
1785                    DPRINTF(EthernetSM, "halting TX state machine\n");
1786                    txState = txIdle;
1787                    goto exit;
1788                } else
1789                    txState = txAdvance;
1790
1791                if (doTxDmaWrite())
1792                    goto exit;
1793            }
1794        } else {
1795            DPRINTF(EthernetSM, "this descriptor isn't done yet\n");
1796            if (!txFifo.full()) {
1797                txState = txFragRead;
1798
1799                /*
1800                 * The number of bytes transferred is either whatever
1801                 * is left in the descriptor (txDescCnt), or if there
1802                 * is not enough room in the fifo, just whatever room
1803                 * is left in the fifo
1804                 */
1805                txXferLen = min<uint32_t>(txDescCnt, txFifo.avail());
1806
1807                txDmaAddr = txFragPtr & 0x3fffffff;
1808                txDmaData = txPacketBufPtr;
1809                txDmaLen = txXferLen;
1810                txDmaFree = dmaDataFree;
1811
1812                if (doTxDmaRead())
1813                    goto exit;
1814            } else {
1815                txState = txFifoBlock;
1816                transmit();
1817
1818                goto exit;
1819            }
1820
1821        }
1822        break;
1823
1824      case txFragRead:
1825        if (txDmaState != dmaIdle)
1826            goto exit;
1827
1828        txPacketBufPtr += txXferLen;
1829        txFragPtr += txXferLen;
1830        txDescCnt -= txXferLen;
1831        txFifo.reserve(txXferLen);
1832
1833        txState = txFifoBlock;
1834        break;
1835
1836      case txDescWrite:
1837        if (txDmaState != dmaIdle)
1838            goto exit;
1839
1840        if (cmdsts & CMDSTS_INTR)
1841            devIntrPost(ISR_TXDESC);
1842
1843        if (!txEnable) {
1844            DPRINTF(EthernetSM, "halting TX state machine\n");
1845            txState = txIdle;
1846            goto exit;
1847        } else
1848            txState = txAdvance;
1849        break;
1850
1851      case txAdvance:
1852        if (link == 0) {
1853            devIntrPost(ISR_TXIDLE);
1854            txState = txIdle;
1855            goto exit;
1856        } else {
1857            if (txDmaState != dmaIdle)
1858                goto exit;
1859            txState = txDescRead;
1860            regs.txdp = link;
1861            CTDD = false;
1862
1863            txDmaAddr = link & 0x3fffffff;
1864            txDmaData = is64bit ? (void *)&txDesc64 : (void *)&txDesc32;
1865            txDmaLen = is64bit ? sizeof(txDesc64) : sizeof(txDesc32);
1866            txDmaFree = dmaDescFree;
1867
1868            if (doTxDmaRead())
1869                goto exit;
1870        }
1871        break;
1872
1873      default:
1874        panic("invalid state");
1875    }
1876
1877    DPRINTF(EthernetSM, "entering next txState=%s\n",
1878            NsTxStateStrings[txState]);
1879    goto next;
1880
1881  exit:
1882    /**
1883     * @todo do we want to schedule a future kick?
1884     */
1885    DPRINTF(EthernetSM, "tx state machine exited txState=%s\n",
1886            NsTxStateStrings[txState]);
1887
1888    if (clock && !txKickEvent.scheduled())
1889        schedule(txKickEvent, txKickTick);
1890}
1891
1892/**
1893 * Advance the EEPROM state machine
1894 * Called on rising edge of EEPROM clock bit in MEAR
1895 */
1896void
1897NSGigE::eepromKick()
1898{
1899    switch (eepromState) {
1900
1901      case eepromStart:
1902
1903        // Wait for start bit
1904        if (regs.mear & MEAR_EEDI) {
1905            // Set up to get 2 opcode bits
1906            eepromState = eepromGetOpcode;
1907            eepromBitsToRx = 2;
1908            eepromOpcode = 0;
1909        }
1910        break;
1911
1912      case eepromGetOpcode:
1913        eepromOpcode <<= 1;
1914        eepromOpcode += (regs.mear & MEAR_EEDI) ? 1 : 0;
1915        --eepromBitsToRx;
1916
1917        // Done getting opcode
1918        if (eepromBitsToRx == 0) {
1919            if (eepromOpcode != EEPROM_READ)
1920                panic("only EEPROM reads are implemented!");
1921
1922            // Set up to get address
1923            eepromState = eepromGetAddress;
1924            eepromBitsToRx = 6;
1925            eepromAddress = 0;
1926        }
1927        break;
1928
1929      case eepromGetAddress:
1930        eepromAddress <<= 1;
1931        eepromAddress += (regs.mear & MEAR_EEDI) ? 1 : 0;
1932        --eepromBitsToRx;
1933
1934        // Done getting address
1935        if (eepromBitsToRx == 0) {
1936
1937            if (eepromAddress >= EEPROM_SIZE)
1938                panic("EEPROM read access out of range!");
1939
1940            switch (eepromAddress) {
1941
1942              case EEPROM_PMATCH2_ADDR:
1943                eepromData = rom.perfectMatch[5];
1944                eepromData <<= 8;
1945                eepromData += rom.perfectMatch[4];
1946                break;
1947
1948              case EEPROM_PMATCH1_ADDR:
1949                eepromData = rom.perfectMatch[3];
1950                eepromData <<= 8;
1951                eepromData += rom.perfectMatch[2];
1952                break;
1953
1954              case EEPROM_PMATCH0_ADDR:
1955                eepromData = rom.perfectMatch[1];
1956                eepromData <<= 8;
1957                eepromData += rom.perfectMatch[0];
1958                break;
1959
1960              default:
1961                panic("FreeBSD driver only uses EEPROM to read PMATCH!");
1962            }
1963            // Set up to read data
1964            eepromState = eepromRead;
1965            eepromBitsToRx = 16;
1966
1967            // Clear data in bit
1968            regs.mear &= ~MEAR_EEDI;
1969        }
1970        break;
1971
1972      case eepromRead:
1973        // Clear Data Out bit
1974        regs.mear &= ~MEAR_EEDO;
1975        // Set bit to value of current EEPROM bit
1976        regs.mear |= (eepromData & 0x8000) ? MEAR_EEDO : 0x0;
1977
1978        eepromData <<= 1;
1979        --eepromBitsToRx;
1980
1981        // All done
1982        if (eepromBitsToRx == 0) {
1983            eepromState = eepromStart;
1984        }
1985        break;
1986
1987      default:
1988        panic("invalid EEPROM state");
1989    }
1990
1991}
1992
1993void
1994NSGigE::transferDone()
1995{
1996    if (txFifo.empty()) {
1997        DPRINTF(Ethernet, "transfer complete: txFifo empty...nothing to do\n");
1998        return;
1999    }
2000
2001    DPRINTF(Ethernet, "transfer complete: data in txFifo...schedule xmit\n");
2002
2003    reschedule(txEvent, curTick + ticks(1), true);
2004}
2005
2006bool
2007NSGigE::rxFilter(const EthPacketPtr &packet)
2008{
2009    EthPtr eth = packet;
2010    bool drop = true;
2011    string type;
2012
2013    const EthAddr &dst = eth->dst();
2014    if (dst.unicast()) {
2015        // If we're accepting all unicast addresses
2016        if (acceptUnicast)
2017            drop = false;
2018
2019        // If we make a perfect match
2020        if (acceptPerfect && dst == rom.perfectMatch)
2021            drop = false;
2022
2023        if (acceptArp && eth->type() == ETH_TYPE_ARP)
2024            drop = false;
2025
2026    } else if (dst.broadcast()) {
2027        // if we're accepting broadcasts
2028        if (acceptBroadcast)
2029            drop = false;
2030
2031    } else if (dst.multicast()) {
2032        // if we're accepting all multicasts
2033        if (acceptMulticast)
2034            drop = false;
2035
2036        // Multicast hashing faked - all packets accepted
2037        if (multicastHashEnable)
2038            drop = false;
2039    }
2040
2041    if (drop) {
2042        DPRINTF(Ethernet, "rxFilter drop\n");
2043        DDUMP(EthernetData, packet->data, packet->length);
2044    }
2045
2046    return drop;
2047}
2048
2049bool
2050NSGigE::recvPacket(EthPacketPtr packet)
2051{
2052    rxBytes += packet->length;
2053    rxPackets++;
2054
2055    DPRINTF(Ethernet, "Receiving packet from wire, rxFifoAvail=%d\n",
2056            rxFifo.avail());
2057
2058    if (!rxEnable) {
2059        DPRINTF(Ethernet, "receive disabled...packet dropped\n");
2060        return true;
2061    }
2062
2063    if (!rxFilterEnable) {
2064        DPRINTF(Ethernet,
2065            "receive packet filtering disabled . . . packet dropped\n");
2066        return true;
2067    }
2068
2069    if (rxFilter(packet)) {
2070        DPRINTF(Ethernet, "packet filtered...dropped\n");
2071        return true;
2072    }
2073
2074    if (rxFifo.avail() < packet->length) {
2075#if TRACING_ON
2076        IpPtr ip(packet);
2077        TcpPtr tcp(ip);
2078        if (ip) {
2079            DPRINTF(Ethernet,
2080                    "packet won't fit in receive buffer...pkt ID %d dropped\n",
2081                    ip->id());
2082            if (tcp) {
2083                DPRINTF(Ethernet, "Seq=%d\n", tcp->seq());
2084            }
2085        }
2086#endif
2087        droppedPackets++;
2088        devIntrPost(ISR_RXORN);
2089        return false;
2090    }
2091
2092    rxFifo.push(packet);
2093
2094    rxKick();
2095    return true;
2096}
2097
2098
2099void
2100NSGigE::resume()
2101{
2102    SimObject::resume();
2103
2104    // During drain we could have left the state machines in a waiting state and
2105    // they wouldn't get out until some other event occured to kick them.
2106    // This way they'll get out immediately
2107    txKick();
2108    rxKick();
2109}
2110
2111
2112//=====================================================================
2113//
2114//
2115void
2116NSGigE::serialize(ostream &os)
2117{
2118    // Serialize the PciDev base class
2119    PciDev::serialize(os);
2120
2121    /*
2122     * Finalize any DMA events now.
2123     */
2124    // @todo will mem system save pending dma?
2125
2126    /*
2127     * Serialize the device registers
2128     */
2129    SERIALIZE_SCALAR(regs.command);
2130    SERIALIZE_SCALAR(regs.config);
2131    SERIALIZE_SCALAR(regs.mear);
2132    SERIALIZE_SCALAR(regs.ptscr);
2133    SERIALIZE_SCALAR(regs.isr);
2134    SERIALIZE_SCALAR(regs.imr);
2135    SERIALIZE_SCALAR(regs.ier);
2136    SERIALIZE_SCALAR(regs.ihr);
2137    SERIALIZE_SCALAR(regs.txdp);
2138    SERIALIZE_SCALAR(regs.txdp_hi);
2139    SERIALIZE_SCALAR(regs.txcfg);
2140    SERIALIZE_SCALAR(regs.gpior);
2141    SERIALIZE_SCALAR(regs.rxdp);
2142    SERIALIZE_SCALAR(regs.rxdp_hi);
2143    SERIALIZE_SCALAR(regs.rxcfg);
2144    SERIALIZE_SCALAR(regs.pqcr);
2145    SERIALIZE_SCALAR(regs.wcsr);
2146    SERIALIZE_SCALAR(regs.pcr);
2147    SERIALIZE_SCALAR(regs.rfcr);
2148    SERIALIZE_SCALAR(regs.rfdr);
2149    SERIALIZE_SCALAR(regs.brar);
2150    SERIALIZE_SCALAR(regs.brdr);
2151    SERIALIZE_SCALAR(regs.srr);
2152    SERIALIZE_SCALAR(regs.mibc);
2153    SERIALIZE_SCALAR(regs.vrcr);
2154    SERIALIZE_SCALAR(regs.vtcr);
2155    SERIALIZE_SCALAR(regs.vdr);
2156    SERIALIZE_SCALAR(regs.ccsr);
2157    SERIALIZE_SCALAR(regs.tbicr);
2158    SERIALIZE_SCALAR(regs.tbisr);
2159    SERIALIZE_SCALAR(regs.tanar);
2160    SERIALIZE_SCALAR(regs.tanlpar);
2161    SERIALIZE_SCALAR(regs.taner);
2162    SERIALIZE_SCALAR(regs.tesr);
2163
2164    SERIALIZE_ARRAY(rom.perfectMatch, ETH_ADDR_LEN);
2165    SERIALIZE_ARRAY(rom.filterHash, FHASH_SIZE);
2166
2167    SERIALIZE_SCALAR(ioEnable);
2168
2169    /*
2170     * Serialize the data Fifos
2171     */
2172    rxFifo.serialize("rxFifo", os);
2173    txFifo.serialize("txFifo", os);
2174
2175    /*
2176     * Serialize the various helper variables
2177     */
2178    bool txPacketExists = txPacket;
2179    SERIALIZE_SCALAR(txPacketExists);
2180    if (txPacketExists) {
2181        txPacket->length = txPacketBufPtr - txPacket->data;
2182        txPacket->serialize("txPacket", os);
2183        uint32_t txPktBufPtr = (uint32_t) (txPacketBufPtr - txPacket->data);
2184        SERIALIZE_SCALAR(txPktBufPtr);
2185    }
2186
2187    bool rxPacketExists = rxPacket;
2188    SERIALIZE_SCALAR(rxPacketExists);
2189    if (rxPacketExists) {
2190        rxPacket->serialize("rxPacket", os);
2191        uint32_t rxPktBufPtr = (uint32_t) (rxPacketBufPtr - rxPacket->data);
2192        SERIALIZE_SCALAR(rxPktBufPtr);
2193    }
2194
2195    SERIALIZE_SCALAR(txXferLen);
2196    SERIALIZE_SCALAR(rxXferLen);
2197
2198    /*
2199     * Serialize Cached Descriptors
2200     */
2201    SERIALIZE_SCALAR(rxDesc64.link);
2202    SERIALIZE_SCALAR(rxDesc64.bufptr);
2203    SERIALIZE_SCALAR(rxDesc64.cmdsts);
2204    SERIALIZE_SCALAR(rxDesc64.extsts);
2205    SERIALIZE_SCALAR(txDesc64.link);
2206    SERIALIZE_SCALAR(txDesc64.bufptr);
2207    SERIALIZE_SCALAR(txDesc64.cmdsts);
2208    SERIALIZE_SCALAR(txDesc64.extsts);
2209    SERIALIZE_SCALAR(rxDesc32.link);
2210    SERIALIZE_SCALAR(rxDesc32.bufptr);
2211    SERIALIZE_SCALAR(rxDesc32.cmdsts);
2212    SERIALIZE_SCALAR(rxDesc32.extsts);
2213    SERIALIZE_SCALAR(txDesc32.link);
2214    SERIALIZE_SCALAR(txDesc32.bufptr);
2215    SERIALIZE_SCALAR(txDesc32.cmdsts);
2216    SERIALIZE_SCALAR(txDesc32.extsts);
2217    SERIALIZE_SCALAR(extstsEnable);
2218
2219    /*
2220     * Serialize tx state machine
2221     */
2222    int txState = this->txState;
2223    SERIALIZE_SCALAR(txState);
2224    SERIALIZE_SCALAR(txEnable);
2225    SERIALIZE_SCALAR(CTDD);
2226    SERIALIZE_SCALAR(txFragPtr);
2227    SERIALIZE_SCALAR(txDescCnt);
2228    int txDmaState = this->txDmaState;
2229    SERIALIZE_SCALAR(txDmaState);
2230    SERIALIZE_SCALAR(txKickTick);
2231
2232    /*
2233     * Serialize rx state machine
2234     */
2235    int rxState = this->rxState;
2236    SERIALIZE_SCALAR(rxState);
2237    SERIALIZE_SCALAR(rxEnable);
2238    SERIALIZE_SCALAR(CRDD);
2239    SERIALIZE_SCALAR(rxPktBytes);
2240    SERIALIZE_SCALAR(rxFragPtr);
2241    SERIALIZE_SCALAR(rxDescCnt);
2242    int rxDmaState = this->rxDmaState;
2243    SERIALIZE_SCALAR(rxDmaState);
2244    SERIALIZE_SCALAR(rxKickTick);
2245
2246    /*
2247     * Serialize EEPROM state machine
2248     */
2249    int eepromState = this->eepromState;
2250    SERIALIZE_SCALAR(eepromState);
2251    SERIALIZE_SCALAR(eepromClk);
2252    SERIALIZE_SCALAR(eepromBitsToRx);
2253    SERIALIZE_SCALAR(eepromOpcode);
2254    SERIALIZE_SCALAR(eepromAddress);
2255    SERIALIZE_SCALAR(eepromData);
2256
2257    /*
2258     * If there's a pending transmit, store the time so we can
2259     * reschedule it later
2260     */
2261    Tick transmitTick = txEvent.scheduled() ? txEvent.when() - curTick : 0;
2262    SERIALIZE_SCALAR(transmitTick);
2263
2264    /*
2265     * receive address filter settings
2266     */
2267    SERIALIZE_SCALAR(rxFilterEnable);
2268    SERIALIZE_SCALAR(acceptBroadcast);
2269    SERIALIZE_SCALAR(acceptMulticast);
2270    SERIALIZE_SCALAR(acceptUnicast);
2271    SERIALIZE_SCALAR(acceptPerfect);
2272    SERIALIZE_SCALAR(acceptArp);
2273    SERIALIZE_SCALAR(multicastHashEnable);
2274
2275    /*
2276     * Keep track of pending interrupt status.
2277     */
2278    SERIALIZE_SCALAR(intrTick);
2279    SERIALIZE_SCALAR(cpuPendingIntr);
2280    Tick intrEventTick = 0;
2281    if (intrEvent)
2282        intrEventTick = intrEvent->when();
2283    SERIALIZE_SCALAR(intrEventTick);
2284
2285}
2286
2287void
2288NSGigE::unserialize(Checkpoint *cp, const std::string &section)
2289{
2290    // Unserialize the PciDev base class
2291    PciDev::unserialize(cp, section);
2292
2293    UNSERIALIZE_SCALAR(regs.command);
2294    UNSERIALIZE_SCALAR(regs.config);
2295    UNSERIALIZE_SCALAR(regs.mear);
2296    UNSERIALIZE_SCALAR(regs.ptscr);
2297    UNSERIALIZE_SCALAR(regs.isr);
2298    UNSERIALIZE_SCALAR(regs.imr);
2299    UNSERIALIZE_SCALAR(regs.ier);
2300    UNSERIALIZE_SCALAR(regs.ihr);
2301    UNSERIALIZE_SCALAR(regs.txdp);
2302    UNSERIALIZE_SCALAR(regs.txdp_hi);
2303    UNSERIALIZE_SCALAR(regs.txcfg);
2304    UNSERIALIZE_SCALAR(regs.gpior);
2305    UNSERIALIZE_SCALAR(regs.rxdp);
2306    UNSERIALIZE_SCALAR(regs.rxdp_hi);
2307    UNSERIALIZE_SCALAR(regs.rxcfg);
2308    UNSERIALIZE_SCALAR(regs.pqcr);
2309    UNSERIALIZE_SCALAR(regs.wcsr);
2310    UNSERIALIZE_SCALAR(regs.pcr);
2311    UNSERIALIZE_SCALAR(regs.rfcr);
2312    UNSERIALIZE_SCALAR(regs.rfdr);
2313    UNSERIALIZE_SCALAR(regs.brar);
2314    UNSERIALIZE_SCALAR(regs.brdr);
2315    UNSERIALIZE_SCALAR(regs.srr);
2316    UNSERIALIZE_SCALAR(regs.mibc);
2317    UNSERIALIZE_SCALAR(regs.vrcr);
2318    UNSERIALIZE_SCALAR(regs.vtcr);
2319    UNSERIALIZE_SCALAR(regs.vdr);
2320    UNSERIALIZE_SCALAR(regs.ccsr);
2321    UNSERIALIZE_SCALAR(regs.tbicr);
2322    UNSERIALIZE_SCALAR(regs.tbisr);
2323    UNSERIALIZE_SCALAR(regs.tanar);
2324    UNSERIALIZE_SCALAR(regs.tanlpar);
2325    UNSERIALIZE_SCALAR(regs.taner);
2326    UNSERIALIZE_SCALAR(regs.tesr);
2327
2328    UNSERIALIZE_ARRAY(rom.perfectMatch, ETH_ADDR_LEN);
2329    UNSERIALIZE_ARRAY(rom.filterHash, FHASH_SIZE);
2330
2331    UNSERIALIZE_SCALAR(ioEnable);
2332
2333    /*
2334     * unserialize the data fifos
2335     */
2336    rxFifo.unserialize("rxFifo", cp, section);
2337    txFifo.unserialize("txFifo", cp, section);
2338
2339    /*
2340     * unserialize the various helper variables
2341     */
2342    bool txPacketExists;
2343    UNSERIALIZE_SCALAR(txPacketExists);
2344    if (txPacketExists) {
2345        txPacket = new EthPacketData(16384);
2346        txPacket->unserialize("txPacket", cp, section);
2347        uint32_t txPktBufPtr;
2348        UNSERIALIZE_SCALAR(txPktBufPtr);
2349        txPacketBufPtr = (uint8_t *) txPacket->data + txPktBufPtr;
2350    } else
2351        txPacket = 0;
2352
2353    bool rxPacketExists;
2354    UNSERIALIZE_SCALAR(rxPacketExists);
2355    rxPacket = 0;
2356    if (rxPacketExists) {
2357        rxPacket = new EthPacketData(16384);
2358        rxPacket->unserialize("rxPacket", cp, section);
2359        uint32_t rxPktBufPtr;
2360        UNSERIALIZE_SCALAR(rxPktBufPtr);
2361        rxPacketBufPtr = (uint8_t *) rxPacket->data + rxPktBufPtr;
2362    } else
2363        rxPacket = 0;
2364
2365    UNSERIALIZE_SCALAR(txXferLen);
2366    UNSERIALIZE_SCALAR(rxXferLen);
2367
2368    /*
2369     * Unserialize Cached Descriptors
2370     */
2371    UNSERIALIZE_SCALAR(rxDesc64.link);
2372    UNSERIALIZE_SCALAR(rxDesc64.bufptr);
2373    UNSERIALIZE_SCALAR(rxDesc64.cmdsts);
2374    UNSERIALIZE_SCALAR(rxDesc64.extsts);
2375    UNSERIALIZE_SCALAR(txDesc64.link);
2376    UNSERIALIZE_SCALAR(txDesc64.bufptr);
2377    UNSERIALIZE_SCALAR(txDesc64.cmdsts);
2378    UNSERIALIZE_SCALAR(txDesc64.extsts);
2379    UNSERIALIZE_SCALAR(rxDesc32.link);
2380    UNSERIALIZE_SCALAR(rxDesc32.bufptr);
2381    UNSERIALIZE_SCALAR(rxDesc32.cmdsts);
2382    UNSERIALIZE_SCALAR(rxDesc32.extsts);
2383    UNSERIALIZE_SCALAR(txDesc32.link);
2384    UNSERIALIZE_SCALAR(txDesc32.bufptr);
2385    UNSERIALIZE_SCALAR(txDesc32.cmdsts);
2386    UNSERIALIZE_SCALAR(txDesc32.extsts);
2387    UNSERIALIZE_SCALAR(extstsEnable);
2388
2389    /*
2390     * unserialize tx state machine
2391     */
2392    int txState;
2393    UNSERIALIZE_SCALAR(txState);
2394    this->txState = (TxState) txState;
2395    UNSERIALIZE_SCALAR(txEnable);
2396    UNSERIALIZE_SCALAR(CTDD);
2397    UNSERIALIZE_SCALAR(txFragPtr);
2398    UNSERIALIZE_SCALAR(txDescCnt);
2399    int txDmaState;
2400    UNSERIALIZE_SCALAR(txDmaState);
2401    this->txDmaState = (DmaState) txDmaState;
2402    UNSERIALIZE_SCALAR(txKickTick);
2403    if (txKickTick)
2404        schedule(txKickEvent, txKickTick);
2405
2406    /*
2407     * unserialize rx state machine
2408     */
2409    int rxState;
2410    UNSERIALIZE_SCALAR(rxState);
2411    this->rxState = (RxState) rxState;
2412    UNSERIALIZE_SCALAR(rxEnable);
2413    UNSERIALIZE_SCALAR(CRDD);
2414    UNSERIALIZE_SCALAR(rxPktBytes);
2415    UNSERIALIZE_SCALAR(rxFragPtr);
2416    UNSERIALIZE_SCALAR(rxDescCnt);
2417    int rxDmaState;
2418    UNSERIALIZE_SCALAR(rxDmaState);
2419    this->rxDmaState = (DmaState) rxDmaState;
2420    UNSERIALIZE_SCALAR(rxKickTick);
2421    if (rxKickTick)
2422        schedule(rxKickEvent, rxKickTick);
2423
2424    /*
2425     * Unserialize EEPROM state machine
2426     */
2427    int eepromState;
2428    UNSERIALIZE_SCALAR(eepromState);
2429    this->eepromState = (EEPROMState) eepromState;
2430    UNSERIALIZE_SCALAR(eepromClk);
2431    UNSERIALIZE_SCALAR(eepromBitsToRx);
2432    UNSERIALIZE_SCALAR(eepromOpcode);
2433    UNSERIALIZE_SCALAR(eepromAddress);
2434    UNSERIALIZE_SCALAR(eepromData);
2435
2436    /*
2437     * If there's a pending transmit, reschedule it now
2438     */
2439    Tick transmitTick;
2440    UNSERIALIZE_SCALAR(transmitTick);
2441    if (transmitTick)
2442        schedule(txEvent, curTick + transmitTick);
2443
2444    /*
2445     * unserialize receive address filter settings
2446     */
2447    UNSERIALIZE_SCALAR(rxFilterEnable);
2448    UNSERIALIZE_SCALAR(acceptBroadcast);
2449    UNSERIALIZE_SCALAR(acceptMulticast);
2450    UNSERIALIZE_SCALAR(acceptUnicast);
2451    UNSERIALIZE_SCALAR(acceptPerfect);
2452    UNSERIALIZE_SCALAR(acceptArp);
2453    UNSERIALIZE_SCALAR(multicastHashEnable);
2454
2455    /*
2456     * Keep track of pending interrupt status.
2457     */
2458    UNSERIALIZE_SCALAR(intrTick);
2459    UNSERIALIZE_SCALAR(cpuPendingIntr);
2460    Tick intrEventTick;
2461    UNSERIALIZE_SCALAR(intrEventTick);
2462    if (intrEventTick) {
2463        intrEvent = new IntrEvent(this, true);
2464        schedule(intrEvent, intrEventTick);
2465    }
2466}
2467
2468NSGigE *
2469NSGigEParams::create()
2470{
2471    return new NSGigE(this);
2472}
2473