ns_gige.cc revision 6658
17119Sgblack@eecs.umich.edu/*
27119Sgblack@eecs.umich.edu * Copyright (c) 2004-2005 The Regents of The University of Michigan
37120Sgblack@eecs.umich.edu * All rights reserved.
47120Sgblack@eecs.umich.edu *
57120Sgblack@eecs.umich.edu * Redistribution and use in source and binary forms, with or without
67120Sgblack@eecs.umich.edu * modification, are permitted provided that the following conditions are
77120Sgblack@eecs.umich.edu * met: redistributions of source code must retain the above copyright
87120Sgblack@eecs.umich.edu * notice, this list of conditions and the following disclaimer;
97120Sgblack@eecs.umich.edu * redistributions in binary form must reproduce the above copyright
107120Sgblack@eecs.umich.edu * notice, this list of conditions and the following disclaimer in the
117120Sgblack@eecs.umich.edu * documentation and/or other materials provided with the distribution;
127120Sgblack@eecs.umich.edu * neither the name of the copyright holders nor the names of its
137120Sgblack@eecs.umich.edu * contributors may be used to endorse or promote products derived from
147120Sgblack@eecs.umich.edu * this software without specific prior written permission.
157119Sgblack@eecs.umich.edu *
167119Sgblack@eecs.umich.edu * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
177119Sgblack@eecs.umich.edu * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
187119Sgblack@eecs.umich.edu * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
197119Sgblack@eecs.umich.edu * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
207119Sgblack@eecs.umich.edu * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
217119Sgblack@eecs.umich.edu * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
227119Sgblack@eecs.umich.edu * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
237119Sgblack@eecs.umich.edu * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
247119Sgblack@eecs.umich.edu * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
257119Sgblack@eecs.umich.edu * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
267119Sgblack@eecs.umich.edu * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
277119Sgblack@eecs.umich.edu *
287119Sgblack@eecs.umich.edu * Authors: Nathan Binkert
297119Sgblack@eecs.umich.edu *          Lisa Hsu
307119Sgblack@eecs.umich.edu */
317119Sgblack@eecs.umich.edu
327119Sgblack@eecs.umich.edu/** @file
337119Sgblack@eecs.umich.edu * Device module for modelling the National Semiconductor
347119Sgblack@eecs.umich.edu * DP83820 ethernet controller.  Does not support priority queueing
357119Sgblack@eecs.umich.edu */
367119Sgblack@eecs.umich.edu#include <deque>
377119Sgblack@eecs.umich.edu#include <string>
387119Sgblack@eecs.umich.edu
397119Sgblack@eecs.umich.edu#include "base/debug.hh"
407119Sgblack@eecs.umich.edu#include "base/inet.hh"
417119Sgblack@eecs.umich.edu#include "base/types.hh"
427119Sgblack@eecs.umich.edu#include "config/the_isa.hh"
437119Sgblack@eecs.umich.edu#include "cpu/thread_context.hh"
447646Sgene.wu@arm.com#include "dev/etherlink.hh"
457646Sgene.wu@arm.com#include "dev/ns_gige.hh"
467646Sgene.wu@arm.com#include "dev/pciconfigall.hh"
477646Sgene.wu@arm.com#include "mem/packet.hh"
487646Sgene.wu@arm.com#include "mem/packet_access.hh"
497646Sgene.wu@arm.com#include "params/NSGigE.hh"
507646Sgene.wu@arm.com#include "sim/system.hh"
517646Sgene.wu@arm.com
527646Sgene.wu@arm.comconst char *NsRxStateStrings[] =
537646Sgene.wu@arm.com{
547646Sgene.wu@arm.com    "rxIdle",
557646Sgene.wu@arm.com    "rxDescRefr",
567646Sgene.wu@arm.com    "rxDescRead",
577646Sgene.wu@arm.com    "rxFifoBlock",
587646Sgene.wu@arm.com    "rxFragWrite",
597646Sgene.wu@arm.com    "rxDescWrite",
607646Sgene.wu@arm.com    "rxAdvance"
617646Sgene.wu@arm.com};
627646Sgene.wu@arm.com
637646Sgene.wu@arm.comconst char *NsTxStateStrings[] =
647646Sgene.wu@arm.com{
657646Sgene.wu@arm.com    "txIdle",
667646Sgene.wu@arm.com    "txDescRefr",
677646Sgene.wu@arm.com    "txDescRead",
687646Sgene.wu@arm.com    "txFifoBlock",
697646Sgene.wu@arm.com    "txFragRead",
707646Sgene.wu@arm.com    "txDescWrite",
717646Sgene.wu@arm.com    "txAdvance"
727646Sgene.wu@arm.com};
737205Sgblack@eecs.umich.edu
747205Sgblack@eecs.umich.educonst char *NsDmaState[] =
757205Sgblack@eecs.umich.edu{
767205Sgblack@eecs.umich.edu    "dmaIdle",
777205Sgblack@eecs.umich.edu    "dmaReading",
787205Sgblack@eecs.umich.edu    "dmaWriting",
797205Sgblack@eecs.umich.edu    "dmaReadWaiting",
807205Sgblack@eecs.umich.edu    "dmaWriteWaiting"
817205Sgblack@eecs.umich.edu};
827205Sgblack@eecs.umich.edu
837205Sgblack@eecs.umich.eduusing namespace std;
847205Sgblack@eecs.umich.eduusing namespace Net;
857205Sgblack@eecs.umich.eduusing namespace TheISA;
867205Sgblack@eecs.umich.edu
877205Sgblack@eecs.umich.edu///////////////////////////////////////////////////////////////////////
887205Sgblack@eecs.umich.edu//
897205Sgblack@eecs.umich.edu// NSGigE PCI Device
908442Sgblack@eecs.umich.edu//
918442Sgblack@eecs.umich.eduNSGigE::NSGigE(Params *p)
927205Sgblack@eecs.umich.edu    : EtherDevice(p), ioEnable(false),
937205Sgblack@eecs.umich.edu      txFifo(p->tx_fifo_size), rxFifo(p->rx_fifo_size),
947205Sgblack@eecs.umich.edu      txPacket(0), rxPacket(0), txPacketBufPtr(NULL), rxPacketBufPtr(NULL),
957205Sgblack@eecs.umich.edu      txXferLen(0), rxXferLen(0), rxDmaFree(false), txDmaFree(false),
967205Sgblack@eecs.umich.edu      clock(p->clock),
977205Sgblack@eecs.umich.edu      txState(txIdle), txEnable(false), CTDD(false), txHalt(false),
987205Sgblack@eecs.umich.edu      txFragPtr(0), txDescCnt(0), txDmaState(dmaIdle), rxState(rxIdle),
997205Sgblack@eecs.umich.edu      rxEnable(false), CRDD(false), rxPktBytes(0), rxHalt(false),
1007205Sgblack@eecs.umich.edu      rxFragPtr(0), rxDescCnt(0), rxDmaState(dmaIdle), extstsEnable(false),
1017597Sminkyu.jeong@arm.com      eepromState(eepromStart), eepromClk(false), eepromBitsToRx(0),
1027597Sminkyu.jeong@arm.com      eepromOpcode(0), eepromAddress(0), eepromData(0),
1037205Sgblack@eecs.umich.edu      dmaReadDelay(p->dma_read_delay), dmaWriteDelay(p->dma_write_delay),
1047205Sgblack@eecs.umich.edu      dmaReadFactor(p->dma_read_factor), dmaWriteFactor(p->dma_write_factor),
1057205Sgblack@eecs.umich.edu      rxDmaData(NULL), rxDmaAddr(0), rxDmaLen(0),
1067205Sgblack@eecs.umich.edu      txDmaData(NULL), txDmaAddr(0), txDmaLen(0),
1077205Sgblack@eecs.umich.edu      rxDmaReadEvent(this), rxDmaWriteEvent(this),
1087205Sgblack@eecs.umich.edu      txDmaReadEvent(this), txDmaWriteEvent(this),
1097205Sgblack@eecs.umich.edu      dmaDescFree(p->dma_desc_free), dmaDataFree(p->dma_data_free),
1107205Sgblack@eecs.umich.edu      txDelay(p->tx_delay), rxDelay(p->rx_delay),
1117205Sgblack@eecs.umich.edu      rxKickTick(0), rxKickEvent(this), txKickTick(0), txKickEvent(this),
1127205Sgblack@eecs.umich.edu      txEvent(this), rxFilterEnable(p->rx_filter),
1137205Sgblack@eecs.umich.edu      acceptBroadcast(false), acceptMulticast(false), acceptUnicast(false),
1147205Sgblack@eecs.umich.edu      acceptPerfect(false), acceptArp(false), multicastHashEnable(false),
1157205Sgblack@eecs.umich.edu      intrDelay(p->intr_delay), intrTick(0), cpuPendingIntr(false),
1167205Sgblack@eecs.umich.edu      intrEvent(0), interface(0)
1177205Sgblack@eecs.umich.edu{
1187205Sgblack@eecs.umich.edu
1197205Sgblack@eecs.umich.edu
1207205Sgblack@eecs.umich.edu    interface = new NSGigEInt(name() + ".int0", this);
1217205Sgblack@eecs.umich.edu
1227205Sgblack@eecs.umich.edu    regsReset();
1237205Sgblack@eecs.umich.edu    memcpy(&rom.perfectMatch, p->hardware_address.bytes(), ETH_ADDR_LEN);
1247205Sgblack@eecs.umich.edu
1257205Sgblack@eecs.umich.edu    memset(&rxDesc32, 0, sizeof(rxDesc32));
1268442Sgblack@eecs.umich.edu    memset(&txDesc32, 0, sizeof(txDesc32));
1278442Sgblack@eecs.umich.edu    memset(&rxDesc64, 0, sizeof(rxDesc64));
1287205Sgblack@eecs.umich.edu    memset(&txDesc64, 0, sizeof(txDesc64));
1297597Sminkyu.jeong@arm.com}
1307597Sminkyu.jeong@arm.com
1317205Sgblack@eecs.umich.eduNSGigE::~NSGigE()
1327205Sgblack@eecs.umich.edu{}
1337205Sgblack@eecs.umich.edu
1347205Sgblack@eecs.umich.edu/**
1357205Sgblack@eecs.umich.edu * This is to write to the PCI general configuration registers
1367205Sgblack@eecs.umich.edu */
1377205Sgblack@eecs.umich.eduTick
1387205Sgblack@eecs.umich.eduNSGigE::writeConfig(PacketPtr pkt)
1397205Sgblack@eecs.umich.edu{
1407205Sgblack@eecs.umich.edu    int offset = pkt->getAddr() & PCI_CONFIG_SIZE;
1417205Sgblack@eecs.umich.edu    if (offset < PCI_DEVICE_SPECIFIC)
1427205Sgblack@eecs.umich.edu        PciDev::writeConfig(pkt);
1437205Sgblack@eecs.umich.edu    else
1447205Sgblack@eecs.umich.edu        panic("Device specific PCI config space not implemented!\n");
1457205Sgblack@eecs.umich.edu
1467205Sgblack@eecs.umich.edu    switch (offset) {
1477205Sgblack@eecs.umich.edu        // seems to work fine without all these PCI settings, but i
1487205Sgblack@eecs.umich.edu        // put in the IO to double check, an assertion will fail if we
1497205Sgblack@eecs.umich.edu        // need to properly implement it
1508442Sgblack@eecs.umich.edu      case PCI_COMMAND:
1518442Sgblack@eecs.umich.edu        if (config.data[offset] & PCI_CMD_IOSE)
1527205Sgblack@eecs.umich.edu            ioEnable = true;
1537205Sgblack@eecs.umich.edu        else
1547205Sgblack@eecs.umich.edu            ioEnable = false;
1557205Sgblack@eecs.umich.edu        break;
1567205Sgblack@eecs.umich.edu    }
1577205Sgblack@eecs.umich.edu
1587205Sgblack@eecs.umich.edu    return configDelay;
1597205Sgblack@eecs.umich.edu}
1607205Sgblack@eecs.umich.edu
1617205Sgblack@eecs.umich.eduEtherInt*
1627205Sgblack@eecs.umich.eduNSGigE::getEthPort(const std::string &if_name, int idx)
1637205Sgblack@eecs.umich.edu{
1647119Sgblack@eecs.umich.edu    if (if_name == "interface") {
1657119Sgblack@eecs.umich.edu       if (interface->getPeer())
1667119Sgblack@eecs.umich.edu           panic("interface already connected to\n");
1677119Sgblack@eecs.umich.edu       return interface;
1687119Sgblack@eecs.umich.edu    }
1697119Sgblack@eecs.umich.edu    return NULL;
1707119Sgblack@eecs.umich.edu}
1717119Sgblack@eecs.umich.edu
1727119Sgblack@eecs.umich.edu/**
1737119Sgblack@eecs.umich.edu * This reads the device registers, which are detailed in the NS83820
1747119Sgblack@eecs.umich.edu * spec sheet
1757119Sgblack@eecs.umich.edu */
1767119Sgblack@eecs.umich.eduTick
1777119Sgblack@eecs.umich.eduNSGigE::read(PacketPtr pkt)
1788442Sgblack@eecs.umich.edu{
1797119Sgblack@eecs.umich.edu    assert(ioEnable);
1807119Sgblack@eecs.umich.edu
1817119Sgblack@eecs.umich.edu    pkt->allocate();
1827119Sgblack@eecs.umich.edu
1837119Sgblack@eecs.umich.edu    //The mask is to give you only the offset into the device register file
1847119Sgblack@eecs.umich.edu    Addr daddr = pkt->getAddr() & 0xfff;
1857597Sminkyu.jeong@arm.com    DPRINTF(EthernetPIO, "read  da=%#x pa=%#x size=%d\n",
1867597Sminkyu.jeong@arm.com            daddr, pkt->getAddr(), pkt->getSize());
1877119Sgblack@eecs.umich.edu
1887119Sgblack@eecs.umich.edu
1897119Sgblack@eecs.umich.edu    // there are some reserved registers, you can see ns_gige_reg.h and
1907119Sgblack@eecs.umich.edu    // the spec sheet for details
1917119Sgblack@eecs.umich.edu    if (daddr > LAST && daddr <=  RESERVED) {
1927119Sgblack@eecs.umich.edu        panic("Accessing reserved register");
1937639Sgblack@eecs.umich.edu    } else if (daddr > RESERVED && daddr <= 0x3FC) {
1947639Sgblack@eecs.umich.edu        return readConfig(pkt);
1957639Sgblack@eecs.umich.edu    } else if (daddr >= MIB_START && daddr <= MIB_END) {
1967639Sgblack@eecs.umich.edu        // don't implement all the MIB's.  hopefully the kernel
1977639Sgblack@eecs.umich.edu        // doesn't actually DEPEND upon their values
1987639Sgblack@eecs.umich.edu        // MIB are just hardware stats keepers
1997639Sgblack@eecs.umich.edu        pkt->set<uint32_t>(0);
2007639Sgblack@eecs.umich.edu        pkt->makeAtomicResponse();
2017639Sgblack@eecs.umich.edu        return pioDelay;
2027639Sgblack@eecs.umich.edu    } else if (daddr > 0x3FC)
2037639Sgblack@eecs.umich.edu        panic("Something is messed up!\n");
2047639Sgblack@eecs.umich.edu
2057639Sgblack@eecs.umich.edu    assert(pkt->getSize() == sizeof(uint32_t));
2067639Sgblack@eecs.umich.edu        uint32_t &reg = *pkt->getPtr<uint32_t>();
2077639Sgblack@eecs.umich.edu        uint16_t rfaddr;
2087639Sgblack@eecs.umich.edu
2097639Sgblack@eecs.umich.edu        switch (daddr) {
2107639Sgblack@eecs.umich.edu          case CR:
2117639Sgblack@eecs.umich.edu            reg = regs.command;
2127639Sgblack@eecs.umich.edu            //these are supposed to be cleared on a read
2137639Sgblack@eecs.umich.edu            reg &= ~(CR_RXD | CR_TXD | CR_TXR | CR_RXR);
2147639Sgblack@eecs.umich.edu            break;
2157639Sgblack@eecs.umich.edu
2167639Sgblack@eecs.umich.edu          case CFGR:
2177639Sgblack@eecs.umich.edu            reg = regs.config;
2187639Sgblack@eecs.umich.edu            break;
2198072SGiacomo.Gabrielli@arm.com
2208072SGiacomo.Gabrielli@arm.com          case MEAR:
2217639Sgblack@eecs.umich.edu            reg = regs.mear;
2227639Sgblack@eecs.umich.edu            break;
2237639Sgblack@eecs.umich.edu
2247639Sgblack@eecs.umich.edu          case PTSCR:
2257639Sgblack@eecs.umich.edu            reg = regs.ptscr;
2267639Sgblack@eecs.umich.edu            break;
2277120Sgblack@eecs.umich.edu
2287120Sgblack@eecs.umich.edu          case ISR:
2297120Sgblack@eecs.umich.edu            reg = regs.isr;
2307120Sgblack@eecs.umich.edu            devIntrClear(ISR_ALL);
2317120Sgblack@eecs.umich.edu            break;
2327120Sgblack@eecs.umich.edu
2337120Sgblack@eecs.umich.edu          case IMR:
2347120Sgblack@eecs.umich.edu            reg = regs.imr;
2357120Sgblack@eecs.umich.edu            break;
2367120Sgblack@eecs.umich.edu
2377120Sgblack@eecs.umich.edu          case IER:
2387120Sgblack@eecs.umich.edu            reg = regs.ier;
2397120Sgblack@eecs.umich.edu            break;
2407120Sgblack@eecs.umich.edu
2417120Sgblack@eecs.umich.edu          case IHR:
2427120Sgblack@eecs.umich.edu            reg = regs.ihr;
2437120Sgblack@eecs.umich.edu            break;
2447120Sgblack@eecs.umich.edu
2458442Sgblack@eecs.umich.edu          case TXDP:
2468442Sgblack@eecs.umich.edu            reg = regs.txdp;
2477120Sgblack@eecs.umich.edu            break;
2487120Sgblack@eecs.umich.edu
2497120Sgblack@eecs.umich.edu          case TXDP_HI:
2507120Sgblack@eecs.umich.edu            reg = regs.txdp_hi;
2517120Sgblack@eecs.umich.edu            break;
2527597Sminkyu.jeong@arm.com
2537597Sminkyu.jeong@arm.com          case TX_CFG:
2547120Sgblack@eecs.umich.edu            reg = regs.txcfg;
2557120Sgblack@eecs.umich.edu            break;
2567120Sgblack@eecs.umich.edu
2577120Sgblack@eecs.umich.edu          case GPIOR:
2587120Sgblack@eecs.umich.edu            reg = regs.gpior;
2597120Sgblack@eecs.umich.edu            break;
2607639Sgblack@eecs.umich.edu
2617639Sgblack@eecs.umich.edu          case RXDP:
2627639Sgblack@eecs.umich.edu            reg = regs.rxdp;
2637639Sgblack@eecs.umich.edu            break;
2647639Sgblack@eecs.umich.edu
2657639Sgblack@eecs.umich.edu          case RXDP_HI:
2667639Sgblack@eecs.umich.edu            reg = regs.rxdp_hi;
2677639Sgblack@eecs.umich.edu            break;
2687639Sgblack@eecs.umich.edu
2697639Sgblack@eecs.umich.edu          case RX_CFG:
2707639Sgblack@eecs.umich.edu            reg = regs.rxcfg;
2717639Sgblack@eecs.umich.edu            break;
2727639Sgblack@eecs.umich.edu
2737639Sgblack@eecs.umich.edu          case PQCR:
2747639Sgblack@eecs.umich.edu            reg = regs.pqcr;
2757639Sgblack@eecs.umich.edu            break;
2767639Sgblack@eecs.umich.edu
2777639Sgblack@eecs.umich.edu          case WCSR:
2787639Sgblack@eecs.umich.edu            reg = regs.wcsr;
2797639Sgblack@eecs.umich.edu            break;
2807639Sgblack@eecs.umich.edu
2817639Sgblack@eecs.umich.edu          case PCR:
2827639Sgblack@eecs.umich.edu            reg = regs.pcr;
2837639Sgblack@eecs.umich.edu            break;
2847639Sgblack@eecs.umich.edu
2857639Sgblack@eecs.umich.edu            // see the spec sheet for how RFCR and RFDR work
2867639Sgblack@eecs.umich.edu            // basically, you write to RFCR to tell the machine
2877639Sgblack@eecs.umich.edu            // what you want to do next, then you act upon RFDR,
2887639Sgblack@eecs.umich.edu            // and the device will be prepared b/c of what you
2897639Sgblack@eecs.umich.edu            // wrote to RFCR
2908072SGiacomo.Gabrielli@arm.com          case RFCR:
2918072SGiacomo.Gabrielli@arm.com            reg = regs.rfcr;
2927639Sgblack@eecs.umich.edu            break;
2937639Sgblack@eecs.umich.edu
2947639Sgblack@eecs.umich.edu          case RFDR:
2957639Sgblack@eecs.umich.edu            rfaddr = (uint16_t)(regs.rfcr & RFCR_RFADDR);
2967639Sgblack@eecs.umich.edu            switch (rfaddr) {
2977639Sgblack@eecs.umich.edu              // Read from perfect match ROM octets
2987303Sgblack@eecs.umich.edu              case 0x000:
2997303Sgblack@eecs.umich.edu                reg = rom.perfectMatch[1];
3007303Sgblack@eecs.umich.edu                reg = reg << 8;
3017303Sgblack@eecs.umich.edu                reg += rom.perfectMatch[0];
3027303Sgblack@eecs.umich.edu                break;
3037303Sgblack@eecs.umich.edu              case 0x002:
3047303Sgblack@eecs.umich.edu                reg = rom.perfectMatch[3] << 8;
3057303Sgblack@eecs.umich.edu                reg += rom.perfectMatch[2];
3067303Sgblack@eecs.umich.edu                break;
3077303Sgblack@eecs.umich.edu              case 0x004:
3087303Sgblack@eecs.umich.edu                reg = rom.perfectMatch[5] << 8;
3097303Sgblack@eecs.umich.edu                reg += rom.perfectMatch[4];
3107303Sgblack@eecs.umich.edu                break;
3117303Sgblack@eecs.umich.edu              default:
3127303Sgblack@eecs.umich.edu                // Read filter hash table
3137303Sgblack@eecs.umich.edu                if (rfaddr >= FHASH_ADDR &&
3147303Sgblack@eecs.umich.edu                    rfaddr < FHASH_ADDR + FHASH_SIZE) {
3157303Sgblack@eecs.umich.edu
3167303Sgblack@eecs.umich.edu                    // Only word-aligned reads supported
3177303Sgblack@eecs.umich.edu                    if (rfaddr % 2)
3188442Sgblack@eecs.umich.edu                        panic("unaligned read from filter hash table!");
3198442Sgblack@eecs.umich.edu
3207303Sgblack@eecs.umich.edu                    reg = rom.filterHash[rfaddr - FHASH_ADDR + 1] << 8;
3217303Sgblack@eecs.umich.edu                    reg += rom.filterHash[rfaddr - FHASH_ADDR];
3227303Sgblack@eecs.umich.edu                    break;
3237303Sgblack@eecs.umich.edu                }
3247303Sgblack@eecs.umich.edu
3257303Sgblack@eecs.umich.edu                panic("reading RFDR for something other than pattern"
3267303Sgblack@eecs.umich.edu                      " matching or hashing! %#x\n", rfaddr);
3277303Sgblack@eecs.umich.edu            }
3287303Sgblack@eecs.umich.edu            break;
3297597Sminkyu.jeong@arm.com
3307597Sminkyu.jeong@arm.com          case SRR:
3317303Sgblack@eecs.umich.edu            reg = regs.srr;
3327303Sgblack@eecs.umich.edu            break;
3337303Sgblack@eecs.umich.edu
3347303Sgblack@eecs.umich.edu          case MIBC:
3357303Sgblack@eecs.umich.edu            reg = regs.mibc;
3367303Sgblack@eecs.umich.edu            reg &= ~(MIBC_MIBS | MIBC_ACLR);
3377303Sgblack@eecs.umich.edu            break;
3387303Sgblack@eecs.umich.edu
3397303Sgblack@eecs.umich.edu          case VRCR:
3407303Sgblack@eecs.umich.edu            reg = regs.vrcr;
3417303Sgblack@eecs.umich.edu            break;
3427303Sgblack@eecs.umich.edu
3437303Sgblack@eecs.umich.edu          case VTCR:
3447303Sgblack@eecs.umich.edu            reg = regs.vtcr;
3457303Sgblack@eecs.umich.edu            break;
3467303Sgblack@eecs.umich.edu
3477303Sgblack@eecs.umich.edu          case VDR:
3487303Sgblack@eecs.umich.edu            reg = regs.vdr;
3497303Sgblack@eecs.umich.edu            break;
3507303Sgblack@eecs.umich.edu
3517303Sgblack@eecs.umich.edu          case CCSR:
3527303Sgblack@eecs.umich.edu            reg = regs.ccsr;
3537303Sgblack@eecs.umich.edu            break;
3547303Sgblack@eecs.umich.edu
3558442Sgblack@eecs.umich.edu          case TBICR:
3568442Sgblack@eecs.umich.edu            reg = regs.tbicr;
3577303Sgblack@eecs.umich.edu            break;
3587597Sminkyu.jeong@arm.com
3597597Sminkyu.jeong@arm.com          case TBISR:
3607303Sgblack@eecs.umich.edu            reg = regs.tbisr;
3617408Sgblack@eecs.umich.edu            break;
3627303Sgblack@eecs.umich.edu
3637303Sgblack@eecs.umich.edu          case TANAR:
3647303Sgblack@eecs.umich.edu            reg = regs.tanar;
3657303Sgblack@eecs.umich.edu            break;
3667120Sgblack@eecs.umich.edu
3677120Sgblack@eecs.umich.edu          case TANLPAR:
3687120Sgblack@eecs.umich.edu            reg = regs.tanlpar;
3697120Sgblack@eecs.umich.edu            break;
3707120Sgblack@eecs.umich.edu
3717120Sgblack@eecs.umich.edu          case TANER:
3727120Sgblack@eecs.umich.edu            reg = regs.taner;
3737120Sgblack@eecs.umich.edu            break;
3747120Sgblack@eecs.umich.edu
3757120Sgblack@eecs.umich.edu          case TESR:
3767120Sgblack@eecs.umich.edu            reg = regs.tesr;
3777120Sgblack@eecs.umich.edu            break;
3787120Sgblack@eecs.umich.edu
3797120Sgblack@eecs.umich.edu          case M5REG:
3807120Sgblack@eecs.umich.edu            reg = 0;
3817120Sgblack@eecs.umich.edu            if (params()->rx_thread)
3827120Sgblack@eecs.umich.edu                reg |= M5REG_RX_THREAD;
3837120Sgblack@eecs.umich.edu            if (params()->tx_thread)
3848442Sgblack@eecs.umich.edu                reg |= M5REG_TX_THREAD;
3858442Sgblack@eecs.umich.edu            if (params()->rss)
3867120Sgblack@eecs.umich.edu                reg |= M5REG_RSS;
3877597Sminkyu.jeong@arm.com            break;
3887597Sminkyu.jeong@arm.com
3897120Sgblack@eecs.umich.edu          default:
3907120Sgblack@eecs.umich.edu            panic("reading unimplemented register: addr=%#x", daddr);
3917120Sgblack@eecs.umich.edu        }
3927120Sgblack@eecs.umich.edu
3937120Sgblack@eecs.umich.edu        DPRINTF(EthernetPIO, "read from %#x: data=%d data=%#x\n",
3947120Sgblack@eecs.umich.edu                daddr, reg, reg);
3957639Sgblack@eecs.umich.edu
3967639Sgblack@eecs.umich.edu    pkt->makeAtomicResponse();
3977639Sgblack@eecs.umich.edu    return pioDelay;
3987639Sgblack@eecs.umich.edu}
3997639Sgblack@eecs.umich.edu
4007639Sgblack@eecs.umich.eduTick
4017639Sgblack@eecs.umich.eduNSGigE::write(PacketPtr pkt)
4027639Sgblack@eecs.umich.edu{
4037639Sgblack@eecs.umich.edu    assert(ioEnable);
4047639Sgblack@eecs.umich.edu
4057639Sgblack@eecs.umich.edu    Addr daddr = pkt->getAddr() & 0xfff;
4067639Sgblack@eecs.umich.edu    DPRINTF(EthernetPIO, "write da=%#x pa=%#x size=%d\n",
4077639Sgblack@eecs.umich.edu            daddr, pkt->getAddr(), pkt->getSize());
4087639Sgblack@eecs.umich.edu
4097639Sgblack@eecs.umich.edu    if (daddr > LAST && daddr <=  RESERVED) {
4107639Sgblack@eecs.umich.edu        panic("Accessing reserved register");
4117639Sgblack@eecs.umich.edu    } else if (daddr > RESERVED && daddr <= 0x3FC) {
4127639Sgblack@eecs.umich.edu        return writeConfig(pkt);
4137639Sgblack@eecs.umich.edu    } else if (daddr > 0x3FC)
4147639Sgblack@eecs.umich.edu        panic("Something is messed up!\n");
4157639Sgblack@eecs.umich.edu
4167639Sgblack@eecs.umich.edu    if (pkt->getSize() == sizeof(uint32_t)) {
4177639Sgblack@eecs.umich.edu        uint32_t reg = pkt->get<uint32_t>();
4187639Sgblack@eecs.umich.edu        uint16_t rfaddr;
4198072SGiacomo.Gabrielli@arm.com
4208072SGiacomo.Gabrielli@arm.com        DPRINTF(EthernetPIO, "write data=%d data=%#x\n", reg, reg);
4217639Sgblack@eecs.umich.edu
4227639Sgblack@eecs.umich.edu        switch (daddr) {
4237639Sgblack@eecs.umich.edu          case CR:
4247639Sgblack@eecs.umich.edu            regs.command = reg;
4257639Sgblack@eecs.umich.edu            if (reg & CR_TXD) {
4267639Sgblack@eecs.umich.edu                txEnable = false;
4277119Sgblack@eecs.umich.edu            } else if (reg & CR_TXE) {
4287119Sgblack@eecs.umich.edu                txEnable = true;
4297119Sgblack@eecs.umich.edu
4307119Sgblack@eecs.umich.edu                // the kernel is enabling the transmit machine
4317119Sgblack@eecs.umich.edu                if (txState == txIdle)
4327119Sgblack@eecs.umich.edu                    txKick();
4337119Sgblack@eecs.umich.edu            }
4347119Sgblack@eecs.umich.edu
4357119Sgblack@eecs.umich.edu            if (reg & CR_RXD) {
4367119Sgblack@eecs.umich.edu                rxEnable = false;
4377119Sgblack@eecs.umich.edu            } else if (reg & CR_RXE) {
4387119Sgblack@eecs.umich.edu                rxEnable = true;
4397119Sgblack@eecs.umich.edu
4407119Sgblack@eecs.umich.edu                if (rxState == rxIdle)
4418442Sgblack@eecs.umich.edu                    rxKick();
4427119Sgblack@eecs.umich.edu            }
4437597Sminkyu.jeong@arm.com
4447597Sminkyu.jeong@arm.com            if (reg & CR_TXR)
4457119Sgblack@eecs.umich.edu                txReset();
4467119Sgblack@eecs.umich.edu
4477119Sgblack@eecs.umich.edu            if (reg & CR_RXR)
4487119Sgblack@eecs.umich.edu                rxReset();
4497119Sgblack@eecs.umich.edu
4507119Sgblack@eecs.umich.edu            if (reg & CR_SWI)
4517639Sgblack@eecs.umich.edu                devIntrPost(ISR_SWI);
4527639Sgblack@eecs.umich.edu
4537639Sgblack@eecs.umich.edu            if (reg & CR_RST) {
4547639Sgblack@eecs.umich.edu                txReset();
4557639Sgblack@eecs.umich.edu                rxReset();
4567639Sgblack@eecs.umich.edu
4577639Sgblack@eecs.umich.edu                regsReset();
4587639Sgblack@eecs.umich.edu            }
4598207SAli.Saidi@ARM.com            break;
4608207SAli.Saidi@ARM.com
4617639Sgblack@eecs.umich.edu          case CFGR:
4627639Sgblack@eecs.umich.edu            if (reg & CFGR_LNKSTS ||
4637639Sgblack@eecs.umich.edu                reg & CFGR_SPDSTS ||
4648207SAli.Saidi@ARM.com                reg & CFGR_DUPSTS ||
4658207SAli.Saidi@ARM.com                reg & CFGR_RESERVED ||
4668207SAli.Saidi@ARM.com                reg & CFGR_T64ADDR ||
4677639Sgblack@eecs.umich.edu                reg & CFGR_PCI64_DET)
4687639Sgblack@eecs.umich.edu
4697639Sgblack@eecs.umich.edu            // First clear all writable bits
4708207SAli.Saidi@ARM.com            regs.config &= CFGR_LNKSTS | CFGR_SPDSTS | CFGR_DUPSTS |
4717639Sgblack@eecs.umich.edu                                   CFGR_RESERVED | CFGR_T64ADDR |
4728072SGiacomo.Gabrielli@arm.com                                   CFGR_PCI64_DET;
4738072SGiacomo.Gabrielli@arm.com            // Now set the appropriate writable bits
4747639Sgblack@eecs.umich.edu            regs.config |= reg & ~(CFGR_LNKSTS | CFGR_SPDSTS | CFGR_DUPSTS |
4757639Sgblack@eecs.umich.edu                                   CFGR_RESERVED | CFGR_T64ADDR |
4767639Sgblack@eecs.umich.edu                                   CFGR_PCI64_DET);
4777639Sgblack@eecs.umich.edu
4787639Sgblack@eecs.umich.edu// all these #if 0's are because i don't THINK the kernel needs to
4797639Sgblack@eecs.umich.edu// have these implemented. if there is a problem relating to one of
4807119Sgblack@eecs.umich.edu// these, you may need to add functionality in.
4817119Sgblack@eecs.umich.edu            if (reg & CFGR_TBI_EN) ;
4827119Sgblack@eecs.umich.edu            if (reg & CFGR_MODE_1000) ;
4837119Sgblack@eecs.umich.edu
4847119Sgblack@eecs.umich.edu            if (reg & CFGR_AUTO_1000)
4857119Sgblack@eecs.umich.edu                panic("CFGR_AUTO_1000 not implemented!\n");
4867119Sgblack@eecs.umich.edu
4877119Sgblack@eecs.umich.edu            if (reg & CFGR_PINT_DUPSTS ||
4887119Sgblack@eecs.umich.edu                reg & CFGR_PINT_LNKSTS ||
4897119Sgblack@eecs.umich.edu                reg & CFGR_PINT_SPDSTS)
4907119Sgblack@eecs.umich.edu                ;
4917119Sgblack@eecs.umich.edu
4927119Sgblack@eecs.umich.edu            if (reg & CFGR_TMRTEST) ;
4938442Sgblack@eecs.umich.edu            if (reg & CFGR_MRM_DIS) ;
4947119Sgblack@eecs.umich.edu            if (reg & CFGR_MWI_DIS) ;
4957119Sgblack@eecs.umich.edu
4967119Sgblack@eecs.umich.edu            if (reg & CFGR_T64ADDR) ;
4977119Sgblack@eecs.umich.edu            // panic("CFGR_T64ADDR is read only register!\n");
4987119Sgblack@eecs.umich.edu
4997119Sgblack@eecs.umich.edu            if (reg & CFGR_PCI64_DET)
5007119Sgblack@eecs.umich.edu                panic("CFGR_PCI64_DET is read only register!\n");
5017119Sgblack@eecs.umich.edu
5027119Sgblack@eecs.umich.edu            if (reg & CFGR_DATA64_EN) ;
5037119Sgblack@eecs.umich.edu            if (reg & CFGR_M64ADDR) ;
5047119Sgblack@eecs.umich.edu            if (reg & CFGR_PHY_RST) ;
5057119Sgblack@eecs.umich.edu            if (reg & CFGR_PHY_DIS) ;
5067119Sgblack@eecs.umich.edu
5077119Sgblack@eecs.umich.edu            if (reg & CFGR_EXTSTS_EN)
5087639Sgblack@eecs.umich.edu                extstsEnable = true;
5097639Sgblack@eecs.umich.edu            else
5107639Sgblack@eecs.umich.edu                extstsEnable = false;
5117639Sgblack@eecs.umich.edu
5127639Sgblack@eecs.umich.edu            if (reg & CFGR_REQALG) ;
5137639Sgblack@eecs.umich.edu            if (reg & CFGR_SB) ;
5147639Sgblack@eecs.umich.edu            if (reg & CFGR_POW) ;
5157639Sgblack@eecs.umich.edu            if (reg & CFGR_EXD) ;
5167639Sgblack@eecs.umich.edu            if (reg & CFGR_PESEL) ;
5177639Sgblack@eecs.umich.edu            if (reg & CFGR_BROM_DIS) ;
5187639Sgblack@eecs.umich.edu            if (reg & CFGR_EXT_125) ;
5197639Sgblack@eecs.umich.edu            if (reg & CFGR_BEM) ;
5207639Sgblack@eecs.umich.edu            break;
5217639Sgblack@eecs.umich.edu
5227639Sgblack@eecs.umich.edu          case MEAR:
5237639Sgblack@eecs.umich.edu            // Clear writable bits
5247639Sgblack@eecs.umich.edu            regs.mear &= MEAR_EEDO;
5257639Sgblack@eecs.umich.edu            // Set appropriate writable bits
5267639Sgblack@eecs.umich.edu            regs.mear |= reg & ~MEAR_EEDO;
5277639Sgblack@eecs.umich.edu
5287639Sgblack@eecs.umich.edu            // FreeBSD uses the EEPROM to read PMATCH (for the MAC address)
5297639Sgblack@eecs.umich.edu            // even though it could get it through RFDR
5307639Sgblack@eecs.umich.edu            if (reg & MEAR_EESEL) {
5317639Sgblack@eecs.umich.edu                // Rising edge of clock
5327639Sgblack@eecs.umich.edu                if (reg & MEAR_EECLK && !eepromClk)
5337639Sgblack@eecs.umich.edu                    eepromKick();
5347639Sgblack@eecs.umich.edu            }
5357639Sgblack@eecs.umich.edu            else {
5367639Sgblack@eecs.umich.edu                eepromState = eepromStart;
5377639Sgblack@eecs.umich.edu                regs.mear &= ~MEAR_EEDI;
5387120Sgblack@eecs.umich.edu            }
5397120Sgblack@eecs.umich.edu
5407120Sgblack@eecs.umich.edu            eepromClk = reg & MEAR_EECLK;
5417120Sgblack@eecs.umich.edu
5427120Sgblack@eecs.umich.edu            // since phy is completely faked, MEAR_MD* don't matter
5437712Sgblack@eecs.umich.edu            if (reg & MEAR_MDIO) ;
5447120Sgblack@eecs.umich.edu            if (reg & MEAR_MDDIR) ;
5457120Sgblack@eecs.umich.edu            if (reg & MEAR_MDC) ;
5467120Sgblack@eecs.umich.edu            break;
5477639Sgblack@eecs.umich.edu
5487639Sgblack@eecs.umich.edu          case PTSCR:
5497639Sgblack@eecs.umich.edu            regs.ptscr = reg & ~(PTSCR_RBIST_RDONLY);
5507639Sgblack@eecs.umich.edu            // these control BISTs for various parts of chip - we
5517639Sgblack@eecs.umich.edu            // don't care or do just fake that the BIST is done
5527639Sgblack@eecs.umich.edu            if (reg & PTSCR_RBIST_EN)
5537712Sgblack@eecs.umich.edu                regs.ptscr |= PTSCR_RBIST_DONE;
5547639Sgblack@eecs.umich.edu            if (reg & PTSCR_EEBIST_EN)
5557639Sgblack@eecs.umich.edu                regs.ptscr &= ~PTSCR_EEBIST_EN;
5567639Sgblack@eecs.umich.edu            if (reg & PTSCR_EELOAD_EN)
5577303Sgblack@eecs.umich.edu                regs.ptscr &= ~PTSCR_EELOAD_EN;
5587303Sgblack@eecs.umich.edu            break;
5597303Sgblack@eecs.umich.edu
5607303Sgblack@eecs.umich.edu          case ISR: /* writing to the ISR has no effect */
5617303Sgblack@eecs.umich.edu            panic("ISR is a read only register!\n");
5627303Sgblack@eecs.umich.edu
5637303Sgblack@eecs.umich.edu          case IMR:
5647303Sgblack@eecs.umich.edu            regs.imr = reg;
5657303Sgblack@eecs.umich.edu            devIntrChangeMask();
5667303Sgblack@eecs.umich.edu            break;
5677303Sgblack@eecs.umich.edu
5687303Sgblack@eecs.umich.edu          case IER:
5697303Sgblack@eecs.umich.edu            regs.ier = reg;
5707303Sgblack@eecs.umich.edu            break;
5717303Sgblack@eecs.umich.edu
5727303Sgblack@eecs.umich.edu          case IHR:
5737303Sgblack@eecs.umich.edu            regs.ihr = reg;
5747303Sgblack@eecs.umich.edu            /* not going to implement real interrupt holdoff */
5757303Sgblack@eecs.umich.edu            break;
5767303Sgblack@eecs.umich.edu
5777303Sgblack@eecs.umich.edu          case TXDP:
5787303Sgblack@eecs.umich.edu            regs.txdp = (reg & 0xFFFFFFFC);
5797303Sgblack@eecs.umich.edu            assert(txState == txIdle);
5807303Sgblack@eecs.umich.edu            CTDD = false;
5817291Sgblack@eecs.umich.edu            break;
5827291Sgblack@eecs.umich.edu
5837291Sgblack@eecs.umich.edu          case TXDP_HI:
5847291Sgblack@eecs.umich.edu            regs.txdp_hi = reg;
5857291Sgblack@eecs.umich.edu            break;
5867291Sgblack@eecs.umich.edu
5877291Sgblack@eecs.umich.edu          case TX_CFG:
5887291Sgblack@eecs.umich.edu            regs.txcfg = reg;
5897291Sgblack@eecs.umich.edu#if 0
5907291Sgblack@eecs.umich.edu            if (reg & TX_CFG_CSI) ;
5917291Sgblack@eecs.umich.edu            if (reg & TX_CFG_HBI) ;
5927291Sgblack@eecs.umich.edu            if (reg & TX_CFG_MLB) ;
5937291Sgblack@eecs.umich.edu            if (reg & TX_CFG_ATP) ;
5947291Sgblack@eecs.umich.edu            if (reg & TX_CFG_ECRETRY) {
5957291Sgblack@eecs.umich.edu                /*
5967291Sgblack@eecs.umich.edu                 * this could easily be implemented, but considering
5977291Sgblack@eecs.umich.edu                 * the network is just a fake pipe, wouldn't make
5987291Sgblack@eecs.umich.edu                 * sense to do this
5997291Sgblack@eecs.umich.edu                 */
6007291Sgblack@eecs.umich.edu            }
6017312Sgblack@eecs.umich.edu
6027312Sgblack@eecs.umich.edu            if (reg & TX_CFG_BRST_DIS) ;
6037312Sgblack@eecs.umich.edu#endif
6047312Sgblack@eecs.umich.edu
6057312Sgblack@eecs.umich.edu#if 0
6067312Sgblack@eecs.umich.edu            /* we handle our own DMA, ignore the kernel's exhortations */
6077312Sgblack@eecs.umich.edu            if (reg & TX_CFG_MXDMA) ;
6087312Sgblack@eecs.umich.edu#endif
6097312Sgblack@eecs.umich.edu
6107312Sgblack@eecs.umich.edu            // also, we currently don't care about fill/drain
6117312Sgblack@eecs.umich.edu            // thresholds though this may change in the future with
6127312Sgblack@eecs.umich.edu            // more realistic networks or a driver which changes it
6137312Sgblack@eecs.umich.edu            // according to feedback
6147312Sgblack@eecs.umich.edu
6157312Sgblack@eecs.umich.edu            break;
6167312Sgblack@eecs.umich.edu
6177312Sgblack@eecs.umich.edu          case GPIOR:
6187312Sgblack@eecs.umich.edu            // Only write writable bits
6197312Sgblack@eecs.umich.edu            regs.gpior &= GPIOR_UNUSED | GPIOR_GP5_IN | GPIOR_GP4_IN
6207312Sgblack@eecs.umich.edu                        | GPIOR_GP3_IN | GPIOR_GP2_IN | GPIOR_GP1_IN;
6217205Sgblack@eecs.umich.edu            regs.gpior |= reg & ~(GPIOR_UNUSED | GPIOR_GP5_IN | GPIOR_GP4_IN
6227205Sgblack@eecs.umich.edu                                | GPIOR_GP3_IN | GPIOR_GP2_IN | GPIOR_GP1_IN);
6237205Sgblack@eecs.umich.edu            /* these just control general purpose i/o pins, don't matter */
6247205Sgblack@eecs.umich.edu            break;
6257205Sgblack@eecs.umich.edu
6267205Sgblack@eecs.umich.edu          case RXDP:
6277205Sgblack@eecs.umich.edu            regs.rxdp = reg;
6287205Sgblack@eecs.umich.edu            CRDD = false;
6297205Sgblack@eecs.umich.edu            break;
6307205Sgblack@eecs.umich.edu
6317205Sgblack@eecs.umich.edu          case RXDP_HI:
6327205Sgblack@eecs.umich.edu            regs.rxdp_hi = reg;
6337205Sgblack@eecs.umich.edu            break;
6347205Sgblack@eecs.umich.edu
6357205Sgblack@eecs.umich.edu          case RX_CFG:
6367205Sgblack@eecs.umich.edu            regs.rxcfg = reg;
6377205Sgblack@eecs.umich.edu#if 0
6387205Sgblack@eecs.umich.edu            if (reg & RX_CFG_AEP) ;
6397205Sgblack@eecs.umich.edu            if (reg & RX_CFG_ARP) ;
6407205Sgblack@eecs.umich.edu            if (reg & RX_CFG_STRIPCRC) ;
6417279Sgblack@eecs.umich.edu            if (reg & RX_CFG_RX_RD) ;
6427279Sgblack@eecs.umich.edu            if (reg & RX_CFG_ALP) ;
6437279Sgblack@eecs.umich.edu            if (reg & RX_CFG_AIRL) ;
6447279Sgblack@eecs.umich.edu
6457279Sgblack@eecs.umich.edu            /* we handle our own DMA, ignore what kernel says about it */
6467279Sgblack@eecs.umich.edu            if (reg & RX_CFG_MXDMA) ;
6477279Sgblack@eecs.umich.edu
6487279Sgblack@eecs.umich.edu            //also, we currently don't care about fill/drain thresholds
6497279Sgblack@eecs.umich.edu            //though this may change in the future with more realistic
6507279Sgblack@eecs.umich.edu            //networks or a driver which changes it according to feedback
6517279Sgblack@eecs.umich.edu            if (reg & (RX_CFG_DRTH | RX_CFG_DRTH0)) ;
6527279Sgblack@eecs.umich.edu#endif
6537279Sgblack@eecs.umich.edu            break;
6547279Sgblack@eecs.umich.edu
6557279Sgblack@eecs.umich.edu          case PQCR:
6567279Sgblack@eecs.umich.edu            /* there is no priority queueing used in the linux 2.6 driver */
6577279Sgblack@eecs.umich.edu            regs.pqcr = reg;
6587279Sgblack@eecs.umich.edu            break;
6597279Sgblack@eecs.umich.edu
6607279Sgblack@eecs.umich.edu          case WCSR:
6617279Sgblack@eecs.umich.edu            /* not going to implement wake on LAN */
6627303Sgblack@eecs.umich.edu            regs.wcsr = reg;
6637303Sgblack@eecs.umich.edu            break;
6647303Sgblack@eecs.umich.edu
6657303Sgblack@eecs.umich.edu          case PCR:
6667303Sgblack@eecs.umich.edu            /* not going to implement pause control */
6677303Sgblack@eecs.umich.edu            regs.pcr = reg;
6687303Sgblack@eecs.umich.edu            break;
6697303Sgblack@eecs.umich.edu
6707303Sgblack@eecs.umich.edu          case RFCR:
6717303Sgblack@eecs.umich.edu            regs.rfcr = reg;
6727303Sgblack@eecs.umich.edu
6737303Sgblack@eecs.umich.edu            rxFilterEnable = (reg & RFCR_RFEN) ? true : false;
6747303Sgblack@eecs.umich.edu            acceptBroadcast = (reg & RFCR_AAB) ? true : false;
6757303Sgblack@eecs.umich.edu            acceptMulticast = (reg & RFCR_AAM) ? true : false;
6767303Sgblack@eecs.umich.edu            acceptUnicast = (reg & RFCR_AAU) ? true : false;
6777303Sgblack@eecs.umich.edu            acceptPerfect = (reg & RFCR_APM) ? true : false;
6787303Sgblack@eecs.umich.edu            acceptArp = (reg & RFCR_AARP) ? true : false;
6797303Sgblack@eecs.umich.edu            multicastHashEnable = (reg & RFCR_MHEN) ? true : false;
6807303Sgblack@eecs.umich.edu
6817303Sgblack@eecs.umich.edu#if 0
6827303Sgblack@eecs.umich.edu            if (reg & RFCR_APAT)
6837119Sgblack@eecs.umich.edu                panic("RFCR_APAT not implemented!\n");
6847119Sgblack@eecs.umich.edu#endif
6857119Sgblack@eecs.umich.edu            if (reg & RFCR_UHEN)
6867119Sgblack@eecs.umich.edu                panic("Unicast hash filtering not used by drivers!\n");
6877119Sgblack@eecs.umich.edu
6887119Sgblack@eecs.umich.edu            if (reg & RFCR_ULM)
6897119Sgblack@eecs.umich.edu                panic("RFCR_ULM not implemented!\n");
6907119Sgblack@eecs.umich.edu
6917119Sgblack@eecs.umich.edu            break;
6927119Sgblack@eecs.umich.edu
6937119Sgblack@eecs.umich.edu          case RFDR:
6947119Sgblack@eecs.umich.edu            rfaddr = (uint16_t)(regs.rfcr & RFCR_RFADDR);
6957119Sgblack@eecs.umich.edu            switch (rfaddr) {
6967119Sgblack@eecs.umich.edu              case 0x000:
6977119Sgblack@eecs.umich.edu                rom.perfectMatch[0] = (uint8_t)reg;
6987119Sgblack@eecs.umich.edu                rom.perfectMatch[1] = (uint8_t)(reg >> 8);
6997119Sgblack@eecs.umich.edu                break;
7007119Sgblack@eecs.umich.edu              case 0x002:
7017119Sgblack@eecs.umich.edu                rom.perfectMatch[2] = (uint8_t)reg;
7027119Sgblack@eecs.umich.edu                rom.perfectMatch[3] = (uint8_t)(reg >> 8);
7037303Sgblack@eecs.umich.edu                break;
7047303Sgblack@eecs.umich.edu              case 0x004:
7057303Sgblack@eecs.umich.edu                rom.perfectMatch[4] = (uint8_t)reg;
7067303Sgblack@eecs.umich.edu                rom.perfectMatch[5] = (uint8_t)(reg >> 8);
7077303Sgblack@eecs.umich.edu                break;
7087303Sgblack@eecs.umich.edu              default:
7097303Sgblack@eecs.umich.edu
7107303Sgblack@eecs.umich.edu                if (rfaddr >= FHASH_ADDR &&
7117303Sgblack@eecs.umich.edu                    rfaddr < FHASH_ADDR + FHASH_SIZE) {
7127303Sgblack@eecs.umich.edu
7137303Sgblack@eecs.umich.edu                    // Only word-aligned writes supported
7147303Sgblack@eecs.umich.edu                    if (rfaddr % 2)
7157303Sgblack@eecs.umich.edu                        panic("unaligned write to filter hash table!");
7167303Sgblack@eecs.umich.edu
7177303Sgblack@eecs.umich.edu                    rom.filterHash[rfaddr - FHASH_ADDR] = (uint8_t)reg;
7187303Sgblack@eecs.umich.edu                    rom.filterHash[rfaddr - FHASH_ADDR + 1]
7197303Sgblack@eecs.umich.edu                        = (uint8_t)(reg >> 8);
7207303Sgblack@eecs.umich.edu                    break;
7217303Sgblack@eecs.umich.edu                }
7227303Sgblack@eecs.umich.edu                panic("writing RFDR for something other than pattern matching\
7237303Sgblack@eecs.umich.edu                    or hashing! %#x\n", rfaddr);
7247646Sgene.wu@arm.com            }
7257279Sgblack@eecs.umich.edu
7267279Sgblack@eecs.umich.edu          case BRAR:
7277279Sgblack@eecs.umich.edu            regs.brar = reg;
7287279Sgblack@eecs.umich.edu            break;
7297279Sgblack@eecs.umich.edu
7307279Sgblack@eecs.umich.edu          case BRDR:
7317279Sgblack@eecs.umich.edu            panic("the driver never uses BRDR, something is wrong!\n");
7327279Sgblack@eecs.umich.edu
7337279Sgblack@eecs.umich.edu          case SRR:
7347279Sgblack@eecs.umich.edu            panic("SRR is read only register!\n");
7357279Sgblack@eecs.umich.edu
7367279Sgblack@eecs.umich.edu          case MIBC:
7377279Sgblack@eecs.umich.edu            panic("the driver never uses MIBC, something is wrong!\n");
7387279Sgblack@eecs.umich.edu
7397279Sgblack@eecs.umich.edu          case VRCR:
7407279Sgblack@eecs.umich.edu            regs.vrcr = reg;
7417279Sgblack@eecs.umich.edu            break;
7427279Sgblack@eecs.umich.edu
7437279Sgblack@eecs.umich.edu          case VTCR:
7447279Sgblack@eecs.umich.edu            regs.vtcr = reg;
7457279Sgblack@eecs.umich.edu            break;
7467279Sgblack@eecs.umich.edu
7477646Sgene.wu@arm.com          case VDR:
7487119Sgblack@eecs.umich.edu            panic("the driver never uses VDR, something is wrong!\n");
7497119Sgblack@eecs.umich.edu
7507119Sgblack@eecs.umich.edu          case CCSR:
7517119Sgblack@eecs.umich.edu            /* not going to implement clockrun stuff */
7527119Sgblack@eecs.umich.edu            regs.ccsr = reg;
7537119Sgblack@eecs.umich.edu            break;
7547119Sgblack@eecs.umich.edu
7557119Sgblack@eecs.umich.edu          case TBICR:
7567119Sgblack@eecs.umich.edu            regs.tbicr = reg;
7577119Sgblack@eecs.umich.edu            if (reg & TBICR_MR_LOOPBACK)
7587119Sgblack@eecs.umich.edu                panic("TBICR_MR_LOOPBACK never used, something wrong!\n");
7597119Sgblack@eecs.umich.edu
7607119Sgblack@eecs.umich.edu            if (reg & TBICR_MR_AN_ENABLE) {
7617119Sgblack@eecs.umich.edu                regs.tanlpar = regs.tanar;
7627119Sgblack@eecs.umich.edu                regs.tbisr |= (TBISR_MR_AN_COMPLETE | TBISR_MR_LINK_STATUS);
7637119Sgblack@eecs.umich.edu            }
7647119Sgblack@eecs.umich.edu
7657119Sgblack@eecs.umich.edu#if 0
7667119Sgblack@eecs.umich.edu            if (reg & TBICR_MR_RESTART_AN) ;
7677119Sgblack@eecs.umich.edu#endif
7687119Sgblack@eecs.umich.edu
7697646Sgene.wu@arm.com            break;
7707646Sgene.wu@arm.com
7717646Sgene.wu@arm.com          case TBISR:
7727646Sgene.wu@arm.com            panic("TBISR is read only register!\n");
7737646Sgene.wu@arm.com
7747646Sgene.wu@arm.com          case TANAR:
7757646Sgene.wu@arm.com            // Only write the writable bits
7767646Sgene.wu@arm.com            regs.tanar &= TANAR_RF1 | TANAR_RF2 | TANAR_UNUSED;
7777646Sgene.wu@arm.com            regs.tanar |= reg & ~(TANAR_RF1 | TANAR_RF2 | TANAR_UNUSED);
7787646Sgene.wu@arm.com
7797646Sgene.wu@arm.com            // Pause capability unimplemented
7807646Sgene.wu@arm.com#if 0
7817646Sgene.wu@arm.com            if (reg & TANAR_PS2) ;
7827646Sgene.wu@arm.com            if (reg & TANAR_PS1) ;
7837646Sgene.wu@arm.com#endif
7847646Sgene.wu@arm.com
7857646Sgene.wu@arm.com            break;
7867646Sgene.wu@arm.com
7877646Sgene.wu@arm.com          case TANLPAR:
7887646Sgene.wu@arm.com            panic("this should only be written to by the fake phy!\n");
7897646Sgene.wu@arm.com
7907646Sgene.wu@arm.com          case TANER:
7917646Sgene.wu@arm.com            panic("TANER is read only register!\n");
7927646Sgene.wu@arm.com
7937646Sgene.wu@arm.com          case TESR:
7947646Sgene.wu@arm.com            regs.tesr = reg;
7957646Sgene.wu@arm.com            break;
7967646Sgene.wu@arm.com
7977646Sgene.wu@arm.com          default:
7987646Sgene.wu@arm.com            panic("invalid register access daddr=%#x", daddr);
7997646Sgene.wu@arm.com        }
8007646Sgene.wu@arm.com    } else {
8017646Sgene.wu@arm.com        panic("Invalid Request Size");
8027646Sgene.wu@arm.com    }
8037646Sgene.wu@arm.com    pkt->makeAtomicResponse();
8047646Sgene.wu@arm.com    return pioDelay;
8057646Sgene.wu@arm.com}
8067646Sgene.wu@arm.com
8077646Sgene.wu@arm.comvoid
8087646Sgene.wu@arm.comNSGigE::devIntrPost(uint32_t interrupts)
8097646Sgene.wu@arm.com{
8107646Sgene.wu@arm.com    if (interrupts & ISR_RESERVE)
8117646Sgene.wu@arm.com        panic("Cannot set a reserved interrupt");
8127646Sgene.wu@arm.com
8137646Sgene.wu@arm.com    if (interrupts & ISR_NOIMPL)
8147646Sgene.wu@arm.com        warn("interrupt not implemented %#x\n", interrupts);
8157646Sgene.wu@arm.com
8167646Sgene.wu@arm.com    interrupts &= ISR_IMPL;
8177646Sgene.wu@arm.com    regs.isr |= interrupts;
8187646Sgene.wu@arm.com
8197646Sgene.wu@arm.com    if (interrupts & regs.imr) {
8207646Sgene.wu@arm.com        if (interrupts & ISR_SWI) {
8217646Sgene.wu@arm.com            totalSwi++;
8227646Sgene.wu@arm.com        }
8237646Sgene.wu@arm.com        if (interrupts & ISR_RXIDLE) {
8247646Sgene.wu@arm.com            totalRxIdle++;
8257646Sgene.wu@arm.com        }
8267646Sgene.wu@arm.com        if (interrupts & ISR_RXOK) {
8277646Sgene.wu@arm.com            totalRxOk++;
8287646Sgene.wu@arm.com        }
8297646Sgene.wu@arm.com        if (interrupts & ISR_RXDESC) {
8307646Sgene.wu@arm.com            totalRxDesc++;
8317646Sgene.wu@arm.com        }
8327646Sgene.wu@arm.com        if (interrupts & ISR_TXOK) {
8337646Sgene.wu@arm.com            totalTxOk++;
8347119Sgblack@eecs.umich.edu        }
8357119Sgblack@eecs.umich.edu        if (interrupts & ISR_TXIDLE) {
8367119Sgblack@eecs.umich.edu            totalTxIdle++;
8377119Sgblack@eecs.umich.edu        }
8387119Sgblack@eecs.umich.edu        if (interrupts & ISR_TXDESC) {
8397119Sgblack@eecs.umich.edu            totalTxDesc++;
8407119Sgblack@eecs.umich.edu        }
8417119Sgblack@eecs.umich.edu        if (interrupts & ISR_RXORN) {
8427291Sgblack@eecs.umich.edu            totalRxOrn++;
8437291Sgblack@eecs.umich.edu        }
8448140SMatt.Horsnell@arm.com    }
8458140SMatt.Horsnell@arm.com
8468140SMatt.Horsnell@arm.com    DPRINTF(EthernetIntr,
8477291Sgblack@eecs.umich.edu            "interrupt written to ISR: intr=%#x isr=%#x imr=%#x\n",
8487291Sgblack@eecs.umich.edu            interrupts, regs.isr, regs.imr);
8497848SAli.Saidi@ARM.com
8507848SAli.Saidi@ARM.com    if ((regs.isr & regs.imr)) {
8517848SAli.Saidi@ARM.com        Tick when = curTick;
8527848SAli.Saidi@ARM.com        if ((regs.isr & regs.imr & ISR_NODELAY) == 0)
8537848SAli.Saidi@ARM.com            when += intrDelay;
8547646Sgene.wu@arm.com        postedInterrupts++;
8558140SMatt.Horsnell@arm.com        cpuIntrPost(when);
8568140SMatt.Horsnell@arm.com    }
8578140SMatt.Horsnell@arm.com}
8588140SMatt.Horsnell@arm.com
8598140SMatt.Horsnell@arm.com/* writing this interrupt counting stats inside this means that this function
8608140SMatt.Horsnell@arm.com   is now limited to being used to clear all interrupts upon the kernel
8618140SMatt.Horsnell@arm.com   reading isr and servicing.  just telling you in case you were thinking
8628140SMatt.Horsnell@arm.com   of expanding use.
8638140SMatt.Horsnell@arm.com*/
8648140SMatt.Horsnell@arm.comvoid
8658140SMatt.Horsnell@arm.comNSGigE::devIntrClear(uint32_t interrupts)
8668140SMatt.Horsnell@arm.com{
8677646Sgene.wu@arm.com    if (interrupts & ISR_RESERVE)
8687291Sgblack@eecs.umich.edu        panic("Cannot clear a reserved interrupt");
8697291Sgblack@eecs.umich.edu
8707291Sgblack@eecs.umich.edu    if (regs.isr & regs.imr & ISR_SWI) {
8717312Sgblack@eecs.umich.edu        postedSwi++;
8727312Sgblack@eecs.umich.edu    }
8737312Sgblack@eecs.umich.edu    if (regs.isr & regs.imr & ISR_RXIDLE) {
8747312Sgblack@eecs.umich.edu        postedRxIdle++;
8757312Sgblack@eecs.umich.edu    }
8767312Sgblack@eecs.umich.edu    if (regs.isr & regs.imr & ISR_RXOK) {
8777312Sgblack@eecs.umich.edu        postedRxOk++;
8787848SAli.Saidi@ARM.com    }
8797848SAli.Saidi@ARM.com    if (regs.isr & regs.imr & ISR_RXDESC) {
8807848SAli.Saidi@ARM.com            postedRxDesc++;
8817848SAli.Saidi@ARM.com    }
8827848SAli.Saidi@ARM.com    if (regs.isr & regs.imr & ISR_TXOK) {
8837646Sgene.wu@arm.com        postedTxOk++;
8847646Sgene.wu@arm.com    }
8857646Sgene.wu@arm.com    if (regs.isr & regs.imr & ISR_TXIDLE) {
8867646Sgene.wu@arm.com        postedTxIdle++;
8877724SAli.Saidi@ARM.com    }
8887646Sgene.wu@arm.com    if (regs.isr & regs.imr & ISR_TXDESC) {
8897646Sgene.wu@arm.com        postedTxDesc++;
8907646Sgene.wu@arm.com    }
8917312Sgblack@eecs.umich.edu    if (regs.isr & regs.imr & ISR_RXORN) {
8927312Sgblack@eecs.umich.edu        postedRxOrn++;
8937312Sgblack@eecs.umich.edu    }
8947205Sgblack@eecs.umich.edu
8957205Sgblack@eecs.umich.edu    interrupts &= ~ISR_NOIMPL;
8967205Sgblack@eecs.umich.edu    regs.isr &= ~interrupts;
8977205Sgblack@eecs.umich.edu
8987205Sgblack@eecs.umich.edu    DPRINTF(EthernetIntr,
8997205Sgblack@eecs.umich.edu            "interrupt cleared from ISR: intr=%x isr=%x imr=%x\n",
9007205Sgblack@eecs.umich.edu            interrupts, regs.isr, regs.imr);
9017848SAli.Saidi@ARM.com
9027848SAli.Saidi@ARM.com    if (!(regs.isr & regs.imr))
9037848SAli.Saidi@ARM.com        cpuIntrClear();
9047848SAli.Saidi@ARM.com}
9057848SAli.Saidi@ARM.com
9067205Sgblack@eecs.umich.eduvoid
9077205Sgblack@eecs.umich.eduNSGigE::devIntrChangeMask()
9087205Sgblack@eecs.umich.edu{
9097279Sgblack@eecs.umich.edu    DPRINTF(EthernetIntr, "interrupt mask changed: isr=%x imr=%x masked=%x\n",
9107279Sgblack@eecs.umich.edu            regs.isr, regs.imr, regs.isr & regs.imr);
9117279Sgblack@eecs.umich.edu
9127279Sgblack@eecs.umich.edu    if (regs.isr & regs.imr)
9137279Sgblack@eecs.umich.edu        cpuIntrPost(curTick);
9147279Sgblack@eecs.umich.edu    else
9157279Sgblack@eecs.umich.edu        cpuIntrClear();
9167279Sgblack@eecs.umich.edu}
9177279Sgblack@eecs.umich.edu
9187848SAli.Saidi@ARM.comvoid
9197848SAli.Saidi@ARM.comNSGigE::cpuIntrPost(Tick when)
9207848SAli.Saidi@ARM.com{
9217848SAli.Saidi@ARM.com    // If the interrupt you want to post is later than an interrupt
9227848SAli.Saidi@ARM.com    // already scheduled, just let it post in the coming one and don't
9237646Sgene.wu@arm.com    // schedule another.
9247646Sgene.wu@arm.com    // HOWEVER, must be sure that the scheduled intrTick is in the
9257646Sgene.wu@arm.com    // future (this was formerly the source of a bug)
9267646Sgene.wu@arm.com    /**
9277724SAli.Saidi@ARM.com     * @todo this warning should be removed and the intrTick code should
9287646Sgene.wu@arm.com     * be fixed.
9297646Sgene.wu@arm.com     */
9307646Sgene.wu@arm.com    assert(when >= curTick);
9317279Sgblack@eecs.umich.edu    assert(intrTick >= curTick || intrTick == 0);
9327279Sgblack@eecs.umich.edu    if (when > intrTick && intrTick != 0) {
9337279Sgblack@eecs.umich.edu        DPRINTF(EthernetIntr, "don't need to schedule event...intrTick=%d\n",
9347303Sgblack@eecs.umich.edu                intrTick);
9357303Sgblack@eecs.umich.edu        return;
9367303Sgblack@eecs.umich.edu    }
9377303Sgblack@eecs.umich.edu
9387303Sgblack@eecs.umich.edu    intrTick = when;
9397303Sgblack@eecs.umich.edu    if (intrTick < curTick) {
9407303Sgblack@eecs.umich.edu        debug_break();
9417303Sgblack@eecs.umich.edu        intrTick = curTick;
9427303Sgblack@eecs.umich.edu    }
9437303Sgblack@eecs.umich.edu
9447848SAli.Saidi@ARM.com    DPRINTF(EthernetIntr, "going to schedule an interrupt for intrTick=%d\n",
9457848SAli.Saidi@ARM.com            intrTick);
9467848SAli.Saidi@ARM.com
9477848SAli.Saidi@ARM.com    if (intrEvent)
9487848SAli.Saidi@ARM.com        intrEvent->squash();
9497646Sgene.wu@arm.com    intrEvent = new IntrEvent(this, true);
9507646Sgene.wu@arm.com    schedule(intrEvent, intrTick);
9517646Sgene.wu@arm.com}
9527646Sgene.wu@arm.com
9537646Sgene.wu@arm.comvoid
9547724SAli.Saidi@ARM.comNSGigE::cpuInterrupt()
9557646Sgene.wu@arm.com{
9567646Sgene.wu@arm.com    assert(intrTick == curTick);
9577646Sgene.wu@arm.com
9587303Sgblack@eecs.umich.edu    // Whether or not there's a pending interrupt, we don't care about
9597303Sgblack@eecs.umich.edu    // it anymore
9607303Sgblack@eecs.umich.edu    intrEvent = 0;
9617119Sgblack@eecs.umich.edu    intrTick = 0;
9627119Sgblack@eecs.umich.edu
9637119Sgblack@eecs.umich.edu    // Don't send an interrupt if there's already one
9647119Sgblack@eecs.umich.edu    if (cpuPendingIntr) {
9657119Sgblack@eecs.umich.edu        DPRINTF(EthernetIntr,
9667119Sgblack@eecs.umich.edu                "would send an interrupt now, but there's already pending\n");
9677119Sgblack@eecs.umich.edu    } else {
9687848SAli.Saidi@ARM.com        // Send interrupt
9697848SAli.Saidi@ARM.com        cpuPendingIntr = true;
9707848SAli.Saidi@ARM.com
9717848SAli.Saidi@ARM.com        DPRINTF(EthernetIntr, "posting interrupt\n");
9727848SAli.Saidi@ARM.com        intrPost();
9737646Sgene.wu@arm.com    }
9747646Sgene.wu@arm.com}
9757646Sgene.wu@arm.com
9767646Sgene.wu@arm.comvoid
9777724SAli.Saidi@ARM.comNSGigE::cpuIntrClear()
9787646Sgene.wu@arm.com{
9797646Sgene.wu@arm.com    if (!cpuPendingIntr)
9807646Sgene.wu@arm.com        return;
9817119Sgblack@eecs.umich.edu
9827119Sgblack@eecs.umich.edu    if (intrEvent) {
9837119Sgblack@eecs.umich.edu        intrEvent->squash();
9847303Sgblack@eecs.umich.edu        intrEvent = 0;
9857303Sgblack@eecs.umich.edu    }
9867303Sgblack@eecs.umich.edu
9877303Sgblack@eecs.umich.edu    intrTick = 0;
9887303Sgblack@eecs.umich.edu
9897303Sgblack@eecs.umich.edu    cpuPendingIntr = false;
9907303Sgblack@eecs.umich.edu
9917303Sgblack@eecs.umich.edu    DPRINTF(EthernetIntr, "clearing interrupt\n");
9927303Sgblack@eecs.umich.edu    intrClear();
9937848SAli.Saidi@ARM.com}
9947848SAli.Saidi@ARM.com
9957848SAli.Saidi@ARM.combool
9967848SAli.Saidi@ARM.comNSGigE::cpuIntrPending() const
9977848SAli.Saidi@ARM.com{ return cpuPendingIntr; }
9987646Sgene.wu@arm.com
9997646Sgene.wu@arm.comvoid
10007646Sgene.wu@arm.comNSGigE::txReset()
10017646Sgene.wu@arm.com{
10027646Sgene.wu@arm.com
10037724SAli.Saidi@ARM.com    DPRINTF(Ethernet, "transmit reset\n");
10047646Sgene.wu@arm.com
10057646Sgene.wu@arm.com    CTDD = false;
10067646Sgene.wu@arm.com    txEnable = false;;
10077303Sgblack@eecs.umich.edu    txFragPtr = 0;
10087303Sgblack@eecs.umich.edu    assert(txDescCnt == 0);
10097303Sgblack@eecs.umich.edu    txFifo.clear();
10107646Sgene.wu@arm.com    txState = txIdle;
10117279Sgblack@eecs.umich.edu    assert(txDmaState == dmaIdle);
10127279Sgblack@eecs.umich.edu}
10137279Sgblack@eecs.umich.edu
10147279Sgblack@eecs.umich.eduvoid
10157279Sgblack@eecs.umich.eduNSGigE::rxReset()
10167279Sgblack@eecs.umich.edu{
10177279Sgblack@eecs.umich.edu    DPRINTF(Ethernet, "receive reset\n");
10187279Sgblack@eecs.umich.edu
10197279Sgblack@eecs.umich.edu    CRDD = false;
10207279Sgblack@eecs.umich.edu    assert(rxPktBytes == 0);
10217848SAli.Saidi@ARM.com    rxEnable = false;
10227848SAli.Saidi@ARM.com    rxFragPtr = 0;
10237848SAli.Saidi@ARM.com    assert(rxDescCnt == 0);
10247848SAli.Saidi@ARM.com    assert(rxDmaState == dmaIdle);
10257848SAli.Saidi@ARM.com    rxFifo.clear();
10267646Sgene.wu@arm.com    rxState = rxIdle;
10277646Sgene.wu@arm.com}
10287646Sgene.wu@arm.com
10297646Sgene.wu@arm.comvoid
10307646Sgene.wu@arm.comNSGigE::regsReset()
10317724SAli.Saidi@ARM.com{
10327646Sgene.wu@arm.com    memset(&regs, 0, sizeof(regs));
10337646Sgene.wu@arm.com    regs.config = (CFGR_LNKSTS | CFGR_TBI_EN | CFGR_MODE_1000);
10347646Sgene.wu@arm.com    regs.mear = 0x12;
10357279Sgblack@eecs.umich.edu    regs.txcfg = 0x120; // set drain threshold to 1024 bytes and
10367279Sgblack@eecs.umich.edu                        // fill threshold to 32 bytes
10377279Sgblack@eecs.umich.edu    regs.rxcfg = 0x4;   // set drain threshold to 16 bytes
10387646Sgene.wu@arm.com    regs.srr = 0x0103;  // set the silicon revision to rev B or 0x103
10397119Sgblack@eecs.umich.edu    regs.mibc = MIBC_FRZ;
10407119Sgblack@eecs.umich.edu    regs.vdr = 0x81;    // set the vlan tag type to 802.1q
10417119Sgblack@eecs.umich.edu    regs.tesr = 0xc000; // TBI capable of both full and half duplex
10427119Sgblack@eecs.umich.edu    regs.brar = 0xffffffff;
10437119Sgblack@eecs.umich.edu
10447119Sgblack@eecs.umich.edu    extstsEnable = false;
10457119Sgblack@eecs.umich.edu    acceptBroadcast = false;
10467119Sgblack@eecs.umich.edu    acceptMulticast = false;
10477119Sgblack@eecs.umich.edu    acceptUnicast = false;
10487848SAli.Saidi@ARM.com    acceptPerfect = false;
10497848SAli.Saidi@ARM.com    acceptArp = false;
10507848SAli.Saidi@ARM.com}
10517848SAli.Saidi@ARM.com
10527848SAli.Saidi@ARM.combool
10537646Sgene.wu@arm.comNSGigE::doRxDmaRead()
10547646Sgene.wu@arm.com{
10557646Sgene.wu@arm.com    assert(rxDmaState == dmaIdle || rxDmaState == dmaReadWaiting);
10567646Sgene.wu@arm.com    rxDmaState = dmaReading;
10577646Sgene.wu@arm.com
10587724SAli.Saidi@ARM.com    if (dmaPending() || getState() != Running)
10597646Sgene.wu@arm.com        rxDmaState = dmaReadWaiting;
10607646Sgene.wu@arm.com    else
10617646Sgene.wu@arm.com        dmaRead(rxDmaAddr, rxDmaLen, &rxDmaReadEvent, (uint8_t*)rxDmaData);
10627119Sgblack@eecs.umich.edu
10637119Sgblack@eecs.umich.edu    return true;
10647646Sgene.wu@arm.com}
10657646Sgene.wu@arm.com
10667646Sgene.wu@arm.comvoid
10677646Sgene.wu@arm.comNSGigE::rxDmaReadDone()
10687646Sgene.wu@arm.com{
10697646Sgene.wu@arm.com    assert(rxDmaState == dmaReading);
10707646Sgene.wu@arm.com    rxDmaState = dmaIdle;
10717646Sgene.wu@arm.com
10727646Sgene.wu@arm.com    DPRINTF(EthernetDMA, "rx dma read  paddr=%#x len=%d\n",
10737646Sgene.wu@arm.com            rxDmaAddr, rxDmaLen);
10747646Sgene.wu@arm.com    DDUMP(EthernetDMA, rxDmaData, rxDmaLen);
10757646Sgene.wu@arm.com
10767848SAli.Saidi@ARM.com    // If the transmit state machine has a pending DMA, let it go first
10777848SAli.Saidi@ARM.com    if (txDmaState == dmaReadWaiting || txDmaState == dmaWriteWaiting)
10787848SAli.Saidi@ARM.com        txKick();
10797848SAli.Saidi@ARM.com
10807848SAli.Saidi@ARM.com    rxKick();
10817646Sgene.wu@arm.com}
10827646Sgene.wu@arm.com
10837646Sgene.wu@arm.combool
10847646Sgene.wu@arm.comNSGigE::doRxDmaWrite()
10857646Sgene.wu@arm.com{
10867646Sgene.wu@arm.com    assert(rxDmaState == dmaIdle || rxDmaState == dmaWriteWaiting);
10877724SAli.Saidi@ARM.com    rxDmaState = dmaWriting;
10887646Sgene.wu@arm.com
10897646Sgene.wu@arm.com    if (dmaPending() || getState() != Running)
10907724SAli.Saidi@ARM.com        rxDmaState = dmaWriteWaiting;
10917646Sgene.wu@arm.com    else
10927646Sgene.wu@arm.com        dmaWrite(rxDmaAddr, rxDmaLen, &rxDmaWriteEvent, (uint8_t*)rxDmaData);
10937646Sgene.wu@arm.com    return true;
10947646Sgene.wu@arm.com}
10957646Sgene.wu@arm.com
10967646Sgene.wu@arm.comvoid
10977724SAli.Saidi@ARM.comNSGigE::rxDmaWriteDone()
10987646Sgene.wu@arm.com{
10997646Sgene.wu@arm.com    assert(rxDmaState == dmaWriting);
11007646Sgene.wu@arm.com    rxDmaState = dmaIdle;
11017646Sgene.wu@arm.com
11027646Sgene.wu@arm.com    DPRINTF(EthernetDMA, "rx dma write paddr=%#x len=%d\n",
11037646Sgene.wu@arm.com            rxDmaAddr, rxDmaLen);
11047646Sgene.wu@arm.com    DDUMP(EthernetDMA, rxDmaData, rxDmaLen);
11057646Sgene.wu@arm.com
11067646Sgene.wu@arm.com    // If the transmit state machine has a pending DMA, let it go first
11077646Sgene.wu@arm.com    if (txDmaState == dmaReadWaiting || txDmaState == dmaWriteWaiting)
11087646Sgene.wu@arm.com        txKick();
11097646Sgene.wu@arm.com
11107646Sgene.wu@arm.com    rxKick();
11117646Sgene.wu@arm.com}
11127646Sgene.wu@arm.com
11137646Sgene.wu@arm.comvoid
11147646Sgene.wu@arm.comNSGigE::rxKick()
11158203SAli.Saidi@ARM.com{
11167848SAli.Saidi@ARM.com    bool is64bit = (bool)(regs.config & CFGR_M64ADDR);
11178203SAli.Saidi@ARM.com
11187848SAli.Saidi@ARM.com    DPRINTF(EthernetSM,
11197848SAli.Saidi@ARM.com            "receive kick rxState=%s (rxBuf.size=%d) %d-bit\n",
11207848SAli.Saidi@ARM.com            NsRxStateStrings[rxState], rxFifo.size(), is64bit ? 64 : 32);
11217848SAli.Saidi@ARM.com
11227646Sgene.wu@arm.com    Addr link, bufptr;
11237646Sgene.wu@arm.com    uint32_t &cmdsts = is64bit ? rxDesc64.cmdsts : rxDesc32.cmdsts;
11247646Sgene.wu@arm.com    uint32_t &extsts = is64bit ? rxDesc64.extsts : rxDesc32.extsts;
11257646Sgene.wu@arm.com
11267646Sgene.wu@arm.com  next:
11277646Sgene.wu@arm.com    if (clock) {
11287646Sgene.wu@arm.com        if (rxKickTick > curTick) {
11297724SAli.Saidi@ARM.com            DPRINTF(EthernetSM, "receive kick exiting, can't run till %d\n",
11307646Sgene.wu@arm.com                    rxKickTick);
11317724SAli.Saidi@ARM.com
11327646Sgene.wu@arm.com            goto exit;
11338203SAli.Saidi@ARM.com        }
11348203SAli.Saidi@ARM.com
11358203SAli.Saidi@ARM.com        // Go to the next state machine clock tick.
11368203SAli.Saidi@ARM.com        rxKickTick = curTick + ticks(1);
11378203SAli.Saidi@ARM.com    }
11388203SAli.Saidi@ARM.com
11397646Sgene.wu@arm.com    switch(rxDmaState) {
11407646Sgene.wu@arm.com      case dmaReadWaiting:
11417646Sgene.wu@arm.com        if (doRxDmaRead())
11427646Sgene.wu@arm.com            goto exit;
11437724SAli.Saidi@ARM.com        break;
11447646Sgene.wu@arm.com      case dmaWriteWaiting:
11457646Sgene.wu@arm.com        if (doRxDmaWrite())
11467724SAli.Saidi@ARM.com            goto exit;
11477646Sgene.wu@arm.com        break;
11487646Sgene.wu@arm.com      default:
11497646Sgene.wu@arm.com        break;
11507646Sgene.wu@arm.com    }
11517646Sgene.wu@arm.com
11527646Sgene.wu@arm.com    link = is64bit ? (Addr)rxDesc64.link : (Addr)rxDesc32.link;
11537724SAli.Saidi@ARM.com    bufptr = is64bit ? (Addr)rxDesc64.bufptr : (Addr)rxDesc32.bufptr;
11547646Sgene.wu@arm.com
11557646Sgene.wu@arm.com    // see state machine from spec for details
11567646Sgene.wu@arm.com    // the way this works is, if you finish work on one state and can
11577646Sgene.wu@arm.com    // go directly to another, you do that through jumping to the
11587646Sgene.wu@arm.com    // label "next".  however, if you have intermediate work, like DMA
11597646Sgene.wu@arm.com    // so that you can't go to the next state yet, you go to exit and
11607646Sgene.wu@arm.com    // exit the loop.  however, when the DMA is done it will trigger
11617646Sgene.wu@arm.com    // an event and come back to this loop.
11627646Sgene.wu@arm.com    switch (rxState) {
11637646Sgene.wu@arm.com      case rxIdle:
11647646Sgene.wu@arm.com        if (!rxEnable) {
11657646Sgene.wu@arm.com            DPRINTF(EthernetSM, "Receive Disabled! Nothing to do.\n");
11667646Sgene.wu@arm.com            goto exit;
11677646Sgene.wu@arm.com        }
11687646Sgene.wu@arm.com
11698203SAli.Saidi@ARM.com        if (CRDD) {
11707848SAli.Saidi@ARM.com            rxState = rxDescRefr;
11718203SAli.Saidi@ARM.com
11727848SAli.Saidi@ARM.com            rxDmaAddr = regs.rxdp & 0x3fffffff;
11737848SAli.Saidi@ARM.com            rxDmaData =
11747848SAli.Saidi@ARM.com                is64bit ? (void *)&rxDesc64.link : (void *)&rxDesc32.link;
11757848SAli.Saidi@ARM.com            rxDmaLen = is64bit ? sizeof(rxDesc64.link) : sizeof(rxDesc32.link);
11767646Sgene.wu@arm.com            rxDmaFree = dmaDescFree;
11777646Sgene.wu@arm.com
11787646Sgene.wu@arm.com            descDmaReads++;
11797646Sgene.wu@arm.com            descDmaRdBytes += rxDmaLen;
11807646Sgene.wu@arm.com
11817646Sgene.wu@arm.com            if (doRxDmaRead())
11827724SAli.Saidi@ARM.com                goto exit;
11837646Sgene.wu@arm.com        } else {
11847724SAli.Saidi@ARM.com            rxState = rxDescRead;
11857646Sgene.wu@arm.com
11868203SAli.Saidi@ARM.com            rxDmaAddr = regs.rxdp & 0x3fffffff;
11878203SAli.Saidi@ARM.com            rxDmaData = is64bit ? (void *)&rxDesc64 : (void *)&rxDesc32;
11888203SAli.Saidi@ARM.com            rxDmaLen = is64bit ? sizeof(rxDesc64) : sizeof(rxDesc32);
11898203SAli.Saidi@ARM.com            rxDmaFree = dmaDescFree;
11908203SAli.Saidi@ARM.com
11918203SAli.Saidi@ARM.com            descDmaReads++;
11928203SAli.Saidi@ARM.com            descDmaRdBytes += rxDmaLen;
11938203SAli.Saidi@ARM.com
11947646Sgene.wu@arm.com            if (doRxDmaRead())
11957646Sgene.wu@arm.com                goto exit;
11967646Sgene.wu@arm.com        }
11977724SAli.Saidi@ARM.com        break;
11987646Sgene.wu@arm.com
11997646Sgene.wu@arm.com      case rxDescRefr:
12007646Sgene.wu@arm.com        if (rxDmaState != dmaIdle)
12017646Sgene.wu@arm.com            goto exit;
12027646Sgene.wu@arm.com
12037646Sgene.wu@arm.com        rxState = rxAdvance;
12047646Sgene.wu@arm.com        break;
1205
1206     case rxDescRead:
1207        if (rxDmaState != dmaIdle)
1208            goto exit;
1209
1210        DPRINTF(EthernetDesc, "rxDesc: addr=%08x read descriptor\n",
1211                regs.rxdp & 0x3fffffff);
1212        DPRINTF(EthernetDesc,
1213                "rxDesc: link=%#x bufptr=%#x cmdsts=%08x extsts=%08x\n",
1214                link, bufptr, cmdsts, extsts);
1215
1216        if (cmdsts & CMDSTS_OWN) {
1217            devIntrPost(ISR_RXIDLE);
1218            rxState = rxIdle;
1219            goto exit;
1220        } else {
1221            rxState = rxFifoBlock;
1222            rxFragPtr = bufptr;
1223            rxDescCnt = cmdsts & CMDSTS_LEN_MASK;
1224        }
1225        break;
1226
1227      case rxFifoBlock:
1228        if (!rxPacket) {
1229            /**
1230             * @todo in reality, we should be able to start processing
1231             * the packet as it arrives, and not have to wait for the
1232             * full packet ot be in the receive fifo.
1233             */
1234            if (rxFifo.empty())
1235                goto exit;
1236
1237            DPRINTF(EthernetSM, "****processing receive of new packet****\n");
1238
1239            // If we don't have a packet, grab a new one from the fifo.
1240            rxPacket = rxFifo.front();
1241            rxPktBytes = rxPacket->length;
1242            rxPacketBufPtr = rxPacket->data;
1243
1244#if TRACING_ON
1245            if (DTRACE(Ethernet)) {
1246                IpPtr ip(rxPacket);
1247                if (ip) {
1248                    DPRINTF(Ethernet, "ID is %d\n", ip->id());
1249                    TcpPtr tcp(ip);
1250                    if (tcp) {
1251                        DPRINTF(Ethernet,
1252                                "Src Port=%d, Dest Port=%d, Seq=%d, Ack=%d\n",
1253                                tcp->sport(), tcp->dport(), tcp->seq(),
1254                                tcp->ack());
1255                    }
1256                }
1257            }
1258#endif
1259
1260            // sanity check - i think the driver behaves like this
1261            assert(rxDescCnt >= rxPktBytes);
1262            rxFifo.pop();
1263        }
1264
1265
1266        // dont' need the && rxDescCnt > 0 if driver sanity check
1267        // above holds
1268        if (rxPktBytes > 0) {
1269            rxState = rxFragWrite;
1270            // don't need min<>(rxPktBytes,rxDescCnt) if above sanity
1271            // check holds
1272            rxXferLen = rxPktBytes;
1273
1274            rxDmaAddr = rxFragPtr & 0x3fffffff;
1275            rxDmaData = rxPacketBufPtr;
1276            rxDmaLen = rxXferLen;
1277            rxDmaFree = dmaDataFree;
1278
1279            if (doRxDmaWrite())
1280                goto exit;
1281
1282        } else {
1283            rxState = rxDescWrite;
1284
1285            //if (rxPktBytes == 0) {  /* packet is done */
1286            assert(rxPktBytes == 0);
1287            DPRINTF(EthernetSM, "done with receiving packet\n");
1288
1289            cmdsts |= CMDSTS_OWN;
1290            cmdsts &= ~CMDSTS_MORE;
1291            cmdsts |= CMDSTS_OK;
1292            cmdsts &= 0xffff0000;
1293            cmdsts += rxPacket->length;   //i.e. set CMDSTS_SIZE
1294
1295#if 0
1296            /*
1297             * all the driver uses these are for its own stats keeping
1298             * which we don't care about, aren't necessary for
1299             * functionality and doing this would just slow us down.
1300             * if they end up using this in a later version for
1301             * functional purposes, just undef
1302             */
1303            if (rxFilterEnable) {
1304                cmdsts &= ~CMDSTS_DEST_MASK;
1305                const EthAddr &dst = rxFifoFront()->dst();
1306                if (dst->unicast())
1307                    cmdsts |= CMDSTS_DEST_SELF;
1308                if (dst->multicast())
1309                    cmdsts |= CMDSTS_DEST_MULTI;
1310                if (dst->broadcast())
1311                    cmdsts |= CMDSTS_DEST_MASK;
1312            }
1313#endif
1314
1315            IpPtr ip(rxPacket);
1316            if (extstsEnable && ip) {
1317                extsts |= EXTSTS_IPPKT;
1318                rxIpChecksums++;
1319                if (cksum(ip) != 0) {
1320                    DPRINTF(EthernetCksum, "Rx IP Checksum Error\n");
1321                    extsts |= EXTSTS_IPERR;
1322                }
1323                TcpPtr tcp(ip);
1324                UdpPtr udp(ip);
1325                if (tcp) {
1326                    extsts |= EXTSTS_TCPPKT;
1327                    rxTcpChecksums++;
1328                    if (cksum(tcp) != 0) {
1329                        DPRINTF(EthernetCksum, "Rx TCP Checksum Error\n");
1330                        extsts |= EXTSTS_TCPERR;
1331
1332                    }
1333                } else if (udp) {
1334                    extsts |= EXTSTS_UDPPKT;
1335                    rxUdpChecksums++;
1336                    if (cksum(udp) != 0) {
1337                        DPRINTF(EthernetCksum, "Rx UDP Checksum Error\n");
1338                        extsts |= EXTSTS_UDPERR;
1339                    }
1340                }
1341            }
1342            rxPacket = 0;
1343
1344            /*
1345             * the driver seems to always receive into desc buffers
1346             * of size 1514, so you never have a pkt that is split
1347             * into multiple descriptors on the receive side, so
1348             * i don't implement that case, hence the assert above.
1349             */
1350
1351            DPRINTF(EthernetDesc,
1352                    "rxDesc: addr=%08x writeback cmdsts extsts\n",
1353                    regs.rxdp & 0x3fffffff);
1354            DPRINTF(EthernetDesc,
1355                    "rxDesc: link=%#x bufptr=%#x cmdsts=%08x extsts=%08x\n",
1356                    link, bufptr, cmdsts, extsts);
1357
1358            rxDmaAddr = regs.rxdp & 0x3fffffff;
1359            rxDmaData = &cmdsts;
1360            if (is64bit) {
1361                rxDmaAddr += offsetof(ns_desc64, cmdsts);
1362                rxDmaLen = sizeof(rxDesc64.cmdsts) + sizeof(rxDesc64.extsts);
1363            } else {
1364                rxDmaAddr += offsetof(ns_desc32, cmdsts);
1365                rxDmaLen = sizeof(rxDesc32.cmdsts) + sizeof(rxDesc32.extsts);
1366            }
1367            rxDmaFree = dmaDescFree;
1368
1369            descDmaWrites++;
1370            descDmaWrBytes += rxDmaLen;
1371
1372            if (doRxDmaWrite())
1373                goto exit;
1374        }
1375        break;
1376
1377      case rxFragWrite:
1378        if (rxDmaState != dmaIdle)
1379            goto exit;
1380
1381        rxPacketBufPtr += rxXferLen;
1382        rxFragPtr += rxXferLen;
1383        rxPktBytes -= rxXferLen;
1384
1385        rxState = rxFifoBlock;
1386        break;
1387
1388      case rxDescWrite:
1389        if (rxDmaState != dmaIdle)
1390            goto exit;
1391
1392        assert(cmdsts & CMDSTS_OWN);
1393
1394        assert(rxPacket == 0);
1395        devIntrPost(ISR_RXOK);
1396
1397        if (cmdsts & CMDSTS_INTR)
1398            devIntrPost(ISR_RXDESC);
1399
1400        if (!rxEnable) {
1401            DPRINTF(EthernetSM, "Halting the RX state machine\n");
1402            rxState = rxIdle;
1403            goto exit;
1404        } else
1405            rxState = rxAdvance;
1406        break;
1407
1408      case rxAdvance:
1409        if (link == 0) {
1410            devIntrPost(ISR_RXIDLE);
1411            rxState = rxIdle;
1412            CRDD = true;
1413            goto exit;
1414        } else {
1415            if (rxDmaState != dmaIdle)
1416                goto exit;
1417            rxState = rxDescRead;
1418            regs.rxdp = link;
1419            CRDD = false;
1420
1421            rxDmaAddr = regs.rxdp & 0x3fffffff;
1422            rxDmaData = is64bit ? (void *)&rxDesc64 : (void *)&rxDesc32;
1423            rxDmaLen = is64bit ? sizeof(rxDesc64) : sizeof(rxDesc32);
1424            rxDmaFree = dmaDescFree;
1425
1426            if (doRxDmaRead())
1427                goto exit;
1428        }
1429        break;
1430
1431      default:
1432        panic("Invalid rxState!");
1433    }
1434
1435    DPRINTF(EthernetSM, "entering next rxState=%s\n",
1436            NsRxStateStrings[rxState]);
1437    goto next;
1438
1439  exit:
1440    /**
1441     * @todo do we want to schedule a future kick?
1442     */
1443    DPRINTF(EthernetSM, "rx state machine exited rxState=%s\n",
1444            NsRxStateStrings[rxState]);
1445
1446    if (clock && !rxKickEvent.scheduled())
1447        schedule(rxKickEvent, rxKickTick);
1448}
1449
1450void
1451NSGigE::transmit()
1452{
1453    if (txFifo.empty()) {
1454        DPRINTF(Ethernet, "nothing to transmit\n");
1455        return;
1456    }
1457
1458    DPRINTF(Ethernet, "Attempt Pkt Transmit: txFifo length=%d\n",
1459            txFifo.size());
1460    if (interface->sendPacket(txFifo.front())) {
1461#if TRACING_ON
1462        if (DTRACE(Ethernet)) {
1463            IpPtr ip(txFifo.front());
1464            if (ip) {
1465                DPRINTF(Ethernet, "ID is %d\n", ip->id());
1466                TcpPtr tcp(ip);
1467                if (tcp) {
1468                    DPRINTF(Ethernet,
1469                            "Src Port=%d, Dest Port=%d, Seq=%d, Ack=%d\n",
1470                            tcp->sport(), tcp->dport(), tcp->seq(),
1471                            tcp->ack());
1472                }
1473            }
1474        }
1475#endif
1476
1477        DDUMP(EthernetData, txFifo.front()->data, txFifo.front()->length);
1478        txBytes += txFifo.front()->length;
1479        txPackets++;
1480
1481        DPRINTF(Ethernet, "Successful Xmit! now txFifoAvail is %d\n",
1482                txFifo.avail());
1483        txFifo.pop();
1484
1485        /*
1486         * normally do a writeback of the descriptor here, and ONLY
1487         * after that is done, send this interrupt.  but since our
1488         * stuff never actually fails, just do this interrupt here,
1489         * otherwise the code has to stray from this nice format.
1490         * besides, it's functionally the same.
1491         */
1492        devIntrPost(ISR_TXOK);
1493    }
1494
1495   if (!txFifo.empty() && !txEvent.scheduled()) {
1496       DPRINTF(Ethernet, "reschedule transmit\n");
1497       schedule(txEvent, curTick + retryTime);
1498   }
1499}
1500
1501bool
1502NSGigE::doTxDmaRead()
1503{
1504    assert(txDmaState == dmaIdle || txDmaState == dmaReadWaiting);
1505    txDmaState = dmaReading;
1506
1507    if (dmaPending() || getState() != Running)
1508        txDmaState = dmaReadWaiting;
1509    else
1510        dmaRead(txDmaAddr, txDmaLen, &txDmaReadEvent, (uint8_t*)txDmaData);
1511
1512    return true;
1513}
1514
1515void
1516NSGigE::txDmaReadDone()
1517{
1518    assert(txDmaState == dmaReading);
1519    txDmaState = dmaIdle;
1520
1521    DPRINTF(EthernetDMA, "tx dma read  paddr=%#x len=%d\n",
1522            txDmaAddr, txDmaLen);
1523    DDUMP(EthernetDMA, txDmaData, txDmaLen);
1524
1525    // If the receive state machine  has a pending DMA, let it go first
1526    if (rxDmaState == dmaReadWaiting || rxDmaState == dmaWriteWaiting)
1527        rxKick();
1528
1529    txKick();
1530}
1531
1532bool
1533NSGigE::doTxDmaWrite()
1534{
1535    assert(txDmaState == dmaIdle || txDmaState == dmaWriteWaiting);
1536    txDmaState = dmaWriting;
1537
1538    if (dmaPending() || getState() != Running)
1539        txDmaState = dmaWriteWaiting;
1540    else
1541        dmaWrite(txDmaAddr, txDmaLen, &txDmaWriteEvent, (uint8_t*)txDmaData);
1542    return true;
1543}
1544
1545void
1546NSGigE::txDmaWriteDone()
1547{
1548    assert(txDmaState == dmaWriting);
1549    txDmaState = dmaIdle;
1550
1551    DPRINTF(EthernetDMA, "tx dma write paddr=%#x len=%d\n",
1552            txDmaAddr, txDmaLen);
1553    DDUMP(EthernetDMA, txDmaData, txDmaLen);
1554
1555    // If the receive state machine  has a pending DMA, let it go first
1556    if (rxDmaState == dmaReadWaiting || rxDmaState == dmaWriteWaiting)
1557        rxKick();
1558
1559    txKick();
1560}
1561
1562void
1563NSGigE::txKick()
1564{
1565    bool is64bit = (bool)(regs.config & CFGR_M64ADDR);
1566
1567    DPRINTF(EthernetSM, "transmit kick txState=%s %d-bit\n",
1568            NsTxStateStrings[txState], is64bit ? 64 : 32);
1569
1570    Addr link, bufptr;
1571    uint32_t &cmdsts = is64bit ? txDesc64.cmdsts : txDesc32.cmdsts;
1572    uint32_t &extsts = is64bit ? txDesc64.extsts : txDesc32.extsts;
1573
1574  next:
1575    if (clock) {
1576        if (txKickTick > curTick) {
1577            DPRINTF(EthernetSM, "transmit kick exiting, can't run till %d\n",
1578                    txKickTick);
1579            goto exit;
1580        }
1581
1582        // Go to the next state machine clock tick.
1583        txKickTick = curTick + ticks(1);
1584    }
1585
1586    switch(txDmaState) {
1587      case dmaReadWaiting:
1588        if (doTxDmaRead())
1589            goto exit;
1590        break;
1591      case dmaWriteWaiting:
1592        if (doTxDmaWrite())
1593            goto exit;
1594        break;
1595      default:
1596        break;
1597    }
1598
1599    link = is64bit ? (Addr)txDesc64.link : (Addr)txDesc32.link;
1600    bufptr = is64bit ? (Addr)txDesc64.bufptr : (Addr)txDesc32.bufptr;
1601    switch (txState) {
1602      case txIdle:
1603        if (!txEnable) {
1604            DPRINTF(EthernetSM, "Transmit disabled.  Nothing to do.\n");
1605            goto exit;
1606        }
1607
1608        if (CTDD) {
1609            txState = txDescRefr;
1610
1611            txDmaAddr = regs.txdp & 0x3fffffff;
1612            txDmaData =
1613                is64bit ? (void *)&txDesc64.link : (void *)&txDesc32.link;
1614            txDmaLen = is64bit ? sizeof(txDesc64.link) : sizeof(txDesc32.link);
1615            txDmaFree = dmaDescFree;
1616
1617            descDmaReads++;
1618            descDmaRdBytes += txDmaLen;
1619
1620            if (doTxDmaRead())
1621                goto exit;
1622
1623        } else {
1624            txState = txDescRead;
1625
1626            txDmaAddr = regs.txdp & 0x3fffffff;
1627            txDmaData = is64bit ? (void *)&txDesc64 : (void *)&txDesc32;
1628            txDmaLen = is64bit ? sizeof(txDesc64) : sizeof(txDesc32);
1629            txDmaFree = dmaDescFree;
1630
1631            descDmaReads++;
1632            descDmaRdBytes += txDmaLen;
1633
1634            if (doTxDmaRead())
1635                goto exit;
1636        }
1637        break;
1638
1639      case txDescRefr:
1640        if (txDmaState != dmaIdle)
1641            goto exit;
1642
1643        txState = txAdvance;
1644        break;
1645
1646      case txDescRead:
1647        if (txDmaState != dmaIdle)
1648            goto exit;
1649
1650        DPRINTF(EthernetDesc, "txDesc: addr=%08x read descriptor\n",
1651                regs.txdp & 0x3fffffff);
1652        DPRINTF(EthernetDesc,
1653                "txDesc: link=%#x bufptr=%#x cmdsts=%#08x extsts=%#08x\n",
1654                link, bufptr, cmdsts, extsts);
1655
1656        if (cmdsts & CMDSTS_OWN) {
1657            txState = txFifoBlock;
1658            txFragPtr = bufptr;
1659            txDescCnt = cmdsts & CMDSTS_LEN_MASK;
1660        } else {
1661            devIntrPost(ISR_TXIDLE);
1662            txState = txIdle;
1663            goto exit;
1664        }
1665        break;
1666
1667      case txFifoBlock:
1668        if (!txPacket) {
1669            DPRINTF(EthernetSM, "****starting the tx of a new packet****\n");
1670            txPacket = new EthPacketData(16384);
1671            txPacketBufPtr = txPacket->data;
1672        }
1673
1674        if (txDescCnt == 0) {
1675            DPRINTF(EthernetSM, "the txDescCnt == 0, done with descriptor\n");
1676            if (cmdsts & CMDSTS_MORE) {
1677                DPRINTF(EthernetSM, "there are more descriptors to come\n");
1678                txState = txDescWrite;
1679
1680                cmdsts &= ~CMDSTS_OWN;
1681
1682                txDmaAddr = regs.txdp & 0x3fffffff;
1683                txDmaData = &cmdsts;
1684                if (is64bit) {
1685                    txDmaAddr += offsetof(ns_desc64, cmdsts);
1686                    txDmaLen = sizeof(txDesc64.cmdsts);
1687                } else {
1688                    txDmaAddr += offsetof(ns_desc32, cmdsts);
1689                    txDmaLen = sizeof(txDesc32.cmdsts);
1690                }
1691                txDmaFree = dmaDescFree;
1692
1693                if (doTxDmaWrite())
1694                    goto exit;
1695
1696            } else { /* this packet is totally done */
1697                DPRINTF(EthernetSM, "This packet is done, let's wrap it up\n");
1698                /* deal with the the packet that just finished */
1699                if ((regs.vtcr & VTCR_PPCHK) && extstsEnable) {
1700                    IpPtr ip(txPacket);
1701                    if (extsts & EXTSTS_UDPPKT) {
1702                        UdpPtr udp(ip);
1703                        if (udp) {
1704                            udp->sum(0);
1705                            udp->sum(cksum(udp));
1706                            txUdpChecksums++;
1707                        } else {
1708                            debug_break();
1709                            warn_once("UDPPKT set, but not UDP!\n");
1710                        }
1711                    } else if (extsts & EXTSTS_TCPPKT) {
1712                        TcpPtr tcp(ip);
1713                        if (tcp) {
1714                            tcp->sum(0);
1715                            tcp->sum(cksum(tcp));
1716                            txTcpChecksums++;
1717                        } else {
1718                            debug_break();
1719                            warn_once("TCPPKT set, but not UDP!\n");
1720                        }
1721                    }
1722                    if (extsts & EXTSTS_IPPKT) {
1723                        if (ip) {
1724                            ip->sum(0);
1725                            ip->sum(cksum(ip));
1726                            txIpChecksums++;
1727                        } else {
1728                            debug_break();
1729                            warn_once("IPPKT set, but not UDP!\n");
1730                        }
1731                    }
1732                }
1733
1734                txPacket->length = txPacketBufPtr - txPacket->data;
1735                // this is just because the receive can't handle a
1736                // packet bigger want to make sure
1737                if (txPacket->length > 1514)
1738                    panic("transmit packet too large, %s > 1514\n",
1739                          txPacket->length);
1740
1741#ifndef NDEBUG
1742                bool success =
1743#endif
1744                    txFifo.push(txPacket);
1745                assert(success);
1746
1747                /*
1748                 * this following section is not tqo spec, but
1749                 * functionally shouldn't be any different.  normally,
1750                 * the chip will wait til the transmit has occurred
1751                 * before writing back the descriptor because it has
1752                 * to wait to see that it was successfully transmitted
1753                 * to decide whether to set CMDSTS_OK or not.
1754                 * however, in the simulator since it is always
1755                 * successfully transmitted, and writing it exactly to
1756                 * spec would complicate the code, we just do it here
1757                 */
1758
1759                cmdsts &= ~CMDSTS_OWN;
1760                cmdsts |= CMDSTS_OK;
1761
1762                DPRINTF(EthernetDesc,
1763                        "txDesc writeback: cmdsts=%08x extsts=%08x\n",
1764                        cmdsts, extsts);
1765
1766                txDmaFree = dmaDescFree;
1767                txDmaAddr = regs.txdp & 0x3fffffff;
1768                txDmaData = &cmdsts;
1769                if (is64bit) {
1770                    txDmaAddr += offsetof(ns_desc64, cmdsts);
1771                    txDmaLen =
1772                        sizeof(txDesc64.cmdsts) + sizeof(txDesc64.extsts);
1773                } else {
1774                    txDmaAddr += offsetof(ns_desc32, cmdsts);
1775                    txDmaLen =
1776                        sizeof(txDesc32.cmdsts) + sizeof(txDesc32.extsts);
1777                }
1778
1779                descDmaWrites++;
1780                descDmaWrBytes += txDmaLen;
1781
1782                transmit();
1783                txPacket = 0;
1784
1785                if (!txEnable) {
1786                    DPRINTF(EthernetSM, "halting TX state machine\n");
1787                    txState = txIdle;
1788                    goto exit;
1789                } else
1790                    txState = txAdvance;
1791
1792                if (doTxDmaWrite())
1793                    goto exit;
1794            }
1795        } else {
1796            DPRINTF(EthernetSM, "this descriptor isn't done yet\n");
1797            if (!txFifo.full()) {
1798                txState = txFragRead;
1799
1800                /*
1801                 * The number of bytes transferred is either whatever
1802                 * is left in the descriptor (txDescCnt), or if there
1803                 * is not enough room in the fifo, just whatever room
1804                 * is left in the fifo
1805                 */
1806                txXferLen = min<uint32_t>(txDescCnt, txFifo.avail());
1807
1808                txDmaAddr = txFragPtr & 0x3fffffff;
1809                txDmaData = txPacketBufPtr;
1810                txDmaLen = txXferLen;
1811                txDmaFree = dmaDataFree;
1812
1813                if (doTxDmaRead())
1814                    goto exit;
1815            } else {
1816                txState = txFifoBlock;
1817                transmit();
1818
1819                goto exit;
1820            }
1821
1822        }
1823        break;
1824
1825      case txFragRead:
1826        if (txDmaState != dmaIdle)
1827            goto exit;
1828
1829        txPacketBufPtr += txXferLen;
1830        txFragPtr += txXferLen;
1831        txDescCnt -= txXferLen;
1832        txFifo.reserve(txXferLen);
1833
1834        txState = txFifoBlock;
1835        break;
1836
1837      case txDescWrite:
1838        if (txDmaState != dmaIdle)
1839            goto exit;
1840
1841        if (cmdsts & CMDSTS_INTR)
1842            devIntrPost(ISR_TXDESC);
1843
1844        if (!txEnable) {
1845            DPRINTF(EthernetSM, "halting TX state machine\n");
1846            txState = txIdle;
1847            goto exit;
1848        } else
1849            txState = txAdvance;
1850        break;
1851
1852      case txAdvance:
1853        if (link == 0) {
1854            devIntrPost(ISR_TXIDLE);
1855            txState = txIdle;
1856            goto exit;
1857        } else {
1858            if (txDmaState != dmaIdle)
1859                goto exit;
1860            txState = txDescRead;
1861            regs.txdp = link;
1862            CTDD = false;
1863
1864            txDmaAddr = link & 0x3fffffff;
1865            txDmaData = is64bit ? (void *)&txDesc64 : (void *)&txDesc32;
1866            txDmaLen = is64bit ? sizeof(txDesc64) : sizeof(txDesc32);
1867            txDmaFree = dmaDescFree;
1868
1869            if (doTxDmaRead())
1870                goto exit;
1871        }
1872        break;
1873
1874      default:
1875        panic("invalid state");
1876    }
1877
1878    DPRINTF(EthernetSM, "entering next txState=%s\n",
1879            NsTxStateStrings[txState]);
1880    goto next;
1881
1882  exit:
1883    /**
1884     * @todo do we want to schedule a future kick?
1885     */
1886    DPRINTF(EthernetSM, "tx state machine exited txState=%s\n",
1887            NsTxStateStrings[txState]);
1888
1889    if (clock && !txKickEvent.scheduled())
1890        schedule(txKickEvent, txKickTick);
1891}
1892
1893/**
1894 * Advance the EEPROM state machine
1895 * Called on rising edge of EEPROM clock bit in MEAR
1896 */
1897void
1898NSGigE::eepromKick()
1899{
1900    switch (eepromState) {
1901
1902      case eepromStart:
1903
1904        // Wait for start bit
1905        if (regs.mear & MEAR_EEDI) {
1906            // Set up to get 2 opcode bits
1907            eepromState = eepromGetOpcode;
1908            eepromBitsToRx = 2;
1909            eepromOpcode = 0;
1910        }
1911        break;
1912
1913      case eepromGetOpcode:
1914        eepromOpcode <<= 1;
1915        eepromOpcode += (regs.mear & MEAR_EEDI) ? 1 : 0;
1916        --eepromBitsToRx;
1917
1918        // Done getting opcode
1919        if (eepromBitsToRx == 0) {
1920            if (eepromOpcode != EEPROM_READ)
1921                panic("only EEPROM reads are implemented!");
1922
1923            // Set up to get address
1924            eepromState = eepromGetAddress;
1925            eepromBitsToRx = 6;
1926            eepromAddress = 0;
1927        }
1928        break;
1929
1930      case eepromGetAddress:
1931        eepromAddress <<= 1;
1932        eepromAddress += (regs.mear & MEAR_EEDI) ? 1 : 0;
1933        --eepromBitsToRx;
1934
1935        // Done getting address
1936        if (eepromBitsToRx == 0) {
1937
1938            if (eepromAddress >= EEPROM_SIZE)
1939                panic("EEPROM read access out of range!");
1940
1941            switch (eepromAddress) {
1942
1943              case EEPROM_PMATCH2_ADDR:
1944                eepromData = rom.perfectMatch[5];
1945                eepromData <<= 8;
1946                eepromData += rom.perfectMatch[4];
1947                break;
1948
1949              case EEPROM_PMATCH1_ADDR:
1950                eepromData = rom.perfectMatch[3];
1951                eepromData <<= 8;
1952                eepromData += rom.perfectMatch[2];
1953                break;
1954
1955              case EEPROM_PMATCH0_ADDR:
1956                eepromData = rom.perfectMatch[1];
1957                eepromData <<= 8;
1958                eepromData += rom.perfectMatch[0];
1959                break;
1960
1961              default:
1962                panic("FreeBSD driver only uses EEPROM to read PMATCH!");
1963            }
1964            // Set up to read data
1965            eepromState = eepromRead;
1966            eepromBitsToRx = 16;
1967
1968            // Clear data in bit
1969            regs.mear &= ~MEAR_EEDI;
1970        }
1971        break;
1972
1973      case eepromRead:
1974        // Clear Data Out bit
1975        regs.mear &= ~MEAR_EEDO;
1976        // Set bit to value of current EEPROM bit
1977        regs.mear |= (eepromData & 0x8000) ? MEAR_EEDO : 0x0;
1978
1979        eepromData <<= 1;
1980        --eepromBitsToRx;
1981
1982        // All done
1983        if (eepromBitsToRx == 0) {
1984            eepromState = eepromStart;
1985        }
1986        break;
1987
1988      default:
1989        panic("invalid EEPROM state");
1990    }
1991
1992}
1993
1994void
1995NSGigE::transferDone()
1996{
1997    if (txFifo.empty()) {
1998        DPRINTF(Ethernet, "transfer complete: txFifo empty...nothing to do\n");
1999        return;
2000    }
2001
2002    DPRINTF(Ethernet, "transfer complete: data in txFifo...schedule xmit\n");
2003
2004    reschedule(txEvent, curTick + ticks(1), true);
2005}
2006
2007bool
2008NSGigE::rxFilter(const EthPacketPtr &packet)
2009{
2010    EthPtr eth = packet;
2011    bool drop = true;
2012    string type;
2013
2014    const EthAddr &dst = eth->dst();
2015    if (dst.unicast()) {
2016        // If we're accepting all unicast addresses
2017        if (acceptUnicast)
2018            drop = false;
2019
2020        // If we make a perfect match
2021        if (acceptPerfect && dst == rom.perfectMatch)
2022            drop = false;
2023
2024        if (acceptArp && eth->type() == ETH_TYPE_ARP)
2025            drop = false;
2026
2027    } else if (dst.broadcast()) {
2028        // if we're accepting broadcasts
2029        if (acceptBroadcast)
2030            drop = false;
2031
2032    } else if (dst.multicast()) {
2033        // if we're accepting all multicasts
2034        if (acceptMulticast)
2035            drop = false;
2036
2037        // Multicast hashing faked - all packets accepted
2038        if (multicastHashEnable)
2039            drop = false;
2040    }
2041
2042    if (drop) {
2043        DPRINTF(Ethernet, "rxFilter drop\n");
2044        DDUMP(EthernetData, packet->data, packet->length);
2045    }
2046
2047    return drop;
2048}
2049
2050bool
2051NSGigE::recvPacket(EthPacketPtr packet)
2052{
2053    rxBytes += packet->length;
2054    rxPackets++;
2055
2056    DPRINTF(Ethernet, "Receiving packet from wire, rxFifoAvail=%d\n",
2057            rxFifo.avail());
2058
2059    if (!rxEnable) {
2060        DPRINTF(Ethernet, "receive disabled...packet dropped\n");
2061        return true;
2062    }
2063
2064    if (!rxFilterEnable) {
2065        DPRINTF(Ethernet,
2066            "receive packet filtering disabled . . . packet dropped\n");
2067        return true;
2068    }
2069
2070    if (rxFilter(packet)) {
2071        DPRINTF(Ethernet, "packet filtered...dropped\n");
2072        return true;
2073    }
2074
2075    if (rxFifo.avail() < packet->length) {
2076#if TRACING_ON
2077        IpPtr ip(packet);
2078        TcpPtr tcp(ip);
2079        if (ip) {
2080            DPRINTF(Ethernet,
2081                    "packet won't fit in receive buffer...pkt ID %d dropped\n",
2082                    ip->id());
2083            if (tcp) {
2084                DPRINTF(Ethernet, "Seq=%d\n", tcp->seq());
2085            }
2086        }
2087#endif
2088        droppedPackets++;
2089        devIntrPost(ISR_RXORN);
2090        return false;
2091    }
2092
2093    rxFifo.push(packet);
2094
2095    rxKick();
2096    return true;
2097}
2098
2099
2100void
2101NSGigE::resume()
2102{
2103    SimObject::resume();
2104
2105    // During drain we could have left the state machines in a waiting state and
2106    // they wouldn't get out until some other event occured to kick them.
2107    // This way they'll get out immediately
2108    txKick();
2109    rxKick();
2110}
2111
2112
2113//=====================================================================
2114//
2115//
2116void
2117NSGigE::serialize(ostream &os)
2118{
2119    // Serialize the PciDev base class
2120    PciDev::serialize(os);
2121
2122    /*
2123     * Finalize any DMA events now.
2124     */
2125    // @todo will mem system save pending dma?
2126
2127    /*
2128     * Serialize the device registers
2129     */
2130    SERIALIZE_SCALAR(regs.command);
2131    SERIALIZE_SCALAR(regs.config);
2132    SERIALIZE_SCALAR(regs.mear);
2133    SERIALIZE_SCALAR(regs.ptscr);
2134    SERIALIZE_SCALAR(regs.isr);
2135    SERIALIZE_SCALAR(regs.imr);
2136    SERIALIZE_SCALAR(regs.ier);
2137    SERIALIZE_SCALAR(regs.ihr);
2138    SERIALIZE_SCALAR(regs.txdp);
2139    SERIALIZE_SCALAR(regs.txdp_hi);
2140    SERIALIZE_SCALAR(regs.txcfg);
2141    SERIALIZE_SCALAR(regs.gpior);
2142    SERIALIZE_SCALAR(regs.rxdp);
2143    SERIALIZE_SCALAR(regs.rxdp_hi);
2144    SERIALIZE_SCALAR(regs.rxcfg);
2145    SERIALIZE_SCALAR(regs.pqcr);
2146    SERIALIZE_SCALAR(regs.wcsr);
2147    SERIALIZE_SCALAR(regs.pcr);
2148    SERIALIZE_SCALAR(regs.rfcr);
2149    SERIALIZE_SCALAR(regs.rfdr);
2150    SERIALIZE_SCALAR(regs.brar);
2151    SERIALIZE_SCALAR(regs.brdr);
2152    SERIALIZE_SCALAR(regs.srr);
2153    SERIALIZE_SCALAR(regs.mibc);
2154    SERIALIZE_SCALAR(regs.vrcr);
2155    SERIALIZE_SCALAR(regs.vtcr);
2156    SERIALIZE_SCALAR(regs.vdr);
2157    SERIALIZE_SCALAR(regs.ccsr);
2158    SERIALIZE_SCALAR(regs.tbicr);
2159    SERIALIZE_SCALAR(regs.tbisr);
2160    SERIALIZE_SCALAR(regs.tanar);
2161    SERIALIZE_SCALAR(regs.tanlpar);
2162    SERIALIZE_SCALAR(regs.taner);
2163    SERIALIZE_SCALAR(regs.tesr);
2164
2165    SERIALIZE_ARRAY(rom.perfectMatch, ETH_ADDR_LEN);
2166    SERIALIZE_ARRAY(rom.filterHash, FHASH_SIZE);
2167
2168    SERIALIZE_SCALAR(ioEnable);
2169
2170    /*
2171     * Serialize the data Fifos
2172     */
2173    rxFifo.serialize("rxFifo", os);
2174    txFifo.serialize("txFifo", os);
2175
2176    /*
2177     * Serialize the various helper variables
2178     */
2179    bool txPacketExists = txPacket;
2180    SERIALIZE_SCALAR(txPacketExists);
2181    if (txPacketExists) {
2182        txPacket->length = txPacketBufPtr - txPacket->data;
2183        txPacket->serialize("txPacket", os);
2184        uint32_t txPktBufPtr = (uint32_t) (txPacketBufPtr - txPacket->data);
2185        SERIALIZE_SCALAR(txPktBufPtr);
2186    }
2187
2188    bool rxPacketExists = rxPacket;
2189    SERIALIZE_SCALAR(rxPacketExists);
2190    if (rxPacketExists) {
2191        rxPacket->serialize("rxPacket", os);
2192        uint32_t rxPktBufPtr = (uint32_t) (rxPacketBufPtr - rxPacket->data);
2193        SERIALIZE_SCALAR(rxPktBufPtr);
2194    }
2195
2196    SERIALIZE_SCALAR(txXferLen);
2197    SERIALIZE_SCALAR(rxXferLen);
2198
2199    /*
2200     * Serialize Cached Descriptors
2201     */
2202    SERIALIZE_SCALAR(rxDesc64.link);
2203    SERIALIZE_SCALAR(rxDesc64.bufptr);
2204    SERIALIZE_SCALAR(rxDesc64.cmdsts);
2205    SERIALIZE_SCALAR(rxDesc64.extsts);
2206    SERIALIZE_SCALAR(txDesc64.link);
2207    SERIALIZE_SCALAR(txDesc64.bufptr);
2208    SERIALIZE_SCALAR(txDesc64.cmdsts);
2209    SERIALIZE_SCALAR(txDesc64.extsts);
2210    SERIALIZE_SCALAR(rxDesc32.link);
2211    SERIALIZE_SCALAR(rxDesc32.bufptr);
2212    SERIALIZE_SCALAR(rxDesc32.cmdsts);
2213    SERIALIZE_SCALAR(rxDesc32.extsts);
2214    SERIALIZE_SCALAR(txDesc32.link);
2215    SERIALIZE_SCALAR(txDesc32.bufptr);
2216    SERIALIZE_SCALAR(txDesc32.cmdsts);
2217    SERIALIZE_SCALAR(txDesc32.extsts);
2218    SERIALIZE_SCALAR(extstsEnable);
2219
2220    /*
2221     * Serialize tx state machine
2222     */
2223    int txState = this->txState;
2224    SERIALIZE_SCALAR(txState);
2225    SERIALIZE_SCALAR(txEnable);
2226    SERIALIZE_SCALAR(CTDD);
2227    SERIALIZE_SCALAR(txFragPtr);
2228    SERIALIZE_SCALAR(txDescCnt);
2229    int txDmaState = this->txDmaState;
2230    SERIALIZE_SCALAR(txDmaState);
2231    SERIALIZE_SCALAR(txKickTick);
2232
2233    /*
2234     * Serialize rx state machine
2235     */
2236    int rxState = this->rxState;
2237    SERIALIZE_SCALAR(rxState);
2238    SERIALIZE_SCALAR(rxEnable);
2239    SERIALIZE_SCALAR(CRDD);
2240    SERIALIZE_SCALAR(rxPktBytes);
2241    SERIALIZE_SCALAR(rxFragPtr);
2242    SERIALIZE_SCALAR(rxDescCnt);
2243    int rxDmaState = this->rxDmaState;
2244    SERIALIZE_SCALAR(rxDmaState);
2245    SERIALIZE_SCALAR(rxKickTick);
2246
2247    /*
2248     * Serialize EEPROM state machine
2249     */
2250    int eepromState = this->eepromState;
2251    SERIALIZE_SCALAR(eepromState);
2252    SERIALIZE_SCALAR(eepromClk);
2253    SERIALIZE_SCALAR(eepromBitsToRx);
2254    SERIALIZE_SCALAR(eepromOpcode);
2255    SERIALIZE_SCALAR(eepromAddress);
2256    SERIALIZE_SCALAR(eepromData);
2257
2258    /*
2259     * If there's a pending transmit, store the time so we can
2260     * reschedule it later
2261     */
2262    Tick transmitTick = txEvent.scheduled() ? txEvent.when() - curTick : 0;
2263    SERIALIZE_SCALAR(transmitTick);
2264
2265    /*
2266     * receive address filter settings
2267     */
2268    SERIALIZE_SCALAR(rxFilterEnable);
2269    SERIALIZE_SCALAR(acceptBroadcast);
2270    SERIALIZE_SCALAR(acceptMulticast);
2271    SERIALIZE_SCALAR(acceptUnicast);
2272    SERIALIZE_SCALAR(acceptPerfect);
2273    SERIALIZE_SCALAR(acceptArp);
2274    SERIALIZE_SCALAR(multicastHashEnable);
2275
2276    /*
2277     * Keep track of pending interrupt status.
2278     */
2279    SERIALIZE_SCALAR(intrTick);
2280    SERIALIZE_SCALAR(cpuPendingIntr);
2281    Tick intrEventTick = 0;
2282    if (intrEvent)
2283        intrEventTick = intrEvent->when();
2284    SERIALIZE_SCALAR(intrEventTick);
2285
2286}
2287
2288void
2289NSGigE::unserialize(Checkpoint *cp, const std::string &section)
2290{
2291    // Unserialize the PciDev base class
2292    PciDev::unserialize(cp, section);
2293
2294    UNSERIALIZE_SCALAR(regs.command);
2295    UNSERIALIZE_SCALAR(regs.config);
2296    UNSERIALIZE_SCALAR(regs.mear);
2297    UNSERIALIZE_SCALAR(regs.ptscr);
2298    UNSERIALIZE_SCALAR(regs.isr);
2299    UNSERIALIZE_SCALAR(regs.imr);
2300    UNSERIALIZE_SCALAR(regs.ier);
2301    UNSERIALIZE_SCALAR(regs.ihr);
2302    UNSERIALIZE_SCALAR(regs.txdp);
2303    UNSERIALIZE_SCALAR(regs.txdp_hi);
2304    UNSERIALIZE_SCALAR(regs.txcfg);
2305    UNSERIALIZE_SCALAR(regs.gpior);
2306    UNSERIALIZE_SCALAR(regs.rxdp);
2307    UNSERIALIZE_SCALAR(regs.rxdp_hi);
2308    UNSERIALIZE_SCALAR(regs.rxcfg);
2309    UNSERIALIZE_SCALAR(regs.pqcr);
2310    UNSERIALIZE_SCALAR(regs.wcsr);
2311    UNSERIALIZE_SCALAR(regs.pcr);
2312    UNSERIALIZE_SCALAR(regs.rfcr);
2313    UNSERIALIZE_SCALAR(regs.rfdr);
2314    UNSERIALIZE_SCALAR(regs.brar);
2315    UNSERIALIZE_SCALAR(regs.brdr);
2316    UNSERIALIZE_SCALAR(regs.srr);
2317    UNSERIALIZE_SCALAR(regs.mibc);
2318    UNSERIALIZE_SCALAR(regs.vrcr);
2319    UNSERIALIZE_SCALAR(regs.vtcr);
2320    UNSERIALIZE_SCALAR(regs.vdr);
2321    UNSERIALIZE_SCALAR(regs.ccsr);
2322    UNSERIALIZE_SCALAR(regs.tbicr);
2323    UNSERIALIZE_SCALAR(regs.tbisr);
2324    UNSERIALIZE_SCALAR(regs.tanar);
2325    UNSERIALIZE_SCALAR(regs.tanlpar);
2326    UNSERIALIZE_SCALAR(regs.taner);
2327    UNSERIALIZE_SCALAR(regs.tesr);
2328
2329    UNSERIALIZE_ARRAY(rom.perfectMatch, ETH_ADDR_LEN);
2330    UNSERIALIZE_ARRAY(rom.filterHash, FHASH_SIZE);
2331
2332    UNSERIALIZE_SCALAR(ioEnable);
2333
2334    /*
2335     * unserialize the data fifos
2336     */
2337    rxFifo.unserialize("rxFifo", cp, section);
2338    txFifo.unserialize("txFifo", cp, section);
2339
2340    /*
2341     * unserialize the various helper variables
2342     */
2343    bool txPacketExists;
2344    UNSERIALIZE_SCALAR(txPacketExists);
2345    if (txPacketExists) {
2346        txPacket = new EthPacketData(16384);
2347        txPacket->unserialize("txPacket", cp, section);
2348        uint32_t txPktBufPtr;
2349        UNSERIALIZE_SCALAR(txPktBufPtr);
2350        txPacketBufPtr = (uint8_t *) txPacket->data + txPktBufPtr;
2351    } else
2352        txPacket = 0;
2353
2354    bool rxPacketExists;
2355    UNSERIALIZE_SCALAR(rxPacketExists);
2356    rxPacket = 0;
2357    if (rxPacketExists) {
2358        rxPacket = new EthPacketData(16384);
2359        rxPacket->unserialize("rxPacket", cp, section);
2360        uint32_t rxPktBufPtr;
2361        UNSERIALIZE_SCALAR(rxPktBufPtr);
2362        rxPacketBufPtr = (uint8_t *) rxPacket->data + rxPktBufPtr;
2363    } else
2364        rxPacket = 0;
2365
2366    UNSERIALIZE_SCALAR(txXferLen);
2367    UNSERIALIZE_SCALAR(rxXferLen);
2368
2369    /*
2370     * Unserialize Cached Descriptors
2371     */
2372    UNSERIALIZE_SCALAR(rxDesc64.link);
2373    UNSERIALIZE_SCALAR(rxDesc64.bufptr);
2374    UNSERIALIZE_SCALAR(rxDesc64.cmdsts);
2375    UNSERIALIZE_SCALAR(rxDesc64.extsts);
2376    UNSERIALIZE_SCALAR(txDesc64.link);
2377    UNSERIALIZE_SCALAR(txDesc64.bufptr);
2378    UNSERIALIZE_SCALAR(txDesc64.cmdsts);
2379    UNSERIALIZE_SCALAR(txDesc64.extsts);
2380    UNSERIALIZE_SCALAR(rxDesc32.link);
2381    UNSERIALIZE_SCALAR(rxDesc32.bufptr);
2382    UNSERIALIZE_SCALAR(rxDesc32.cmdsts);
2383    UNSERIALIZE_SCALAR(rxDesc32.extsts);
2384    UNSERIALIZE_SCALAR(txDesc32.link);
2385    UNSERIALIZE_SCALAR(txDesc32.bufptr);
2386    UNSERIALIZE_SCALAR(txDesc32.cmdsts);
2387    UNSERIALIZE_SCALAR(txDesc32.extsts);
2388    UNSERIALIZE_SCALAR(extstsEnable);
2389
2390    /*
2391     * unserialize tx state machine
2392     */
2393    int txState;
2394    UNSERIALIZE_SCALAR(txState);
2395    this->txState = (TxState) txState;
2396    UNSERIALIZE_SCALAR(txEnable);
2397    UNSERIALIZE_SCALAR(CTDD);
2398    UNSERIALIZE_SCALAR(txFragPtr);
2399    UNSERIALIZE_SCALAR(txDescCnt);
2400    int txDmaState;
2401    UNSERIALIZE_SCALAR(txDmaState);
2402    this->txDmaState = (DmaState) txDmaState;
2403    UNSERIALIZE_SCALAR(txKickTick);
2404    if (txKickTick)
2405        schedule(txKickEvent, txKickTick);
2406
2407    /*
2408     * unserialize rx state machine
2409     */
2410    int rxState;
2411    UNSERIALIZE_SCALAR(rxState);
2412    this->rxState = (RxState) rxState;
2413    UNSERIALIZE_SCALAR(rxEnable);
2414    UNSERIALIZE_SCALAR(CRDD);
2415    UNSERIALIZE_SCALAR(rxPktBytes);
2416    UNSERIALIZE_SCALAR(rxFragPtr);
2417    UNSERIALIZE_SCALAR(rxDescCnt);
2418    int rxDmaState;
2419    UNSERIALIZE_SCALAR(rxDmaState);
2420    this->rxDmaState = (DmaState) rxDmaState;
2421    UNSERIALIZE_SCALAR(rxKickTick);
2422    if (rxKickTick)
2423        schedule(rxKickEvent, rxKickTick);
2424
2425    /*
2426     * Unserialize EEPROM state machine
2427     */
2428    int eepromState;
2429    UNSERIALIZE_SCALAR(eepromState);
2430    this->eepromState = (EEPROMState) eepromState;
2431    UNSERIALIZE_SCALAR(eepromClk);
2432    UNSERIALIZE_SCALAR(eepromBitsToRx);
2433    UNSERIALIZE_SCALAR(eepromOpcode);
2434    UNSERIALIZE_SCALAR(eepromAddress);
2435    UNSERIALIZE_SCALAR(eepromData);
2436
2437    /*
2438     * If there's a pending transmit, reschedule it now
2439     */
2440    Tick transmitTick;
2441    UNSERIALIZE_SCALAR(transmitTick);
2442    if (transmitTick)
2443        schedule(txEvent, curTick + transmitTick);
2444
2445    /*
2446     * unserialize receive address filter settings
2447     */
2448    UNSERIALIZE_SCALAR(rxFilterEnable);
2449    UNSERIALIZE_SCALAR(acceptBroadcast);
2450    UNSERIALIZE_SCALAR(acceptMulticast);
2451    UNSERIALIZE_SCALAR(acceptUnicast);
2452    UNSERIALIZE_SCALAR(acceptPerfect);
2453    UNSERIALIZE_SCALAR(acceptArp);
2454    UNSERIALIZE_SCALAR(multicastHashEnable);
2455
2456    /*
2457     * Keep track of pending interrupt status.
2458     */
2459    UNSERIALIZE_SCALAR(intrTick);
2460    UNSERIALIZE_SCALAR(cpuPendingIntr);
2461    Tick intrEventTick;
2462    UNSERIALIZE_SCALAR(intrEventTick);
2463    if (intrEventTick) {
2464        intrEvent = new IntrEvent(this, true);
2465        schedule(intrEvent, intrEventTick);
2466    }
2467}
2468
2469NSGigE *
2470NSGigEParams::create()
2471{
2472    return new NSGigE(this);
2473}
2474