ns_gige.cc revision 13342
16657Snate@binkert.org/*
26657Snate@binkert.org * Copyright (c) 2004-2005 The Regents of The University of Michigan
36657Snate@binkert.org * All rights reserved.
46657Snate@binkert.org *
56657Snate@binkert.org * Redistribution and use in source and binary forms, with or without
66657Snate@binkert.org * modification, are permitted provided that the following conditions are
76657Snate@binkert.org * met: redistributions of source code must retain the above copyright
86657Snate@binkert.org * notice, this list of conditions and the following disclaimer;
96657Snate@binkert.org * redistributions in binary form must reproduce the above copyright
106657Snate@binkert.org * notice, this list of conditions and the following disclaimer in the
116657Snate@binkert.org * documentation and/or other materials provided with the distribution;
126657Snate@binkert.org * neither the name of the copyright holders nor the names of its
136657Snate@binkert.org * contributors may be used to endorse or promote products derived from
146657Snate@binkert.org * this software without specific prior written permission.
156657Snate@binkert.org *
166657Snate@binkert.org * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
176657Snate@binkert.org * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
186657Snate@binkert.org * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
196657Snate@binkert.org * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
206657Snate@binkert.org * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
216657Snate@binkert.org * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
226657Snate@binkert.org * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
236657Snate@binkert.org * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
246657Snate@binkert.org * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
256657Snate@binkert.org * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
266657Snate@binkert.org * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
276657Snate@binkert.org *
286999Snate@binkert.org * Authors: Nathan Binkert
296657Snate@binkert.org *          Lisa Hsu
306657Snate@binkert.org */
316657Snate@binkert.org
326657Snate@binkert.org/** @file
336657Snate@binkert.org * Device module for modelling the National Semiconductor
346882SBrad.Beckmann@amd.com * DP83820 ethernet controller.  Does not support priority queueing
357055Snate@binkert.org */
366882SBrad.Beckmann@amd.com
376882SBrad.Beckmann@amd.com#include "dev/net/ns_gige.hh"
386882SBrad.Beckmann@amd.com
396882SBrad.Beckmann@amd.com#include <deque>
406882SBrad.Beckmann@amd.com#include <memory>
416888SBrad.Beckmann@amd.com#include <string>
426882SBrad.Beckmann@amd.com
436882SBrad.Beckmann@amd.com#include "base/debug.hh"
446657Snate@binkert.org#include "base/inet.hh"
456657Snate@binkert.org#include "base/types.hh"
466657Snate@binkert.org#include "config/the_isa.hh"
476657Snate@binkert.org#include "debug/EthernetAll.hh"
486657Snate@binkert.org#include "dev/net/etherlink.hh"
497839Snilay@cs.wisc.edu#include "mem/packet.hh"
506657Snate@binkert.org#include "mem/packet_access.hh"
516882SBrad.Beckmann@amd.com#include "params/NSGigE.hh"
526882SBrad.Beckmann@amd.com#include "sim/system.hh"
536882SBrad.Beckmann@amd.com
546882SBrad.Beckmann@amd.com// clang complains about std::set being overloaded with Packet::set if
556882SBrad.Beckmann@amd.com// we open up the entire namespace std
566882SBrad.Beckmann@amd.comusing std::make_shared;
576657Snate@binkert.orgusing std::min;
586657Snate@binkert.orgusing std::ostream;
596657Snate@binkert.orgusing std::string;
606657Snate@binkert.org
616657Snate@binkert.orgconst char *NsRxStateStrings[] =
626657Snate@binkert.org{
636657Snate@binkert.org    "rxIdle",
646657Snate@binkert.org    "rxDescRefr",
656657Snate@binkert.org    "rxDescRead",
667839Snilay@cs.wisc.edu    "rxFifoBlock",
677839Snilay@cs.wisc.edu    "rxFragWrite",
686657Snate@binkert.org    "rxDescWrite",
696657Snate@binkert.org    "rxAdvance"
706657Snate@binkert.org};
716657Snate@binkert.org
726657Snate@binkert.orgconst char *NsTxStateStrings[] =
736657Snate@binkert.org{
746657Snate@binkert.org    "txIdle",
756657Snate@binkert.org    "txDescRefr",
766657Snate@binkert.org    "txDescRead",
776657Snate@binkert.org    "txFifoBlock",
786657Snate@binkert.org    "txFragRead",
796657Snate@binkert.org    "txDescWrite",
806657Snate@binkert.org    "txAdvance"
816657Snate@binkert.org};
826657Snate@binkert.org
836657Snate@binkert.orgconst char *NsDmaState[] =
846657Snate@binkert.org{
856657Snate@binkert.org    "dmaIdle",
866657Snate@binkert.org    "dmaReading",
876657Snate@binkert.org    "dmaWriting",
886779SBrad.Beckmann@amd.com    "dmaReadWaiting",
896657Snate@binkert.org    "dmaWriteWaiting"
906657Snate@binkert.org};
916657Snate@binkert.org
926657Snate@binkert.orgusing namespace Net;
936657Snate@binkert.orgusing namespace TheISA;
946657Snate@binkert.org
956657Snate@binkert.org///////////////////////////////////////////////////////////////////////
966657Snate@binkert.org//
976657Snate@binkert.org// NSGigE PCI Device
986657Snate@binkert.org//
996657Snate@binkert.orgNSGigE::NSGigE(Params *p)
1006657Snate@binkert.org    : EtherDevBase(p), ioEnable(false),
1016657Snate@binkert.org      txFifo(p->tx_fifo_size), rxFifo(p->rx_fifo_size),
1026657Snate@binkert.org      txPacket(0), rxPacket(0), txPacketBufPtr(NULL), rxPacketBufPtr(NULL),
1036657Snate@binkert.org      txXferLen(0), rxXferLen(0), rxDmaFree(false), txDmaFree(false),
1046657Snate@binkert.org      txState(txIdle), txEnable(false), CTDD(false), txHalt(false),
1056657Snate@binkert.org      txFragPtr(0), txDescCnt(0), txDmaState(dmaIdle), rxState(rxIdle),
1066657Snate@binkert.org      rxEnable(false), CRDD(false), rxPktBytes(0), rxHalt(false),
1076657Snate@binkert.org      rxFragPtr(0), rxDescCnt(0), rxDmaState(dmaIdle), extstsEnable(false),
1086657Snate@binkert.org      eepromState(eepromStart), eepromClk(false), eepromBitsToRx(0),
1096657Snate@binkert.org      eepromOpcode(0), eepromAddress(0), eepromData(0),
1106657Snate@binkert.org      dmaReadDelay(p->dma_read_delay), dmaWriteDelay(p->dma_write_delay),
1116657Snate@binkert.org      dmaReadFactor(p->dma_read_factor), dmaWriteFactor(p->dma_write_factor),
1126657Snate@binkert.org      rxDmaData(NULL), rxDmaAddr(0), rxDmaLen(0),
1137839Snilay@cs.wisc.edu      txDmaData(NULL), txDmaAddr(0), txDmaLen(0),
1147839Snilay@cs.wisc.edu      rxDmaReadEvent([this]{ rxDmaReadDone(); }, name()),
1157839Snilay@cs.wisc.edu      rxDmaWriteEvent([this]{ rxDmaWriteDone(); }, name()),
1167839Snilay@cs.wisc.edu      txDmaReadEvent([this]{ txDmaReadDone(); }, name()),
1177839Snilay@cs.wisc.edu      txDmaWriteEvent([this]{ txDmaWriteDone(); }, name()),
1187839Snilay@cs.wisc.edu      dmaDescFree(p->dma_desc_free), dmaDataFree(p->dma_data_free),
1197839Snilay@cs.wisc.edu      txDelay(p->tx_delay), rxDelay(p->rx_delay),
1207839Snilay@cs.wisc.edu      rxKickTick(0),
1217839Snilay@cs.wisc.edu      rxKickEvent([this]{ rxKick(); }, name()),
1227839Snilay@cs.wisc.edu      txKickTick(0),
1237839Snilay@cs.wisc.edu      txKickEvent([this]{ txKick(); }, name()),
1247839Snilay@cs.wisc.edu      txEvent([this]{ txEventTransmit(); }, name()),
1257839Snilay@cs.wisc.edu      rxFilterEnable(p->rx_filter),
1267839Snilay@cs.wisc.edu      acceptBroadcast(false), acceptMulticast(false), acceptUnicast(false),
1277839Snilay@cs.wisc.edu      acceptPerfect(false), acceptArp(false), multicastHashEnable(false),
1286657Snate@binkert.org      intrDelay(p->intr_delay), intrTick(0), cpuPendingIntr(false),
1296657Snate@binkert.org      intrEvent(0), interface(0)
1306657Snate@binkert.org{
1316657Snate@binkert.org
1326657Snate@binkert.org
1336657Snate@binkert.org    interface = new NSGigEInt(name() + ".int0", this);
1346657Snate@binkert.org
1356657Snate@binkert.org    regsReset();
1366657Snate@binkert.org    memcpy(&rom.perfectMatch, p->hardware_address.bytes(), ETH_ADDR_LEN);
1376657Snate@binkert.org
1386657Snate@binkert.org    memset(&rxDesc32, 0, sizeof(rxDesc32));
1396657Snate@binkert.org    memset(&txDesc32, 0, sizeof(txDesc32));
1406657Snate@binkert.org    memset(&rxDesc64, 0, sizeof(rxDesc64));
1416657Snate@binkert.org    memset(&txDesc64, 0, sizeof(txDesc64));
1426657Snate@binkert.org}
1436657Snate@binkert.org
1446657Snate@binkert.orgNSGigE::~NSGigE()
1456657Snate@binkert.org{
1466657Snate@binkert.org    delete interface;
1476657Snate@binkert.org}
1486657Snate@binkert.org
1496657Snate@binkert.org/**
1506657Snate@binkert.org * This is to write to the PCI general configuration registers
1516657Snate@binkert.org */
1526657Snate@binkert.orgTick
1536657Snate@binkert.orgNSGigE::writeConfig(PacketPtr pkt)
1546657Snate@binkert.org{
1556657Snate@binkert.org    int offset = pkt->getAddr() & PCI_CONFIG_SIZE;
1566657Snate@binkert.org    if (offset < PCI_DEVICE_SPECIFIC)
1576657Snate@binkert.org        PciDevice::writeConfig(pkt);
1586657Snate@binkert.org    else
1596877Ssteve.reinhardt@amd.com        panic("Device specific PCI config space not implemented!\n");
1606657Snate@binkert.org
1616657Snate@binkert.org    switch (offset) {
1626657Snate@binkert.org        // seems to work fine without all these PCI settings, but i
1636657Snate@binkert.org        // put in the IO to double check, an assertion will fail if we
1646657Snate@binkert.org        // need to properly implement it
1656657Snate@binkert.org      case PCI_COMMAND:
1667542SBrad.Beckmann@amd.com        if (config.data[offset] & PCI_CMD_IOSE)
1677542SBrad.Beckmann@amd.com            ioEnable = true;
1686657Snate@binkert.org        else
1696657Snate@binkert.org            ioEnable = false;
1706657Snate@binkert.org        break;
1716657Snate@binkert.org    }
1726877Ssteve.reinhardt@amd.com
1736999Snate@binkert.org    return configDelay;
1746877Ssteve.reinhardt@amd.com}
1756877Ssteve.reinhardt@amd.com
1766877Ssteve.reinhardt@amd.comEtherInt*
1776877Ssteve.reinhardt@amd.comNSGigE::getEthPort(const std::string &if_name, int idx)
1786877Ssteve.reinhardt@amd.com{
1796877Ssteve.reinhardt@amd.com    if (if_name == "interface") {
1806877Ssteve.reinhardt@amd.com       if (interface->getPeer())
1816877Ssteve.reinhardt@amd.com           panic("interface already connected to\n");
1826877Ssteve.reinhardt@amd.com       return interface;
1836877Ssteve.reinhardt@amd.com    }
1846877Ssteve.reinhardt@amd.com    return NULL;
1856877Ssteve.reinhardt@amd.com}
1866877Ssteve.reinhardt@amd.com
1876877Ssteve.reinhardt@amd.com/**
1886877Ssteve.reinhardt@amd.com * This reads the device registers, which are detailed in the NS83820
1896877Ssteve.reinhardt@amd.com * spec sheet
1906882SBrad.Beckmann@amd.com */
1916882SBrad.Beckmann@amd.comTick
1926882SBrad.Beckmann@amd.comNSGigE::read(PacketPtr pkt)
1936882SBrad.Beckmann@amd.com{
1946882SBrad.Beckmann@amd.com    assert(ioEnable);
1956882SBrad.Beckmann@amd.com
1966882SBrad.Beckmann@amd.com    //The mask is to give you only the offset into the device register file
1976877Ssteve.reinhardt@amd.com    Addr daddr = pkt->getAddr() & 0xfff;
1986877Ssteve.reinhardt@amd.com    DPRINTF(EthernetPIO, "read  da=%#x pa=%#x size=%d\n",
1996877Ssteve.reinhardt@amd.com            daddr, pkt->getAddr(), pkt->getSize());
2006877Ssteve.reinhardt@amd.com
2016657Snate@binkert.org
2026657Snate@binkert.org    // there are some reserved registers, you can see ns_gige_reg.h and
2036999Snate@binkert.org    // the spec sheet for details
2046657Snate@binkert.org    if (daddr > LAST && daddr <=  RESERVED) {
2056657Snate@binkert.org        panic("Accessing reserved register");
2066657Snate@binkert.org    } else if (daddr > RESERVED && daddr <= 0x3FC) {
2076657Snate@binkert.org        return readConfig(pkt);
2086657Snate@binkert.org    } else if (daddr >= MIB_START && daddr <= MIB_END) {
2096657Snate@binkert.org        // don't implement all the MIB's.  hopefully the kernel
2107007Snate@binkert.org        // doesn't actually DEPEND upon their values
2116657Snate@binkert.org        // MIB are just hardware stats keepers
2126657Snate@binkert.org        pkt->setLE<uint32_t>(0);
2136657Snate@binkert.org        pkt->makeAtomicResponse();
2146657Snate@binkert.org        return pioDelay;
2156657Snate@binkert.org    } else if (daddr > 0x3FC)
2167007Snate@binkert.org        panic("Something is messed up!\n");
2177007Snate@binkert.org
2186657Snate@binkert.org    assert(pkt->getSize() == sizeof(uint32_t));
2197002Snate@binkert.org        uint32_t &reg = *pkt->getPtr<uint32_t>();
2207002Snate@binkert.org        uint16_t rfaddr;
2217002Snate@binkert.org
2227002Snate@binkert.org        switch (daddr) {
2236877Ssteve.reinhardt@amd.com          case CR:
2246877Ssteve.reinhardt@amd.com            reg = regs.command;
2256657Snate@binkert.org            //these are supposed to be cleared on a read
2266657Snate@binkert.org            reg &= ~(CR_RXD | CR_TXD | CR_TXR | CR_RXR);
2276657Snate@binkert.org            break;
2286657Snate@binkert.org
2296657Snate@binkert.org          case CFGR:
2306657Snate@binkert.org            reg = regs.config;
2317542SBrad.Beckmann@amd.com            break;
2326657Snate@binkert.org
2336657Snate@binkert.org          case MEAR:
2346657Snate@binkert.org            reg = regs.mear;
2356657Snate@binkert.org            break;
2366793SBrad.Beckmann@amd.com
2376657Snate@binkert.org          case PTSCR:
2386657Snate@binkert.org            reg = regs.ptscr;
2396657Snate@binkert.org            break;
2406657Snate@binkert.org
2416657Snate@binkert.org          case ISR:
2427002Snate@binkert.org            reg = regs.isr;
2436657Snate@binkert.org            devIntrClear(ISR_ALL);
2447007Snate@binkert.org            break;
2457007Snate@binkert.org
2467007Snate@binkert.org          case IMR:
2477007Snate@binkert.org            reg = regs.imr;
2487007Snate@binkert.org            break;
2496657Snate@binkert.org
2506877Ssteve.reinhardt@amd.com          case IER:
2516877Ssteve.reinhardt@amd.com            reg = regs.ier;
2526657Snate@binkert.org            break;
2536877Ssteve.reinhardt@amd.com
2546657Snate@binkert.org          case IHR:
2556657Snate@binkert.org            reg = regs.ihr;
2567002Snate@binkert.org            break;
2577002Snate@binkert.org
2586657Snate@binkert.org          case TXDP:
2597567SBrad.Beckmann@amd.com            reg = regs.txdp;
2607567SBrad.Beckmann@amd.com            break;
2617922SBrad.Beckmann@amd.com
2626881SBrad.Beckmann@amd.com          case TXDP_HI:
2637002Snate@binkert.org            reg = regs.txdp_hi;
2647002Snate@binkert.org            break;
2656657Snate@binkert.org
2667002Snate@binkert.org          case TX_CFG:
2676902SBrad.Beckmann@amd.com            reg = regs.txcfg;
2686863Sdrh5@cs.wisc.edu            break;
2696863Sdrh5@cs.wisc.edu
2707007Snate@binkert.org          case GPIOR:
2716657Snate@binkert.org            reg = regs.gpior;
2726657Snate@binkert.org            break;
2736657Snate@binkert.org
2746657Snate@binkert.org          case RXDP:
2756657Snate@binkert.org            reg = regs.rxdp;
2766657Snate@binkert.org            break;
2776882SBrad.Beckmann@amd.com
2786882SBrad.Beckmann@amd.com          case RXDP_HI:
2796882SBrad.Beckmann@amd.com            reg = regs.rxdp_hi;
2806882SBrad.Beckmann@amd.com            break;
2816657Snate@binkert.org
2826657Snate@binkert.org          case RX_CFG:
2836657Snate@binkert.org            reg = regs.rxcfg;
2846657Snate@binkert.org            break;
2857007Snate@binkert.org
2867839Snilay@cs.wisc.edu          case PQCR:
2877839Snilay@cs.wisc.edu            reg = regs.pqcr;
2887839Snilay@cs.wisc.edu            break;
2897839Snilay@cs.wisc.edu
2907839Snilay@cs.wisc.edu          case WCSR:
2917839Snilay@cs.wisc.edu            reg = regs.wcsr;
2927839Snilay@cs.wisc.edu            break;
2937839Snilay@cs.wisc.edu
2947839Snilay@cs.wisc.edu          case PCR:
2957839Snilay@cs.wisc.edu            reg = regs.pcr;
2967839Snilay@cs.wisc.edu            break;
2977839Snilay@cs.wisc.edu
2987007Snate@binkert.org            // see the spec sheet for how RFCR and RFDR work
2997007Snate@binkert.org            // basically, you write to RFCR to tell the machine
3007007Snate@binkert.org            // what you want to do next, then you act upon RFDR,
3017007Snate@binkert.org            // and the device will be prepared b/c of what you
3027007Snate@binkert.org            // wrote to RFCR
3037839Snilay@cs.wisc.edu          case RFCR:
3047839Snilay@cs.wisc.edu            reg = regs.rfcr;
3057839Snilay@cs.wisc.edu            break;
3067839Snilay@cs.wisc.edu
3077839Snilay@cs.wisc.edu          case RFDR:
3087839Snilay@cs.wisc.edu            rfaddr = (uint16_t)(regs.rfcr & RFCR_RFADDR);
3097839Snilay@cs.wisc.edu            switch (rfaddr) {
3107839Snilay@cs.wisc.edu              // Read from perfect match ROM octets
3117839Snilay@cs.wisc.edu              case 0x000:
3127839Snilay@cs.wisc.edu                reg = rom.perfectMatch[1];
3137839Snilay@cs.wisc.edu                reg = reg << 8;
3147839Snilay@cs.wisc.edu                reg += rom.perfectMatch[0];
3157007Snate@binkert.org                break;
3167007Snate@binkert.org              case 0x002:
3177002Snate@binkert.org                reg = rom.perfectMatch[3] << 8;
3186657Snate@binkert.org                reg += rom.perfectMatch[2];
3196657Snate@binkert.org                break;
3206657Snate@binkert.org              case 0x004:
3217055Snate@binkert.org                reg = rom.perfectMatch[5] << 8;
3226657Snate@binkert.org                reg += rom.perfectMatch[4];
3236657Snate@binkert.org                break;
3246657Snate@binkert.org              default:
3256863Sdrh5@cs.wisc.edu                // Read filter hash table
3267055Snate@binkert.org                if (rfaddr >= FHASH_ADDR &&
3277567SBrad.Beckmann@amd.com                    rfaddr < FHASH_ADDR + FHASH_SIZE) {
3287567SBrad.Beckmann@amd.com
3297567SBrad.Beckmann@amd.com                    // Only word-aligned reads supported
3307567SBrad.Beckmann@amd.com                    if (rfaddr % 2)
3317567SBrad.Beckmann@amd.com                        panic("unaligned read from filter hash table!");
3327542SBrad.Beckmann@amd.com
3337542SBrad.Beckmann@amd.com                    reg = rom.filterHash[rfaddr - FHASH_ADDR + 1] << 8;
3346657Snate@binkert.org                    reg += rom.filterHash[rfaddr - FHASH_ADDR];
3357007Snate@binkert.org                    break;
3366657Snate@binkert.org                }
3376657Snate@binkert.org
3386657Snate@binkert.org                panic("reading RFDR for something other than pattern"
3396657Snate@binkert.org                      " matching or hashing! %#x\n", rfaddr);
3406657Snate@binkert.org            }
3416657Snate@binkert.org            break;
3426657Snate@binkert.org
3436657Snate@binkert.org          case SRR:
3447839Snilay@cs.wisc.edu            reg = regs.srr;
3457839Snilay@cs.wisc.edu            break;
3467839Snilay@cs.wisc.edu
3477839Snilay@cs.wisc.edu          case MIBC:
3487839Snilay@cs.wisc.edu            reg = regs.mibc;
3497839Snilay@cs.wisc.edu            reg &= ~(MIBC_MIBS | MIBC_ACLR);
3508086SBrad.Beckmann@amd.com            break;
3518086SBrad.Beckmann@amd.com
3527839Snilay@cs.wisc.edu          case VRCR:
3537839Snilay@cs.wisc.edu            reg = regs.vrcr;
3547839Snilay@cs.wisc.edu            break;
3557839Snilay@cs.wisc.edu
3567839Snilay@cs.wisc.edu          case VTCR:
3577839Snilay@cs.wisc.edu            reg = regs.vtcr;
3587839Snilay@cs.wisc.edu            break;
3597839Snilay@cs.wisc.edu
3607839Snilay@cs.wisc.edu          case VDR:
3617839Snilay@cs.wisc.edu            reg = regs.vdr;
3626657Snate@binkert.org            break;
3636657Snate@binkert.org
3646657Snate@binkert.org          case CCSR:
3656657Snate@binkert.org            reg = regs.ccsr;
3667839Snilay@cs.wisc.edu            break;
3677839Snilay@cs.wisc.edu
3687839Snilay@cs.wisc.edu          case TBICR:
3697839Snilay@cs.wisc.edu            reg = regs.tbicr;
3707839Snilay@cs.wisc.edu            break;
3717839Snilay@cs.wisc.edu
3727839Snilay@cs.wisc.edu          case TBISR:
3737839Snilay@cs.wisc.edu            reg = regs.tbisr;
3747839Snilay@cs.wisc.edu            break;
3757839Snilay@cs.wisc.edu
3767839Snilay@cs.wisc.edu          case TANAR:
3777839Snilay@cs.wisc.edu            reg = regs.tanar;
3787839Snilay@cs.wisc.edu            break;
3797839Snilay@cs.wisc.edu
3807839Snilay@cs.wisc.edu          case TANLPAR:
3817839Snilay@cs.wisc.edu            reg = regs.tanlpar;
3826657Snate@binkert.org            break;
3836657Snate@binkert.org
3846657Snate@binkert.org          case TANER:
3856657Snate@binkert.org            reg = regs.taner;
3867007Snate@binkert.org            break;
3876657Snate@binkert.org
3886657Snate@binkert.org          case TESR:
3896657Snate@binkert.org            reg = regs.tesr;
3906657Snate@binkert.org            break;
3916657Snate@binkert.org
3926657Snate@binkert.org          case M5REG:
3936657Snate@binkert.org            reg = 0;
3946657Snate@binkert.org            if (params()->rx_thread)
3956657Snate@binkert.org                reg |= M5REG_RX_THREAD;
3966657Snate@binkert.org            if (params()->tx_thread)
3977007Snate@binkert.org                reg |= M5REG_TX_THREAD;
3986657Snate@binkert.org            if (params()->rss)
3996657Snate@binkert.org                reg |= M5REG_RSS;
4006657Snate@binkert.org            break;
4016657Snate@binkert.org
4026657Snate@binkert.org          default:
4036999Snate@binkert.org            panic("reading unimplemented register: addr=%#x", daddr);
4046657Snate@binkert.org        }
4056657Snate@binkert.org
4066657Snate@binkert.org        DPRINTF(EthernetPIO, "read from %#x: data=%d data=%#x\n",
4076657Snate@binkert.org                daddr, reg, reg);
4087007Snate@binkert.org
4096657Snate@binkert.org    pkt->makeAtomicResponse();
4106657Snate@binkert.org    return pioDelay;
4116657Snate@binkert.org}
4126657Snate@binkert.org
4136657Snate@binkert.orgTick
4147832Snate@binkert.orgNSGigE::write(PacketPtr pkt)
4157002Snate@binkert.org{
4167002Snate@binkert.org    assert(ioEnable);
4177002Snate@binkert.org
4187056Snate@binkert.org    Addr daddr = pkt->getAddr() & 0xfff;
4196657Snate@binkert.org    DPRINTF(EthernetPIO, "write da=%#x pa=%#x size=%d\n",
4206657Snate@binkert.org            daddr, pkt->getAddr(), pkt->getSize());
4216657Snate@binkert.org
4226657Snate@binkert.org    if (daddr > LAST && daddr <=  RESERVED) {
4237056Snate@binkert.org        panic("Accessing reserved register");
4247056Snate@binkert.org    } else if (daddr > RESERVED && daddr <= 0x3FC) {
4256657Snate@binkert.org        return writeConfig(pkt);
4267002Snate@binkert.org    } else if (daddr > 0x3FC)
4277002Snate@binkert.org        panic("Something is messed up!\n");
4286657Snate@binkert.org
4296657Snate@binkert.org    if (pkt->getSize() == sizeof(uint32_t)) {
4306657Snate@binkert.org        uint32_t reg = pkt->getLE<uint32_t>();
4316657Snate@binkert.org        uint16_t rfaddr;
4326657Snate@binkert.org
4336793SBrad.Beckmann@amd.com        DPRINTF(EthernetPIO, "write data=%d data=%#x\n", reg, reg);
4346657Snate@binkert.org
4356657Snate@binkert.org        switch (daddr) {
4366657Snate@binkert.org          case CR:
4376657Snate@binkert.org            regs.command = reg;
4386877Ssteve.reinhardt@amd.com            if (reg & CR_TXD) {
4396877Ssteve.reinhardt@amd.com                txEnable = false;
4406877Ssteve.reinhardt@amd.com            } else if (reg & CR_TXE) {
4416877Ssteve.reinhardt@amd.com                txEnable = true;
4426877Ssteve.reinhardt@amd.com
4436877Ssteve.reinhardt@amd.com                // the kernel is enabling the transmit machine
4446657Snate@binkert.org                if (txState == txIdle)
4457542SBrad.Beckmann@amd.com                    txKick();
4466657Snate@binkert.org            }
4477007Snate@binkert.org
4486657Snate@binkert.org            if (reg & CR_RXD) {
4496657Snate@binkert.org                rxEnable = false;
4507007Snate@binkert.org            } else if (reg & CR_RXE) {
4516657Snate@binkert.org                rxEnable = true;
4526877Ssteve.reinhardt@amd.com
4536877Ssteve.reinhardt@amd.com                if (rxState == rxIdle)
4546657Snate@binkert.org                    rxKick();
4556877Ssteve.reinhardt@amd.com            }
4566877Ssteve.reinhardt@amd.com
4576877Ssteve.reinhardt@amd.com            if (reg & CR_TXR)
4586877Ssteve.reinhardt@amd.com                txReset();
4596877Ssteve.reinhardt@amd.com
4606969SBrad.Beckmann@amd.com            if (reg & CR_RXR)
4616657Snate@binkert.org                rxReset();
4627567SBrad.Beckmann@amd.com
4637567SBrad.Beckmann@amd.com            if (reg & CR_SWI)
4647567SBrad.Beckmann@amd.com                devIntrPost(ISR_SWI);
4657567SBrad.Beckmann@amd.com
4667567SBrad.Beckmann@amd.com            if (reg & CR_RST) {
4677567SBrad.Beckmann@amd.com                txReset();
4686657Snate@binkert.org                rxReset();
4696882SBrad.Beckmann@amd.com
4706882SBrad.Beckmann@amd.com                regsReset();
4716882SBrad.Beckmann@amd.com            }
4726882SBrad.Beckmann@amd.com            break;
4736882SBrad.Beckmann@amd.com
4746882SBrad.Beckmann@amd.com          case CFGR:
4756882SBrad.Beckmann@amd.com            if (reg & CFGR_LNKSTS ||
4766882SBrad.Beckmann@amd.com                reg & CFGR_SPDSTS ||
4776877Ssteve.reinhardt@amd.com                reg & CFGR_DUPSTS ||
4786888SBrad.Beckmann@amd.com                reg & CFGR_RESERVED ||
4796882SBrad.Beckmann@amd.com                reg & CFGR_T64ADDR ||
4806882SBrad.Beckmann@amd.com                reg & CFGR_PCI64_DET) {
4816882SBrad.Beckmann@amd.com                // First clear all writable bits
4826882SBrad.Beckmann@amd.com                regs.config &= CFGR_LNKSTS | CFGR_SPDSTS | CFGR_DUPSTS |
4836882SBrad.Beckmann@amd.com                    CFGR_RESERVED | CFGR_T64ADDR |
4846882SBrad.Beckmann@amd.com                    CFGR_PCI64_DET;
4856882SBrad.Beckmann@amd.com                // Now set the appropriate writable bits
4866882SBrad.Beckmann@amd.com                regs.config |= reg & ~(CFGR_LNKSTS | CFGR_SPDSTS | CFGR_DUPSTS |
4876882SBrad.Beckmann@amd.com                                       CFGR_RESERVED | CFGR_T64ADDR |
4886882SBrad.Beckmann@amd.com                                       CFGR_PCI64_DET);
4896882SBrad.Beckmann@amd.com            }
4906882SBrad.Beckmann@amd.com
4916882SBrad.Beckmann@amd.com// all these #if 0's are because i don't THINK the kernel needs to
4926882SBrad.Beckmann@amd.com// have these implemented. if there is a problem relating to one of
4936882SBrad.Beckmann@amd.com// these, you may need to add functionality in.
4946882SBrad.Beckmann@amd.com
4956882SBrad.Beckmann@amd.com// grouped together and #if 0'ed to avoid empty if body and make clang happy
4966882SBrad.Beckmann@amd.com#if 0
4976888SBrad.Beckmann@amd.com            if (reg & CFGR_TBI_EN) ;
4986888SBrad.Beckmann@amd.com            if (reg & CFGR_MODE_1000) ;
4996888SBrad.Beckmann@amd.com
5006888SBrad.Beckmann@amd.com            if (reg & CFGR_PINT_DUPSTS ||
5016888SBrad.Beckmann@amd.com                reg & CFGR_PINT_LNKSTS ||
5026888SBrad.Beckmann@amd.com                reg & CFGR_PINT_SPDSTS)
5036888SBrad.Beckmann@amd.com                ;
5046888SBrad.Beckmann@amd.com
5056657Snate@binkert.org            if (reg & CFGR_TMRTEST) ;
5066888SBrad.Beckmann@amd.com            if (reg & CFGR_MRM_DIS) ;
5076888SBrad.Beckmann@amd.com            if (reg & CFGR_MWI_DIS) ;
5086888SBrad.Beckmann@amd.com
5096888SBrad.Beckmann@amd.com            if (reg & CFGR_DATA64_EN) ;
5106657Snate@binkert.org            if (reg & CFGR_M64ADDR) ;
5116657Snate@binkert.org            if (reg & CFGR_PHY_RST) ;
5126657Snate@binkert.org            if (reg & CFGR_PHY_DIS) ;
5136657Snate@binkert.org
5146657Snate@binkert.org            if (reg & CFGR_REQALG) ;
5156657Snate@binkert.org            if (reg & CFGR_SB) ;
5166657Snate@binkert.org            if (reg & CFGR_POW) ;
5176657Snate@binkert.org            if (reg & CFGR_EXD) ;
5186657Snate@binkert.org            if (reg & CFGR_PESEL) ;
5197007Snate@binkert.org            if (reg & CFGR_BROM_DIS) ;
5207007Snate@binkert.org            if (reg & CFGR_EXT_125) ;
5216657Snate@binkert.org            if (reg & CFGR_BEM) ;
5227007Snate@binkert.org
5237007Snate@binkert.org            if (reg & CFGR_T64ADDR) ;
5247007Snate@binkert.org            // panic("CFGR_T64ADDR is read only register!\n");
5256657Snate@binkert.org#endif
5266657Snate@binkert.org            if (reg & CFGR_AUTO_1000)
5276657Snate@binkert.org                panic("CFGR_AUTO_1000 not implemented!\n");
5287007Snate@binkert.org
5297542SBrad.Beckmann@amd.com            if (reg & CFGR_PCI64_DET)
5307542SBrad.Beckmann@amd.com                panic("CFGR_PCI64_DET is read only register!\n");
5317007Snate@binkert.org
5326657Snate@binkert.org            if (reg & CFGR_EXTSTS_EN)
5336657Snate@binkert.org                extstsEnable = true;
5346657Snate@binkert.org            else
5356657Snate@binkert.org                extstsEnable = false;
5366657Snate@binkert.org            break;
5376657Snate@binkert.org
5386657Snate@binkert.org          case MEAR:
5396657Snate@binkert.org            // Clear writable bits
5406657Snate@binkert.org            regs.mear &= MEAR_EEDO;
5416657Snate@binkert.org            // Set appropriate writable bits
5426657Snate@binkert.org            regs.mear |= reg & ~MEAR_EEDO;
5436657Snate@binkert.org
5446657Snate@binkert.org            // FreeBSD uses the EEPROM to read PMATCH (for the MAC address)
5456657Snate@binkert.org            // even though it could get it through RFDR
5466657Snate@binkert.org            if (reg & MEAR_EESEL) {
5476657Snate@binkert.org                // Rising edge of clock
5486657Snate@binkert.org                if (reg & MEAR_EECLK && !eepromClk)
5496657Snate@binkert.org                    eepromKick();
5506657Snate@binkert.org            }
5516657Snate@binkert.org            else {
5526657Snate@binkert.org                eepromState = eepromStart;
5536657Snate@binkert.org                regs.mear &= ~MEAR_EEDI;
5546657Snate@binkert.org            }
5556657Snate@binkert.org
5566657Snate@binkert.org            eepromClk = reg & MEAR_EECLK;
5576657Snate@binkert.org
5586657Snate@binkert.org            // since phy is completely faked, MEAR_MD* don't matter
5596657Snate@binkert.org
5607007Snate@binkert.org// grouped together and #if 0'ed to avoid empty if body and make clang happy
5616657Snate@binkert.org#if 0
5626657Snate@binkert.org            if (reg & MEAR_MDIO) ;
5636657Snate@binkert.org            if (reg & MEAR_MDDIR) ;
5646657Snate@binkert.org            if (reg & MEAR_MDC) ;
5657007Snate@binkert.org#endif
5666657Snate@binkert.org            break;
5677007Snate@binkert.org
5687007Snate@binkert.org          case PTSCR:
5696657Snate@binkert.org            regs.ptscr = reg & ~(PTSCR_RBIST_RDONLY);
5706657Snate@binkert.org            // these control BISTs for various parts of chip - we
5716657Snate@binkert.org            // don't care or do just fake that the BIST is done
5726657Snate@binkert.org            if (reg & PTSCR_RBIST_EN)
5736657Snate@binkert.org                regs.ptscr |= PTSCR_RBIST_DONE;
5746657Snate@binkert.org            if (reg & PTSCR_EEBIST_EN)
5756657Snate@binkert.org                regs.ptscr &= ~PTSCR_EEBIST_EN;
5766657Snate@binkert.org            if (reg & PTSCR_EELOAD_EN)
5776657Snate@binkert.org                regs.ptscr &= ~PTSCR_EELOAD_EN;
5786657Snate@binkert.org            break;
5796657Snate@binkert.org
5806657Snate@binkert.org          case ISR: /* writing to the ISR has no effect */
5816657Snate@binkert.org            panic("ISR is a read only register!\n");
5826657Snate@binkert.org
5836657Snate@binkert.org          case IMR:
5847566SBrad.Beckmann@amd.com            regs.imr = reg;
5856657Snate@binkert.org            devIntrChangeMask();
5866657Snate@binkert.org            break;
5876657Snate@binkert.org
5886657Snate@binkert.org          case IER:
5896657Snate@binkert.org            regs.ier = reg;
5906657Snate@binkert.org            break;
5916657Snate@binkert.org
5926657Snate@binkert.org          case IHR:
5937007Snate@binkert.org            regs.ihr = reg;
5947007Snate@binkert.org            /* not going to implement real interrupt holdoff */
5957007Snate@binkert.org            break;
5966657Snate@binkert.org
5976657Snate@binkert.org          case TXDP:
5986657Snate@binkert.org            regs.txdp = (reg & 0xFFFFFFFC);
5996657Snate@binkert.org            assert(txState == txIdle);
6006657Snate@binkert.org            CTDD = false;
6016657Snate@binkert.org            break;
6026657Snate@binkert.org
6036657Snate@binkert.org          case TXDP_HI:
6046657Snate@binkert.org            regs.txdp_hi = reg;
6056657Snate@binkert.org            break;
6066657Snate@binkert.org
6076657Snate@binkert.org          case TX_CFG:
6086657Snate@binkert.org            regs.txcfg = reg;
6096657Snate@binkert.org#if 0
6106657Snate@binkert.org            if (reg & TX_CFG_CSI) ;
6116657Snate@binkert.org            if (reg & TX_CFG_HBI) ;
6126657Snate@binkert.org            if (reg & TX_CFG_MLB) ;
6136657Snate@binkert.org            if (reg & TX_CFG_ATP) ;
6146657Snate@binkert.org            if (reg & TX_CFG_ECRETRY) {
6156657Snate@binkert.org                /*
6166657Snate@binkert.org                 * this could easily be implemented, but considering
6176657Snate@binkert.org                 * the network is just a fake pipe, wouldn't make
6187454Snate@binkert.org                 * sense to do this
6196657Snate@binkert.org                 */
6206657Snate@binkert.org            }
6216657Snate@binkert.org
6226657Snate@binkert.org            if (reg & TX_CFG_BRST_DIS) ;
6237007Snate@binkert.org#endif
6247056Snate@binkert.org
6257007Snate@binkert.org#if 0
6267007Snate@binkert.org            /* we handle our own DMA, ignore the kernel's exhortations */
6276657Snate@binkert.org            if (reg & TX_CFG_MXDMA) ;
6287566SBrad.Beckmann@amd.com#endif
6297566SBrad.Beckmann@amd.com
6307566SBrad.Beckmann@amd.com            // also, we currently don't care about fill/drain
6317566SBrad.Beckmann@amd.com            // thresholds though this may change in the future with
6327566SBrad.Beckmann@amd.com            // more realistic networks or a driver which changes it
6337566SBrad.Beckmann@amd.com            // according to feedback
6347566SBrad.Beckmann@amd.com
6356657Snate@binkert.org            break;
6367672Snate@binkert.org
6376657Snate@binkert.org          case GPIOR:
6386657Snate@binkert.org            // Only write writable bits
6396657Snate@binkert.org            regs.gpior &= GPIOR_UNUSED | GPIOR_GP5_IN | GPIOR_GP4_IN
6406657Snate@binkert.org                        | GPIOR_GP3_IN | GPIOR_GP2_IN | GPIOR_GP1_IN;
6417672Snate@binkert.org            regs.gpior |= reg & ~(GPIOR_UNUSED | GPIOR_GP5_IN | GPIOR_GP4_IN
6426657Snate@binkert.org                                | GPIOR_GP3_IN | GPIOR_GP2_IN | GPIOR_GP1_IN);
6437056Snate@binkert.org            /* these just control general purpose i/o pins, don't matter */
6446657Snate@binkert.org            break;
6456657Snate@binkert.org
6467672Snate@binkert.org          case RXDP:
6476657Snate@binkert.org            regs.rxdp = reg;
6486657Snate@binkert.org            CRDD = false;
6496657Snate@binkert.org            break;
6506657Snate@binkert.org
6516657Snate@binkert.org          case RXDP_HI:
6526657Snate@binkert.org            regs.rxdp_hi = reg;
6536657Snate@binkert.org            break;
6546657Snate@binkert.org
6556657Snate@binkert.org          case RX_CFG:
6566657Snate@binkert.org            regs.rxcfg = reg;
6576657Snate@binkert.org#if 0
6587542SBrad.Beckmann@amd.com            if (reg & RX_CFG_AEP) ;
6596657Snate@binkert.org            if (reg & RX_CFG_ARP) ;
6606657Snate@binkert.org            if (reg & RX_CFG_STRIPCRC) ;
6616657Snate@binkert.org            if (reg & RX_CFG_RX_RD) ;
6626657Snate@binkert.org            if (reg & RX_CFG_ALP) ;
6636657Snate@binkert.org            if (reg & RX_CFG_AIRL) ;
6646657Snate@binkert.org
6656657Snate@binkert.org            /* we handle our own DMA, ignore what kernel says about it */
6666657Snate@binkert.org            if (reg & RX_CFG_MXDMA) ;
6676657Snate@binkert.org
6686657Snate@binkert.org            //also, we currently don't care about fill/drain thresholds
6696657Snate@binkert.org            //though this may change in the future with more realistic
6706657Snate@binkert.org            //networks or a driver which changes it according to feedback
6716657Snate@binkert.org            if (reg & (RX_CFG_DRTH | RX_CFG_DRTH0)) ;
6726657Snate@binkert.org#endif
6736657Snate@binkert.org            break;
6747007Snate@binkert.org
6757007Snate@binkert.org          case PQCR:
6767007Snate@binkert.org            /* there is no priority queueing used in the linux 2.6 driver */
6776657Snate@binkert.org            regs.pqcr = reg;
6786657Snate@binkert.org            break;
6796657Snate@binkert.org
6807007Snate@binkert.org          case WCSR:
6817007Snate@binkert.org            /* not going to implement wake on LAN */
6827007Snate@binkert.org            regs.wcsr = reg;
6836657Snate@binkert.org            break;
6846657Snate@binkert.org
6856657Snate@binkert.org          case PCR:
6867007Snate@binkert.org            /* not going to implement pause control */
6877007Snate@binkert.org            regs.pcr = reg;
6887007Snate@binkert.org            break;
6896657Snate@binkert.org
6906657Snate@binkert.org          case RFCR:
6916657Snate@binkert.org            regs.rfcr = reg;
6927007Snate@binkert.org
6937007Snate@binkert.org            rxFilterEnable = (reg & RFCR_RFEN) ? true : false;
6947007Snate@binkert.org            acceptBroadcast = (reg & RFCR_AAB) ? true : false;
6956657Snate@binkert.org            acceptMulticast = (reg & RFCR_AAM) ? true : false;
6966657Snate@binkert.org            acceptUnicast = (reg & RFCR_AAU) ? true : false;
6976657Snate@binkert.org            acceptPerfect = (reg & RFCR_APM) ? true : false;
6987007Snate@binkert.org            acceptArp = (reg & RFCR_AARP) ? true : false;
6997007Snate@binkert.org            multicastHashEnable = (reg & RFCR_MHEN) ? true : false;
7007007Snate@binkert.org
7016657Snate@binkert.org#if 0
7026657Snate@binkert.org            if (reg & RFCR_APAT)
7037007Snate@binkert.org                panic("RFCR_APAT not implemented!\n");
7047007Snate@binkert.org#endif
7057007Snate@binkert.org            if (reg & RFCR_UHEN)
7067007Snate@binkert.org                panic("Unicast hash filtering not used by drivers!\n");
7076657Snate@binkert.org
7086657Snate@binkert.org            if (reg & RFCR_ULM)
7096657Snate@binkert.org                panic("RFCR_ULM not implemented!\n");
7107007Snate@binkert.org
7117567SBrad.Beckmann@amd.com            break;
7127567SBrad.Beckmann@amd.com
7137567SBrad.Beckmann@amd.com          case RFDR:
7147567SBrad.Beckmann@amd.com            rfaddr = (uint16_t)(regs.rfcr & RFCR_RFADDR);
7157567SBrad.Beckmann@amd.com            switch (rfaddr) {
7167567SBrad.Beckmann@amd.com              case 0x000:
7177567SBrad.Beckmann@amd.com                rom.perfectMatch[0] = (uint8_t)reg;
7187567SBrad.Beckmann@amd.com                rom.perfectMatch[1] = (uint8_t)(reg >> 8);
7197567SBrad.Beckmann@amd.com                break;
7207567SBrad.Beckmann@amd.com              case 0x002:
7217567SBrad.Beckmann@amd.com                rom.perfectMatch[2] = (uint8_t)reg;
7227567SBrad.Beckmann@amd.com                rom.perfectMatch[3] = (uint8_t)(reg >> 8);
7237567SBrad.Beckmann@amd.com                break;
7248155Snilay@cs.wisc.edu              case 0x004:
7258155Snilay@cs.wisc.edu                rom.perfectMatch[4] = (uint8_t)reg;
7268155Snilay@cs.wisc.edu                rom.perfectMatch[5] = (uint8_t)(reg >> 8);
7278155Snilay@cs.wisc.edu                break;
7288155Snilay@cs.wisc.edu              default:
7298155Snilay@cs.wisc.edu
7308155Snilay@cs.wisc.edu                if (rfaddr >= FHASH_ADDR &&
7318155Snilay@cs.wisc.edu                    rfaddr < FHASH_ADDR + FHASH_SIZE) {
7328155Snilay@cs.wisc.edu
7338155Snilay@cs.wisc.edu                    // Only word-aligned writes supported
7348155Snilay@cs.wisc.edu                    if (rfaddr % 2)
7357567SBrad.Beckmann@amd.com                        panic("unaligned write to filter hash table!");
7368155Snilay@cs.wisc.edu
7378155Snilay@cs.wisc.edu                    rom.filterHash[rfaddr - FHASH_ADDR] = (uint8_t)reg;
7387567SBrad.Beckmann@amd.com                    rom.filterHash[rfaddr - FHASH_ADDR + 1]
7397567SBrad.Beckmann@amd.com                        = (uint8_t)(reg >> 8);
7407567SBrad.Beckmann@amd.com                    break;
7417567SBrad.Beckmann@amd.com                }
7427922SBrad.Beckmann@amd.com                panic("writing RFDR for something other than pattern matching "
7437922SBrad.Beckmann@amd.com                    "or hashing! %#x\n", rfaddr);
7447922SBrad.Beckmann@amd.com            }
7457922SBrad.Beckmann@amd.com            break;
7467922SBrad.Beckmann@amd.com
7477922SBrad.Beckmann@amd.com          case BRAR:
7487922SBrad.Beckmann@amd.com            regs.brar = reg;
7497922SBrad.Beckmann@amd.com            break;
7508154Snilay@cs.wisc.edu
7518154Snilay@cs.wisc.edu          case BRDR:
7528154Snilay@cs.wisc.edu            panic("the driver never uses BRDR, something is wrong!\n");
7538154Snilay@cs.wisc.edu
7548154Snilay@cs.wisc.edu          case SRR:
7558154Snilay@cs.wisc.edu            panic("SRR is read only register!\n");
7568154Snilay@cs.wisc.edu
7578154Snilay@cs.wisc.edu          case MIBC:
7588154Snilay@cs.wisc.edu            panic("the driver never uses MIBC, something is wrong!\n");
7598154Snilay@cs.wisc.edu
7608154Snilay@cs.wisc.edu          case VRCR:
7618154Snilay@cs.wisc.edu            regs.vrcr = reg;
7628154Snilay@cs.wisc.edu            break;
7638154Snilay@cs.wisc.edu
7648154Snilay@cs.wisc.edu          case VTCR:
7658154Snilay@cs.wisc.edu            regs.vtcr = reg;
7668154Snilay@cs.wisc.edu            break;
7678154Snilay@cs.wisc.edu
7688154Snilay@cs.wisc.edu          case VDR:
7698154Snilay@cs.wisc.edu            panic("the driver never uses VDR, something is wrong!\n");
7708154Snilay@cs.wisc.edu
7717922SBrad.Beckmann@amd.com          case CCSR:
7727922SBrad.Beckmann@amd.com            /* not going to implement clockrun stuff */
7737922SBrad.Beckmann@amd.com            regs.ccsr = reg;
7747922SBrad.Beckmann@amd.com            break;
7757007Snate@binkert.org
7767007Snate@binkert.org          case TBICR:
7776863Sdrh5@cs.wisc.edu            regs.tbicr = reg;
7786863Sdrh5@cs.wisc.edu            if (reg & TBICR_MR_LOOPBACK)
7796863Sdrh5@cs.wisc.edu                panic("TBICR_MR_LOOPBACK never used, something wrong!\n");
7807007Snate@binkert.org
7817007Snate@binkert.org            if (reg & TBICR_MR_AN_ENABLE) {
7827007Snate@binkert.org                regs.tanlpar = regs.tanar;
7837007Snate@binkert.org                regs.tbisr |= (TBISR_MR_AN_COMPLETE | TBISR_MR_LINK_STATUS);
7846863Sdrh5@cs.wisc.edu            }
7856863Sdrh5@cs.wisc.edu
7866863Sdrh5@cs.wisc.edu#if 0
7876863Sdrh5@cs.wisc.edu            if (reg & TBICR_MR_RESTART_AN) ;
7886863Sdrh5@cs.wisc.edu#endif
7896863Sdrh5@cs.wisc.edu
7907007Snate@binkert.org            break;
7917007Snate@binkert.org
7927007Snate@binkert.org          case TBISR:
7937007Snate@binkert.org            panic("TBISR is read only register!\n");
7947007Snate@binkert.org
7956657Snate@binkert.org          case TANAR:
7967007Snate@binkert.org            // Only write the writable bits
7977007Snate@binkert.org            regs.tanar &= TANAR_RF1 | TANAR_RF2 | TANAR_UNUSED;
7987007Snate@binkert.org            regs.tanar |= reg & ~(TANAR_RF1 | TANAR_RF2 | TANAR_UNUSED);
7996657Snate@binkert.org
8006657Snate@binkert.org            // Pause capability unimplemented
8017007Snate@binkert.org#if 0
8027007Snate@binkert.org            if (reg & TANAR_PS2) ;
8037007Snate@binkert.org            if (reg & TANAR_PS1) ;
8046657Snate@binkert.org#endif
8056657Snate@binkert.org
8067007Snate@binkert.org            break;
8077007Snate@binkert.org
8087007Snate@binkert.org          case TANLPAR:
8096902SBrad.Beckmann@amd.com            panic("this should only be written to by the fake phy!\n");
8106902SBrad.Beckmann@amd.com
8116902SBrad.Beckmann@amd.com          case TANER:
8126902SBrad.Beckmann@amd.com            panic("TANER is read only register!\n");
8136902SBrad.Beckmann@amd.com
8146902SBrad.Beckmann@amd.com          case TESR:
8156902SBrad.Beckmann@amd.com            regs.tesr = reg;
8167025SBrad.Beckmann@amd.com            break;
8176902SBrad.Beckmann@amd.com
8186902SBrad.Beckmann@amd.com          default:
8196902SBrad.Beckmann@amd.com            panic("invalid register access daddr=%#x", daddr);
8206902SBrad.Beckmann@amd.com        }
8216902SBrad.Beckmann@amd.com    } else {
8227542SBrad.Beckmann@amd.com        panic("Invalid Request Size");
8237542SBrad.Beckmann@amd.com    }
8247542SBrad.Beckmann@amd.com    pkt->makeAtomicResponse();
8256902SBrad.Beckmann@amd.com    return pioDelay;
8266902SBrad.Beckmann@amd.com}
8276902SBrad.Beckmann@amd.com
8286902SBrad.Beckmann@amd.comvoid
8296902SBrad.Beckmann@amd.comNSGigE::devIntrPost(uint32_t interrupts)
8306902SBrad.Beckmann@amd.com{
8316902SBrad.Beckmann@amd.com    if (interrupts & ISR_RESERVE)
8326902SBrad.Beckmann@amd.com        panic("Cannot set a reserved interrupt");
8336902SBrad.Beckmann@amd.com
8346902SBrad.Beckmann@amd.com    if (interrupts & ISR_NOIMPL)
8356902SBrad.Beckmann@amd.com        warn("interrupt not implemented %#x\n", interrupts);
8366902SBrad.Beckmann@amd.com
8376902SBrad.Beckmann@amd.com    interrupts &= ISR_IMPL;
8386902SBrad.Beckmann@amd.com    regs.isr |= interrupts;
8396902SBrad.Beckmann@amd.com
8407542SBrad.Beckmann@amd.com    if (interrupts & regs.imr) {
8416902SBrad.Beckmann@amd.com        if (interrupts & ISR_SWI) {
8427839Snilay@cs.wisc.edu            totalSwi++;
8437839Snilay@cs.wisc.edu        }
8447839Snilay@cs.wisc.edu        if (interrupts & ISR_RXIDLE) {
8457839Snilay@cs.wisc.edu            totalRxIdle++;
8467839Snilay@cs.wisc.edu        }
8477839Snilay@cs.wisc.edu        if (interrupts & ISR_RXOK) {
8487839Snilay@cs.wisc.edu            totalRxOk++;
8497839Snilay@cs.wisc.edu        }
8507839Snilay@cs.wisc.edu        if (interrupts & ISR_RXDESC) {
8517839Snilay@cs.wisc.edu            totalRxDesc++;
8527839Snilay@cs.wisc.edu        }
8537839Snilay@cs.wisc.edu        if (interrupts & ISR_TXOK) {
8547839Snilay@cs.wisc.edu            totalTxOk++;
8557839Snilay@cs.wisc.edu        }
8567839Snilay@cs.wisc.edu        if (interrupts & ISR_TXIDLE) {
8577839Snilay@cs.wisc.edu            totalTxIdle++;
8587839Snilay@cs.wisc.edu        }
8598086SBrad.Beckmann@amd.com        if (interrupts & ISR_TXDESC) {
8608086SBrad.Beckmann@amd.com            totalTxDesc++;
8618086SBrad.Beckmann@amd.com        }
8628086SBrad.Beckmann@amd.com        if (interrupts & ISR_RXORN) {
8638086SBrad.Beckmann@amd.com            totalRxOrn++;
8648086SBrad.Beckmann@amd.com        }
8658086SBrad.Beckmann@amd.com    }
8668086SBrad.Beckmann@amd.com
8678086SBrad.Beckmann@amd.com    DPRINTF(EthernetIntr,
8687839Snilay@cs.wisc.edu            "interrupt written to ISR: intr=%#x isr=%#x imr=%#x\n",
8697839Snilay@cs.wisc.edu            interrupts, regs.isr, regs.imr);
8707839Snilay@cs.wisc.edu
8717839Snilay@cs.wisc.edu    if ((regs.isr & regs.imr)) {
8727839Snilay@cs.wisc.edu        Tick when = curTick();
8737839Snilay@cs.wisc.edu        if ((regs.isr & regs.imr & ISR_NODELAY) == 0)
8747839Snilay@cs.wisc.edu            when += intrDelay;
8757839Snilay@cs.wisc.edu        postedInterrupts++;
8767839Snilay@cs.wisc.edu        cpuIntrPost(when);
8777839Snilay@cs.wisc.edu    }
8787839Snilay@cs.wisc.edu}
8797839Snilay@cs.wisc.edu
8807839Snilay@cs.wisc.edu/* writing this interrupt counting stats inside this means that this function
8817839Snilay@cs.wisc.edu   is now limited to being used to clear all interrupts upon the kernel
8827839Snilay@cs.wisc.edu   reading isr and servicing.  just telling you in case you were thinking
8837839Snilay@cs.wisc.edu   of expanding use.
8847839Snilay@cs.wisc.edu*/
8857839Snilay@cs.wisc.eduvoid
8867839Snilay@cs.wisc.eduNSGigE::devIntrClear(uint32_t interrupts)
8877839Snilay@cs.wisc.edu{
8886902SBrad.Beckmann@amd.com    if (interrupts & ISR_RESERVE)
8896657Snate@binkert.org        panic("Cannot clear a reserved interrupt");
8906657Snate@binkert.org
8917839Snilay@cs.wisc.edu    if (regs.isr & regs.imr & ISR_SWI) {
8927839Snilay@cs.wisc.edu        postedSwi++;
8937839Snilay@cs.wisc.edu    }
8947839Snilay@cs.wisc.edu    if (regs.isr & regs.imr & ISR_RXIDLE) {
8956657Snate@binkert.org        postedRxIdle++;
8967839Snilay@cs.wisc.edu    }
8977839Snilay@cs.wisc.edu    if (regs.isr & regs.imr & ISR_RXOK) {
8987839Snilay@cs.wisc.edu        postedRxOk++;
8997839Snilay@cs.wisc.edu    }
9007839Snilay@cs.wisc.edu    if (regs.isr & regs.imr & ISR_RXDESC) {
9018055Sksewell@umich.edu            postedRxDesc++;
9027839Snilay@cs.wisc.edu    }
9037839Snilay@cs.wisc.edu    if (regs.isr & regs.imr & ISR_TXOK) {
9046657Snate@binkert.org        postedTxOk++;
9057839Snilay@cs.wisc.edu    }
9067839Snilay@cs.wisc.edu    if (regs.isr & regs.imr & ISR_TXIDLE) {
9077839Snilay@cs.wisc.edu        postedTxIdle++;
9087839Snilay@cs.wisc.edu    }
9097839Snilay@cs.wisc.edu    if (regs.isr & regs.imr & ISR_TXDESC) {
9107839Snilay@cs.wisc.edu        postedTxDesc++;
9117839Snilay@cs.wisc.edu    }
9127839Snilay@cs.wisc.edu    if (regs.isr & regs.imr & ISR_RXORN) {
9137839Snilay@cs.wisc.edu        postedRxOrn++;
9147839Snilay@cs.wisc.edu    }
9157839Snilay@cs.wisc.edu
9168055Sksewell@umich.edu    interrupts &= ~ISR_NOIMPL;
9177839Snilay@cs.wisc.edu    regs.isr &= ~interrupts;
9187839Snilay@cs.wisc.edu
9197839Snilay@cs.wisc.edu    DPRINTF(EthernetIntr,
9207839Snilay@cs.wisc.edu            "interrupt cleared from ISR: intr=%x isr=%x imr=%x\n",
9217839Snilay@cs.wisc.edu            interrupts, regs.isr, regs.imr);
9227839Snilay@cs.wisc.edu
9237839Snilay@cs.wisc.edu    if (!(regs.isr & regs.imr))
9247839Snilay@cs.wisc.edu        cpuIntrClear();
9257839Snilay@cs.wisc.edu}
9267839Snilay@cs.wisc.edu
9277839Snilay@cs.wisc.eduvoid
9287839Snilay@cs.wisc.eduNSGigE::devIntrChangeMask()
9297839Snilay@cs.wisc.edu{
9307839Snilay@cs.wisc.edu    DPRINTF(EthernetIntr, "interrupt mask changed: isr=%x imr=%x masked=%x\n",
9318055Sksewell@umich.edu            regs.isr, regs.imr, regs.isr & regs.imr);
9327839Snilay@cs.wisc.edu
9337839Snilay@cs.wisc.edu    if (regs.isr & regs.imr)
9347839Snilay@cs.wisc.edu        cpuIntrPost(curTick());
9357839Snilay@cs.wisc.edu    else
9367839Snilay@cs.wisc.edu        cpuIntrClear();
9377839Snilay@cs.wisc.edu}
9387839Snilay@cs.wisc.edu
9397839Snilay@cs.wisc.eduvoid
9407839Snilay@cs.wisc.eduNSGigE::cpuIntrPost(Tick when)
9417839Snilay@cs.wisc.edu{
9426657Snate@binkert.org    // If the interrupt you want to post is later than an interrupt
9437007Snate@binkert.org    // already scheduled, just let it post in the coming one and don't
9447007Snate@binkert.org    // schedule another.
9456657Snate@binkert.org    // HOWEVER, must be sure that the scheduled intrTick is in the
9468055Sksewell@umich.edu    // future (this was formerly the source of a bug)
9476657Snate@binkert.org    /**
9486657Snate@binkert.org     * @todo this warning should be removed and the intrTick code should
9496657Snate@binkert.org     * be fixed.
9506657Snate@binkert.org     */
9516657Snate@binkert.org    assert(when >= curTick());
9526657Snate@binkert.org    assert(intrTick >= curTick() || intrTick == 0);
9536657Snate@binkert.org    if (when > intrTick && intrTick != 0) {
9546657Snate@binkert.org        DPRINTF(EthernetIntr, "don't need to schedule event...intrTick=%d\n",
9556657Snate@binkert.org                intrTick);
9566999Snate@binkert.org        return;
9576657Snate@binkert.org    }
9586657Snate@binkert.org
9596657Snate@binkert.org    intrTick = when;
9606657Snate@binkert.org    if (intrTick < curTick()) {
9616657Snate@binkert.org        intrTick = curTick();
9626657Snate@binkert.org    }
9637832Snate@binkert.org
9647832Snate@binkert.org    DPRINTF(EthernetIntr, "going to schedule an interrupt for intrTick=%d\n",
9657007Snate@binkert.org            intrTick);
9666657Snate@binkert.org
9676657Snate@binkert.org    if (intrEvent)
9686657Snate@binkert.org        intrEvent->squash();
9696657Snate@binkert.org
9706657Snate@binkert.org    intrEvent = new EventFunctionWrapper([this]{ cpuInterrupt(); },
9716657Snate@binkert.org                                         name(), true);
9726657Snate@binkert.org    schedule(intrEvent, intrTick);
9736657Snate@binkert.org}
9747055Snate@binkert.org
9757055Snate@binkert.orgvoid
9767007Snate@binkert.orgNSGigE::cpuInterrupt()
9777007Snate@binkert.org{
9786657Snate@binkert.org    assert(intrTick == curTick());
9796657Snate@binkert.org
9806657Snate@binkert.org    // Whether or not there's a pending interrupt, we don't care about
9816657Snate@binkert.org    // it anymore
9826657Snate@binkert.org    intrEvent = 0;
9836657Snate@binkert.org    intrTick = 0;
9847007Snate@binkert.org
9857007Snate@binkert.org    // Don't send an interrupt if there's already one
9867007Snate@binkert.org    if (cpuPendingIntr) {
9877007Snate@binkert.org        DPRINTF(EthernetIntr,
9887007Snate@binkert.org                "would send an interrupt now, but there's already pending\n");
9896657Snate@binkert.org    } else {
9906657Snate@binkert.org        // Send interrupt
9916657Snate@binkert.org        cpuPendingIntr = true;
9926657Snate@binkert.org
9936657Snate@binkert.org        DPRINTF(EthernetIntr, "posting interrupt\n");
9946657Snate@binkert.org        intrPost();
9956657Snate@binkert.org    }
9966657Snate@binkert.org}
9976657Snate@binkert.org
9986657Snate@binkert.orgvoid
9996657Snate@binkert.orgNSGigE::cpuIntrClear()
10006657Snate@binkert.org{
10017567SBrad.Beckmann@amd.com    if (!cpuPendingIntr)
10027567SBrad.Beckmann@amd.com        return;
10037567SBrad.Beckmann@amd.com
10047567SBrad.Beckmann@amd.com    if (intrEvent) {
10056657Snate@binkert.org        intrEvent->squash();
10066657Snate@binkert.org        intrEvent = 0;
10076657Snate@binkert.org    }
10086657Snate@binkert.org
10096657Snate@binkert.org    intrTick = 0;
10106657Snate@binkert.org
10116657Snate@binkert.org    cpuPendingIntr = false;
10126657Snate@binkert.org
10136657Snate@binkert.org    DPRINTF(EthernetIntr, "clearing interrupt\n");
10146657Snate@binkert.org    intrClear();
10157007Snate@binkert.org}
10166657Snate@binkert.org
10176657Snate@binkert.orgbool
10186657Snate@binkert.orgNSGigE::cpuIntrPending() const
10196657Snate@binkert.org{ return cpuPendingIntr; }
10206657Snate@binkert.org
10216657Snate@binkert.orgvoid
10226657Snate@binkert.orgNSGigE::txReset()
10236657Snate@binkert.org{
10246999Snate@binkert.org
10256657Snate@binkert.org    DPRINTF(Ethernet, "transmit reset\n");
10266657Snate@binkert.org
10276657Snate@binkert.org    CTDD = false;
10286657Snate@binkert.org    txEnable = false;;
10296657Snate@binkert.org    txFragPtr = 0;
10306657Snate@binkert.org    assert(txDescCnt == 0);
10317832Snate@binkert.org    txFifo.clear();
10327832Snate@binkert.org    txState = txIdle;
10337805Snilay@cs.wisc.edu    assert(txDmaState == dmaIdle);
10347832Snate@binkert.org}
10356657Snate@binkert.org
10366657Snate@binkert.orgvoid
10376657Snate@binkert.orgNSGigE::rxReset()
10386657Snate@binkert.org{
10396657Snate@binkert.org    DPRINTF(Ethernet, "receive reset\n");
10406657Snate@binkert.org
10416657Snate@binkert.org    CRDD = false;
10426657Snate@binkert.org    assert(rxPktBytes == 0);
10436657Snate@binkert.org    rxEnable = false;
10446657Snate@binkert.org    rxFragPtr = 0;
10456657Snate@binkert.org    assert(rxDescCnt == 0);
10466657Snate@binkert.org    assert(rxDmaState == dmaIdle);
10477007Snate@binkert.org    rxFifo.clear();
10487007Snate@binkert.org    rxState = rxIdle;
10497839Snilay@cs.wisc.edu}
10507839Snilay@cs.wisc.edu
10517839Snilay@cs.wisc.eduvoid
10527839Snilay@cs.wisc.eduNSGigE::regsReset()
10537839Snilay@cs.wisc.edu{
10547839Snilay@cs.wisc.edu    memset(&regs, 0, sizeof(regs));
10557839Snilay@cs.wisc.edu    regs.config = (CFGR_LNKSTS | CFGR_TBI_EN | CFGR_MODE_1000);
10567839Snilay@cs.wisc.edu    regs.mear = 0x12;
10577839Snilay@cs.wisc.edu    regs.txcfg = 0x120; // set drain threshold to 1024 bytes and
10587839Snilay@cs.wisc.edu                        // fill threshold to 32 bytes
10597007Snate@binkert.org    regs.rxcfg = 0x4;   // set drain threshold to 16 bytes
10606657Snate@binkert.org    regs.srr = 0x0103;  // set the silicon revision to rev B or 0x103
10617839Snilay@cs.wisc.edu    regs.mibc = MIBC_FRZ;
10627839Snilay@cs.wisc.edu    regs.vdr = 0x81;    // set the vlan tag type to 802.1q
10637839Snilay@cs.wisc.edu    regs.tesr = 0xc000; // TBI capable of both full and half duplex
10647839Snilay@cs.wisc.edu    regs.brar = 0xffffffff;
10657839Snilay@cs.wisc.edu
10667839Snilay@cs.wisc.edu    extstsEnable = false;
10677839Snilay@cs.wisc.edu    acceptBroadcast = false;
10687839Snilay@cs.wisc.edu    acceptMulticast = false;
10697839Snilay@cs.wisc.edu    acceptUnicast = false;
10707839Snilay@cs.wisc.edu    acceptPerfect = false;
10717839Snilay@cs.wisc.edu    acceptArp = false;
10726657Snate@binkert.org}
10736657Snate@binkert.org
10747780Snilay@cs.wisc.edubool
10757780Snilay@cs.wisc.eduNSGigE::doRxDmaRead()
10767780Snilay@cs.wisc.edu{
10777780Snilay@cs.wisc.edu    assert(rxDmaState == dmaIdle || rxDmaState == dmaReadWaiting);
10787780Snilay@cs.wisc.edu    rxDmaState = dmaReading;
10797780Snilay@cs.wisc.edu
10806657Snate@binkert.org    if (dmaPending() || drainState() != DrainState::Running)
10817007Snate@binkert.org        rxDmaState = dmaReadWaiting;
10827839Snilay@cs.wisc.edu    else
10837839Snilay@cs.wisc.edu        dmaRead(rxDmaAddr, rxDmaLen, &rxDmaReadEvent, (uint8_t*)rxDmaData);
10847839Snilay@cs.wisc.edu
10857839Snilay@cs.wisc.edu    return true;
10867839Snilay@cs.wisc.edu}
10877839Snilay@cs.wisc.edu
10887839Snilay@cs.wisc.eduvoid
10897839Snilay@cs.wisc.eduNSGigE::rxDmaReadDone()
10907839Snilay@cs.wisc.edu{
10916657Snate@binkert.org    assert(rxDmaState == dmaReading);
10927839Snilay@cs.wisc.edu    rxDmaState = dmaIdle;
10936657Snate@binkert.org
10947780Snilay@cs.wisc.edu    DPRINTF(EthernetDMA, "rx dma read  paddr=%#x len=%d\n",
10957780Snilay@cs.wisc.edu            rxDmaAddr, rxDmaLen);
10967542SBrad.Beckmann@amd.com    DDUMP(EthernetDMA, rxDmaData, rxDmaLen);
10977832Snate@binkert.org
10987832Snate@binkert.org    // If the transmit state machine has a pending DMA, let it go first
10997832Snate@binkert.org    if (txDmaState == dmaReadWaiting || txDmaState == dmaWriteWaiting)
11007832Snate@binkert.org        txKick();
11017832Snate@binkert.org
11027832Snate@binkert.org    rxKick();
11036657Snate@binkert.org}
11047832Snate@binkert.org
11057839Snilay@cs.wisc.edubool
11067839Snilay@cs.wisc.eduNSGigE::doRxDmaWrite()
11077839Snilay@cs.wisc.edu{
11088086SBrad.Beckmann@amd.com    assert(rxDmaState == dmaIdle || rxDmaState == dmaWriteWaiting);
11097839Snilay@cs.wisc.edu    rxDmaState = dmaWriting;
11107839Snilay@cs.wisc.edu
11117839Snilay@cs.wisc.edu    if (dmaPending() || drainState() != DrainState::Running)
11127839Snilay@cs.wisc.edu        rxDmaState = dmaWriteWaiting;
11138086SBrad.Beckmann@amd.com    else
11147839Snilay@cs.wisc.edu        dmaWrite(rxDmaAddr, rxDmaLen, &rxDmaWriteEvent, (uint8_t*)rxDmaData);
11157839Snilay@cs.wisc.edu    return true;
11167839Snilay@cs.wisc.edu}
11177839Snilay@cs.wisc.edu
11186657Snate@binkert.orgvoid
11197832Snate@binkert.orgNSGigE::rxDmaWriteDone()
11207832Snate@binkert.org{
11217832Snate@binkert.org    assert(rxDmaState == dmaWriting);
11227832Snate@binkert.org    rxDmaState = dmaIdle;
11237832Snate@binkert.org
11247832Snate@binkert.org    DPRINTF(EthernetDMA, "rx dma write paddr=%#x len=%d\n",
11256657Snate@binkert.org            rxDmaAddr, rxDmaLen);
11267780Snilay@cs.wisc.edu    DDUMP(EthernetDMA, rxDmaData, rxDmaLen);
11277832Snate@binkert.org
11287832Snate@binkert.org    // If the transmit state machine has a pending DMA, let it go first
11297832Snate@binkert.org    if (txDmaState == dmaReadWaiting || txDmaState == dmaWriteWaiting)
11307832Snate@binkert.org        txKick();
11317832Snate@binkert.org
11327832Snate@binkert.org    rxKick();
11336657Snate@binkert.org}
11346657Snate@binkert.org
11356657Snate@binkert.orgvoid
11366657Snate@binkert.orgNSGigE::rxKick()
11376657Snate@binkert.org{
11387007Snate@binkert.org    bool is64bit = (bool)(regs.config & CFGR_M64ADDR);
11397007Snate@binkert.org
11407007Snate@binkert.org    DPRINTF(EthernetSM,
11417007Snate@binkert.org            "receive kick rxState=%s (rxBuf.size=%d) %d-bit\n",
11427839Snilay@cs.wisc.edu            NsRxStateStrings[rxState], rxFifo.size(), is64bit ? 64 : 32);
11437839Snilay@cs.wisc.edu
11447839Snilay@cs.wisc.edu    Addr link, bufptr;
11457839Snilay@cs.wisc.edu    uint32_t &cmdsts = is64bit ? rxDesc64.cmdsts : rxDesc32.cmdsts;
11467839Snilay@cs.wisc.edu    uint32_t &extsts = is64bit ? rxDesc64.extsts : rxDesc32.extsts;
11477839Snilay@cs.wisc.edu
11487839Snilay@cs.wisc.edu  next:
11497839Snilay@cs.wisc.edu    if (rxKickTick > curTick()) {
11507839Snilay@cs.wisc.edu        DPRINTF(EthernetSM, "receive kick exiting, can't run till %d\n",
11517839Snilay@cs.wisc.edu                rxKickTick);
11527839Snilay@cs.wisc.edu
11537007Snate@binkert.org        goto exit;
11546657Snate@binkert.org    }
11556657Snate@binkert.org
11566657Snate@binkert.org    // Go to the next state machine clock tick.
11576657Snate@binkert.org    rxKickTick = clockEdge(Cycles(1));
11586657Snate@binkert.org
11596657Snate@binkert.org    switch(rxDmaState) {
11606657Snate@binkert.org      case dmaReadWaiting:
11616657Snate@binkert.org        if (doRxDmaRead())
11626657Snate@binkert.org            goto exit;
11636657Snate@binkert.org        break;
11646657Snate@binkert.org      case dmaWriteWaiting:
11656999Snate@binkert.org        if (doRxDmaWrite())
11666657Snate@binkert.org            goto exit;
11676657Snate@binkert.org        break;
11686657Snate@binkert.org      default:
11696657Snate@binkert.org        break;
11706657Snate@binkert.org    }
11716657Snate@binkert.org
11726657Snate@binkert.org    link = is64bit ? (Addr)rxDesc64.link : (Addr)rxDesc32.link;
11736657Snate@binkert.org    bufptr = is64bit ? (Addr)rxDesc64.bufptr : (Addr)rxDesc32.bufptr;
11746657Snate@binkert.org
11756657Snate@binkert.org    // see state machine from spec for details
11766657Snate@binkert.org    // the way this works is, if you finish work on one state and can
11776657Snate@binkert.org    // go directly to another, you do that through jumping to the
11786657Snate@binkert.org    // label "next".  however, if you have intermediate work, like DMA
11797007Snate@binkert.org    // so that you can't go to the next state yet, you go to exit and
11806657Snate@binkert.org    // exit the loop.  however, when the DMA is done it will trigger
11816657Snate@binkert.org    // an event and come back to this loop.
11826657Snate@binkert.org    switch (rxState) {
11836657Snate@binkert.org      case rxIdle:
11846657Snate@binkert.org        if (!rxEnable) {
11856657Snate@binkert.org            DPRINTF(EthernetSM, "Receive Disabled! Nothing to do.\n");
11866657Snate@binkert.org            goto exit;
11876657Snate@binkert.org        }
11886657Snate@binkert.org
11896657Snate@binkert.org        if (CRDD) {
11906657Snate@binkert.org            rxState = rxDescRefr;
11916657Snate@binkert.org
11926657Snate@binkert.org            rxDmaAddr = regs.rxdp & 0x3fffffff;
11936657Snate@binkert.org            rxDmaData =
11946657Snate@binkert.org                is64bit ? (void *)&rxDesc64.link : (void *)&rxDesc32.link;
11956657Snate@binkert.org            rxDmaLen = is64bit ? sizeof(rxDesc64.link) : sizeof(rxDesc32.link);
11966657Snate@binkert.org            rxDmaFree = dmaDescFree;
11976657Snate@binkert.org
11986657Snate@binkert.org            descDmaReads++;
11996657Snate@binkert.org            descDmaRdBytes += rxDmaLen;
12006657Snate@binkert.org
12017839Snilay@cs.wisc.edu            if (doRxDmaRead())
12027839Snilay@cs.wisc.edu                goto exit;
12037839Snilay@cs.wisc.edu        } else {
12047839Snilay@cs.wisc.edu            rxState = rxDescRead;
12057839Snilay@cs.wisc.edu
12067839Snilay@cs.wisc.edu            rxDmaAddr = regs.rxdp & 0x3fffffff;
12077839Snilay@cs.wisc.edu            rxDmaData = is64bit ? (void *)&rxDesc64 : (void *)&rxDesc32;
12087839Snilay@cs.wisc.edu            rxDmaLen = is64bit ? sizeof(rxDesc64) : sizeof(rxDesc32);
12097839Snilay@cs.wisc.edu            rxDmaFree = dmaDescFree;
12107839Snilay@cs.wisc.edu
12117839Snilay@cs.wisc.edu            descDmaReads++;
12127839Snilay@cs.wisc.edu            descDmaRdBytes += rxDmaLen;
12136657Snate@binkert.org
12146657Snate@binkert.org            if (doRxDmaRead())
12156657Snate@binkert.org                goto exit;
12166657Snate@binkert.org        }
12176657Snate@binkert.org        break;
12186657Snate@binkert.org
12196657Snate@binkert.org      case rxDescRefr:
12206657Snate@binkert.org        if (rxDmaState != dmaIdle)
12216657Snate@binkert.org            goto exit;
12226657Snate@binkert.org
12236657Snate@binkert.org        rxState = rxAdvance;
12246657Snate@binkert.org        break;
12256657Snate@binkert.org
12266657Snate@binkert.org     case rxDescRead:
12276657Snate@binkert.org        if (rxDmaState != dmaIdle)
12286657Snate@binkert.org            goto exit;
12296657Snate@binkert.org
12306657Snate@binkert.org        DPRINTF(EthernetDesc, "rxDesc: addr=%08x read descriptor\n",
12316657Snate@binkert.org                regs.rxdp & 0x3fffffff);
12326657Snate@binkert.org        DPRINTF(EthernetDesc,
12336657Snate@binkert.org                "rxDesc: link=%#x bufptr=%#x cmdsts=%08x extsts=%08x\n",
12347805Snilay@cs.wisc.edu                link, bufptr, cmdsts, extsts);
12358159SBrad.Beckmann@amd.com
12368159SBrad.Beckmann@amd.com        if (cmdsts & CMDSTS_OWN) {
12376657Snate@binkert.org            devIntrPost(ISR_RXIDLE);
12386657Snate@binkert.org            rxState = rxIdle;
12396657Snate@binkert.org            goto exit;
12406657Snate@binkert.org        } else {
12416657Snate@binkert.org            rxState = rxFifoBlock;
12426657Snate@binkert.org            rxFragPtr = bufptr;
12437542SBrad.Beckmann@amd.com            rxDescCnt = cmdsts & CMDSTS_LEN_MASK;
12447542SBrad.Beckmann@amd.com        }
12457542SBrad.Beckmann@amd.com        break;
12467542SBrad.Beckmann@amd.com
12477542SBrad.Beckmann@amd.com      case rxFifoBlock:
12487542SBrad.Beckmann@amd.com        if (!rxPacket) {
12497542SBrad.Beckmann@amd.com            /**
12507542SBrad.Beckmann@amd.com             * @todo in reality, we should be able to start processing
12517542SBrad.Beckmann@amd.com             * the packet as it arrives, and not have to wait for the
12527542SBrad.Beckmann@amd.com             * full packet ot be in the receive fifo.
12537542SBrad.Beckmann@amd.com             */
12547832Snate@binkert.org            if (rxFifo.empty())
12557542SBrad.Beckmann@amd.com                goto exit;
12567542SBrad.Beckmann@amd.com
12577542SBrad.Beckmann@amd.com            DPRINTF(EthernetSM, "****processing receive of new packet****\n");
12587542SBrad.Beckmann@amd.com
12597542SBrad.Beckmann@amd.com            // If we don't have a packet, grab a new one from the fifo.
12607542SBrad.Beckmann@amd.com            rxPacket = rxFifo.front();
12617542SBrad.Beckmann@amd.com            rxPktBytes = rxPacket->length;
12627542SBrad.Beckmann@amd.com            rxPacketBufPtr = rxPacket->data;
12637542SBrad.Beckmann@amd.com
12647542SBrad.Beckmann@amd.com#if TRACING_ON
12657542SBrad.Beckmann@amd.com            if (DTRACE(Ethernet)) {
12667542SBrad.Beckmann@amd.com                IpPtr ip(rxPacket);
12677542SBrad.Beckmann@amd.com                if (ip) {
12687542SBrad.Beckmann@amd.com                    DPRINTF(Ethernet, "ID is %d\n", ip->id());
12697542SBrad.Beckmann@amd.com                    TcpPtr tcp(ip);
12707542SBrad.Beckmann@amd.com                    if (tcp) {
12717542SBrad.Beckmann@amd.com                        DPRINTF(Ethernet,
12727542SBrad.Beckmann@amd.com                                "Src Port=%d, Dest Port=%d, Seq=%d, Ack=%d\n",
12737542SBrad.Beckmann@amd.com                                tcp->sport(), tcp->dport(), tcp->seq(),
12747542SBrad.Beckmann@amd.com                                tcp->ack());
12757542SBrad.Beckmann@amd.com                    }
12767542SBrad.Beckmann@amd.com                }
12777542SBrad.Beckmann@amd.com            }
12787542SBrad.Beckmann@amd.com#endif
12797542SBrad.Beckmann@amd.com
12807542SBrad.Beckmann@amd.com            // sanity check - i think the driver behaves like this
12817542SBrad.Beckmann@amd.com            assert(rxDescCnt >= rxPktBytes);
12827542SBrad.Beckmann@amd.com            rxFifo.pop();
12837542SBrad.Beckmann@amd.com        }
12847542SBrad.Beckmann@amd.com
12857542SBrad.Beckmann@amd.com
12867542SBrad.Beckmann@amd.com        // dont' need the && rxDescCnt > 0 if driver sanity check
12877542SBrad.Beckmann@amd.com        // above holds
12887542SBrad.Beckmann@amd.com        if (rxPktBytes > 0) {
12897542SBrad.Beckmann@amd.com            rxState = rxFragWrite;
12907542SBrad.Beckmann@amd.com            // don't need min<>(rxPktBytes,rxDescCnt) if above sanity
12917542SBrad.Beckmann@amd.com            // check holds
12927542SBrad.Beckmann@amd.com            rxXferLen = rxPktBytes;
12937542SBrad.Beckmann@amd.com
12947542SBrad.Beckmann@amd.com            rxDmaAddr = rxFragPtr & 0x3fffffff;
12957542SBrad.Beckmann@amd.com            rxDmaData = rxPacketBufPtr;
12967542SBrad.Beckmann@amd.com            rxDmaLen = rxXferLen;
12977542SBrad.Beckmann@amd.com            rxDmaFree = dmaDataFree;
12987542SBrad.Beckmann@amd.com
12997542SBrad.Beckmann@amd.com            if (doRxDmaWrite())
13007542SBrad.Beckmann@amd.com                goto exit;
13017542SBrad.Beckmann@amd.com
13027542SBrad.Beckmann@amd.com        } else {
13037542SBrad.Beckmann@amd.com            rxState = rxDescWrite;
13047542SBrad.Beckmann@amd.com
13057542SBrad.Beckmann@amd.com            //if (rxPktBytes == 0) {  /* packet is done */
13067542SBrad.Beckmann@amd.com            assert(rxPktBytes == 0);
13077542SBrad.Beckmann@amd.com            DPRINTF(EthernetSM, "done with receiving packet\n");
13087542SBrad.Beckmann@amd.com
13097542SBrad.Beckmann@amd.com            cmdsts |= CMDSTS_OWN;
13107542SBrad.Beckmann@amd.com            cmdsts &= ~CMDSTS_MORE;
13117542SBrad.Beckmann@amd.com            cmdsts |= CMDSTS_OK;
13127542SBrad.Beckmann@amd.com            cmdsts &= 0xffff0000;
13137542SBrad.Beckmann@amd.com            cmdsts += rxPacket->length;   //i.e. set CMDSTS_SIZE
13147542SBrad.Beckmann@amd.com
13157542SBrad.Beckmann@amd.com#if 0
13167542SBrad.Beckmann@amd.com            /*
13177542SBrad.Beckmann@amd.com             * all the driver uses these are for its own stats keeping
13187542SBrad.Beckmann@amd.com             * which we don't care about, aren't necessary for
13197542SBrad.Beckmann@amd.com             * functionality and doing this would just slow us down.
13207542SBrad.Beckmann@amd.com             * if they end up using this in a later version for
13217542SBrad.Beckmann@amd.com             * functional purposes, just undef
13227542SBrad.Beckmann@amd.com             */
13237542SBrad.Beckmann@amd.com            if (rxFilterEnable) {
13247542SBrad.Beckmann@amd.com                cmdsts &= ~CMDSTS_DEST_MASK;
13257542SBrad.Beckmann@amd.com                const EthAddr &dst = rxFifoFront()->dst();
13267542SBrad.Beckmann@amd.com                if (dst->unicast())
13277542SBrad.Beckmann@amd.com                    cmdsts |= CMDSTS_DEST_SELF;
13287542SBrad.Beckmann@amd.com                if (dst->multicast())
13297542SBrad.Beckmann@amd.com                    cmdsts |= CMDSTS_DEST_MULTI;
13307542SBrad.Beckmann@amd.com                if (dst->broadcast())
13317542SBrad.Beckmann@amd.com                    cmdsts |= CMDSTS_DEST_MASK;
13327542SBrad.Beckmann@amd.com            }
13337542SBrad.Beckmann@amd.com#endif
13347542SBrad.Beckmann@amd.com
13357542SBrad.Beckmann@amd.com            IpPtr ip(rxPacket);
13367542SBrad.Beckmann@amd.com            if (extstsEnable && ip) {
13377542SBrad.Beckmann@amd.com                extsts |= EXTSTS_IPPKT;
13387542SBrad.Beckmann@amd.com                rxIpChecksums++;
13396657Snate@binkert.org                if (cksum(ip) != 0) {
13406999Snate@binkert.org                    DPRINTF(EthernetCksum, "Rx IP Checksum Error\n");
13416657Snate@binkert.org                    extsts |= EXTSTS_IPERR;
13426657Snate@binkert.org                }
13436657Snate@binkert.org                TcpPtr tcp(ip);
13446657Snate@binkert.org                UdpPtr udp(ip);
13456657Snate@binkert.org                if (tcp) {
13466657Snate@binkert.org                    extsts |= EXTSTS_TCPPKT;
13477542SBrad.Beckmann@amd.com                    rxTcpChecksums++;
13487542SBrad.Beckmann@amd.com                    if (cksum(tcp) != 0) {
13496657Snate@binkert.org                        DPRINTF(EthernetCksum, "Rx TCP Checksum Error\n");
13507832Snate@binkert.org                        extsts |= EXTSTS_TCPERR;
13517002Snate@binkert.org
13527002Snate@binkert.org                    }
13536657Snate@binkert.org                } else if (udp) {
13546657Snate@binkert.org                    extsts |= EXTSTS_UDPPKT;
13556657Snate@binkert.org                    rxUdpChecksums++;
13566657Snate@binkert.org                    if (cksum(udp) != 0) {
13577007Snate@binkert.org                        DPRINTF(EthernetCksum, "Rx UDP Checksum Error\n");
13587007Snate@binkert.org                        extsts |= EXTSTS_UDPERR;
13596657Snate@binkert.org                    }
13606657Snate@binkert.org                }
13616657Snate@binkert.org            }
13626657Snate@binkert.org            rxPacket = 0;
13636657Snate@binkert.org
13647542SBrad.Beckmann@amd.com            /*
13657542SBrad.Beckmann@amd.com             * the driver seems to always receive into desc buffers
13667542SBrad.Beckmann@amd.com             * of size 1514, so you never have a pkt that is split
13676657Snate@binkert.org             * into multiple descriptors on the receive side, so
13686657Snate@binkert.org             * i don't implement that case, hence the assert above.
13696657Snate@binkert.org             */
13706657Snate@binkert.org
13716657Snate@binkert.org            DPRINTF(EthernetDesc,
13726657Snate@binkert.org                    "rxDesc: addr=%08x writeback cmdsts extsts\n",
13736657Snate@binkert.org                    regs.rxdp & 0x3fffffff);
13746657Snate@binkert.org            DPRINTF(EthernetDesc,
13756657Snate@binkert.org                    "rxDesc: link=%#x bufptr=%#x cmdsts=%08x extsts=%08x\n",
13767007Snate@binkert.org                    link, bufptr, cmdsts, extsts);
13776657Snate@binkert.org
13786657Snate@binkert.org            rxDmaAddr = regs.rxdp & 0x3fffffff;
13796657Snate@binkert.org            rxDmaData = &cmdsts;
13806657Snate@binkert.org            if (is64bit) {
13816999Snate@binkert.org                rxDmaAddr += offsetof(ns_desc64, cmdsts);
13826657Snate@binkert.org                rxDmaLen = sizeof(rxDesc64.cmdsts) + sizeof(rxDesc64.extsts);
13836657Snate@binkert.org            } else {
13846657Snate@binkert.org                rxDmaAddr += offsetof(ns_desc32, cmdsts);
13856657Snate@binkert.org                rxDmaLen = sizeof(rxDesc32.cmdsts) + sizeof(rxDesc32.extsts);
13866657Snate@binkert.org            }
13876657Snate@binkert.org            rxDmaFree = dmaDescFree;
13887832Snate@binkert.org
13897832Snate@binkert.org            descDmaWrites++;
13906657Snate@binkert.org            descDmaWrBytes += rxDmaLen;
13916657Snate@binkert.org
13926657Snate@binkert.org            if (doRxDmaWrite())
13936657Snate@binkert.org                goto exit;
13946657Snate@binkert.org        }
13956657Snate@binkert.org        break;
13966657Snate@binkert.org
13976657Snate@binkert.org      case rxFragWrite:
13986657Snate@binkert.org        if (rxDmaState != dmaIdle)
13996657Snate@binkert.org            goto exit;
14006657Snate@binkert.org
14016657Snate@binkert.org        rxPacketBufPtr += rxXferLen;
14026657Snate@binkert.org        rxFragPtr += rxXferLen;
14036657Snate@binkert.org        rxPktBytes -= rxXferLen;
14047007Snate@binkert.org
14057007Snate@binkert.org        rxState = rxFifoBlock;
14067007Snate@binkert.org        break;
14076657Snate@binkert.org
14086657Snate@binkert.org      case rxDescWrite:
14096657Snate@binkert.org        if (rxDmaState != dmaIdle)
14107007Snate@binkert.org            goto exit;
14117007Snate@binkert.org
14127007Snate@binkert.org        assert(cmdsts & CMDSTS_OWN);
14136657Snate@binkert.org
14146657Snate@binkert.org        assert(rxPacket == 0);
14156657Snate@binkert.org        devIntrPost(ISR_RXOK);
14166657Snate@binkert.org
14176657Snate@binkert.org        if (cmdsts & CMDSTS_INTR)
14186657Snate@binkert.org            devIntrPost(ISR_RXDESC);
14196657Snate@binkert.org
14206657Snate@binkert.org        if (!rxEnable) {
14216657Snate@binkert.org            DPRINTF(EthernetSM, "Halting the RX state machine\n");
14226657Snate@binkert.org            rxState = rxIdle;
14236657Snate@binkert.org            goto exit;
14247007Snate@binkert.org        } else
14257007Snate@binkert.org            rxState = rxAdvance;
14266657Snate@binkert.org        break;
14276657Snate@binkert.org
14286657Snate@binkert.org      case rxAdvance:
14296657Snate@binkert.org        if (link == 0) {
14306657Snate@binkert.org            devIntrPost(ISR_RXIDLE);
14317007Snate@binkert.org            rxState = rxIdle;
14327007Snate@binkert.org            CRDD = true;
14337007Snate@binkert.org            goto exit;
14346657Snate@binkert.org        } else {
14356657Snate@binkert.org            if (rxDmaState != dmaIdle)
14366657Snate@binkert.org                goto exit;
14377007Snate@binkert.org            rxState = rxDescRead;
14387542SBrad.Beckmann@amd.com            regs.rxdp = link;
14397542SBrad.Beckmann@amd.com            CRDD = false;
14406657Snate@binkert.org
14417542SBrad.Beckmann@amd.com            rxDmaAddr = regs.rxdp & 0x3fffffff;
14427542SBrad.Beckmann@amd.com            rxDmaData = is64bit ? (void *)&rxDesc64 : (void *)&rxDesc32;
14437002Snate@binkert.org            rxDmaLen = is64bit ? sizeof(rxDesc64) : sizeof(rxDesc32);
14447542SBrad.Beckmann@amd.com            rxDmaFree = dmaDescFree;
14457542SBrad.Beckmann@amd.com
14467542SBrad.Beckmann@amd.com            if (doRxDmaRead())
14477542SBrad.Beckmann@amd.com                goto exit;
14486657Snate@binkert.org        }
14497542SBrad.Beckmann@amd.com        break;
14507542SBrad.Beckmann@amd.com
14517542SBrad.Beckmann@amd.com      default:
14527542SBrad.Beckmann@amd.com        panic("Invalid rxState!");
14537542SBrad.Beckmann@amd.com    }
14547542SBrad.Beckmann@amd.com
14557542SBrad.Beckmann@amd.com    DPRINTF(EthernetSM, "entering next rxState=%s\n",
14567542SBrad.Beckmann@amd.com            NsRxStateStrings[rxState]);
14576657Snate@binkert.org    goto next;
14586657Snate@binkert.org
14596657Snate@binkert.org  exit:
14606657Snate@binkert.org    /**
14616657Snate@binkert.org     * @todo do we want to schedule a future kick?
14626657Snate@binkert.org     */
14637007Snate@binkert.org    DPRINTF(EthernetSM, "rx state machine exited rxState=%s\n",
14646999Snate@binkert.org            NsRxStateStrings[rxState]);
14657007Snate@binkert.org
14667007Snate@binkert.org    if (!rxKickEvent.scheduled())
14677007Snate@binkert.org        schedule(rxKickEvent, rxKickTick);
14687007Snate@binkert.org}
14697007Snate@binkert.org
14707007Snate@binkert.orgvoid
14716657Snate@binkert.orgNSGigE::transmit()
14726657Snate@binkert.org{
14736657Snate@binkert.org    if (txFifo.empty()) {
14746657Snate@binkert.org        DPRINTF(Ethernet, "nothing to transmit\n");
14756657Snate@binkert.org        return;
14766657Snate@binkert.org    }
14776657Snate@binkert.org
14786657Snate@binkert.org    DPRINTF(Ethernet, "Attempt Pkt Transmit: txFifo length=%d\n",
14796657Snate@binkert.org            txFifo.size());
14806657Snate@binkert.org    if (interface->sendPacket(txFifo.front())) {
14816657Snate@binkert.org#if TRACING_ON
14826657Snate@binkert.org        if (DTRACE(Ethernet)) {
14836657Snate@binkert.org            IpPtr ip(txFifo.front());
14846657Snate@binkert.org            if (ip) {
14856657Snate@binkert.org                DPRINTF(Ethernet, "ID is %d\n", ip->id());
14866657Snate@binkert.org                TcpPtr tcp(ip);
14876657Snate@binkert.org                if (tcp) {
14886657Snate@binkert.org                    DPRINTF(Ethernet,
14896657Snate@binkert.org                            "Src Port=%d, Dest Port=%d, Seq=%d, Ack=%d\n",
14906657Snate@binkert.org                            tcp->sport(), tcp->dport(), tcp->seq(),
14916657Snate@binkert.org                            tcp->ack());
14926657Snate@binkert.org                }
14936657Snate@binkert.org            }
14946657Snate@binkert.org        }
14956657Snate@binkert.org#endif
14966657Snate@binkert.org
14976657Snate@binkert.org        DDUMP(EthernetData, txFifo.front()->data, txFifo.front()->length);
14986657Snate@binkert.org        txBytes += txFifo.front()->length;
14996657Snate@binkert.org        txPackets++;
15006999Snate@binkert.org
15016657Snate@binkert.org        DPRINTF(Ethernet, "Successful Xmit! now txFifoAvail is %d\n",
15026657Snate@binkert.org                txFifo.avail());
15037007Snate@binkert.org        txFifo.pop();
15047007Snate@binkert.org
15056657Snate@binkert.org        /*
15066657Snate@binkert.org         * normally do a writeback of the descriptor here, and ONLY
15076657Snate@binkert.org         * after that is done, send this interrupt.  but since our
15086657Snate@binkert.org         * stuff never actually fails, just do this interrupt here,
15096657Snate@binkert.org         * otherwise the code has to stray from this nice format.
15106657Snate@binkert.org         * besides, it's functionally the same.
15116657Snate@binkert.org         */
15126657Snate@binkert.org        devIntrPost(ISR_TXOK);
15136657Snate@binkert.org    }
15146657Snate@binkert.org
15156657Snate@binkert.org   if (!txFifo.empty() && !txEvent.scheduled()) {
15166657Snate@binkert.org       DPRINTF(Ethernet, "reschedule transmit\n");
15176657Snate@binkert.org       schedule(txEvent, curTick() + retryTime);
15186657Snate@binkert.org   }
15196657Snate@binkert.org}
15206657Snate@binkert.org
15216657Snate@binkert.orgbool
15226657Snate@binkert.orgNSGigE::doTxDmaRead()
15236657Snate@binkert.org{
15246657Snate@binkert.org    assert(txDmaState == dmaIdle || txDmaState == dmaReadWaiting);
15256657Snate@binkert.org    txDmaState = dmaReading;
15266657Snate@binkert.org
15276657Snate@binkert.org    if (dmaPending() || drainState() != DrainState::Running)
15286657Snate@binkert.org        txDmaState = dmaReadWaiting;
15296657Snate@binkert.org    else
15306657Snate@binkert.org        dmaRead(txDmaAddr, txDmaLen, &txDmaReadEvent, (uint8_t*)txDmaData);
15316657Snate@binkert.org
15326657Snate@binkert.org    return true;
15336657Snate@binkert.org}
15346657Snate@binkert.org
15356657Snate@binkert.orgvoid
15366657Snate@binkert.orgNSGigE::txDmaReadDone()
15376657Snate@binkert.org{
15386657Snate@binkert.org    assert(txDmaState == dmaReading);
15396657Snate@binkert.org    txDmaState = dmaIdle;
15406657Snate@binkert.org
15416657Snate@binkert.org    DPRINTF(EthernetDMA, "tx dma read  paddr=%#x len=%d\n",
15426657Snate@binkert.org            txDmaAddr, txDmaLen);
15436657Snate@binkert.org    DDUMP(EthernetDMA, txDmaData, txDmaLen);
15446657Snate@binkert.org
15456657Snate@binkert.org    // If the receive state machine  has a pending DMA, let it go first
15466657Snate@binkert.org    if (rxDmaState == dmaReadWaiting || rxDmaState == dmaWriteWaiting)
15476657Snate@binkert.org        rxKick();
15486657Snate@binkert.org
15496657Snate@binkert.org    txKick();
15506657Snate@binkert.org}
15516657Snate@binkert.org
15526657Snate@binkert.orgbool
15536657Snate@binkert.orgNSGigE::doTxDmaWrite()
15546657Snate@binkert.org{
15556657Snate@binkert.org    assert(txDmaState == dmaIdle || txDmaState == dmaWriteWaiting);
15566657Snate@binkert.org    txDmaState = dmaWriting;
15576657Snate@binkert.org
15586657Snate@binkert.org    if (dmaPending() || drainState() != DrainState::Running)
15596657Snate@binkert.org        txDmaState = dmaWriteWaiting;
15606657Snate@binkert.org    else
15616657Snate@binkert.org        dmaWrite(txDmaAddr, txDmaLen, &txDmaWriteEvent, (uint8_t*)txDmaData);
15626657Snate@binkert.org    return true;
15636657Snate@binkert.org}
15646657Snate@binkert.org
15656657Snate@binkert.orgvoid
15666657Snate@binkert.orgNSGigE::txDmaWriteDone()
15676657Snate@binkert.org{
15686657Snate@binkert.org    assert(txDmaState == dmaWriting);
15696657Snate@binkert.org    txDmaState = dmaIdle;
15706657Snate@binkert.org
15716657Snate@binkert.org    DPRINTF(EthernetDMA, "tx dma write paddr=%#x len=%d\n",
15726657Snate@binkert.org            txDmaAddr, txDmaLen);
15736657Snate@binkert.org    DDUMP(EthernetDMA, txDmaData, txDmaLen);
15746657Snate@binkert.org
15756657Snate@binkert.org    // If the receive state machine  has a pending DMA, let it go first
15766657Snate@binkert.org    if (rxDmaState == dmaReadWaiting || rxDmaState == dmaWriteWaiting)
15776657Snate@binkert.org        rxKick();
15786657Snate@binkert.org
15796657Snate@binkert.org    txKick();
15806657Snate@binkert.org}
15816657Snate@binkert.org
15826657Snate@binkert.orgvoid
15836657Snate@binkert.orgNSGigE::txKick()
15846657Snate@binkert.org{
15856657Snate@binkert.org    bool is64bit = (bool)(regs.config & CFGR_M64ADDR);
15866657Snate@binkert.org
15876657Snate@binkert.org    DPRINTF(EthernetSM, "transmit kick txState=%s %d-bit\n",
15886657Snate@binkert.org            NsTxStateStrings[txState], is64bit ? 64 : 32);
15896657Snate@binkert.org
15906657Snate@binkert.org    Addr link, bufptr;
15916657Snate@binkert.org    uint32_t &cmdsts = is64bit ? txDesc64.cmdsts : txDesc32.cmdsts;
15926657Snate@binkert.org    uint32_t &extsts = is64bit ? txDesc64.extsts : txDesc32.extsts;
15937007Snate@binkert.org
15946657Snate@binkert.org  next:
15956657Snate@binkert.org    if (txKickTick > curTick()) {
15966657Snate@binkert.org        DPRINTF(EthernetSM, "transmit kick exiting, can't run till %d\n",
15976657Snate@binkert.org                txKickTick);
15986657Snate@binkert.org        goto exit;
15996657Snate@binkert.org    }
16006657Snate@binkert.org
16017007Snate@binkert.org    // Go to the next state machine clock tick.
16026657Snate@binkert.org    txKickTick = clockEdge(Cycles(1));
16036657Snate@binkert.org
16046657Snate@binkert.org    switch(txDmaState) {
16056657Snate@binkert.org      case dmaReadWaiting:
16066657Snate@binkert.org        if (doTxDmaRead())
16076657Snate@binkert.org            goto exit;
16086657Snate@binkert.org        break;
16096657Snate@binkert.org      case dmaWriteWaiting:
16106657Snate@binkert.org        if (doTxDmaWrite())
16116657Snate@binkert.org            goto exit;
16126657Snate@binkert.org        break;
16136657Snate@binkert.org      default:
16146657Snate@binkert.org        break;
16156657Snate@binkert.org    }
16166657Snate@binkert.org
16177007Snate@binkert.org    link = is64bit ? (Addr)txDesc64.link : (Addr)txDesc32.link;
16186657Snate@binkert.org    bufptr = is64bit ? (Addr)txDesc64.bufptr : (Addr)txDesc32.bufptr;
16196657Snate@binkert.org    switch (txState) {
16206657Snate@binkert.org      case txIdle:
16216657Snate@binkert.org        if (!txEnable) {
16226657Snate@binkert.org            DPRINTF(EthernetSM, "Transmit disabled.  Nothing to do.\n");
16236657Snate@binkert.org            goto exit;
16246657Snate@binkert.org        }
16256657Snate@binkert.org
16266657Snate@binkert.org        if (CTDD) {
16276657Snate@binkert.org            txState = txDescRefr;
16286657Snate@binkert.org
16296657Snate@binkert.org            txDmaAddr = regs.txdp & 0x3fffffff;
16306657Snate@binkert.org            txDmaData =
16316657Snate@binkert.org                is64bit ? (void *)&txDesc64.link : (void *)&txDesc32.link;
16326657Snate@binkert.org            txDmaLen = is64bit ? sizeof(txDesc64.link) : sizeof(txDesc32.link);
16336657Snate@binkert.org            txDmaFree = dmaDescFree;
16346657Snate@binkert.org
16356657Snate@binkert.org            descDmaReads++;
16366657Snate@binkert.org            descDmaRdBytes += txDmaLen;
16376657Snate@binkert.org
16386657Snate@binkert.org            if (doTxDmaRead())
16396657Snate@binkert.org                goto exit;
1640
1641        } else {
1642            txState = txDescRead;
1643
1644            txDmaAddr = regs.txdp & 0x3fffffff;
1645            txDmaData = is64bit ? (void *)&txDesc64 : (void *)&txDesc32;
1646            txDmaLen = is64bit ? sizeof(txDesc64) : sizeof(txDesc32);
1647            txDmaFree = dmaDescFree;
1648
1649            descDmaReads++;
1650            descDmaRdBytes += txDmaLen;
1651
1652            if (doTxDmaRead())
1653                goto exit;
1654        }
1655        break;
1656
1657      case txDescRefr:
1658        if (txDmaState != dmaIdle)
1659            goto exit;
1660
1661        txState = txAdvance;
1662        break;
1663
1664      case txDescRead:
1665        if (txDmaState != dmaIdle)
1666            goto exit;
1667
1668        DPRINTF(EthernetDesc, "txDesc: addr=%08x read descriptor\n",
1669                regs.txdp & 0x3fffffff);
1670        DPRINTF(EthernetDesc,
1671                "txDesc: link=%#x bufptr=%#x cmdsts=%#08x extsts=%#08x\n",
1672                link, bufptr, cmdsts, extsts);
1673
1674        if (cmdsts & CMDSTS_OWN) {
1675            txState = txFifoBlock;
1676            txFragPtr = bufptr;
1677            txDescCnt = cmdsts & CMDSTS_LEN_MASK;
1678        } else {
1679            devIntrPost(ISR_TXIDLE);
1680            txState = txIdle;
1681            goto exit;
1682        }
1683        break;
1684
1685      case txFifoBlock:
1686        if (!txPacket) {
1687            DPRINTF(EthernetSM, "****starting the tx of a new packet****\n");
1688            txPacket = make_shared<EthPacketData>(16384);
1689            txPacketBufPtr = txPacket->data;
1690        }
1691
1692        if (txDescCnt == 0) {
1693            DPRINTF(EthernetSM, "the txDescCnt == 0, done with descriptor\n");
1694            if (cmdsts & CMDSTS_MORE) {
1695                DPRINTF(EthernetSM, "there are more descriptors to come\n");
1696                txState = txDescWrite;
1697
1698                cmdsts &= ~CMDSTS_OWN;
1699
1700                txDmaAddr = regs.txdp & 0x3fffffff;
1701                txDmaData = &cmdsts;
1702                if (is64bit) {
1703                    txDmaAddr += offsetof(ns_desc64, cmdsts);
1704                    txDmaLen = sizeof(txDesc64.cmdsts);
1705                } else {
1706                    txDmaAddr += offsetof(ns_desc32, cmdsts);
1707                    txDmaLen = sizeof(txDesc32.cmdsts);
1708                }
1709                txDmaFree = dmaDescFree;
1710
1711                if (doTxDmaWrite())
1712                    goto exit;
1713
1714            } else { /* this packet is totally done */
1715                DPRINTF(EthernetSM, "This packet is done, let's wrap it up\n");
1716                /* deal with the the packet that just finished */
1717                if ((regs.vtcr & VTCR_PPCHK) && extstsEnable) {
1718                    IpPtr ip(txPacket);
1719                    if (extsts & EXTSTS_UDPPKT) {
1720                        UdpPtr udp(ip);
1721                        if (udp) {
1722                            udp->sum(0);
1723                            udp->sum(cksum(udp));
1724                            txUdpChecksums++;
1725                        } else {
1726                            Debug::breakpoint();
1727                            warn_once("UDPPKT set, but not UDP!\n");
1728                        }
1729                    } else if (extsts & EXTSTS_TCPPKT) {
1730                        TcpPtr tcp(ip);
1731                        if (tcp) {
1732                            tcp->sum(0);
1733                            tcp->sum(cksum(tcp));
1734                            txTcpChecksums++;
1735                        } else {
1736                            warn_once("TCPPKT set, but not UDP!\n");
1737                        }
1738                    }
1739                    if (extsts & EXTSTS_IPPKT) {
1740                        if (ip) {
1741                            ip->sum(0);
1742                            ip->sum(cksum(ip));
1743                            txIpChecksums++;
1744                        } else {
1745                            warn_once("IPPKT set, but not UDP!\n");
1746                        }
1747                    }
1748                }
1749
1750                txPacket->simLength = txPacketBufPtr - txPacket->data;
1751                txPacket->length = txPacketBufPtr - txPacket->data;
1752                // this is just because the receive can't handle a
1753                // packet bigger want to make sure
1754                if (txPacket->length > 1514)
1755                    panic("transmit packet too large, %s > 1514\n",
1756                          txPacket->length);
1757
1758#ifndef NDEBUG
1759                bool success =
1760#endif
1761                    txFifo.push(txPacket);
1762                assert(success);
1763
1764                /*
1765                 * this following section is not tqo spec, but
1766                 * functionally shouldn't be any different.  normally,
1767                 * the chip will wait til the transmit has occurred
1768                 * before writing back the descriptor because it has
1769                 * to wait to see that it was successfully transmitted
1770                 * to decide whether to set CMDSTS_OK or not.
1771                 * however, in the simulator since it is always
1772                 * successfully transmitted, and writing it exactly to
1773                 * spec would complicate the code, we just do it here
1774                 */
1775
1776                cmdsts &= ~CMDSTS_OWN;
1777                cmdsts |= CMDSTS_OK;
1778
1779                DPRINTF(EthernetDesc,
1780                        "txDesc writeback: cmdsts=%08x extsts=%08x\n",
1781                        cmdsts, extsts);
1782
1783                txDmaFree = dmaDescFree;
1784                txDmaAddr = regs.txdp & 0x3fffffff;
1785                txDmaData = &cmdsts;
1786                if (is64bit) {
1787                    txDmaAddr += offsetof(ns_desc64, cmdsts);
1788                    txDmaLen =
1789                        sizeof(txDesc64.cmdsts) + sizeof(txDesc64.extsts);
1790                } else {
1791                    txDmaAddr += offsetof(ns_desc32, cmdsts);
1792                    txDmaLen =
1793                        sizeof(txDesc32.cmdsts) + sizeof(txDesc32.extsts);
1794                }
1795
1796                descDmaWrites++;
1797                descDmaWrBytes += txDmaLen;
1798
1799                transmit();
1800                txPacket = 0;
1801
1802                if (!txEnable) {
1803                    DPRINTF(EthernetSM, "halting TX state machine\n");
1804                    txState = txIdle;
1805                    goto exit;
1806                } else
1807                    txState = txAdvance;
1808
1809                if (doTxDmaWrite())
1810                    goto exit;
1811            }
1812        } else {
1813            DPRINTF(EthernetSM, "this descriptor isn't done yet\n");
1814            if (!txFifo.full()) {
1815                txState = txFragRead;
1816
1817                /*
1818                 * The number of bytes transferred is either whatever
1819                 * is left in the descriptor (txDescCnt), or if there
1820                 * is not enough room in the fifo, just whatever room
1821                 * is left in the fifo
1822                 */
1823                txXferLen = min<uint32_t>(txDescCnt, txFifo.avail());
1824
1825                txDmaAddr = txFragPtr & 0x3fffffff;
1826                txDmaData = txPacketBufPtr;
1827                txDmaLen = txXferLen;
1828                txDmaFree = dmaDataFree;
1829
1830                if (doTxDmaRead())
1831                    goto exit;
1832            } else {
1833                txState = txFifoBlock;
1834                transmit();
1835
1836                goto exit;
1837            }
1838
1839        }
1840        break;
1841
1842      case txFragRead:
1843        if (txDmaState != dmaIdle)
1844            goto exit;
1845
1846        txPacketBufPtr += txXferLen;
1847        txFragPtr += txXferLen;
1848        txDescCnt -= txXferLen;
1849        txFifo.reserve(txXferLen);
1850
1851        txState = txFifoBlock;
1852        break;
1853
1854      case txDescWrite:
1855        if (txDmaState != dmaIdle)
1856            goto exit;
1857
1858        if (cmdsts & CMDSTS_INTR)
1859            devIntrPost(ISR_TXDESC);
1860
1861        if (!txEnable) {
1862            DPRINTF(EthernetSM, "halting TX state machine\n");
1863            txState = txIdle;
1864            goto exit;
1865        } else
1866            txState = txAdvance;
1867        break;
1868
1869      case txAdvance:
1870        if (link == 0) {
1871            devIntrPost(ISR_TXIDLE);
1872            txState = txIdle;
1873            goto exit;
1874        } else {
1875            if (txDmaState != dmaIdle)
1876                goto exit;
1877            txState = txDescRead;
1878            regs.txdp = link;
1879            CTDD = false;
1880
1881            txDmaAddr = link & 0x3fffffff;
1882            txDmaData = is64bit ? (void *)&txDesc64 : (void *)&txDesc32;
1883            txDmaLen = is64bit ? sizeof(txDesc64) : sizeof(txDesc32);
1884            txDmaFree = dmaDescFree;
1885
1886            if (doTxDmaRead())
1887                goto exit;
1888        }
1889        break;
1890
1891      default:
1892        panic("invalid state");
1893    }
1894
1895    DPRINTF(EthernetSM, "entering next txState=%s\n",
1896            NsTxStateStrings[txState]);
1897    goto next;
1898
1899  exit:
1900    /**
1901     * @todo do we want to schedule a future kick?
1902     */
1903    DPRINTF(EthernetSM, "tx state machine exited txState=%s\n",
1904            NsTxStateStrings[txState]);
1905
1906    if (!txKickEvent.scheduled())
1907        schedule(txKickEvent, txKickTick);
1908}
1909
1910/**
1911 * Advance the EEPROM state machine
1912 * Called on rising edge of EEPROM clock bit in MEAR
1913 */
1914void
1915NSGigE::eepromKick()
1916{
1917    switch (eepromState) {
1918
1919      case eepromStart:
1920
1921        // Wait for start bit
1922        if (regs.mear & MEAR_EEDI) {
1923            // Set up to get 2 opcode bits
1924            eepromState = eepromGetOpcode;
1925            eepromBitsToRx = 2;
1926            eepromOpcode = 0;
1927        }
1928        break;
1929
1930      case eepromGetOpcode:
1931        eepromOpcode <<= 1;
1932        eepromOpcode += (regs.mear & MEAR_EEDI) ? 1 : 0;
1933        --eepromBitsToRx;
1934
1935        // Done getting opcode
1936        if (eepromBitsToRx == 0) {
1937            if (eepromOpcode != EEPROM_READ)
1938                panic("only EEPROM reads are implemented!");
1939
1940            // Set up to get address
1941            eepromState = eepromGetAddress;
1942            eepromBitsToRx = 6;
1943            eepromAddress = 0;
1944        }
1945        break;
1946
1947      case eepromGetAddress:
1948        eepromAddress <<= 1;
1949        eepromAddress += (regs.mear & MEAR_EEDI) ? 1 : 0;
1950        --eepromBitsToRx;
1951
1952        // Done getting address
1953        if (eepromBitsToRx == 0) {
1954
1955            if (eepromAddress >= EEPROM_SIZE)
1956                panic("EEPROM read access out of range!");
1957
1958            switch (eepromAddress) {
1959
1960              case EEPROM_PMATCH2_ADDR:
1961                eepromData = rom.perfectMatch[5];
1962                eepromData <<= 8;
1963                eepromData += rom.perfectMatch[4];
1964                break;
1965
1966              case EEPROM_PMATCH1_ADDR:
1967                eepromData = rom.perfectMatch[3];
1968                eepromData <<= 8;
1969                eepromData += rom.perfectMatch[2];
1970                break;
1971
1972              case EEPROM_PMATCH0_ADDR:
1973                eepromData = rom.perfectMatch[1];
1974                eepromData <<= 8;
1975                eepromData += rom.perfectMatch[0];
1976                break;
1977
1978              default:
1979                panic("FreeBSD driver only uses EEPROM to read PMATCH!");
1980            }
1981            // Set up to read data
1982            eepromState = eepromRead;
1983            eepromBitsToRx = 16;
1984
1985            // Clear data in bit
1986            regs.mear &= ~MEAR_EEDI;
1987        }
1988        break;
1989
1990      case eepromRead:
1991        // Clear Data Out bit
1992        regs.mear &= ~MEAR_EEDO;
1993        // Set bit to value of current EEPROM bit
1994        regs.mear |= (eepromData & 0x8000) ? MEAR_EEDO : 0x0;
1995
1996        eepromData <<= 1;
1997        --eepromBitsToRx;
1998
1999        // All done
2000        if (eepromBitsToRx == 0) {
2001            eepromState = eepromStart;
2002        }
2003        break;
2004
2005      default:
2006        panic("invalid EEPROM state");
2007    }
2008
2009}
2010
2011void
2012NSGigE::transferDone()
2013{
2014    if (txFifo.empty()) {
2015        DPRINTF(Ethernet, "transfer complete: txFifo empty...nothing to do\n");
2016        return;
2017    }
2018
2019    DPRINTF(Ethernet, "transfer complete: data in txFifo...schedule xmit\n");
2020
2021    reschedule(txEvent, clockEdge(Cycles(1)), true);
2022}
2023
2024bool
2025NSGigE::rxFilter(const EthPacketPtr &packet)
2026{
2027    EthPtr eth = packet;
2028    bool drop = true;
2029    string type;
2030
2031    const EthAddr &dst = eth->dst();
2032    if (dst.unicast()) {
2033        // If we're accepting all unicast addresses
2034        if (acceptUnicast)
2035            drop = false;
2036
2037        // If we make a perfect match
2038        if (acceptPerfect && dst == rom.perfectMatch)
2039            drop = false;
2040
2041        if (acceptArp && eth->type() == ETH_TYPE_ARP)
2042            drop = false;
2043
2044    } else if (dst.broadcast()) {
2045        // if we're accepting broadcasts
2046        if (acceptBroadcast)
2047            drop = false;
2048
2049    } else if (dst.multicast()) {
2050        // if we're accepting all multicasts
2051        if (acceptMulticast)
2052            drop = false;
2053
2054        // Multicast hashing faked - all packets accepted
2055        if (multicastHashEnable)
2056            drop = false;
2057    }
2058
2059    if (drop) {
2060        DPRINTF(Ethernet, "rxFilter drop\n");
2061        DDUMP(EthernetData, packet->data, packet->length);
2062    }
2063
2064    return drop;
2065}
2066
2067bool
2068NSGigE::recvPacket(EthPacketPtr packet)
2069{
2070    rxBytes += packet->length;
2071    rxPackets++;
2072
2073    DPRINTF(Ethernet, "Receiving packet from wire, rxFifoAvail=%d\n",
2074            rxFifo.avail());
2075
2076    if (!rxEnable) {
2077        DPRINTF(Ethernet, "receive disabled...packet dropped\n");
2078        return true;
2079    }
2080
2081    if (!rxFilterEnable) {
2082        DPRINTF(Ethernet,
2083            "receive packet filtering disabled . . . packet dropped\n");
2084        return true;
2085    }
2086
2087    if (rxFilter(packet)) {
2088        DPRINTF(Ethernet, "packet filtered...dropped\n");
2089        return true;
2090    }
2091
2092    if (rxFifo.avail() < packet->length) {
2093#if TRACING_ON
2094        IpPtr ip(packet);
2095        TcpPtr tcp(ip);
2096        if (ip) {
2097            DPRINTF(Ethernet,
2098                    "packet won't fit in receive buffer...pkt ID %d dropped\n",
2099                    ip->id());
2100            if (tcp) {
2101                DPRINTF(Ethernet, "Seq=%d\n", tcp->seq());
2102            }
2103        }
2104#endif
2105        droppedPackets++;
2106        devIntrPost(ISR_RXORN);
2107        return false;
2108    }
2109
2110    rxFifo.push(packet);
2111
2112    rxKick();
2113    return true;
2114}
2115
2116
2117void
2118NSGigE::drainResume()
2119{
2120    Drainable::drainResume();
2121
2122    // During drain we could have left the state machines in a waiting state and
2123    // they wouldn't get out until some other event occured to kick them.
2124    // This way they'll get out immediately
2125    txKick();
2126    rxKick();
2127}
2128
2129
2130//=====================================================================
2131//
2132//
2133void
2134NSGigE::serialize(CheckpointOut &cp) const
2135{
2136    // Serialize the PciDevice base class
2137    PciDevice::serialize(cp);
2138
2139    /*
2140     * Finalize any DMA events now.
2141     */
2142    // @todo will mem system save pending dma?
2143
2144    /*
2145     * Serialize the device registers
2146     */
2147    SERIALIZE_SCALAR(regs.command);
2148    SERIALIZE_SCALAR(regs.config);
2149    SERIALIZE_SCALAR(regs.mear);
2150    SERIALIZE_SCALAR(regs.ptscr);
2151    SERIALIZE_SCALAR(regs.isr);
2152    SERIALIZE_SCALAR(regs.imr);
2153    SERIALIZE_SCALAR(regs.ier);
2154    SERIALIZE_SCALAR(regs.ihr);
2155    SERIALIZE_SCALAR(regs.txdp);
2156    SERIALIZE_SCALAR(regs.txdp_hi);
2157    SERIALIZE_SCALAR(regs.txcfg);
2158    SERIALIZE_SCALAR(regs.gpior);
2159    SERIALIZE_SCALAR(regs.rxdp);
2160    SERIALIZE_SCALAR(regs.rxdp_hi);
2161    SERIALIZE_SCALAR(regs.rxcfg);
2162    SERIALIZE_SCALAR(regs.pqcr);
2163    SERIALIZE_SCALAR(regs.wcsr);
2164    SERIALIZE_SCALAR(regs.pcr);
2165    SERIALIZE_SCALAR(regs.rfcr);
2166    SERIALIZE_SCALAR(regs.rfdr);
2167    SERIALIZE_SCALAR(regs.brar);
2168    SERIALIZE_SCALAR(regs.brdr);
2169    SERIALIZE_SCALAR(regs.srr);
2170    SERIALIZE_SCALAR(regs.mibc);
2171    SERIALIZE_SCALAR(regs.vrcr);
2172    SERIALIZE_SCALAR(regs.vtcr);
2173    SERIALIZE_SCALAR(regs.vdr);
2174    SERIALIZE_SCALAR(regs.ccsr);
2175    SERIALIZE_SCALAR(regs.tbicr);
2176    SERIALIZE_SCALAR(regs.tbisr);
2177    SERIALIZE_SCALAR(regs.tanar);
2178    SERIALIZE_SCALAR(regs.tanlpar);
2179    SERIALIZE_SCALAR(regs.taner);
2180    SERIALIZE_SCALAR(regs.tesr);
2181
2182    SERIALIZE_ARRAY(rom.perfectMatch, ETH_ADDR_LEN);
2183    SERIALIZE_ARRAY(rom.filterHash, FHASH_SIZE);
2184
2185    SERIALIZE_SCALAR(ioEnable);
2186
2187    /*
2188     * Serialize the data Fifos
2189     */
2190    rxFifo.serialize("rxFifo", cp);
2191    txFifo.serialize("txFifo", cp);
2192
2193    /*
2194     * Serialize the various helper variables
2195     */
2196    bool txPacketExists = txPacket != nullptr;
2197    SERIALIZE_SCALAR(txPacketExists);
2198    if (txPacketExists) {
2199        txPacket->simLength = txPacketBufPtr - txPacket->data;
2200        txPacket->length = txPacketBufPtr - txPacket->data;
2201        txPacket->serialize("txPacket", cp);
2202        uint32_t txPktBufPtr = (uint32_t) (txPacketBufPtr - txPacket->data);
2203        SERIALIZE_SCALAR(txPktBufPtr);
2204    }
2205
2206    bool rxPacketExists = rxPacket != nullptr;
2207    SERIALIZE_SCALAR(rxPacketExists);
2208    if (rxPacketExists) {
2209        rxPacket->serialize("rxPacket", cp);
2210        uint32_t rxPktBufPtr = (uint32_t) (rxPacketBufPtr - rxPacket->data);
2211        SERIALIZE_SCALAR(rxPktBufPtr);
2212    }
2213
2214    SERIALIZE_SCALAR(txXferLen);
2215    SERIALIZE_SCALAR(rxXferLen);
2216
2217    /*
2218     * Serialize Cached Descriptors
2219     */
2220    SERIALIZE_SCALAR(rxDesc64.link);
2221    SERIALIZE_SCALAR(rxDesc64.bufptr);
2222    SERIALIZE_SCALAR(rxDesc64.cmdsts);
2223    SERIALIZE_SCALAR(rxDesc64.extsts);
2224    SERIALIZE_SCALAR(txDesc64.link);
2225    SERIALIZE_SCALAR(txDesc64.bufptr);
2226    SERIALIZE_SCALAR(txDesc64.cmdsts);
2227    SERIALIZE_SCALAR(txDesc64.extsts);
2228    SERIALIZE_SCALAR(rxDesc32.link);
2229    SERIALIZE_SCALAR(rxDesc32.bufptr);
2230    SERIALIZE_SCALAR(rxDesc32.cmdsts);
2231    SERIALIZE_SCALAR(rxDesc32.extsts);
2232    SERIALIZE_SCALAR(txDesc32.link);
2233    SERIALIZE_SCALAR(txDesc32.bufptr);
2234    SERIALIZE_SCALAR(txDesc32.cmdsts);
2235    SERIALIZE_SCALAR(txDesc32.extsts);
2236    SERIALIZE_SCALAR(extstsEnable);
2237
2238    /*
2239     * Serialize tx state machine
2240     */
2241    int txState = this->txState;
2242    SERIALIZE_SCALAR(txState);
2243    SERIALIZE_SCALAR(txEnable);
2244    SERIALIZE_SCALAR(CTDD);
2245    SERIALIZE_SCALAR(txFragPtr);
2246    SERIALIZE_SCALAR(txDescCnt);
2247    int txDmaState = this->txDmaState;
2248    SERIALIZE_SCALAR(txDmaState);
2249    SERIALIZE_SCALAR(txKickTick);
2250
2251    /*
2252     * Serialize rx state machine
2253     */
2254    int rxState = this->rxState;
2255    SERIALIZE_SCALAR(rxState);
2256    SERIALIZE_SCALAR(rxEnable);
2257    SERIALIZE_SCALAR(CRDD);
2258    SERIALIZE_SCALAR(rxPktBytes);
2259    SERIALIZE_SCALAR(rxFragPtr);
2260    SERIALIZE_SCALAR(rxDescCnt);
2261    int rxDmaState = this->rxDmaState;
2262    SERIALIZE_SCALAR(rxDmaState);
2263    SERIALIZE_SCALAR(rxKickTick);
2264
2265    /*
2266     * Serialize EEPROM state machine
2267     */
2268    int eepromState = this->eepromState;
2269    SERIALIZE_SCALAR(eepromState);
2270    SERIALIZE_SCALAR(eepromClk);
2271    SERIALIZE_SCALAR(eepromBitsToRx);
2272    SERIALIZE_SCALAR(eepromOpcode);
2273    SERIALIZE_SCALAR(eepromAddress);
2274    SERIALIZE_SCALAR(eepromData);
2275
2276    /*
2277     * If there's a pending transmit, store the time so we can
2278     * reschedule it later
2279     */
2280    Tick transmitTick = txEvent.scheduled() ? txEvent.when() - curTick() : 0;
2281    SERIALIZE_SCALAR(transmitTick);
2282
2283    /*
2284     * receive address filter settings
2285     */
2286    SERIALIZE_SCALAR(rxFilterEnable);
2287    SERIALIZE_SCALAR(acceptBroadcast);
2288    SERIALIZE_SCALAR(acceptMulticast);
2289    SERIALIZE_SCALAR(acceptUnicast);
2290    SERIALIZE_SCALAR(acceptPerfect);
2291    SERIALIZE_SCALAR(acceptArp);
2292    SERIALIZE_SCALAR(multicastHashEnable);
2293
2294    /*
2295     * Keep track of pending interrupt status.
2296     */
2297    SERIALIZE_SCALAR(intrTick);
2298    SERIALIZE_SCALAR(cpuPendingIntr);
2299    Tick intrEventTick = 0;
2300    if (intrEvent)
2301        intrEventTick = intrEvent->when();
2302    SERIALIZE_SCALAR(intrEventTick);
2303
2304}
2305
2306void
2307NSGigE::unserialize(CheckpointIn &cp)
2308{
2309    // Unserialize the PciDevice base class
2310    PciDevice::unserialize(cp);
2311
2312    UNSERIALIZE_SCALAR(regs.command);
2313    UNSERIALIZE_SCALAR(regs.config);
2314    UNSERIALIZE_SCALAR(regs.mear);
2315    UNSERIALIZE_SCALAR(regs.ptscr);
2316    UNSERIALIZE_SCALAR(regs.isr);
2317    UNSERIALIZE_SCALAR(regs.imr);
2318    UNSERIALIZE_SCALAR(regs.ier);
2319    UNSERIALIZE_SCALAR(regs.ihr);
2320    UNSERIALIZE_SCALAR(regs.txdp);
2321    UNSERIALIZE_SCALAR(regs.txdp_hi);
2322    UNSERIALIZE_SCALAR(regs.txcfg);
2323    UNSERIALIZE_SCALAR(regs.gpior);
2324    UNSERIALIZE_SCALAR(regs.rxdp);
2325    UNSERIALIZE_SCALAR(regs.rxdp_hi);
2326    UNSERIALIZE_SCALAR(regs.rxcfg);
2327    UNSERIALIZE_SCALAR(regs.pqcr);
2328    UNSERIALIZE_SCALAR(regs.wcsr);
2329    UNSERIALIZE_SCALAR(regs.pcr);
2330    UNSERIALIZE_SCALAR(regs.rfcr);
2331    UNSERIALIZE_SCALAR(regs.rfdr);
2332    UNSERIALIZE_SCALAR(regs.brar);
2333    UNSERIALIZE_SCALAR(regs.brdr);
2334    UNSERIALIZE_SCALAR(regs.srr);
2335    UNSERIALIZE_SCALAR(regs.mibc);
2336    UNSERIALIZE_SCALAR(regs.vrcr);
2337    UNSERIALIZE_SCALAR(regs.vtcr);
2338    UNSERIALIZE_SCALAR(regs.vdr);
2339    UNSERIALIZE_SCALAR(regs.ccsr);
2340    UNSERIALIZE_SCALAR(regs.tbicr);
2341    UNSERIALIZE_SCALAR(regs.tbisr);
2342    UNSERIALIZE_SCALAR(regs.tanar);
2343    UNSERIALIZE_SCALAR(regs.tanlpar);
2344    UNSERIALIZE_SCALAR(regs.taner);
2345    UNSERIALIZE_SCALAR(regs.tesr);
2346
2347    UNSERIALIZE_ARRAY(rom.perfectMatch, ETH_ADDR_LEN);
2348    UNSERIALIZE_ARRAY(rom.filterHash, FHASH_SIZE);
2349
2350    UNSERIALIZE_SCALAR(ioEnable);
2351
2352    /*
2353     * unserialize the data fifos
2354     */
2355    rxFifo.unserialize("rxFifo", cp);
2356    txFifo.unserialize("txFifo", cp);
2357
2358    /*
2359     * unserialize the various helper variables
2360     */
2361    bool txPacketExists;
2362    UNSERIALIZE_SCALAR(txPacketExists);
2363    if (txPacketExists) {
2364        txPacket = make_shared<EthPacketData>(16384);
2365        txPacket->unserialize("txPacket", cp);
2366        uint32_t txPktBufPtr;
2367        UNSERIALIZE_SCALAR(txPktBufPtr);
2368        txPacketBufPtr = (uint8_t *) txPacket->data + txPktBufPtr;
2369    } else
2370        txPacket = 0;
2371
2372    bool rxPacketExists;
2373    UNSERIALIZE_SCALAR(rxPacketExists);
2374    rxPacket = 0;
2375    if (rxPacketExists) {
2376        rxPacket = make_shared<EthPacketData>();
2377        rxPacket->unserialize("rxPacket", cp);
2378        uint32_t rxPktBufPtr;
2379        UNSERIALIZE_SCALAR(rxPktBufPtr);
2380        rxPacketBufPtr = (uint8_t *) rxPacket->data + rxPktBufPtr;
2381    } else
2382        rxPacket = 0;
2383
2384    UNSERIALIZE_SCALAR(txXferLen);
2385    UNSERIALIZE_SCALAR(rxXferLen);
2386
2387    /*
2388     * Unserialize Cached Descriptors
2389     */
2390    UNSERIALIZE_SCALAR(rxDesc64.link);
2391    UNSERIALIZE_SCALAR(rxDesc64.bufptr);
2392    UNSERIALIZE_SCALAR(rxDesc64.cmdsts);
2393    UNSERIALIZE_SCALAR(rxDesc64.extsts);
2394    UNSERIALIZE_SCALAR(txDesc64.link);
2395    UNSERIALIZE_SCALAR(txDesc64.bufptr);
2396    UNSERIALIZE_SCALAR(txDesc64.cmdsts);
2397    UNSERIALIZE_SCALAR(txDesc64.extsts);
2398    UNSERIALIZE_SCALAR(rxDesc32.link);
2399    UNSERIALIZE_SCALAR(rxDesc32.bufptr);
2400    UNSERIALIZE_SCALAR(rxDesc32.cmdsts);
2401    UNSERIALIZE_SCALAR(rxDesc32.extsts);
2402    UNSERIALIZE_SCALAR(txDesc32.link);
2403    UNSERIALIZE_SCALAR(txDesc32.bufptr);
2404    UNSERIALIZE_SCALAR(txDesc32.cmdsts);
2405    UNSERIALIZE_SCALAR(txDesc32.extsts);
2406    UNSERIALIZE_SCALAR(extstsEnable);
2407
2408    /*
2409     * unserialize tx state machine
2410     */
2411    int txState;
2412    UNSERIALIZE_SCALAR(txState);
2413    this->txState = (TxState) txState;
2414    UNSERIALIZE_SCALAR(txEnable);
2415    UNSERIALIZE_SCALAR(CTDD);
2416    UNSERIALIZE_SCALAR(txFragPtr);
2417    UNSERIALIZE_SCALAR(txDescCnt);
2418    int txDmaState;
2419    UNSERIALIZE_SCALAR(txDmaState);
2420    this->txDmaState = (DmaState) txDmaState;
2421    UNSERIALIZE_SCALAR(txKickTick);
2422    if (txKickTick)
2423        schedule(txKickEvent, txKickTick);
2424
2425    /*
2426     * unserialize rx state machine
2427     */
2428    int rxState;
2429    UNSERIALIZE_SCALAR(rxState);
2430    this->rxState = (RxState) rxState;
2431    UNSERIALIZE_SCALAR(rxEnable);
2432    UNSERIALIZE_SCALAR(CRDD);
2433    UNSERIALIZE_SCALAR(rxPktBytes);
2434    UNSERIALIZE_SCALAR(rxFragPtr);
2435    UNSERIALIZE_SCALAR(rxDescCnt);
2436    int rxDmaState;
2437    UNSERIALIZE_SCALAR(rxDmaState);
2438    this->rxDmaState = (DmaState) rxDmaState;
2439    UNSERIALIZE_SCALAR(rxKickTick);
2440    if (rxKickTick)
2441        schedule(rxKickEvent, rxKickTick);
2442
2443    /*
2444     * Unserialize EEPROM state machine
2445     */
2446    int eepromState;
2447    UNSERIALIZE_SCALAR(eepromState);
2448    this->eepromState = (EEPROMState) eepromState;
2449    UNSERIALIZE_SCALAR(eepromClk);
2450    UNSERIALIZE_SCALAR(eepromBitsToRx);
2451    UNSERIALIZE_SCALAR(eepromOpcode);
2452    UNSERIALIZE_SCALAR(eepromAddress);
2453    UNSERIALIZE_SCALAR(eepromData);
2454
2455    /*
2456     * If there's a pending transmit, reschedule it now
2457     */
2458    Tick transmitTick;
2459    UNSERIALIZE_SCALAR(transmitTick);
2460    if (transmitTick)
2461        schedule(txEvent, curTick() + transmitTick);
2462
2463    /*
2464     * unserialize receive address filter settings
2465     */
2466    UNSERIALIZE_SCALAR(rxFilterEnable);
2467    UNSERIALIZE_SCALAR(acceptBroadcast);
2468    UNSERIALIZE_SCALAR(acceptMulticast);
2469    UNSERIALIZE_SCALAR(acceptUnicast);
2470    UNSERIALIZE_SCALAR(acceptPerfect);
2471    UNSERIALIZE_SCALAR(acceptArp);
2472    UNSERIALIZE_SCALAR(multicastHashEnable);
2473
2474    /*
2475     * Keep track of pending interrupt status.
2476     */
2477    UNSERIALIZE_SCALAR(intrTick);
2478    UNSERIALIZE_SCALAR(cpuPendingIntr);
2479    Tick intrEventTick;
2480    UNSERIALIZE_SCALAR(intrEventTick);
2481    if (intrEventTick) {
2482        intrEvent = new EventFunctionWrapper([this]{ cpuInterrupt(); },
2483                                             name(), true);
2484        schedule(intrEvent, intrEventTick);
2485    }
2486}
2487
2488NSGigE *
2489NSGigEParams::create()
2490{
2491    return new NSGigE(this);
2492}
2493