ns_gige.cc revision 9342
12292SN/A/*
27597Sminkyu.jeong@arm.com * Copyright (c) 2004-2005 The Regents of The University of Michigan
37597Sminkyu.jeong@arm.com * All rights reserved.
47597Sminkyu.jeong@arm.com *
57597Sminkyu.jeong@arm.com * Redistribution and use in source and binary forms, with or without
67597Sminkyu.jeong@arm.com * modification, are permitted provided that the following conditions are
77597Sminkyu.jeong@arm.com * met: redistributions of source code must retain the above copyright
87597Sminkyu.jeong@arm.com * notice, this list of conditions and the following disclaimer;
97597Sminkyu.jeong@arm.com * redistributions in binary form must reproduce the above copyright
107597Sminkyu.jeong@arm.com * notice, this list of conditions and the following disclaimer in the
117597Sminkyu.jeong@arm.com * documentation and/or other materials provided with the distribution;
127597Sminkyu.jeong@arm.com * neither the name of the copyright holders nor the names of its
137597Sminkyu.jeong@arm.com * contributors may be used to endorse or promote products derived from
142292SN/A * this software without specific prior written permission.
152292SN/A *
162292SN/A * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
172292SN/A * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
182292SN/A * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
192292SN/A * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
202292SN/A * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
212292SN/A * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
222292SN/A * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
232292SN/A * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
242292SN/A * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
252292SN/A * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
262292SN/A * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
272292SN/A *
282292SN/A * Authors: Nathan Binkert
292292SN/A *          Lisa Hsu
302292SN/A */
312292SN/A
322292SN/A/** @file
332292SN/A * Device module for modelling the National Semiconductor
342292SN/A * DP83820 ethernet controller.  Does not support priority queueing
352292SN/A */
362292SN/A#include <deque>
372292SN/A#include <string>
382292SN/A
392689Sktlim@umich.edu#include "base/debug.hh"
402689Sktlim@umich.edu#include "base/inet.hh"
412689Sktlim@umich.edu#include "base/types.hh"
422292SN/A#include "config/the_isa.hh"
432292SN/A#include "cpu/thread_context.hh"
443326Sktlim@umich.edu#include "debug/EthernetAll.hh"
456658Snate@binkert.org#include "dev/etherlink.hh"
462733Sktlim@umich.edu#include "dev/ns_gige.hh"
472907Sktlim@umich.edu#include "dev/pciconfigall.hh"
482292SN/A#include "mem/packet.hh"
492292SN/A#include "mem/packet_access.hh"
502722Sktlim@umich.edu#include "params/NSGigE.hh"
512669Sktlim@umich.edu#include "sim/system.hh"
522292SN/A
532790Sktlim@umich.edu// clang complains about std::set being overloaded with Packet::set if
542790Sktlim@umich.edu// we open up the entire namespace std
552790Sktlim@umich.eduusing std::min;
562790Sktlim@umich.eduusing std::ostream;
572669Sktlim@umich.eduusing std::string;
582678Sktlim@umich.edu
592678Sktlim@umich.educonst char *NsRxStateStrings[] =
605606Snate@binkert.org{
612292SN/A    "rxIdle",
622678Sktlim@umich.edu    "rxDescRefr",
632292SN/A    "rxDescRead",
642292SN/A    "rxFifoBlock",
652669Sktlim@umich.edu    "rxFragWrite",
662292SN/A    "rxDescWrite",
672678Sktlim@umich.edu    "rxAdvance"
682292SN/A};
692678Sktlim@umich.edu
702678Sktlim@umich.educonst char *NsTxStateStrings[] =
712678Sktlim@umich.edu{
724319Sktlim@umich.edu    "txIdle",
734319Sktlim@umich.edu    "txDescRefr",
744319Sktlim@umich.edu    "txDescRead",
754319Sktlim@umich.edu    "txFifoBlock",
764319Sktlim@umich.edu    "txFragRead",
772678Sktlim@umich.edu    "txDescWrite",
782678Sktlim@umich.edu    "txAdvance"
792292SN/A};
802678Sktlim@umich.edu
812678Sktlim@umich.educonst char *NsDmaState[] =
825336Shines@cs.fsu.edu{
832678Sktlim@umich.edu    "dmaIdle",
844873Sstever@eecs.umich.edu    "dmaReading",
852678Sktlim@umich.edu    "dmaWriting",
862292SN/A    "dmaReadWaiting",
872678Sktlim@umich.edu    "dmaWriteWaiting"
882678Sktlim@umich.edu};
892678Sktlim@umich.edu
902678Sktlim@umich.eduusing namespace Net;
912678Sktlim@umich.eduusing namespace TheISA;
922678Sktlim@umich.edu
932678Sktlim@umich.edu///////////////////////////////////////////////////////////////////////
942698Sktlim@umich.edu//
952344SN/A// NSGigE PCI Device
962678Sktlim@umich.edu//
972678Sktlim@umich.eduNSGigE::NSGigE(Params *p)
984986Ssaidi@eecs.umich.edu    : EtherDevBase(p), ioEnable(false),
994986Ssaidi@eecs.umich.edu      txFifo(p->tx_fifo_size), rxFifo(p->rx_fifo_size),
1006974Stjones1@inf.ed.ac.uk      txPacket(0), rxPacket(0), txPacketBufPtr(NULL), rxPacketBufPtr(NULL),
1016974Stjones1@inf.ed.ac.uk      txXferLen(0), rxXferLen(0), rxDmaFree(false), txDmaFree(false),
1026974Stjones1@inf.ed.ac.uk      txState(txIdle), txEnable(false), CTDD(false), txHalt(false),
1036974Stjones1@inf.ed.ac.uk      txFragPtr(0), txDescCnt(0), txDmaState(dmaIdle), rxState(rxIdle),
1046974Stjones1@inf.ed.ac.uk      rxEnable(false), CRDD(false), rxPktBytes(0), rxHalt(false),
1056974Stjones1@inf.ed.ac.uk      rxFragPtr(0), rxDescCnt(0), rxDmaState(dmaIdle), extstsEnable(false),
1066974Stjones1@inf.ed.ac.uk      eepromState(eepromStart), eepromClk(false), eepromBitsToRx(0),
1072678Sktlim@umich.edu      eepromOpcode(0), eepromAddress(0), eepromData(0),
1082820Sktlim@umich.edu      dmaReadDelay(p->dma_read_delay), dmaWriteDelay(p->dma_write_delay),
1092678Sktlim@umich.edu      dmaReadFactor(p->dma_read_factor), dmaWriteFactor(p->dma_write_factor),
1102678Sktlim@umich.edu      rxDmaData(NULL), rxDmaAddr(0), rxDmaLen(0),
1116974Stjones1@inf.ed.ac.uk      txDmaData(NULL), txDmaAddr(0), txDmaLen(0),
1126974Stjones1@inf.ed.ac.uk      rxDmaReadEvent(this), rxDmaWriteEvent(this),
1136974Stjones1@inf.ed.ac.uk      txDmaReadEvent(this), txDmaWriteEvent(this),
1146974Stjones1@inf.ed.ac.uk      dmaDescFree(p->dma_desc_free), dmaDataFree(p->dma_data_free),
1156974Stjones1@inf.ed.ac.uk      txDelay(p->tx_delay), rxDelay(p->rx_delay),
1166974Stjones1@inf.ed.ac.uk      rxKickTick(0), rxKickEvent(this), txKickTick(0), txKickEvent(this),
1172678Sktlim@umich.edu      txEvent(this), rxFilterEnable(p->rx_filter),
1182678Sktlim@umich.edu      acceptBroadcast(false), acceptMulticast(false), acceptUnicast(false),
1192678Sktlim@umich.edu      acceptPerfect(false), acceptArp(false), multicastHashEnable(false),
1202678Sktlim@umich.edu      intrDelay(p->intr_delay), intrTick(0), cpuPendingIntr(false),
1212678Sktlim@umich.edu      intrEvent(0), interface(0)
1222344SN/A{
1232307SN/A
1246974Stjones1@inf.ed.ac.uk
1256974Stjones1@inf.ed.ac.uk    interface = new NSGigEInt(name() + ".int0", this);
1266974Stjones1@inf.ed.ac.uk
1276974Stjones1@inf.ed.ac.uk    regsReset();
1282678Sktlim@umich.edu    memcpy(&rom.perfectMatch, p->hardware_address.bytes(), ETH_ADDR_LEN);
1294032Sktlim@umich.edu
1302678Sktlim@umich.edu    memset(&rxDesc32, 0, sizeof(rxDesc32));
1312292SN/A    memset(&txDesc32, 0, sizeof(txDesc32));
1322292SN/A    memset(&rxDesc64, 0, sizeof(rxDesc64));
1332292SN/A    memset(&txDesc64, 0, sizeof(txDesc64));
1342292SN/A}
1352678Sktlim@umich.edu
1362678Sktlim@umich.eduNSGigE::~NSGigE()
1376974Stjones1@inf.ed.ac.uk{
1382292SN/A    delete interface;
1392292SN/A}
1402292SN/A
1412292SN/A/**
1422292SN/A * This is to write to the PCI general configuration registers
1435529Snate@binkert.org */
1445529Snate@binkert.orgTick
1455529Snate@binkert.orgNSGigE::writeConfig(PacketPtr pkt)
1462292SN/A{
1474329Sktlim@umich.edu    int offset = pkt->getAddr() & PCI_CONFIG_SIZE;
1484329Sktlim@umich.edu    if (offset < PCI_DEVICE_SPECIFIC)
1494329Sktlim@umich.edu        PciDev::writeConfig(pkt);
1504329Sktlim@umich.edu    else
1512292SN/A        panic("Device specific PCI config space not implemented!\n");
1522307SN/A
1532307SN/A    switch (offset) {
1542907Sktlim@umich.edu        // seems to work fine without all these PCI settings, but i
1552907Sktlim@umich.edu        // put in the IO to double check, an assertion will fail if we
1562292SN/A        // need to properly implement it
1572292SN/A      case PCI_COMMAND:
1582329SN/A        if (config.data[offset] & PCI_CMD_IOSE)
1592329SN/A            ioEnable = true;
1602329SN/A        else
1612292SN/A            ioEnable = false;
1622292SN/A        break;
1632292SN/A    }
1642292SN/A
1652292SN/A    return configDelay;
1662292SN/A}
1672292SN/A
1682292SN/AEtherInt*
1692292SN/ANSGigE::getEthPort(const std::string &if_name, int idx)
1702292SN/A{
1712292SN/A    if (if_name == "interface") {
1723492Sktlim@umich.edu       if (interface->getPeer())
1732329SN/A           panic("interface already connected to\n");
1742292SN/A       return interface;
1752292SN/A    }
1762292SN/A    return NULL;
1772292SN/A}
1782292SN/A
1792292SN/A/**
1802292SN/A * This reads the device registers, which are detailed in the NS83820
1812292SN/A * spec sheet
1822292SN/A */
1832292SN/ATick
1842292SN/ANSGigE::read(PacketPtr pkt)
1852292SN/A{
1862292SN/A    assert(ioEnable);
1872292SN/A
1882292SN/A    pkt->allocate();
1892292SN/A
1902292SN/A    //The mask is to give you only the offset into the device register file
1912727Sktlim@umich.edu    Addr daddr = pkt->getAddr() & 0xfff;
1922727Sktlim@umich.edu    DPRINTF(EthernetPIO, "read  da=%#x pa=%#x size=%d\n",
1932727Sktlim@umich.edu            daddr, pkt->getAddr(), pkt->getSize());
1942727Sktlim@umich.edu
1952727Sktlim@umich.edu
1962727Sktlim@umich.edu    // there are some reserved registers, you can see ns_gige_reg.h and
1972727Sktlim@umich.edu    // the spec sheet for details
1982727Sktlim@umich.edu    if (daddr > LAST && daddr <=  RESERVED) {
1992727Sktlim@umich.edu        panic("Accessing reserved register");
2002727Sktlim@umich.edu    } else if (daddr > RESERVED && daddr <= 0x3FC) {
2012727Sktlim@umich.edu        return readConfig(pkt);
2022727Sktlim@umich.edu    } else if (daddr >= MIB_START && daddr <= MIB_END) {
2032727Sktlim@umich.edu        // don't implement all the MIB's.  hopefully the kernel
2042727Sktlim@umich.edu        // doesn't actually DEPEND upon their values
2052727Sktlim@umich.edu        // MIB are just hardware stats keepers
2062727Sktlim@umich.edu        pkt->set<uint32_t>(0);
2072727Sktlim@umich.edu        pkt->makeAtomicResponse();
2082727Sktlim@umich.edu        return pioDelay;
2092361SN/A    } else if (daddr > 0x3FC)
2102361SN/A        panic("Something is messed up!\n");
2112361SN/A
2122361SN/A    assert(pkt->getSize() == sizeof(uint32_t));
2132727Sktlim@umich.edu        uint32_t &reg = *pkt->getPtr<uint32_t>();
2142727Sktlim@umich.edu        uint16_t rfaddr;
2152727Sktlim@umich.edu
2162727Sktlim@umich.edu        switch (daddr) {
2172727Sktlim@umich.edu          case CR:
2182727Sktlim@umich.edu            reg = regs.command;
2192727Sktlim@umich.edu            //these are supposed to be cleared on a read
2202727Sktlim@umich.edu            reg &= ~(CR_RXD | CR_TXD | CR_TXR | CR_RXR);
2212727Sktlim@umich.edu            break;
2222727Sktlim@umich.edu
2232727Sktlim@umich.edu          case CFGR:
2242727Sktlim@umich.edu            reg = regs.config;
2252727Sktlim@umich.edu            break;
2262727Sktlim@umich.edu
2272727Sktlim@umich.edu          case MEAR:
2282727Sktlim@umich.edu            reg = regs.mear;
2292727Sktlim@umich.edu            break;
2302727Sktlim@umich.edu
2312727Sktlim@umich.edu          case PTSCR:
2322727Sktlim@umich.edu            reg = regs.ptscr;
2332727Sktlim@umich.edu            break;
2342727Sktlim@umich.edu
2352727Sktlim@umich.edu          case ISR:
2364329Sktlim@umich.edu            reg = regs.isr;
2374329Sktlim@umich.edu            devIntrClear(ISR_ALL);
2384329Sktlim@umich.edu            break;
2394329Sktlim@umich.edu
2404329Sktlim@umich.edu          case IMR:
2414329Sktlim@umich.edu            reg = regs.imr;
2424329Sktlim@umich.edu            break;
2434329Sktlim@umich.edu
2444329Sktlim@umich.edu          case IER:
2454329Sktlim@umich.edu            reg = regs.ier;
2464329Sktlim@umich.edu            break;
2474329Sktlim@umich.edu
2484329Sktlim@umich.edu          case IHR:
2492292SN/A            reg = regs.ihr;
2502292SN/A            break;
2512292SN/A
2522292SN/A          case TXDP:
2532292SN/A            reg = regs.txdp;
2542292SN/A            break;
2552292SN/A
2562292SN/A          case TXDP_HI:
2572292SN/A            reg = regs.txdp_hi;
2582292SN/A            break;
2592292SN/A
2602292SN/A          case TX_CFG:
2612292SN/A            reg = regs.txcfg;
2622292SN/A            break;
2632307SN/A
2642307SN/A          case GPIOR:
2652307SN/A            reg = regs.gpior;
2662367SN/A            break;
2672367SN/A
2682307SN/A          case RXDP:
2692367SN/A            reg = regs.rxdp;
2702307SN/A            break;
2712329SN/A
2722307SN/A          case RXDP_HI:
2732307SN/A            reg = regs.rxdp_hi;
2742307SN/A            break;
2752307SN/A
2762307SN/A          case RX_CFG:
2772307SN/A            reg = regs.rxcfg;
2782307SN/A            break;
2792307SN/A
2802307SN/A          case PQCR:
2812307SN/A            reg = regs.pqcr;
2822307SN/A            break;
2832307SN/A
2842307SN/A          case WCSR:
2852307SN/A            reg = regs.wcsr;
2862307SN/A            break;
2872329SN/A
2882307SN/A          case PCR:
2892307SN/A            reg = regs.pcr;
2902307SN/A            break;
2912307SN/A
2922307SN/A            // see the spec sheet for how RFCR and RFDR work
2932307SN/A            // basically, you write to RFCR to tell the machine
2942307SN/A            // what you want to do next, then you act upon RFDR,
2952307SN/A            // and the device will be prepared b/c of what you
2962307SN/A            // wrote to RFCR
2972307SN/A          case RFCR:
2982292SN/A            reg = regs.rfcr;
2992292SN/A            break;
3002329SN/A
3012329SN/A          case RFDR:
3022292SN/A            rfaddr = (uint16_t)(regs.rfcr & RFCR_RFADDR);
3032329SN/A            switch (rfaddr) {
3042329SN/A              // Read from perfect match ROM octets
3052292SN/A              case 0x000:
3062292SN/A                reg = rom.perfectMatch[1];
3072292SN/A                reg = reg << 8;
3082292SN/A                reg += rom.perfectMatch[0];
3092292SN/A                break;
3102329SN/A              case 0x002:
3112292SN/A                reg = rom.perfectMatch[3] << 8;
3122292SN/A                reg += rom.perfectMatch[2];
3132292SN/A                break;
3142292SN/A              case 0x004:
3152292SN/A                reg = rom.perfectMatch[5] << 8;
3162292SN/A                reg += rom.perfectMatch[4];
3172292SN/A                break;
3182292SN/A              default:
3192329SN/A                // Read filter hash table
3202329SN/A                if (rfaddr >= FHASH_ADDR &&
3212329SN/A                    rfaddr < FHASH_ADDR + FHASH_SIZE) {
3222292SN/A
3232292SN/A                    // Only word-aligned reads supported
3242292SN/A                    if (rfaddr % 2)
3252292SN/A                        panic("unaligned read from filter hash table!");
3262292SN/A
3272329SN/A                    reg = rom.filterHash[rfaddr - FHASH_ADDR + 1] << 8;
3282292SN/A                    reg += rom.filterHash[rfaddr - FHASH_ADDR];
3292292SN/A                    break;
3302292SN/A                }
3312292SN/A
3322292SN/A                panic("reading RFDR for something other than pattern"
3332292SN/A                      " matching or hashing! %#x\n", rfaddr);
3342292SN/A            }
3352292SN/A            break;
3362292SN/A
3372292SN/A          case SRR:
3382292SN/A            reg = regs.srr;
3392292SN/A            break;
3402292SN/A
3412292SN/A          case MIBC:
3422292SN/A            reg = regs.mibc;
3432292SN/A            reg &= ~(MIBC_MIBS | MIBC_ACLR);
3442292SN/A            break;
3452292SN/A
3462292SN/A          case VRCR:
3472292SN/A            reg = regs.vrcr;
3482292SN/A            break;
3492292SN/A
3502292SN/A          case VTCR:
3512292SN/A            reg = regs.vtcr;
3522329SN/A            break;
3532329SN/A
3542292SN/A          case VDR:
3557720Sgblack@eecs.umich.edu            reg = regs.vdr;
3567720Sgblack@eecs.umich.edu            break;
3572292SN/A
3582292SN/A          case CCSR:
3592292SN/A            reg = regs.ccsr;
3602292SN/A            break;
3612292SN/A
3622292SN/A          case TBICR:
3632292SN/A            reg = regs.tbicr;
3642292SN/A            break;
3652292SN/A
3662292SN/A          case TBISR:
3672292SN/A            reg = regs.tbisr;
3682292SN/A            break;
3692292SN/A
3702292SN/A          case TANAR:
3712292SN/A            reg = regs.tanar;
3722292SN/A            break;
3732292SN/A
3742292SN/A          case TANLPAR:
3752292SN/A            reg = regs.tanlpar;
3762292SN/A            break;
3772292SN/A
3782292SN/A          case TANER:
3792292SN/A            reg = regs.taner;
3802292SN/A            break;
3817720Sgblack@eecs.umich.edu
3827720Sgblack@eecs.umich.edu          case TESR:
3832292SN/A            reg = regs.tesr;
3842292SN/A            break;
3852292SN/A
3862292SN/A          case M5REG:
3872292SN/A            reg = 0;
3882292SN/A            if (params()->rx_thread)
3892292SN/A                reg |= M5REG_RX_THREAD;
3902292SN/A            if (params()->tx_thread)
3912292SN/A                reg |= M5REG_TX_THREAD;
3922292SN/A            if (params()->rss)
3932292SN/A                reg |= M5REG_RSS;
3942292SN/A            break;
3952292SN/A
3962292SN/A          default:
3972292SN/A            panic("reading unimplemented register: addr=%#x", daddr);
3982292SN/A        }
3992292SN/A
4002292SN/A        DPRINTF(EthernetPIO, "read from %#x: data=%d data=%#x\n",
4012292SN/A                daddr, reg, reg);
4022292SN/A
4032292SN/A    pkt->makeAtomicResponse();
4042292SN/A    return pioDelay;
4052292SN/A}
4062292SN/A
4072292SN/ATick
4082292SN/ANSGigE::write(PacketPtr pkt)
4092292SN/A{
4102292SN/A    assert(ioEnable);
4112292SN/A
4122292SN/A    Addr daddr = pkt->getAddr() & 0xfff;
4132292SN/A    DPRINTF(EthernetPIO, "write da=%#x pa=%#x size=%d\n",
4142292SN/A            daddr, pkt->getAddr(), pkt->getSize());
4152292SN/A
4162292SN/A    if (daddr > LAST && daddr <=  RESERVED) {
4172292SN/A        panic("Accessing reserved register");
4182292SN/A    } else if (daddr > RESERVED && daddr <= 0x3FC) {
4192292SN/A        return writeConfig(pkt);
4202292SN/A    } else if (daddr > 0x3FC)
4212292SN/A        panic("Something is messed up!\n");
4222292SN/A
4232292SN/A    if (pkt->getSize() == sizeof(uint32_t)) {
4242292SN/A        uint32_t reg = pkt->get<uint32_t>();
4252292SN/A        uint16_t rfaddr;
4262292SN/A
4272292SN/A        DPRINTF(EthernetPIO, "write data=%d data=%#x\n", reg, reg);
4282292SN/A
4292292SN/A        switch (daddr) {
4302292SN/A          case CR:
4312292SN/A            regs.command = reg;
4322292SN/A            if (reg & CR_TXD) {
4332292SN/A                txEnable = false;
4342292SN/A            } else if (reg & CR_TXE) {
4352292SN/A                txEnable = true;
4362292SN/A
4372292SN/A                // the kernel is enabling the transmit machine
4382292SN/A                if (txState == txIdle)
4392292SN/A                    txKick();
4402292SN/A            }
4412292SN/A
4422292SN/A            if (reg & CR_RXD) {
4434032Sktlim@umich.edu                rxEnable = false;
4442292SN/A            } else if (reg & CR_RXE) {
4452292SN/A                rxEnable = true;
4462292SN/A
4477720Sgblack@eecs.umich.edu                if (rxState == rxIdle)
4487720Sgblack@eecs.umich.edu                    rxKick();
4492292SN/A            }
4504032Sktlim@umich.edu
4514032Sktlim@umich.edu            if (reg & CR_TXR)
4522669Sktlim@umich.edu                txReset();
4532292SN/A
4547597Sminkyu.jeong@arm.com            if (reg & CR_RXR)
4557597Sminkyu.jeong@arm.com                rxReset();
4567597Sminkyu.jeong@arm.com
4572329SN/A            if (reg & CR_SWI)
4582329SN/A                devIntrPost(ISR_SWI);
4592367SN/A
4602367SN/A            if (reg & CR_RST) {
4617600Sminkyu.jeong@arm.com                txReset();
4627600Sminkyu.jeong@arm.com                rxReset();
4637600Sminkyu.jeong@arm.com
4644032Sktlim@umich.edu                regsReset();
4653731Sktlim@umich.edu            }
4662367SN/A            break;
4672367SN/A
4682292SN/A          case CFGR:
4692292SN/A            if (reg & CFGR_LNKSTS ||
4704032Sktlim@umich.edu                reg & CFGR_SPDSTS ||
4714032Sktlim@umich.edu                reg & CFGR_DUPSTS ||
4724032Sktlim@umich.edu                reg & CFGR_RESERVED ||
4734032Sktlim@umich.edu                reg & CFGR_T64ADDR ||
4744032Sktlim@umich.edu                reg & CFGR_PCI64_DET) {
4754032Sktlim@umich.edu                // First clear all writable bits
4764032Sktlim@umich.edu                regs.config &= CFGR_LNKSTS | CFGR_SPDSTS | CFGR_DUPSTS |
4774032Sktlim@umich.edu                    CFGR_RESERVED | CFGR_T64ADDR |
4784032Sktlim@umich.edu                    CFGR_PCI64_DET;
4794032Sktlim@umich.edu                // Now set the appropriate writable bits
4804032Sktlim@umich.edu                regs.config |= reg & ~(CFGR_LNKSTS | CFGR_SPDSTS | CFGR_DUPSTS |
4814032Sktlim@umich.edu                                       CFGR_RESERVED | CFGR_T64ADDR |
4827616Sminkyu.jeong@arm.com                                       CFGR_PCI64_DET);
4837616Sminkyu.jeong@arm.com            }
4847616Sminkyu.jeong@arm.com
4857616Sminkyu.jeong@arm.com// all these #if 0's are because i don't THINK the kernel needs to
4864032Sktlim@umich.edu// have these implemented. if there is a problem relating to one of
4877616Sminkyu.jeong@arm.com// these, you may need to add functionality in.
4887616Sminkyu.jeong@arm.com
4897616Sminkyu.jeong@arm.com// grouped together and #if 0'ed to avoid empty if body and make clang happy
4904032Sktlim@umich.edu#if 0
4914032Sktlim@umich.edu            if (reg & CFGR_TBI_EN) ;
4924032Sktlim@umich.edu            if (reg & CFGR_MODE_1000) ;
4934032Sktlim@umich.edu
4944032Sktlim@umich.edu            if (reg & CFGR_PINT_DUPSTS ||
4954032Sktlim@umich.edu                reg & CFGR_PINT_LNKSTS ||
4964032Sktlim@umich.edu                reg & CFGR_PINT_SPDSTS)
4974032Sktlim@umich.edu                ;
4984032Sktlim@umich.edu
4994032Sktlim@umich.edu            if (reg & CFGR_TMRTEST) ;
5004032Sktlim@umich.edu            if (reg & CFGR_MRM_DIS) ;
5014032Sktlim@umich.edu            if (reg & CFGR_MWI_DIS) ;
5024032Sktlim@umich.edu
5034032Sktlim@umich.edu            if (reg & CFGR_DATA64_EN) ;
5044032Sktlim@umich.edu            if (reg & CFGR_M64ADDR) ;
5054032Sktlim@umich.edu            if (reg & CFGR_PHY_RST) ;
5064032Sktlim@umich.edu            if (reg & CFGR_PHY_DIS) ;
5072292SN/A
5082292SN/A            if (reg & CFGR_REQALG) ;
5092292SN/A            if (reg & CFGR_SB) ;
5102292SN/A            if (reg & CFGR_POW) ;
5112292SN/A            if (reg & CFGR_EXD) ;
5122292SN/A            if (reg & CFGR_PESEL) ;
5132292SN/A            if (reg & CFGR_BROM_DIS) ;
5142292SN/A            if (reg & CFGR_EXT_125) ;
5152292SN/A            if (reg & CFGR_BEM) ;
5162292SN/A
5172292SN/A            if (reg & CFGR_T64ADDR) ;
5182292SN/A            // panic("CFGR_T64ADDR is read only register!\n");
5192292SN/A#endif
5202292SN/A            if (reg & CFGR_AUTO_1000)
5212292SN/A                panic("CFGR_AUTO_1000 not implemented!\n");
5227720Sgblack@eecs.umich.edu
5237720Sgblack@eecs.umich.edu            if (reg & CFGR_PCI64_DET)
5242292SN/A                panic("CFGR_PCI64_DET is read only register!\n");
5254032Sktlim@umich.edu
5264032Sktlim@umich.edu            if (reg & CFGR_EXTSTS_EN)
5272292SN/A                extstsEnable = true;
5282292SN/A            else
5292292SN/A                extstsEnable = false;
5302292SN/A            break;
5312292SN/A
5322292SN/A          case MEAR:
5332329SN/A            // Clear writable bits
5347782Sminkyu.jeong@arm.com            regs.mear &= MEAR_EEDO;
5357720Sgblack@eecs.umich.edu            // Set appropriate writable bits
5362292SN/A            regs.mear |= reg & ~MEAR_EEDO;
5372292SN/A
5387782Sminkyu.jeong@arm.com            // FreeBSD uses the EEPROM to read PMATCH (for the MAC address)
5397782Sminkyu.jeong@arm.com            // even though it could get it through RFDR
5407782Sminkyu.jeong@arm.com            if (reg & MEAR_EESEL) {
5417782Sminkyu.jeong@arm.com                // Rising edge of clock
5422292SN/A                if (reg & MEAR_EECLK && !eepromClk)
5432292SN/A                    eepromKick();
5442292SN/A            }
5452292SN/A            else {
5462336SN/A                eepromState = eepromStart;
5472336SN/A                regs.mear &= ~MEAR_EEDI;
5482336SN/A            }
5492329SN/A
5502292SN/A            eepromClk = reg & MEAR_EECLK;
5512329SN/A
5522292SN/A            // since phy is completely faked, MEAR_MD* don't matter
5532292SN/A
5544032Sktlim@umich.edu// grouped together and #if 0'ed to avoid empty if body and make clang happy
5554032Sktlim@umich.edu#if 0
5564032Sktlim@umich.edu            if (reg & MEAR_MDIO) ;
5574032Sktlim@umich.edu            if (reg & MEAR_MDDIR) ;
5584032Sktlim@umich.edu            if (reg & MEAR_MDC) ;
5592292SN/A#endif
5604032Sktlim@umich.edu            break;
5614032Sktlim@umich.edu
5624032Sktlim@umich.edu          case PTSCR:
5632329SN/A            regs.ptscr = reg & ~(PTSCR_RBIST_RDONLY);
5644032Sktlim@umich.edu            // these control BISTs for various parts of chip - we
5657616Sminkyu.jeong@arm.com            // don't care or do just fake that the BIST is done
5667616Sminkyu.jeong@arm.com            if (reg & PTSCR_RBIST_EN)
5677616Sminkyu.jeong@arm.com                regs.ptscr |= PTSCR_RBIST_DONE;
5687616Sminkyu.jeong@arm.com            if (reg & PTSCR_EEBIST_EN)
5694032Sktlim@umich.edu                regs.ptscr &= ~PTSCR_EEBIST_EN;
5707616Sminkyu.jeong@arm.com            if (reg & PTSCR_EELOAD_EN)
5717616Sminkyu.jeong@arm.com                regs.ptscr &= ~PTSCR_EELOAD_EN;
5727616Sminkyu.jeong@arm.com            break;
5734032Sktlim@umich.edu
5744032Sktlim@umich.edu          case ISR: /* writing to the ISR has no effect */
5754032Sktlim@umich.edu            panic("ISR is a read only register!\n");
5764032Sktlim@umich.edu
5774032Sktlim@umich.edu          case IMR:
5784032Sktlim@umich.edu            regs.imr = reg;
5794032Sktlim@umich.edu            devIntrChangeMask();
5804032Sktlim@umich.edu            break;
5812292SN/A
5822292SN/A          case IER:
5834032Sktlim@umich.edu            regs.ier = reg;
5844032Sktlim@umich.edu            break;
5854032Sktlim@umich.edu
5862292SN/A          case IHR:
5872292SN/A            regs.ihr = reg;
5884032Sktlim@umich.edu            /* not going to implement real interrupt holdoff */
5892292SN/A            break;
5902292SN/A
5912292SN/A          case TXDP:
5922292SN/A            regs.txdp = (reg & 0xFFFFFFFC);
5932292SN/A            assert(txState == txIdle);
5942292SN/A            CTDD = false;
5952292SN/A            break;
5962292SN/A
5972292SN/A          case TXDP_HI:
5982292SN/A            regs.txdp_hi = reg;
5992292SN/A            break;
6007720Sgblack@eecs.umich.edu
6017720Sgblack@eecs.umich.edu          case TX_CFG:
6022292SN/A            regs.txcfg = reg;
6032292SN/A#if 0
6042292SN/A            if (reg & TX_CFG_CSI) ;
6052292SN/A            if (reg & TX_CFG_HBI) ;
6062292SN/A            if (reg & TX_CFG_MLB) ;
6072292SN/A            if (reg & TX_CFG_ATP) ;
6082292SN/A            if (reg & TX_CFG_ECRETRY) {
6092292SN/A                /*
6102292SN/A                 * this could easily be implemented, but considering
6112292SN/A                 * the network is just a fake pipe, wouldn't make
6122292SN/A                 * sense to do this
6132292SN/A                 */
6142292SN/A            }
6152292SN/A
6162292SN/A            if (reg & TX_CFG_BRST_DIS) ;
6172292SN/A#endif
6182292SN/A
6192292SN/A#if 0
6202292SN/A            /* we handle our own DMA, ignore the kernel's exhortations */
6212292SN/A            if (reg & TX_CFG_MXDMA) ;
6222292SN/A#endif
6232292SN/A
6242292SN/A            // also, we currently don't care about fill/drain
6252292SN/A            // thresholds though this may change in the future with
6262292SN/A            // more realistic networks or a driver which changes it
6272292SN/A            // according to feedback
6282292SN/A
6292292SN/A            break;
6302292SN/A
6312329SN/A          case GPIOR:
6322329SN/A            // Only write writable bits
6332292SN/A            regs.gpior &= GPIOR_UNUSED | GPIOR_GP5_IN | GPIOR_GP4_IN
6342292SN/A                        | GPIOR_GP3_IN | GPIOR_GP2_IN | GPIOR_GP1_IN;
6352292SN/A            regs.gpior |= reg & ~(GPIOR_UNUSED | GPIOR_GP5_IN | GPIOR_GP4_IN
6362292SN/A                                | GPIOR_GP3_IN | GPIOR_GP2_IN | GPIOR_GP1_IN);
6372292SN/A            /* these just control general purpose i/o pins, don't matter */
6387720Sgblack@eecs.umich.edu            break;
6397720Sgblack@eecs.umich.edu
6402292SN/A          case RXDP:
6412292SN/A            regs.rxdp = reg;
6422292SN/A            CRDD = false;
6432292SN/A            break;
6442292SN/A
6452292SN/A          case RXDP_HI:
6462292SN/A            regs.rxdp_hi = reg;
6472292SN/A            break;
6482292SN/A
6492292SN/A          case RX_CFG:
6502292SN/A            regs.rxcfg = reg;
6512292SN/A#if 0
6522292SN/A            if (reg & RX_CFG_AEP) ;
6536974Stjones1@inf.ed.ac.uk            if (reg & RX_CFG_ARP) ;
6546974Stjones1@inf.ed.ac.uk            if (reg & RX_CFG_STRIPCRC) ;
6556974Stjones1@inf.ed.ac.uk            if (reg & RX_CFG_RX_RD) ;
6566974Stjones1@inf.ed.ac.uk            if (reg & RX_CFG_ALP) ;
6576974Stjones1@inf.ed.ac.uk            if (reg & RX_CFG_AIRL) ;
6586974Stjones1@inf.ed.ac.uk
6596974Stjones1@inf.ed.ac.uk            /* we handle our own DMA, ignore what kernel says about it */
6606974Stjones1@inf.ed.ac.uk            if (reg & RX_CFG_MXDMA) ;
6616974Stjones1@inf.ed.ac.uk
6626974Stjones1@inf.ed.ac.uk            //also, we currently don't care about fill/drain thresholds
6636974Stjones1@inf.ed.ac.uk            //though this may change in the future with more realistic
6646974Stjones1@inf.ed.ac.uk            //networks or a driver which changes it according to feedback
6656974Stjones1@inf.ed.ac.uk            if (reg & (RX_CFG_DRTH | RX_CFG_DRTH0)) ;
6666974Stjones1@inf.ed.ac.uk#endif
6676974Stjones1@inf.ed.ac.uk            break;
6686974Stjones1@inf.ed.ac.uk
6692292SN/A          case PQCR:
6702292SN/A            /* there is no priority queueing used in the linux 2.6 driver */
6716974Stjones1@inf.ed.ac.uk            regs.pqcr = reg;
6726974Stjones1@inf.ed.ac.uk            break;
6736974Stjones1@inf.ed.ac.uk
6746974Stjones1@inf.ed.ac.uk          case WCSR:
6756974Stjones1@inf.ed.ac.uk            /* not going to implement wake on LAN */
6766974Stjones1@inf.ed.ac.uk            regs.wcsr = reg;
6772292SN/A            break;
6782292SN/A
6792292SN/A          case PCR:
6802292SN/A            /* not going to implement pause control */
6812292SN/A            regs.pcr = reg;
6822292SN/A            break;
6832907Sktlim@umich.edu
6842678Sktlim@umich.edu          case RFCR:
6852678Sktlim@umich.edu            regs.rfcr = reg;
6862678Sktlim@umich.edu
6872678Sktlim@umich.edu            rxFilterEnable = (reg & RFCR_RFEN) ? true : false;
6882678Sktlim@umich.edu            acceptBroadcast = (reg & RFCR_AAB) ? true : false;
6892329SN/A            acceptMulticast = (reg & RFCR_AAM) ? true : false;
6902329SN/A            acceptUnicast = (reg & RFCR_AAU) ? true : false;
6912292SN/A            acceptPerfect = (reg & RFCR_APM) ? true : false;
6922292SN/A            acceptArp = (reg & RFCR_AARP) ? true : false;
6932292SN/A            multicastHashEnable = (reg & RFCR_MHEN) ? true : false;
6942292SN/A
6952292SN/A#if 0
6962292SN/A            if (reg & RFCR_APAT)
6972292SN/A                panic("RFCR_APAT not implemented!\n");
6982678Sktlim@umich.edu#endif
6992292SN/A            if (reg & RFCR_UHEN)
7002292SN/A                panic("Unicast hash filtering not used by drivers!\n");
7012292SN/A
7022292SN/A            if (reg & RFCR_ULM)
7032292SN/A                panic("RFCR_ULM not implemented!\n");
7042292SN/A
7052292SN/A            break;
7062292SN/A
7072292SN/A          case RFDR:
7082292SN/A            rfaddr = (uint16_t)(regs.rfcr & RFCR_RFADDR);
7092292SN/A            switch (rfaddr) {
7106974Stjones1@inf.ed.ac.uk              case 0x000:
7116974Stjones1@inf.ed.ac.uk                rom.perfectMatch[0] = (uint8_t)reg;
7126974Stjones1@inf.ed.ac.uk                rom.perfectMatch[1] = (uint8_t)(reg >> 8);
7136974Stjones1@inf.ed.ac.uk                break;
7146974Stjones1@inf.ed.ac.uk              case 0x002:
7152669Sktlim@umich.edu                rom.perfectMatch[2] = (uint8_t)reg;
7162669Sktlim@umich.edu                rom.perfectMatch[3] = (uint8_t)(reg >> 8);
7172669Sktlim@umich.edu                break;
7182292SN/A              case 0x004:
7192292SN/A                rom.perfectMatch[4] = (uint8_t)reg;
7202669Sktlim@umich.edu                rom.perfectMatch[5] = (uint8_t)(reg >> 8);
7212669Sktlim@umich.edu                break;
7223772Sgblack@eecs.umich.edu              default:
7234326Sgblack@eecs.umich.edu
7242669Sktlim@umich.edu                if (rfaddr >= FHASH_ADDR &&
7254878Sstever@eecs.umich.edu                    rfaddr < FHASH_ADDR + FHASH_SIZE) {
7264878Sstever@eecs.umich.edu
7276102Sgblack@eecs.umich.edu                    // Only word-aligned writes supported
7286974Stjones1@inf.ed.ac.uk                    if (rfaddr % 2)
7296974Stjones1@inf.ed.ac.uk                        panic("unaligned write to filter hash table!");
7302292SN/A
7312678Sktlim@umich.edu                    rom.filterHash[rfaddr - FHASH_ADDR] = (uint8_t)reg;
7322678Sktlim@umich.edu                    rom.filterHash[rfaddr - FHASH_ADDR + 1]
7332678Sktlim@umich.edu                        = (uint8_t)(reg >> 8);
7342678Sktlim@umich.edu                    break;
7356974Stjones1@inf.ed.ac.uk                }
7366974Stjones1@inf.ed.ac.uk                panic("writing RFDR for something other than pattern matching\
7376974Stjones1@inf.ed.ac.uk                    or hashing! %#x\n", rfaddr);
7386974Stjones1@inf.ed.ac.uk            }
7396974Stjones1@inf.ed.ac.uk
7406974Stjones1@inf.ed.ac.uk          case BRAR:
7416974Stjones1@inf.ed.ac.uk            regs.brar = reg;
7426974Stjones1@inf.ed.ac.uk            break;
7436974Stjones1@inf.ed.ac.uk
7446974Stjones1@inf.ed.ac.uk          case BRDR:
7456974Stjones1@inf.ed.ac.uk            panic("the driver never uses BRDR, something is wrong!\n");
7466974Stjones1@inf.ed.ac.uk
7476974Stjones1@inf.ed.ac.uk          case SRR:
7486974Stjones1@inf.ed.ac.uk            panic("SRR is read only register!\n");
7496974Stjones1@inf.ed.ac.uk
7506974Stjones1@inf.ed.ac.uk          case MIBC:
7516974Stjones1@inf.ed.ac.uk            panic("the driver never uses MIBC, something is wrong!\n");
7526974Stjones1@inf.ed.ac.uk
7536974Stjones1@inf.ed.ac.uk          case VRCR:
7546974Stjones1@inf.ed.ac.uk            regs.vrcr = reg;
7556974Stjones1@inf.ed.ac.uk            break;
7566974Stjones1@inf.ed.ac.uk
7576974Stjones1@inf.ed.ac.uk          case VTCR:
7586974Stjones1@inf.ed.ac.uk            regs.vtcr = reg;
7596974Stjones1@inf.ed.ac.uk            break;
7606974Stjones1@inf.ed.ac.uk
7616974Stjones1@inf.ed.ac.uk          case VDR:
7626974Stjones1@inf.ed.ac.uk            panic("the driver never uses VDR, something is wrong!\n");
7632678Sktlim@umich.edu
7647720Sgblack@eecs.umich.edu          case CCSR:
7652292SN/A            /* not going to implement clockrun stuff */
7667720Sgblack@eecs.umich.edu            regs.ccsr = reg;
7673797Sgblack@eecs.umich.edu            break;
7683221Sktlim@umich.edu
7692292SN/A          case TBICR:
7702693Sktlim@umich.edu            regs.tbicr = reg;
7714350Sgblack@eecs.umich.edu            if (reg & TBICR_MR_LOOPBACK)
7726974Stjones1@inf.ed.ac.uk                panic("TBICR_MR_LOOPBACK never used, something wrong!\n");
7733326Sktlim@umich.edu
7743326Sktlim@umich.edu            if (reg & TBICR_MR_AN_ENABLE) {
7753326Sktlim@umich.edu                regs.tanlpar = regs.tanar;
7763326Sktlim@umich.edu                regs.tbisr |= (TBISR_MR_AN_COMPLETE | TBISR_MR_LINK_STATUS);
7773326Sktlim@umich.edu            }
7783326Sktlim@umich.edu
7793326Sktlim@umich.edu#if 0
7803326Sktlim@umich.edu            if (reg & TBICR_MR_RESTART_AN) ;
7813326Sktlim@umich.edu#endif
7823326Sktlim@umich.edu
7833326Sktlim@umich.edu            break;
7843326Sktlim@umich.edu
7853326Sktlim@umich.edu          case TBISR:
7865606Snate@binkert.org            panic("TBISR is read only register!\n");
7873326Sktlim@umich.edu
7883326Sktlim@umich.edu          case TANAR:
7893326Sktlim@umich.edu            // Only write the writable bits
7902693Sktlim@umich.edu            regs.tanar &= TANAR_RF1 | TANAR_RF2 | TANAR_UNUSED;
7912693Sktlim@umich.edu            regs.tanar |= reg & ~(TANAR_RF1 | TANAR_RF2 | TANAR_UNUSED);
7922693Sktlim@umich.edu
7932693Sktlim@umich.edu            // Pause capability unimplemented
7942693Sktlim@umich.edu#if 0
7952693Sktlim@umich.edu            if (reg & TANAR_PS2) ;
7966974Stjones1@inf.ed.ac.uk            if (reg & TANAR_PS1) ;
7974032Sktlim@umich.edu#endif
7983221Sktlim@umich.edu
7993221Sktlim@umich.edu            break;
8006974Stjones1@inf.ed.ac.uk
8016974Stjones1@inf.ed.ac.uk          case TANLPAR:
8026974Stjones1@inf.ed.ac.uk            panic("this should only be written to by the fake phy!\n");
8036974Stjones1@inf.ed.ac.uk
8046974Stjones1@inf.ed.ac.uk          case TANER:
8056974Stjones1@inf.ed.ac.uk            panic("TANER is read only register!\n");
8062669Sktlim@umich.edu
8076974Stjones1@inf.ed.ac.uk          case TESR:
8086974Stjones1@inf.ed.ac.uk            regs.tesr = reg;
8096974Stjones1@inf.ed.ac.uk            break;
8106974Stjones1@inf.ed.ac.uk
8116974Stjones1@inf.ed.ac.uk          default:
8126974Stjones1@inf.ed.ac.uk            panic("invalid register access daddr=%#x", daddr);
8136974Stjones1@inf.ed.ac.uk        }
8146974Stjones1@inf.ed.ac.uk    } else {
8156974Stjones1@inf.ed.ac.uk        panic("Invalid Request Size");
8166974Stjones1@inf.ed.ac.uk    }
8176974Stjones1@inf.ed.ac.uk    pkt->makeAtomicResponse();
8186974Stjones1@inf.ed.ac.uk    return pioDelay;
8196974Stjones1@inf.ed.ac.uk}
8206974Stjones1@inf.ed.ac.uk
8216974Stjones1@inf.ed.ac.ukvoid
8226974Stjones1@inf.ed.ac.ukNSGigE::devIntrPost(uint32_t interrupts)
8236974Stjones1@inf.ed.ac.uk{
8246974Stjones1@inf.ed.ac.uk    if (interrupts & ISR_RESERVE)
8256974Stjones1@inf.ed.ac.uk        panic("Cannot set a reserved interrupt");
8266974Stjones1@inf.ed.ac.uk
8276974Stjones1@inf.ed.ac.uk    if (interrupts & ISR_NOIMPL)
8286974Stjones1@inf.ed.ac.uk        warn("interrupt not implemented %#x\n", interrupts);
8296974Stjones1@inf.ed.ac.uk
8306974Stjones1@inf.ed.ac.uk    interrupts &= ISR_IMPL;
8316974Stjones1@inf.ed.ac.uk    regs.isr |= interrupts;
8326974Stjones1@inf.ed.ac.uk
8336974Stjones1@inf.ed.ac.uk    if (interrupts & regs.imr) {
8342292SN/A        if (interrupts & ISR_SWI) {
8352292SN/A            totalSwi++;
8362292SN/A        }
8372292SN/A        if (interrupts & ISR_RXIDLE) {
8382292SN/A            totalRxIdle++;
8392292SN/A        }
8402292SN/A        if (interrupts & ISR_RXOK) {
8412292SN/A            totalRxOk++;
8422292SN/A        }
8432292SN/A        if (interrupts & ISR_RXDESC) {
8442292SN/A            totalRxDesc++;
8452292SN/A        }
8462292SN/A        if (interrupts & ISR_TXOK) {
8472292SN/A            totalTxOk++;
8482292SN/A        }
8492292SN/A        if (interrupts & ISR_TXIDLE) {
8502292SN/A            totalTxIdle++;
8512292SN/A        }
8522292SN/A        if (interrupts & ISR_TXDESC) {
8532292SN/A            totalTxDesc++;
8542292SN/A        }
8552292SN/A        if (interrupts & ISR_RXORN) {
8562292SN/A            totalRxOrn++;
8572292SN/A        }
8582292SN/A    }
8592292SN/A
8602292SN/A    DPRINTF(EthernetIntr,
8612292SN/A            "interrupt written to ISR: intr=%#x isr=%#x imr=%#x\n",
8622329SN/A            interrupts, regs.isr, regs.imr);
8632292SN/A
8642292SN/A    if ((regs.isr & regs.imr)) {
8652292SN/A        Tick when = curTick();
8662292SN/A        if ((regs.isr & regs.imr & ISR_NODELAY) == 0)
8672292SN/A            when += intrDelay;
8687720Sgblack@eecs.umich.edu        postedInterrupts++;
8692292SN/A        cpuIntrPost(when);
8707720Sgblack@eecs.umich.edu    }
8712292SN/A}
8722292SN/A
8732292SN/A/* writing this interrupt counting stats inside this means that this function
8742292SN/A   is now limited to being used to clear all interrupts upon the kernel
8752292SN/A   reading isr and servicing.  just telling you in case you were thinking
8762292SN/A   of expanding use.
8772292SN/A*/
8782292SN/Avoid
8792329SN/ANSGigE::devIntrClear(uint32_t interrupts)
8802731Sktlim@umich.edu{
8812292SN/A    if (interrupts & ISR_RESERVE)
8822292SN/A        panic("Cannot clear a reserved interrupt");
8832292SN/A
8842292SN/A    if (regs.isr & regs.imr & ISR_SWI) {
8852292SN/A        postedSwi++;
8862292SN/A    }
8872292SN/A    if (regs.isr & regs.imr & ISR_RXIDLE) {
8882727Sktlim@umich.edu        postedRxIdle++;
8892292SN/A    }
8902292SN/A    if (regs.isr & regs.imr & ISR_RXOK) {
8912292SN/A        postedRxOk++;
8922292SN/A    }
8932292SN/A    if (regs.isr & regs.imr & ISR_RXDESC) {
8942292SN/A            postedRxDesc++;
8952292SN/A    }
8962292SN/A    if (regs.isr & regs.imr & ISR_TXOK) {
8972292SN/A        postedTxOk++;
8982292SN/A    }
8994032Sktlim@umich.edu    if (regs.isr & regs.imr & ISR_TXIDLE) {
9004032Sktlim@umich.edu        postedTxIdle++;
9014032Sktlim@umich.edu    }
9024032Sktlim@umich.edu    if (regs.isr & regs.imr & ISR_TXDESC) {
9032292SN/A        postedTxDesc++;
9042292SN/A    }
9052292SN/A    if (regs.isr & regs.imr & ISR_RXORN) {
9062292SN/A        postedRxOrn++;
9072292SN/A    }
9082329SN/A
9092292SN/A    interrupts &= ~ISR_NOIMPL;
9102292SN/A    regs.isr &= ~interrupts;
9112292SN/A
9122292SN/A    DPRINTF(EthernetIntr,
9137720Sgblack@eecs.umich.edu            "interrupt cleared from ISR: intr=%x isr=%x imr=%x\n",
9142292SN/A            interrupts, regs.isr, regs.imr);
9157720Sgblack@eecs.umich.edu
9162292SN/A    if (!(regs.isr & regs.imr))
9172292SN/A        cpuIntrClear();
9182329SN/A}
9192329SN/A
9202292SN/Avoid
9212292SN/ANSGigE::devIntrChangeMask()
9222292SN/A{
9232292SN/A    DPRINTF(EthernetIntr, "interrupt mask changed: isr=%x imr=%x masked=%x\n",
9242292SN/A            regs.isr, regs.imr, regs.isr & regs.imr);
9252292SN/A
9262292SN/A    if (regs.isr & regs.imr)
9272329SN/A        cpuIntrPost(curTick());
9282731Sktlim@umich.edu    else
9292292SN/A        cpuIntrClear();
9302292SN/A}
9312292SN/A
9324032Sktlim@umich.eduvoid
9334032Sktlim@umich.eduNSGigE::cpuIntrPost(Tick when)
9344032Sktlim@umich.edu{
9354032Sktlim@umich.edu    // If the interrupt you want to post is later than an interrupt
9366974Stjones1@inf.ed.ac.uk    // already scheduled, just let it post in the coming one and don't
9376974Stjones1@inf.ed.ac.uk    // schedule another.
9386974Stjones1@inf.ed.ac.uk    // HOWEVER, must be sure that the scheduled intrTick is in the
9396974Stjones1@inf.ed.ac.uk    // future (this was formerly the source of a bug)
9406974Stjones1@inf.ed.ac.uk    /**
9416974Stjones1@inf.ed.ac.uk     * @todo this warning should be removed and the intrTick code should
9426974Stjones1@inf.ed.ac.uk     * be fixed.
9434032Sktlim@umich.edu     */
9442292SN/A    assert(when >= curTick());
9452292SN/A    assert(intrTick >= curTick() || intrTick == 0);
9462292SN/A    if (when > intrTick && intrTick != 0) {
9472292SN/A        DPRINTF(EthernetIntr, "don't need to schedule event...intrTick=%d\n",
9482292SN/A                intrTick);
9492292SN/A        return;
9502292SN/A    }
9512727Sktlim@umich.edu
9522292SN/A    intrTick = when;
9532292SN/A    if (intrTick < curTick()) {
9542292SN/A        Debug::breakpoint();
9552292SN/A        intrTick = curTick();
9562292SN/A    }
9573349Sbinkertn@umich.edu
9582693Sktlim@umich.edu    DPRINTF(EthernetIntr, "going to schedule an interrupt for intrTick=%d\n",
9592693Sktlim@umich.edu            intrTick);
9602693Sktlim@umich.edu
9612693Sktlim@umich.edu    if (intrEvent)
9622693Sktlim@umich.edu        intrEvent->squash();
9632693Sktlim@umich.edu    intrEvent = new IntrEvent(this, true);
9642693Sktlim@umich.edu    schedule(intrEvent, intrTick);
9652693Sktlim@umich.edu}
9662693Sktlim@umich.edu
9672693Sktlim@umich.eduvoid
9682693Sktlim@umich.eduNSGigE::cpuInterrupt()
9692693Sktlim@umich.edu{
9702693Sktlim@umich.edu    assert(intrTick == curTick());
9712693Sktlim@umich.edu
9722693Sktlim@umich.edu    // Whether or not there's a pending interrupt, we don't care about
9732693Sktlim@umich.edu    // it anymore
9742733Sktlim@umich.edu    intrEvent = 0;
9752693Sktlim@umich.edu    intrTick = 0;
9762732Sktlim@umich.edu
9772693Sktlim@umich.edu    // Don't send an interrupt if there's already one
9782733Sktlim@umich.edu    if (cpuPendingIntr) {
9792693Sktlim@umich.edu        DPRINTF(EthernetIntr,
9802693Sktlim@umich.edu                "would send an interrupt now, but there's already pending\n");
9812693Sktlim@umich.edu    } else {
9822693Sktlim@umich.edu        // Send interrupt
9832693Sktlim@umich.edu        cpuPendingIntr = true;
9842693Sktlim@umich.edu
9852693Sktlim@umich.edu        DPRINTF(EthernetIntr, "posting interrupt\n");
9862678Sktlim@umich.edu        intrPost();
9872678Sktlim@umich.edu    }
9882678Sktlim@umich.edu}
9892678Sktlim@umich.edu
9902678Sktlim@umich.eduvoid
9912678Sktlim@umich.eduNSGigE::cpuIntrClear()
9922927Sktlim@umich.edu{
9932678Sktlim@umich.edu    if (!cpuPendingIntr)
9942727Sktlim@umich.edu        return;
9952678Sktlim@umich.edu
9962678Sktlim@umich.edu    if (intrEvent) {
9972678Sktlim@umich.edu        intrEvent->squash();
9982678Sktlim@umich.edu        intrEvent = 0;
9992678Sktlim@umich.edu    }
10002678Sktlim@umich.edu
10012678Sktlim@umich.edu    intrTick = 0;
10022678Sktlim@umich.edu
10032678Sktlim@umich.edu    cpuPendingIntr = false;
10042678Sktlim@umich.edu
10052678Sktlim@umich.edu    DPRINTF(EthernetIntr, "clearing interrupt\n");
10062678Sktlim@umich.edu    intrClear();
10072678Sktlim@umich.edu}
10082678Sktlim@umich.edu
10097598Sminkyu.jeong@arm.combool
10107598Sminkyu.jeong@arm.comNSGigE::cpuIntrPending() const
10117598Sminkyu.jeong@arm.com{ return cpuPendingIntr; }
10122678Sktlim@umich.edu
10132678Sktlim@umich.eduvoid
10142678Sktlim@umich.eduNSGigE::txReset()
10152678Sktlim@umich.edu{
10162292SN/A
10172292SN/A    DPRINTF(Ethernet, "transmit reset\n");
10182292SN/A
10192292SN/A    CTDD = false;
10202292SN/A    txEnable = false;;
10212292SN/A    txFragPtr = 0;
10222292SN/A    assert(txDescCnt == 0);
10232292SN/A    txFifo.clear();
10243126Sktlim@umich.edu    txState = txIdle;
10252292SN/A    assert(txDmaState == dmaIdle);
10262292SN/A}
10272292SN/A
10282292SN/Avoid
10292292SN/ANSGigE::rxReset()
10302292SN/A{
10312292SN/A    DPRINTF(Ethernet, "receive reset\n");
10322292SN/A
10332292SN/A    CRDD = false;
10342292SN/A    assert(rxPktBytes == 0);
10352292SN/A    rxEnable = false;
10362292SN/A    rxFragPtr = 0;
10372292SN/A    assert(rxDescCnt == 0);
10382329SN/A    assert(rxDmaState == dmaIdle);
10392329SN/A    rxFifo.clear();
10402329SN/A    rxState = rxIdle;
10412292SN/A}
10422292SN/A
10432292SN/Avoid
10442292SN/ANSGigE::regsReset()
10452292SN/A{
10462292SN/A    memset(&regs, 0, sizeof(regs));
10472292SN/A    regs.config = (CFGR_LNKSTS | CFGR_TBI_EN | CFGR_MODE_1000);
10482292SN/A    regs.mear = 0x12;
10492292SN/A    regs.txcfg = 0x120; // set drain threshold to 1024 bytes and
10502292SN/A                        // fill threshold to 32 bytes
10512316SN/A    regs.rxcfg = 0x4;   // set drain threshold to 16 bytes
10522316SN/A    regs.srr = 0x0103;  // set the silicon revision to rev B or 0x103
10532329SN/A    regs.mibc = MIBC_FRZ;
10542329SN/A    regs.vdr = 0x81;    // set the vlan tag type to 802.1q
10552329SN/A    regs.tesr = 0xc000; // TBI capable of both full and half duplex
10562329SN/A    regs.brar = 0xffffffff;
10572733Sktlim@umich.edu
10582316SN/A    extstsEnable = false;
10592732Sktlim@umich.edu    acceptBroadcast = false;
10602316SN/A    acceptMulticast = false;
10612733Sktlim@umich.edu    acceptUnicast = false;
10622292SN/A    acceptPerfect = false;
10632292SN/A    acceptArp = false;
10642292SN/A}
10656974Stjones1@inf.ed.ac.uk
10666974Stjones1@inf.ed.ac.ukbool
10676974Stjones1@inf.ed.ac.ukNSGigE::doRxDmaRead()
10686974Stjones1@inf.ed.ac.uk{
10696974Stjones1@inf.ed.ac.uk    assert(rxDmaState == dmaIdle || rxDmaState == dmaReadWaiting);
10706974Stjones1@inf.ed.ac.uk    rxDmaState = dmaReading;
10716974Stjones1@inf.ed.ac.uk
10726974Stjones1@inf.ed.ac.uk    if (dmaPending() || getDrainState() != Drainable::Running)
10736974Stjones1@inf.ed.ac.uk        rxDmaState = dmaReadWaiting;
10746974Stjones1@inf.ed.ac.uk    else
10756974Stjones1@inf.ed.ac.uk        dmaRead(rxDmaAddr, rxDmaLen, &rxDmaReadEvent, (uint8_t*)rxDmaData);
10766974Stjones1@inf.ed.ac.uk
10776974Stjones1@inf.ed.ac.uk    return true;
10786974Stjones1@inf.ed.ac.uk}
10796974Stjones1@inf.ed.ac.uk
10806974Stjones1@inf.ed.ac.ukvoid
10812693Sktlim@umich.eduNSGigE::rxDmaReadDone()
10822693Sktlim@umich.edu{
10832693Sktlim@umich.edu    assert(rxDmaState == dmaReading);
10842698Sktlim@umich.edu    rxDmaState = dmaIdle;
10854985Sktlim@umich.edu
10862698Sktlim@umich.edu    DPRINTF(EthernetDMA, "rx dma read  paddr=%#x len=%d\n",
10872693Sktlim@umich.edu            rxDmaAddr, rxDmaLen);
10882698Sktlim@umich.edu    DDUMP(EthernetDMA, rxDmaData, rxDmaLen);
10896974Stjones1@inf.ed.ac.uk
10906974Stjones1@inf.ed.ac.uk    // If the transmit state machine has a pending DMA, let it go first
10916974Stjones1@inf.ed.ac.uk    if (txDmaState == dmaReadWaiting || txDmaState == dmaWriteWaiting)
10926974Stjones1@inf.ed.ac.uk        txKick();
10936974Stjones1@inf.ed.ac.uk
10946974Stjones1@inf.ed.ac.uk    rxKick();
10956974Stjones1@inf.ed.ac.uk}
10962699Sktlim@umich.edu
10972693Sktlim@umich.edubool
10986221Snate@binkert.orgNSGigE::doRxDmaWrite()
10996974Stjones1@inf.ed.ac.uk{
11006974Stjones1@inf.ed.ac.uk    assert(rxDmaState == dmaIdle || rxDmaState == dmaWriteWaiting);
11016974Stjones1@inf.ed.ac.uk    rxDmaState = dmaWriting;
11026974Stjones1@inf.ed.ac.uk
11036974Stjones1@inf.ed.ac.uk    if (dmaPending() || getDrainState() != Running)
11046974Stjones1@inf.ed.ac.uk        rxDmaState = dmaWriteWaiting;
11056974Stjones1@inf.ed.ac.uk    else
11066974Stjones1@inf.ed.ac.uk        dmaWrite(rxDmaAddr, rxDmaLen, &rxDmaWriteEvent, (uint8_t*)rxDmaData);
11072693Sktlim@umich.edu    return true;
11082693Sktlim@umich.edu}
11092727Sktlim@umich.edu
11102907Sktlim@umich.eduvoid
11112693Sktlim@umich.eduNSGigE::rxDmaWriteDone()
11122693Sktlim@umich.edu{
11132693Sktlim@umich.edu    assert(rxDmaState == dmaWriting);
11142693Sktlim@umich.edu    rxDmaState = dmaIdle;
11152693Sktlim@umich.edu
11162693Sktlim@umich.edu    DPRINTF(EthernetDMA, "rx dma write paddr=%#x len=%d\n",
11172693Sktlim@umich.edu            rxDmaAddr, rxDmaLen);
11182693Sktlim@umich.edu    DDUMP(EthernetDMA, rxDmaData, rxDmaLen);
11192693Sktlim@umich.edu
11202693Sktlim@umich.edu    // If the transmit state machine has a pending DMA, let it go first
11212292SN/A    if (txDmaState == dmaReadWaiting || txDmaState == dmaWriteWaiting)
11222292SN/A        txKick();
11232292SN/A
11242292SN/A    rxKick();
11252292SN/A}
11262292SN/A
11272292SN/Avoid
11282292SN/ANSGigE::rxKick()
11292292SN/A{
11302292SN/A    bool is64bit = (bool)(regs.config & CFGR_M64ADDR);
11312292SN/A
11322292SN/A    DPRINTF(EthernetSM,
11332292SN/A            "receive kick rxState=%s (rxBuf.size=%d) %d-bit\n",
11342292SN/A            NsRxStateStrings[rxState], rxFifo.size(), is64bit ? 64 : 32);
11352292SN/A
11362292SN/A    Addr link, bufptr;
11372292SN/A    uint32_t &cmdsts = is64bit ? rxDesc64.cmdsts : rxDesc32.cmdsts;
11382292SN/A    uint32_t &extsts = is64bit ? rxDesc64.extsts : rxDesc32.extsts;
11392292SN/A
11402292SN/A  next:
11412292SN/A    if (clock) {
11422292SN/A        if (rxKickTick > curTick()) {
11432292SN/A            DPRINTF(EthernetSM, "receive kick exiting, can't run till %d\n",
11442292SN/A                    rxKickTick);
11452292SN/A
11462292SN/A            goto exit;
11472292SN/A        }
11482292SN/A
11492292SN/A        // Go to the next state machine clock tick.
11502292SN/A        rxKickTick = curTick() + clockPeriod();
11512329SN/A    }
11522329SN/A
11532329SN/A    switch(rxDmaState) {
11542329SN/A      case dmaReadWaiting:
11552329SN/A        if (doRxDmaRead())
11562329SN/A            goto exit;
11572329SN/A        break;
11582329SN/A      case dmaWriteWaiting:
11592329SN/A        if (doRxDmaWrite())
11602329SN/A            goto exit;
11612329SN/A        break;
11622329SN/A      default:
11637720Sgblack@eecs.umich.edu        break;
11642329SN/A    }
11652329SN/A
11662329SN/A    link = is64bit ? (Addr)rxDesc64.link : (Addr)rxDesc32.link;
11672329SN/A    bufptr = is64bit ? (Addr)rxDesc64.bufptr : (Addr)rxDesc32.bufptr;
11682329SN/A
11692329SN/A    // see state machine from spec for details
11702329SN/A    // the way this works is, if you finish work on one state and can
11712329SN/A    // go directly to another, you do that through jumping to the
11722329SN/A    // label "next".  however, if you have intermediate work, like DMA
11732329SN/A    // so that you can't go to the next state yet, you go to exit and
11747720Sgblack@eecs.umich.edu    // exit the loop.  however, when the DMA is done it will trigger
11752329SN/A    // an event and come back to this loop.
11762329SN/A    switch (rxState) {
11772329SN/A      case rxIdle:
11782329SN/A        if (!rxEnable) {
11792329SN/A            DPRINTF(EthernetSM, "Receive Disabled! Nothing to do.\n");
11802329SN/A            goto exit;
1181        }
1182
1183        if (CRDD) {
1184            rxState = rxDescRefr;
1185
1186            rxDmaAddr = regs.rxdp & 0x3fffffff;
1187            rxDmaData =
1188                is64bit ? (void *)&rxDesc64.link : (void *)&rxDesc32.link;
1189            rxDmaLen = is64bit ? sizeof(rxDesc64.link) : sizeof(rxDesc32.link);
1190            rxDmaFree = dmaDescFree;
1191
1192            descDmaReads++;
1193            descDmaRdBytes += rxDmaLen;
1194
1195            if (doRxDmaRead())
1196                goto exit;
1197        } else {
1198            rxState = rxDescRead;
1199
1200            rxDmaAddr = regs.rxdp & 0x3fffffff;
1201            rxDmaData = is64bit ? (void *)&rxDesc64 : (void *)&rxDesc32;
1202            rxDmaLen = is64bit ? sizeof(rxDesc64) : sizeof(rxDesc32);
1203            rxDmaFree = dmaDescFree;
1204
1205            descDmaReads++;
1206            descDmaRdBytes += rxDmaLen;
1207
1208            if (doRxDmaRead())
1209                goto exit;
1210        }
1211        break;
1212
1213      case rxDescRefr:
1214        if (rxDmaState != dmaIdle)
1215            goto exit;
1216
1217        rxState = rxAdvance;
1218        break;
1219
1220     case rxDescRead:
1221        if (rxDmaState != dmaIdle)
1222            goto exit;
1223
1224        DPRINTF(EthernetDesc, "rxDesc: addr=%08x read descriptor\n",
1225                regs.rxdp & 0x3fffffff);
1226        DPRINTF(EthernetDesc,
1227                "rxDesc: link=%#x bufptr=%#x cmdsts=%08x extsts=%08x\n",
1228                link, bufptr, cmdsts, extsts);
1229
1230        if (cmdsts & CMDSTS_OWN) {
1231            devIntrPost(ISR_RXIDLE);
1232            rxState = rxIdle;
1233            goto exit;
1234        } else {
1235            rxState = rxFifoBlock;
1236            rxFragPtr = bufptr;
1237            rxDescCnt = cmdsts & CMDSTS_LEN_MASK;
1238        }
1239        break;
1240
1241      case rxFifoBlock:
1242        if (!rxPacket) {
1243            /**
1244             * @todo in reality, we should be able to start processing
1245             * the packet as it arrives, and not have to wait for the
1246             * full packet ot be in the receive fifo.
1247             */
1248            if (rxFifo.empty())
1249                goto exit;
1250
1251            DPRINTF(EthernetSM, "****processing receive of new packet****\n");
1252
1253            // If we don't have a packet, grab a new one from the fifo.
1254            rxPacket = rxFifo.front();
1255            rxPktBytes = rxPacket->length;
1256            rxPacketBufPtr = rxPacket->data;
1257
1258#if TRACING_ON
1259            if (DTRACE(Ethernet)) {
1260                IpPtr ip(rxPacket);
1261                if (ip) {
1262                    DPRINTF(Ethernet, "ID is %d\n", ip->id());
1263                    TcpPtr tcp(ip);
1264                    if (tcp) {
1265                        DPRINTF(Ethernet,
1266                                "Src Port=%d, Dest Port=%d, Seq=%d, Ack=%d\n",
1267                                tcp->sport(), tcp->dport(), tcp->seq(),
1268                                tcp->ack());
1269                    }
1270                }
1271            }
1272#endif
1273
1274            // sanity check - i think the driver behaves like this
1275            assert(rxDescCnt >= rxPktBytes);
1276            rxFifo.pop();
1277        }
1278
1279
1280        // dont' need the && rxDescCnt > 0 if driver sanity check
1281        // above holds
1282        if (rxPktBytes > 0) {
1283            rxState = rxFragWrite;
1284            // don't need min<>(rxPktBytes,rxDescCnt) if above sanity
1285            // check holds
1286            rxXferLen = rxPktBytes;
1287
1288            rxDmaAddr = rxFragPtr & 0x3fffffff;
1289            rxDmaData = rxPacketBufPtr;
1290            rxDmaLen = rxXferLen;
1291            rxDmaFree = dmaDataFree;
1292
1293            if (doRxDmaWrite())
1294                goto exit;
1295
1296        } else {
1297            rxState = rxDescWrite;
1298
1299            //if (rxPktBytes == 0) {  /* packet is done */
1300            assert(rxPktBytes == 0);
1301            DPRINTF(EthernetSM, "done with receiving packet\n");
1302
1303            cmdsts |= CMDSTS_OWN;
1304            cmdsts &= ~CMDSTS_MORE;
1305            cmdsts |= CMDSTS_OK;
1306            cmdsts &= 0xffff0000;
1307            cmdsts += rxPacket->length;   //i.e. set CMDSTS_SIZE
1308
1309#if 0
1310            /*
1311             * all the driver uses these are for its own stats keeping
1312             * which we don't care about, aren't necessary for
1313             * functionality and doing this would just slow us down.
1314             * if they end up using this in a later version for
1315             * functional purposes, just undef
1316             */
1317            if (rxFilterEnable) {
1318                cmdsts &= ~CMDSTS_DEST_MASK;
1319                const EthAddr &dst = rxFifoFront()->dst();
1320                if (dst->unicast())
1321                    cmdsts |= CMDSTS_DEST_SELF;
1322                if (dst->multicast())
1323                    cmdsts |= CMDSTS_DEST_MULTI;
1324                if (dst->broadcast())
1325                    cmdsts |= CMDSTS_DEST_MASK;
1326            }
1327#endif
1328
1329            IpPtr ip(rxPacket);
1330            if (extstsEnable && ip) {
1331                extsts |= EXTSTS_IPPKT;
1332                rxIpChecksums++;
1333                if (cksum(ip) != 0) {
1334                    DPRINTF(EthernetCksum, "Rx IP Checksum Error\n");
1335                    extsts |= EXTSTS_IPERR;
1336                }
1337                TcpPtr tcp(ip);
1338                UdpPtr udp(ip);
1339                if (tcp) {
1340                    extsts |= EXTSTS_TCPPKT;
1341                    rxTcpChecksums++;
1342                    if (cksum(tcp) != 0) {
1343                        DPRINTF(EthernetCksum, "Rx TCP Checksum Error\n");
1344                        extsts |= EXTSTS_TCPERR;
1345
1346                    }
1347                } else if (udp) {
1348                    extsts |= EXTSTS_UDPPKT;
1349                    rxUdpChecksums++;
1350                    if (cksum(udp) != 0) {
1351                        DPRINTF(EthernetCksum, "Rx UDP Checksum Error\n");
1352                        extsts |= EXTSTS_UDPERR;
1353                    }
1354                }
1355            }
1356            rxPacket = 0;
1357
1358            /*
1359             * the driver seems to always receive into desc buffers
1360             * of size 1514, so you never have a pkt that is split
1361             * into multiple descriptors on the receive side, so
1362             * i don't implement that case, hence the assert above.
1363             */
1364
1365            DPRINTF(EthernetDesc,
1366                    "rxDesc: addr=%08x writeback cmdsts extsts\n",
1367                    regs.rxdp & 0x3fffffff);
1368            DPRINTF(EthernetDesc,
1369                    "rxDesc: link=%#x bufptr=%#x cmdsts=%08x extsts=%08x\n",
1370                    link, bufptr, cmdsts, extsts);
1371
1372            rxDmaAddr = regs.rxdp & 0x3fffffff;
1373            rxDmaData = &cmdsts;
1374            if (is64bit) {
1375                rxDmaAddr += offsetof(ns_desc64, cmdsts);
1376                rxDmaLen = sizeof(rxDesc64.cmdsts) + sizeof(rxDesc64.extsts);
1377            } else {
1378                rxDmaAddr += offsetof(ns_desc32, cmdsts);
1379                rxDmaLen = sizeof(rxDesc32.cmdsts) + sizeof(rxDesc32.extsts);
1380            }
1381            rxDmaFree = dmaDescFree;
1382
1383            descDmaWrites++;
1384            descDmaWrBytes += rxDmaLen;
1385
1386            if (doRxDmaWrite())
1387                goto exit;
1388        }
1389        break;
1390
1391      case rxFragWrite:
1392        if (rxDmaState != dmaIdle)
1393            goto exit;
1394
1395        rxPacketBufPtr += rxXferLen;
1396        rxFragPtr += rxXferLen;
1397        rxPktBytes -= rxXferLen;
1398
1399        rxState = rxFifoBlock;
1400        break;
1401
1402      case rxDescWrite:
1403        if (rxDmaState != dmaIdle)
1404            goto exit;
1405
1406        assert(cmdsts & CMDSTS_OWN);
1407
1408        assert(rxPacket == 0);
1409        devIntrPost(ISR_RXOK);
1410
1411        if (cmdsts & CMDSTS_INTR)
1412            devIntrPost(ISR_RXDESC);
1413
1414        if (!rxEnable) {
1415            DPRINTF(EthernetSM, "Halting the RX state machine\n");
1416            rxState = rxIdle;
1417            goto exit;
1418        } else
1419            rxState = rxAdvance;
1420        break;
1421
1422      case rxAdvance:
1423        if (link == 0) {
1424            devIntrPost(ISR_RXIDLE);
1425            rxState = rxIdle;
1426            CRDD = true;
1427            goto exit;
1428        } else {
1429            if (rxDmaState != dmaIdle)
1430                goto exit;
1431            rxState = rxDescRead;
1432            regs.rxdp = link;
1433            CRDD = false;
1434
1435            rxDmaAddr = regs.rxdp & 0x3fffffff;
1436            rxDmaData = is64bit ? (void *)&rxDesc64 : (void *)&rxDesc32;
1437            rxDmaLen = is64bit ? sizeof(rxDesc64) : sizeof(rxDesc32);
1438            rxDmaFree = dmaDescFree;
1439
1440            if (doRxDmaRead())
1441                goto exit;
1442        }
1443        break;
1444
1445      default:
1446        panic("Invalid rxState!");
1447    }
1448
1449    DPRINTF(EthernetSM, "entering next rxState=%s\n",
1450            NsRxStateStrings[rxState]);
1451    goto next;
1452
1453  exit:
1454    /**
1455     * @todo do we want to schedule a future kick?
1456     */
1457    DPRINTF(EthernetSM, "rx state machine exited rxState=%s\n",
1458            NsRxStateStrings[rxState]);
1459
1460    if (clock && !rxKickEvent.scheduled())
1461        schedule(rxKickEvent, rxKickTick);
1462}
1463
1464void
1465NSGigE::transmit()
1466{
1467    if (txFifo.empty()) {
1468        DPRINTF(Ethernet, "nothing to transmit\n");
1469        return;
1470    }
1471
1472    DPRINTF(Ethernet, "Attempt Pkt Transmit: txFifo length=%d\n",
1473            txFifo.size());
1474    if (interface->sendPacket(txFifo.front())) {
1475#if TRACING_ON
1476        if (DTRACE(Ethernet)) {
1477            IpPtr ip(txFifo.front());
1478            if (ip) {
1479                DPRINTF(Ethernet, "ID is %d\n", ip->id());
1480                TcpPtr tcp(ip);
1481                if (tcp) {
1482                    DPRINTF(Ethernet,
1483                            "Src Port=%d, Dest Port=%d, Seq=%d, Ack=%d\n",
1484                            tcp->sport(), tcp->dport(), tcp->seq(),
1485                            tcp->ack());
1486                }
1487            }
1488        }
1489#endif
1490
1491        DDUMP(EthernetData, txFifo.front()->data, txFifo.front()->length);
1492        txBytes += txFifo.front()->length;
1493        txPackets++;
1494
1495        DPRINTF(Ethernet, "Successful Xmit! now txFifoAvail is %d\n",
1496                txFifo.avail());
1497        txFifo.pop();
1498
1499        /*
1500         * normally do a writeback of the descriptor here, and ONLY
1501         * after that is done, send this interrupt.  but since our
1502         * stuff never actually fails, just do this interrupt here,
1503         * otherwise the code has to stray from this nice format.
1504         * besides, it's functionally the same.
1505         */
1506        devIntrPost(ISR_TXOK);
1507    }
1508
1509   if (!txFifo.empty() && !txEvent.scheduled()) {
1510       DPRINTF(Ethernet, "reschedule transmit\n");
1511       schedule(txEvent, curTick() + retryTime);
1512   }
1513}
1514
1515bool
1516NSGigE::doTxDmaRead()
1517{
1518    assert(txDmaState == dmaIdle || txDmaState == dmaReadWaiting);
1519    txDmaState = dmaReading;
1520
1521    if (dmaPending() || getDrainState() != Running)
1522        txDmaState = dmaReadWaiting;
1523    else
1524        dmaRead(txDmaAddr, txDmaLen, &txDmaReadEvent, (uint8_t*)txDmaData);
1525
1526    return true;
1527}
1528
1529void
1530NSGigE::txDmaReadDone()
1531{
1532    assert(txDmaState == dmaReading);
1533    txDmaState = dmaIdle;
1534
1535    DPRINTF(EthernetDMA, "tx dma read  paddr=%#x len=%d\n",
1536            txDmaAddr, txDmaLen);
1537    DDUMP(EthernetDMA, txDmaData, txDmaLen);
1538
1539    // If the receive state machine  has a pending DMA, let it go first
1540    if (rxDmaState == dmaReadWaiting || rxDmaState == dmaWriteWaiting)
1541        rxKick();
1542
1543    txKick();
1544}
1545
1546bool
1547NSGigE::doTxDmaWrite()
1548{
1549    assert(txDmaState == dmaIdle || txDmaState == dmaWriteWaiting);
1550    txDmaState = dmaWriting;
1551
1552    if (dmaPending() || getDrainState() != Running)
1553        txDmaState = dmaWriteWaiting;
1554    else
1555        dmaWrite(txDmaAddr, txDmaLen, &txDmaWriteEvent, (uint8_t*)txDmaData);
1556    return true;
1557}
1558
1559void
1560NSGigE::txDmaWriteDone()
1561{
1562    assert(txDmaState == dmaWriting);
1563    txDmaState = dmaIdle;
1564
1565    DPRINTF(EthernetDMA, "tx dma write paddr=%#x len=%d\n",
1566            txDmaAddr, txDmaLen);
1567    DDUMP(EthernetDMA, txDmaData, txDmaLen);
1568
1569    // If the receive state machine  has a pending DMA, let it go first
1570    if (rxDmaState == dmaReadWaiting || rxDmaState == dmaWriteWaiting)
1571        rxKick();
1572
1573    txKick();
1574}
1575
1576void
1577NSGigE::txKick()
1578{
1579    bool is64bit = (bool)(regs.config & CFGR_M64ADDR);
1580
1581    DPRINTF(EthernetSM, "transmit kick txState=%s %d-bit\n",
1582            NsTxStateStrings[txState], is64bit ? 64 : 32);
1583
1584    Addr link, bufptr;
1585    uint32_t &cmdsts = is64bit ? txDesc64.cmdsts : txDesc32.cmdsts;
1586    uint32_t &extsts = is64bit ? txDesc64.extsts : txDesc32.extsts;
1587
1588  next:
1589    if (clock) {
1590        if (txKickTick > curTick()) {
1591            DPRINTF(EthernetSM, "transmit kick exiting, can't run till %d\n",
1592                    txKickTick);
1593            goto exit;
1594        }
1595
1596        // Go to the next state machine clock tick.
1597        txKickTick = curTick() + clockPeriod();
1598    }
1599
1600    switch(txDmaState) {
1601      case dmaReadWaiting:
1602        if (doTxDmaRead())
1603            goto exit;
1604        break;
1605      case dmaWriteWaiting:
1606        if (doTxDmaWrite())
1607            goto exit;
1608        break;
1609      default:
1610        break;
1611    }
1612
1613    link = is64bit ? (Addr)txDesc64.link : (Addr)txDesc32.link;
1614    bufptr = is64bit ? (Addr)txDesc64.bufptr : (Addr)txDesc32.bufptr;
1615    switch (txState) {
1616      case txIdle:
1617        if (!txEnable) {
1618            DPRINTF(EthernetSM, "Transmit disabled.  Nothing to do.\n");
1619            goto exit;
1620        }
1621
1622        if (CTDD) {
1623            txState = txDescRefr;
1624
1625            txDmaAddr = regs.txdp & 0x3fffffff;
1626            txDmaData =
1627                is64bit ? (void *)&txDesc64.link : (void *)&txDesc32.link;
1628            txDmaLen = is64bit ? sizeof(txDesc64.link) : sizeof(txDesc32.link);
1629            txDmaFree = dmaDescFree;
1630
1631            descDmaReads++;
1632            descDmaRdBytes += txDmaLen;
1633
1634            if (doTxDmaRead())
1635                goto exit;
1636
1637        } else {
1638            txState = txDescRead;
1639
1640            txDmaAddr = regs.txdp & 0x3fffffff;
1641            txDmaData = is64bit ? (void *)&txDesc64 : (void *)&txDesc32;
1642            txDmaLen = is64bit ? sizeof(txDesc64) : sizeof(txDesc32);
1643            txDmaFree = dmaDescFree;
1644
1645            descDmaReads++;
1646            descDmaRdBytes += txDmaLen;
1647
1648            if (doTxDmaRead())
1649                goto exit;
1650        }
1651        break;
1652
1653      case txDescRefr:
1654        if (txDmaState != dmaIdle)
1655            goto exit;
1656
1657        txState = txAdvance;
1658        break;
1659
1660      case txDescRead:
1661        if (txDmaState != dmaIdle)
1662            goto exit;
1663
1664        DPRINTF(EthernetDesc, "txDesc: addr=%08x read descriptor\n",
1665                regs.txdp & 0x3fffffff);
1666        DPRINTF(EthernetDesc,
1667                "txDesc: link=%#x bufptr=%#x cmdsts=%#08x extsts=%#08x\n",
1668                link, bufptr, cmdsts, extsts);
1669
1670        if (cmdsts & CMDSTS_OWN) {
1671            txState = txFifoBlock;
1672            txFragPtr = bufptr;
1673            txDescCnt = cmdsts & CMDSTS_LEN_MASK;
1674        } else {
1675            devIntrPost(ISR_TXIDLE);
1676            txState = txIdle;
1677            goto exit;
1678        }
1679        break;
1680
1681      case txFifoBlock:
1682        if (!txPacket) {
1683            DPRINTF(EthernetSM, "****starting the tx of a new packet****\n");
1684            txPacket = new EthPacketData(16384);
1685            txPacketBufPtr = txPacket->data;
1686        }
1687
1688        if (txDescCnt == 0) {
1689            DPRINTF(EthernetSM, "the txDescCnt == 0, done with descriptor\n");
1690            if (cmdsts & CMDSTS_MORE) {
1691                DPRINTF(EthernetSM, "there are more descriptors to come\n");
1692                txState = txDescWrite;
1693
1694                cmdsts &= ~CMDSTS_OWN;
1695
1696                txDmaAddr = regs.txdp & 0x3fffffff;
1697                txDmaData = &cmdsts;
1698                if (is64bit) {
1699                    txDmaAddr += offsetof(ns_desc64, cmdsts);
1700                    txDmaLen = sizeof(txDesc64.cmdsts);
1701                } else {
1702                    txDmaAddr += offsetof(ns_desc32, cmdsts);
1703                    txDmaLen = sizeof(txDesc32.cmdsts);
1704                }
1705                txDmaFree = dmaDescFree;
1706
1707                if (doTxDmaWrite())
1708                    goto exit;
1709
1710            } else { /* this packet is totally done */
1711                DPRINTF(EthernetSM, "This packet is done, let's wrap it up\n");
1712                /* deal with the the packet that just finished */
1713                if ((regs.vtcr & VTCR_PPCHK) && extstsEnable) {
1714                    IpPtr ip(txPacket);
1715                    if (extsts & EXTSTS_UDPPKT) {
1716                        UdpPtr udp(ip);
1717                        if (udp) {
1718                            udp->sum(0);
1719                            udp->sum(cksum(udp));
1720                            txUdpChecksums++;
1721                        } else {
1722                            Debug::breakpoint();
1723                            warn_once("UDPPKT set, but not UDP!\n");
1724                        }
1725                    } else if (extsts & EXTSTS_TCPPKT) {
1726                        TcpPtr tcp(ip);
1727                        if (tcp) {
1728                            tcp->sum(0);
1729                            tcp->sum(cksum(tcp));
1730                            txTcpChecksums++;
1731                        } else {
1732                            Debug::breakpoint();
1733                            warn_once("TCPPKT set, but not UDP!\n");
1734                        }
1735                    }
1736                    if (extsts & EXTSTS_IPPKT) {
1737                        if (ip) {
1738                            ip->sum(0);
1739                            ip->sum(cksum(ip));
1740                            txIpChecksums++;
1741                        } else {
1742                            Debug::breakpoint();
1743                            warn_once("IPPKT set, but not UDP!\n");
1744                        }
1745                    }
1746                }
1747
1748                txPacket->length = txPacketBufPtr - txPacket->data;
1749                // this is just because the receive can't handle a
1750                // packet bigger want to make sure
1751                if (txPacket->length > 1514)
1752                    panic("transmit packet too large, %s > 1514\n",
1753                          txPacket->length);
1754
1755#ifndef NDEBUG
1756                bool success =
1757#endif
1758                    txFifo.push(txPacket);
1759                assert(success);
1760
1761                /*
1762                 * this following section is not tqo spec, but
1763                 * functionally shouldn't be any different.  normally,
1764                 * the chip will wait til the transmit has occurred
1765                 * before writing back the descriptor because it has
1766                 * to wait to see that it was successfully transmitted
1767                 * to decide whether to set CMDSTS_OK or not.
1768                 * however, in the simulator since it is always
1769                 * successfully transmitted, and writing it exactly to
1770                 * spec would complicate the code, we just do it here
1771                 */
1772
1773                cmdsts &= ~CMDSTS_OWN;
1774                cmdsts |= CMDSTS_OK;
1775
1776                DPRINTF(EthernetDesc,
1777                        "txDesc writeback: cmdsts=%08x extsts=%08x\n",
1778                        cmdsts, extsts);
1779
1780                txDmaFree = dmaDescFree;
1781                txDmaAddr = regs.txdp & 0x3fffffff;
1782                txDmaData = &cmdsts;
1783                if (is64bit) {
1784                    txDmaAddr += offsetof(ns_desc64, cmdsts);
1785                    txDmaLen =
1786                        sizeof(txDesc64.cmdsts) + sizeof(txDesc64.extsts);
1787                } else {
1788                    txDmaAddr += offsetof(ns_desc32, cmdsts);
1789                    txDmaLen =
1790                        sizeof(txDesc32.cmdsts) + sizeof(txDesc32.extsts);
1791                }
1792
1793                descDmaWrites++;
1794                descDmaWrBytes += txDmaLen;
1795
1796                transmit();
1797                txPacket = 0;
1798
1799                if (!txEnable) {
1800                    DPRINTF(EthernetSM, "halting TX state machine\n");
1801                    txState = txIdle;
1802                    goto exit;
1803                } else
1804                    txState = txAdvance;
1805
1806                if (doTxDmaWrite())
1807                    goto exit;
1808            }
1809        } else {
1810            DPRINTF(EthernetSM, "this descriptor isn't done yet\n");
1811            if (!txFifo.full()) {
1812                txState = txFragRead;
1813
1814                /*
1815                 * The number of bytes transferred is either whatever
1816                 * is left in the descriptor (txDescCnt), or if there
1817                 * is not enough room in the fifo, just whatever room
1818                 * is left in the fifo
1819                 */
1820                txXferLen = min<uint32_t>(txDescCnt, txFifo.avail());
1821
1822                txDmaAddr = txFragPtr & 0x3fffffff;
1823                txDmaData = txPacketBufPtr;
1824                txDmaLen = txXferLen;
1825                txDmaFree = dmaDataFree;
1826
1827                if (doTxDmaRead())
1828                    goto exit;
1829            } else {
1830                txState = txFifoBlock;
1831                transmit();
1832
1833                goto exit;
1834            }
1835
1836        }
1837        break;
1838
1839      case txFragRead:
1840        if (txDmaState != dmaIdle)
1841            goto exit;
1842
1843        txPacketBufPtr += txXferLen;
1844        txFragPtr += txXferLen;
1845        txDescCnt -= txXferLen;
1846        txFifo.reserve(txXferLen);
1847
1848        txState = txFifoBlock;
1849        break;
1850
1851      case txDescWrite:
1852        if (txDmaState != dmaIdle)
1853            goto exit;
1854
1855        if (cmdsts & CMDSTS_INTR)
1856            devIntrPost(ISR_TXDESC);
1857
1858        if (!txEnable) {
1859            DPRINTF(EthernetSM, "halting TX state machine\n");
1860            txState = txIdle;
1861            goto exit;
1862        } else
1863            txState = txAdvance;
1864        break;
1865
1866      case txAdvance:
1867        if (link == 0) {
1868            devIntrPost(ISR_TXIDLE);
1869            txState = txIdle;
1870            goto exit;
1871        } else {
1872            if (txDmaState != dmaIdle)
1873                goto exit;
1874            txState = txDescRead;
1875            regs.txdp = link;
1876            CTDD = false;
1877
1878            txDmaAddr = link & 0x3fffffff;
1879            txDmaData = is64bit ? (void *)&txDesc64 : (void *)&txDesc32;
1880            txDmaLen = is64bit ? sizeof(txDesc64) : sizeof(txDesc32);
1881            txDmaFree = dmaDescFree;
1882
1883            if (doTxDmaRead())
1884                goto exit;
1885        }
1886        break;
1887
1888      default:
1889        panic("invalid state");
1890    }
1891
1892    DPRINTF(EthernetSM, "entering next txState=%s\n",
1893            NsTxStateStrings[txState]);
1894    goto next;
1895
1896  exit:
1897    /**
1898     * @todo do we want to schedule a future kick?
1899     */
1900    DPRINTF(EthernetSM, "tx state machine exited txState=%s\n",
1901            NsTxStateStrings[txState]);
1902
1903    if (clock && !txKickEvent.scheduled())
1904        schedule(txKickEvent, txKickTick);
1905}
1906
1907/**
1908 * Advance the EEPROM state machine
1909 * Called on rising edge of EEPROM clock bit in MEAR
1910 */
1911void
1912NSGigE::eepromKick()
1913{
1914    switch (eepromState) {
1915
1916      case eepromStart:
1917
1918        // Wait for start bit
1919        if (regs.mear & MEAR_EEDI) {
1920            // Set up to get 2 opcode bits
1921            eepromState = eepromGetOpcode;
1922            eepromBitsToRx = 2;
1923            eepromOpcode = 0;
1924        }
1925        break;
1926
1927      case eepromGetOpcode:
1928        eepromOpcode <<= 1;
1929        eepromOpcode += (regs.mear & MEAR_EEDI) ? 1 : 0;
1930        --eepromBitsToRx;
1931
1932        // Done getting opcode
1933        if (eepromBitsToRx == 0) {
1934            if (eepromOpcode != EEPROM_READ)
1935                panic("only EEPROM reads are implemented!");
1936
1937            // Set up to get address
1938            eepromState = eepromGetAddress;
1939            eepromBitsToRx = 6;
1940            eepromAddress = 0;
1941        }
1942        break;
1943
1944      case eepromGetAddress:
1945        eepromAddress <<= 1;
1946        eepromAddress += (regs.mear & MEAR_EEDI) ? 1 : 0;
1947        --eepromBitsToRx;
1948
1949        // Done getting address
1950        if (eepromBitsToRx == 0) {
1951
1952            if (eepromAddress >= EEPROM_SIZE)
1953                panic("EEPROM read access out of range!");
1954
1955            switch (eepromAddress) {
1956
1957              case EEPROM_PMATCH2_ADDR:
1958                eepromData = rom.perfectMatch[5];
1959                eepromData <<= 8;
1960                eepromData += rom.perfectMatch[4];
1961                break;
1962
1963              case EEPROM_PMATCH1_ADDR:
1964                eepromData = rom.perfectMatch[3];
1965                eepromData <<= 8;
1966                eepromData += rom.perfectMatch[2];
1967                break;
1968
1969              case EEPROM_PMATCH0_ADDR:
1970                eepromData = rom.perfectMatch[1];
1971                eepromData <<= 8;
1972                eepromData += rom.perfectMatch[0];
1973                break;
1974
1975              default:
1976                panic("FreeBSD driver only uses EEPROM to read PMATCH!");
1977            }
1978            // Set up to read data
1979            eepromState = eepromRead;
1980            eepromBitsToRx = 16;
1981
1982            // Clear data in bit
1983            regs.mear &= ~MEAR_EEDI;
1984        }
1985        break;
1986
1987      case eepromRead:
1988        // Clear Data Out bit
1989        regs.mear &= ~MEAR_EEDO;
1990        // Set bit to value of current EEPROM bit
1991        regs.mear |= (eepromData & 0x8000) ? MEAR_EEDO : 0x0;
1992
1993        eepromData <<= 1;
1994        --eepromBitsToRx;
1995
1996        // All done
1997        if (eepromBitsToRx == 0) {
1998            eepromState = eepromStart;
1999        }
2000        break;
2001
2002      default:
2003        panic("invalid EEPROM state");
2004    }
2005
2006}
2007
2008void
2009NSGigE::transferDone()
2010{
2011    if (txFifo.empty()) {
2012        DPRINTF(Ethernet, "transfer complete: txFifo empty...nothing to do\n");
2013        return;
2014    }
2015
2016    DPRINTF(Ethernet, "transfer complete: data in txFifo...schedule xmit\n");
2017
2018    reschedule(txEvent, curTick() + clockPeriod(), true);
2019}
2020
2021bool
2022NSGigE::rxFilter(const EthPacketPtr &packet)
2023{
2024    EthPtr eth = packet;
2025    bool drop = true;
2026    string type;
2027
2028    const EthAddr &dst = eth->dst();
2029    if (dst.unicast()) {
2030        // If we're accepting all unicast addresses
2031        if (acceptUnicast)
2032            drop = false;
2033
2034        // If we make a perfect match
2035        if (acceptPerfect && dst == rom.perfectMatch)
2036            drop = false;
2037
2038        if (acceptArp && eth->type() == ETH_TYPE_ARP)
2039            drop = false;
2040
2041    } else if (dst.broadcast()) {
2042        // if we're accepting broadcasts
2043        if (acceptBroadcast)
2044            drop = false;
2045
2046    } else if (dst.multicast()) {
2047        // if we're accepting all multicasts
2048        if (acceptMulticast)
2049            drop = false;
2050
2051        // Multicast hashing faked - all packets accepted
2052        if (multicastHashEnable)
2053            drop = false;
2054    }
2055
2056    if (drop) {
2057        DPRINTF(Ethernet, "rxFilter drop\n");
2058        DDUMP(EthernetData, packet->data, packet->length);
2059    }
2060
2061    return drop;
2062}
2063
2064bool
2065NSGigE::recvPacket(EthPacketPtr packet)
2066{
2067    rxBytes += packet->length;
2068    rxPackets++;
2069
2070    DPRINTF(Ethernet, "Receiving packet from wire, rxFifoAvail=%d\n",
2071            rxFifo.avail());
2072
2073    if (!rxEnable) {
2074        DPRINTF(Ethernet, "receive disabled...packet dropped\n");
2075        return true;
2076    }
2077
2078    if (!rxFilterEnable) {
2079        DPRINTF(Ethernet,
2080            "receive packet filtering disabled . . . packet dropped\n");
2081        return true;
2082    }
2083
2084    if (rxFilter(packet)) {
2085        DPRINTF(Ethernet, "packet filtered...dropped\n");
2086        return true;
2087    }
2088
2089    if (rxFifo.avail() < packet->length) {
2090#if TRACING_ON
2091        IpPtr ip(packet);
2092        TcpPtr tcp(ip);
2093        if (ip) {
2094            DPRINTF(Ethernet,
2095                    "packet won't fit in receive buffer...pkt ID %d dropped\n",
2096                    ip->id());
2097            if (tcp) {
2098                DPRINTF(Ethernet, "Seq=%d\n", tcp->seq());
2099            }
2100        }
2101#endif
2102        droppedPackets++;
2103        devIntrPost(ISR_RXORN);
2104        return false;
2105    }
2106
2107    rxFifo.push(packet);
2108
2109    rxKick();
2110    return true;
2111}
2112
2113
2114void
2115NSGigE::drainResume()
2116{
2117    Drainable::drainResume();
2118
2119    // During drain we could have left the state machines in a waiting state and
2120    // they wouldn't get out until some other event occured to kick them.
2121    // This way they'll get out immediately
2122    txKick();
2123    rxKick();
2124}
2125
2126
2127//=====================================================================
2128//
2129//
2130void
2131NSGigE::serialize(ostream &os)
2132{
2133    // Serialize the PciDev base class
2134    PciDev::serialize(os);
2135
2136    /*
2137     * Finalize any DMA events now.
2138     */
2139    // @todo will mem system save pending dma?
2140
2141    /*
2142     * Serialize the device registers
2143     */
2144    SERIALIZE_SCALAR(regs.command);
2145    SERIALIZE_SCALAR(regs.config);
2146    SERIALIZE_SCALAR(regs.mear);
2147    SERIALIZE_SCALAR(regs.ptscr);
2148    SERIALIZE_SCALAR(regs.isr);
2149    SERIALIZE_SCALAR(regs.imr);
2150    SERIALIZE_SCALAR(regs.ier);
2151    SERIALIZE_SCALAR(regs.ihr);
2152    SERIALIZE_SCALAR(regs.txdp);
2153    SERIALIZE_SCALAR(regs.txdp_hi);
2154    SERIALIZE_SCALAR(regs.txcfg);
2155    SERIALIZE_SCALAR(regs.gpior);
2156    SERIALIZE_SCALAR(regs.rxdp);
2157    SERIALIZE_SCALAR(regs.rxdp_hi);
2158    SERIALIZE_SCALAR(regs.rxcfg);
2159    SERIALIZE_SCALAR(regs.pqcr);
2160    SERIALIZE_SCALAR(regs.wcsr);
2161    SERIALIZE_SCALAR(regs.pcr);
2162    SERIALIZE_SCALAR(regs.rfcr);
2163    SERIALIZE_SCALAR(regs.rfdr);
2164    SERIALIZE_SCALAR(regs.brar);
2165    SERIALIZE_SCALAR(regs.brdr);
2166    SERIALIZE_SCALAR(regs.srr);
2167    SERIALIZE_SCALAR(regs.mibc);
2168    SERIALIZE_SCALAR(regs.vrcr);
2169    SERIALIZE_SCALAR(regs.vtcr);
2170    SERIALIZE_SCALAR(regs.vdr);
2171    SERIALIZE_SCALAR(regs.ccsr);
2172    SERIALIZE_SCALAR(regs.tbicr);
2173    SERIALIZE_SCALAR(regs.tbisr);
2174    SERIALIZE_SCALAR(regs.tanar);
2175    SERIALIZE_SCALAR(regs.tanlpar);
2176    SERIALIZE_SCALAR(regs.taner);
2177    SERIALIZE_SCALAR(regs.tesr);
2178
2179    SERIALIZE_ARRAY(rom.perfectMatch, ETH_ADDR_LEN);
2180    SERIALIZE_ARRAY(rom.filterHash, FHASH_SIZE);
2181
2182    SERIALIZE_SCALAR(ioEnable);
2183
2184    /*
2185     * Serialize the data Fifos
2186     */
2187    rxFifo.serialize("rxFifo", os);
2188    txFifo.serialize("txFifo", os);
2189
2190    /*
2191     * Serialize the various helper variables
2192     */
2193    bool txPacketExists = txPacket;
2194    SERIALIZE_SCALAR(txPacketExists);
2195    if (txPacketExists) {
2196        txPacket->length = txPacketBufPtr - txPacket->data;
2197        txPacket->serialize("txPacket", os);
2198        uint32_t txPktBufPtr = (uint32_t) (txPacketBufPtr - txPacket->data);
2199        SERIALIZE_SCALAR(txPktBufPtr);
2200    }
2201
2202    bool rxPacketExists = rxPacket;
2203    SERIALIZE_SCALAR(rxPacketExists);
2204    if (rxPacketExists) {
2205        rxPacket->serialize("rxPacket", os);
2206        uint32_t rxPktBufPtr = (uint32_t) (rxPacketBufPtr - rxPacket->data);
2207        SERIALIZE_SCALAR(rxPktBufPtr);
2208    }
2209
2210    SERIALIZE_SCALAR(txXferLen);
2211    SERIALIZE_SCALAR(rxXferLen);
2212
2213    /*
2214     * Serialize Cached Descriptors
2215     */
2216    SERIALIZE_SCALAR(rxDesc64.link);
2217    SERIALIZE_SCALAR(rxDesc64.bufptr);
2218    SERIALIZE_SCALAR(rxDesc64.cmdsts);
2219    SERIALIZE_SCALAR(rxDesc64.extsts);
2220    SERIALIZE_SCALAR(txDesc64.link);
2221    SERIALIZE_SCALAR(txDesc64.bufptr);
2222    SERIALIZE_SCALAR(txDesc64.cmdsts);
2223    SERIALIZE_SCALAR(txDesc64.extsts);
2224    SERIALIZE_SCALAR(rxDesc32.link);
2225    SERIALIZE_SCALAR(rxDesc32.bufptr);
2226    SERIALIZE_SCALAR(rxDesc32.cmdsts);
2227    SERIALIZE_SCALAR(rxDesc32.extsts);
2228    SERIALIZE_SCALAR(txDesc32.link);
2229    SERIALIZE_SCALAR(txDesc32.bufptr);
2230    SERIALIZE_SCALAR(txDesc32.cmdsts);
2231    SERIALIZE_SCALAR(txDesc32.extsts);
2232    SERIALIZE_SCALAR(extstsEnable);
2233
2234    /*
2235     * Serialize tx state machine
2236     */
2237    int txState = this->txState;
2238    SERIALIZE_SCALAR(txState);
2239    SERIALIZE_SCALAR(txEnable);
2240    SERIALIZE_SCALAR(CTDD);
2241    SERIALIZE_SCALAR(txFragPtr);
2242    SERIALIZE_SCALAR(txDescCnt);
2243    int txDmaState = this->txDmaState;
2244    SERIALIZE_SCALAR(txDmaState);
2245    SERIALIZE_SCALAR(txKickTick);
2246
2247    /*
2248     * Serialize rx state machine
2249     */
2250    int rxState = this->rxState;
2251    SERIALIZE_SCALAR(rxState);
2252    SERIALIZE_SCALAR(rxEnable);
2253    SERIALIZE_SCALAR(CRDD);
2254    SERIALIZE_SCALAR(rxPktBytes);
2255    SERIALIZE_SCALAR(rxFragPtr);
2256    SERIALIZE_SCALAR(rxDescCnt);
2257    int rxDmaState = this->rxDmaState;
2258    SERIALIZE_SCALAR(rxDmaState);
2259    SERIALIZE_SCALAR(rxKickTick);
2260
2261    /*
2262     * Serialize EEPROM state machine
2263     */
2264    int eepromState = this->eepromState;
2265    SERIALIZE_SCALAR(eepromState);
2266    SERIALIZE_SCALAR(eepromClk);
2267    SERIALIZE_SCALAR(eepromBitsToRx);
2268    SERIALIZE_SCALAR(eepromOpcode);
2269    SERIALIZE_SCALAR(eepromAddress);
2270    SERIALIZE_SCALAR(eepromData);
2271
2272    /*
2273     * If there's a pending transmit, store the time so we can
2274     * reschedule it later
2275     */
2276    Tick transmitTick = txEvent.scheduled() ? txEvent.when() - curTick() : 0;
2277    SERIALIZE_SCALAR(transmitTick);
2278
2279    /*
2280     * receive address filter settings
2281     */
2282    SERIALIZE_SCALAR(rxFilterEnable);
2283    SERIALIZE_SCALAR(acceptBroadcast);
2284    SERIALIZE_SCALAR(acceptMulticast);
2285    SERIALIZE_SCALAR(acceptUnicast);
2286    SERIALIZE_SCALAR(acceptPerfect);
2287    SERIALIZE_SCALAR(acceptArp);
2288    SERIALIZE_SCALAR(multicastHashEnable);
2289
2290    /*
2291     * Keep track of pending interrupt status.
2292     */
2293    SERIALIZE_SCALAR(intrTick);
2294    SERIALIZE_SCALAR(cpuPendingIntr);
2295    Tick intrEventTick = 0;
2296    if (intrEvent)
2297        intrEventTick = intrEvent->when();
2298    SERIALIZE_SCALAR(intrEventTick);
2299
2300}
2301
2302void
2303NSGigE::unserialize(Checkpoint *cp, const std::string &section)
2304{
2305    // Unserialize the PciDev base class
2306    PciDev::unserialize(cp, section);
2307
2308    UNSERIALIZE_SCALAR(regs.command);
2309    UNSERIALIZE_SCALAR(regs.config);
2310    UNSERIALIZE_SCALAR(regs.mear);
2311    UNSERIALIZE_SCALAR(regs.ptscr);
2312    UNSERIALIZE_SCALAR(regs.isr);
2313    UNSERIALIZE_SCALAR(regs.imr);
2314    UNSERIALIZE_SCALAR(regs.ier);
2315    UNSERIALIZE_SCALAR(regs.ihr);
2316    UNSERIALIZE_SCALAR(regs.txdp);
2317    UNSERIALIZE_SCALAR(regs.txdp_hi);
2318    UNSERIALIZE_SCALAR(regs.txcfg);
2319    UNSERIALIZE_SCALAR(regs.gpior);
2320    UNSERIALIZE_SCALAR(regs.rxdp);
2321    UNSERIALIZE_SCALAR(regs.rxdp_hi);
2322    UNSERIALIZE_SCALAR(regs.rxcfg);
2323    UNSERIALIZE_SCALAR(regs.pqcr);
2324    UNSERIALIZE_SCALAR(regs.wcsr);
2325    UNSERIALIZE_SCALAR(regs.pcr);
2326    UNSERIALIZE_SCALAR(regs.rfcr);
2327    UNSERIALIZE_SCALAR(regs.rfdr);
2328    UNSERIALIZE_SCALAR(regs.brar);
2329    UNSERIALIZE_SCALAR(regs.brdr);
2330    UNSERIALIZE_SCALAR(regs.srr);
2331    UNSERIALIZE_SCALAR(regs.mibc);
2332    UNSERIALIZE_SCALAR(regs.vrcr);
2333    UNSERIALIZE_SCALAR(regs.vtcr);
2334    UNSERIALIZE_SCALAR(regs.vdr);
2335    UNSERIALIZE_SCALAR(regs.ccsr);
2336    UNSERIALIZE_SCALAR(regs.tbicr);
2337    UNSERIALIZE_SCALAR(regs.tbisr);
2338    UNSERIALIZE_SCALAR(regs.tanar);
2339    UNSERIALIZE_SCALAR(regs.tanlpar);
2340    UNSERIALIZE_SCALAR(regs.taner);
2341    UNSERIALIZE_SCALAR(regs.tesr);
2342
2343    UNSERIALIZE_ARRAY(rom.perfectMatch, ETH_ADDR_LEN);
2344    UNSERIALIZE_ARRAY(rom.filterHash, FHASH_SIZE);
2345
2346    UNSERIALIZE_SCALAR(ioEnable);
2347
2348    /*
2349     * unserialize the data fifos
2350     */
2351    rxFifo.unserialize("rxFifo", cp, section);
2352    txFifo.unserialize("txFifo", cp, section);
2353
2354    /*
2355     * unserialize the various helper variables
2356     */
2357    bool txPacketExists;
2358    UNSERIALIZE_SCALAR(txPacketExists);
2359    if (txPacketExists) {
2360        txPacket = new EthPacketData(16384);
2361        txPacket->unserialize("txPacket", cp, section);
2362        uint32_t txPktBufPtr;
2363        UNSERIALIZE_SCALAR(txPktBufPtr);
2364        txPacketBufPtr = (uint8_t *) txPacket->data + txPktBufPtr;
2365    } else
2366        txPacket = 0;
2367
2368    bool rxPacketExists;
2369    UNSERIALIZE_SCALAR(rxPacketExists);
2370    rxPacket = 0;
2371    if (rxPacketExists) {
2372        rxPacket = new EthPacketData(16384);
2373        rxPacket->unserialize("rxPacket", cp, section);
2374        uint32_t rxPktBufPtr;
2375        UNSERIALIZE_SCALAR(rxPktBufPtr);
2376        rxPacketBufPtr = (uint8_t *) rxPacket->data + rxPktBufPtr;
2377    } else
2378        rxPacket = 0;
2379
2380    UNSERIALIZE_SCALAR(txXferLen);
2381    UNSERIALIZE_SCALAR(rxXferLen);
2382
2383    /*
2384     * Unserialize Cached Descriptors
2385     */
2386    UNSERIALIZE_SCALAR(rxDesc64.link);
2387    UNSERIALIZE_SCALAR(rxDesc64.bufptr);
2388    UNSERIALIZE_SCALAR(rxDesc64.cmdsts);
2389    UNSERIALIZE_SCALAR(rxDesc64.extsts);
2390    UNSERIALIZE_SCALAR(txDesc64.link);
2391    UNSERIALIZE_SCALAR(txDesc64.bufptr);
2392    UNSERIALIZE_SCALAR(txDesc64.cmdsts);
2393    UNSERIALIZE_SCALAR(txDesc64.extsts);
2394    UNSERIALIZE_SCALAR(rxDesc32.link);
2395    UNSERIALIZE_SCALAR(rxDesc32.bufptr);
2396    UNSERIALIZE_SCALAR(rxDesc32.cmdsts);
2397    UNSERIALIZE_SCALAR(rxDesc32.extsts);
2398    UNSERIALIZE_SCALAR(txDesc32.link);
2399    UNSERIALIZE_SCALAR(txDesc32.bufptr);
2400    UNSERIALIZE_SCALAR(txDesc32.cmdsts);
2401    UNSERIALIZE_SCALAR(txDesc32.extsts);
2402    UNSERIALIZE_SCALAR(extstsEnable);
2403
2404    /*
2405     * unserialize tx state machine
2406     */
2407    int txState;
2408    UNSERIALIZE_SCALAR(txState);
2409    this->txState = (TxState) txState;
2410    UNSERIALIZE_SCALAR(txEnable);
2411    UNSERIALIZE_SCALAR(CTDD);
2412    UNSERIALIZE_SCALAR(txFragPtr);
2413    UNSERIALIZE_SCALAR(txDescCnt);
2414    int txDmaState;
2415    UNSERIALIZE_SCALAR(txDmaState);
2416    this->txDmaState = (DmaState) txDmaState;
2417    UNSERIALIZE_SCALAR(txKickTick);
2418    if (txKickTick)
2419        schedule(txKickEvent, txKickTick);
2420
2421    /*
2422     * unserialize rx state machine
2423     */
2424    int rxState;
2425    UNSERIALIZE_SCALAR(rxState);
2426    this->rxState = (RxState) rxState;
2427    UNSERIALIZE_SCALAR(rxEnable);
2428    UNSERIALIZE_SCALAR(CRDD);
2429    UNSERIALIZE_SCALAR(rxPktBytes);
2430    UNSERIALIZE_SCALAR(rxFragPtr);
2431    UNSERIALIZE_SCALAR(rxDescCnt);
2432    int rxDmaState;
2433    UNSERIALIZE_SCALAR(rxDmaState);
2434    this->rxDmaState = (DmaState) rxDmaState;
2435    UNSERIALIZE_SCALAR(rxKickTick);
2436    if (rxKickTick)
2437        schedule(rxKickEvent, rxKickTick);
2438
2439    /*
2440     * Unserialize EEPROM state machine
2441     */
2442    int eepromState;
2443    UNSERIALIZE_SCALAR(eepromState);
2444    this->eepromState = (EEPROMState) eepromState;
2445    UNSERIALIZE_SCALAR(eepromClk);
2446    UNSERIALIZE_SCALAR(eepromBitsToRx);
2447    UNSERIALIZE_SCALAR(eepromOpcode);
2448    UNSERIALIZE_SCALAR(eepromAddress);
2449    UNSERIALIZE_SCALAR(eepromData);
2450
2451    /*
2452     * If there's a pending transmit, reschedule it now
2453     */
2454    Tick transmitTick;
2455    UNSERIALIZE_SCALAR(transmitTick);
2456    if (transmitTick)
2457        schedule(txEvent, curTick() + transmitTick);
2458
2459    /*
2460     * unserialize receive address filter settings
2461     */
2462    UNSERIALIZE_SCALAR(rxFilterEnable);
2463    UNSERIALIZE_SCALAR(acceptBroadcast);
2464    UNSERIALIZE_SCALAR(acceptMulticast);
2465    UNSERIALIZE_SCALAR(acceptUnicast);
2466    UNSERIALIZE_SCALAR(acceptPerfect);
2467    UNSERIALIZE_SCALAR(acceptArp);
2468    UNSERIALIZE_SCALAR(multicastHashEnable);
2469
2470    /*
2471     * Keep track of pending interrupt status.
2472     */
2473    UNSERIALIZE_SCALAR(intrTick);
2474    UNSERIALIZE_SCALAR(cpuPendingIntr);
2475    Tick intrEventTick;
2476    UNSERIALIZE_SCALAR(intrEventTick);
2477    if (intrEventTick) {
2478        intrEvent = new IntrEvent(this, true);
2479        schedule(intrEvent, intrEventTick);
2480    }
2481}
2482
2483NSGigE *
2484NSGigEParams::create()
2485{
2486    return new NSGigE(this);
2487}
2488