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