1837SN/A/*
21762SN/A * Copyright (c) 2004-2005 The Regents of The University of Michigan
3837SN/A * All rights reserved.
4837SN/A *
5837SN/A * Redistribution and use in source and binary forms, with or without
6837SN/A * modification, are permitted provided that the following conditions are
7837SN/A * met: redistributions of source code must retain the above copyright
8837SN/A * notice, this list of conditions and the following disclaimer;
9837SN/A * redistributions in binary form must reproduce the above copyright
10837SN/A * notice, this list of conditions and the following disclaimer in the
11837SN/A * documentation and/or other materials provided with the distribution;
12837SN/A * neither the name of the copyright holders nor the names of its
13837SN/A * contributors may be used to endorse or promote products derived from
14837SN/A * this software without specific prior written permission.
15837SN/A *
16837SN/A * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
17837SN/A * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
18837SN/A * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
19837SN/A * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
20837SN/A * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
21837SN/A * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
22837SN/A * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
23837SN/A * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
24837SN/A * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
25837SN/A * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
26837SN/A * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
272665SN/A *
282760SN/A * Authors: Nathan Binkert
292760SN/A *          Lisa Hsu
30837SN/A */
31837SN/A
321730SN/A/** @file
33837SN/A * Device module for modelling the National Semiconductor
34837SN/A * DP83820 ethernet controller.  Does not support priority queueing
35837SN/A */
3611263Sandreas.sandberg@arm.com
3711263Sandreas.sandberg@arm.com#include "dev/net/ns_gige.hh"
3811263Sandreas.sandberg@arm.com
39837SN/A#include <deque>
4010469SN/A#include <memory>
41837SN/A#include <string>
42837SN/A
435882SN/A#include "base/debug.hh"
44837SN/A#include "base/inet.hh"
456216SN/A#include "base/types.hh"
466658SN/A#include "config/the_isa.hh"
478232SN/A#include "debug/EthernetAll.hh"
4811263Sandreas.sandberg@arm.com#include "dev/net/etherlink.hh"
492566SN/A#include "mem/packet.hh"
503348SN/A#include "mem/packet_access.hh"
514762SN/A#include "params/NSGigE.hh"
522566SN/A#include "sim/system.hh"
53854SN/A
548737SN/A// clang complains about std::set being overloaded with Packet::set if
558737SN/A// we open up the entire namespace std
5610469SN/Ausing std::make_shared;
578737SN/Ausing std::min;
588737SN/Ausing std::ostream;
598737SN/Ausing std::string;
608737SN/A
61854SN/Aconst char *NsRxStateStrings[] =
62854SN/A{
63854SN/A    "rxIdle",
64854SN/A    "rxDescRefr",
65854SN/A    "rxDescRead",
66854SN/A    "rxFifoBlock",
67854SN/A    "rxFragWrite",
68854SN/A    "rxDescWrite",
69854SN/A    "rxAdvance"
70854SN/A};
71854SN/A
72854SN/Aconst char *NsTxStateStrings[] =
73854SN/A{
74854SN/A    "txIdle",
75854SN/A    "txDescRefr",
76854SN/A    "txDescRead",
77854SN/A    "txFifoBlock",
78854SN/A    "txFragRead",
79854SN/A    "txDescWrite",
80854SN/A    "txAdvance"
81854SN/A};
82854SN/A
83854SN/Aconst char *NsDmaState[] =
84854SN/A{
85854SN/A    "dmaIdle",
86854SN/A    "dmaReading",
87854SN/A    "dmaWriting",
88854SN/A    "dmaReadWaiting",
89854SN/A    "dmaWriteWaiting"
90854SN/A};
91837SN/A
921114SN/Ausing namespace Net;
932107SN/Ausing namespace TheISA;
94927SN/A
95837SN/A///////////////////////////////////////////////////////////////////////
96837SN/A//
97879SN/A// NSGigE PCI Device
98837SN/A//
991149SN/ANSGigE::NSGigE(Params *p)
1009339SN/A    : EtherDevBase(p), ioEnable(false),
1011149SN/A      txFifo(p->tx_fifo_size), rxFifo(p->rx_fifo_size),
102915SN/A      txPacket(0), rxPacket(0), txPacketBufPtr(NULL), rxPacketBufPtr(NULL),
1034093SN/A      txXferLen(0), rxXferLen(0), rxDmaFree(false), txDmaFree(false),
1044093SN/A      txState(txIdle), txEnable(false), CTDD(false), txHalt(false),
105854SN/A      txFragPtr(0), txDescCnt(0), txDmaState(dmaIdle), rxState(rxIdle),
1064093SN/A      rxEnable(false), CRDD(false), rxPktBytes(0), rxHalt(false),
107854SN/A      rxFragPtr(0), rxDescCnt(0), rxDmaState(dmaIdle), extstsEnable(false),
1084093SN/A      eepromState(eepromStart), eepromClk(false), eepromBitsToRx(0),
1094093SN/A      eepromOpcode(0), eepromAddress(0), eepromData(0),
1104093SN/A      dmaReadDelay(p->dma_read_delay), dmaWriteDelay(p->dma_write_delay),
1114093SN/A      dmaReadFactor(p->dma_read_factor), dmaWriteFactor(p->dma_write_factor),
1124093SN/A      rxDmaData(NULL), rxDmaAddr(0), rxDmaLen(0),
1134093SN/A      txDmaData(NULL), txDmaAddr(0), txDmaLen(0),
11412087Sspwilson2@wisc.edu      rxDmaReadEvent([this]{ rxDmaReadDone(); }, name()),
11512087Sspwilson2@wisc.edu      rxDmaWriteEvent([this]{ rxDmaWriteDone(); }, name()),
11612087Sspwilson2@wisc.edu      txDmaReadEvent([this]{ txDmaReadDone(); }, name()),
11712087Sspwilson2@wisc.edu      txDmaWriteEvent([this]{ txDmaWriteDone(); }, name()),
1181149SN/A      dmaDescFree(p->dma_desc_free), dmaDataFree(p->dma_data_free),
1191149SN/A      txDelay(p->tx_delay), rxDelay(p->rx_delay),
12012087Sspwilson2@wisc.edu      rxKickTick(0),
12112087Sspwilson2@wisc.edu      rxKickEvent([this]{ rxKick(); }, name()),
12212087Sspwilson2@wisc.edu      txKickTick(0),
12312087Sspwilson2@wisc.edu      txKickEvent([this]{ txKick(); }, name()),
12412087Sspwilson2@wisc.edu      txEvent([this]{ txEventTransmit(); }, name()),
12512087Sspwilson2@wisc.edu      rxFilterEnable(p->rx_filter),
1264093SN/A      acceptBroadcast(false), acceptMulticast(false), acceptUnicast(false),
1271843SN/A      acceptPerfect(false), acceptArp(false), multicastHashEnable(false),
1284093SN/A      intrDelay(p->intr_delay), intrTick(0), cpuPendingIntr(false),
129995SN/A      intrEvent(0), interface(0)
130837SN/A{
131854SN/A
132854SN/A
1334981SN/A    interface = new NSGigEInt(name() + ".int0", this);
1344981SN/A
135837SN/A    regsReset();
1364762SN/A    memcpy(&rom.perfectMatch, p->hardware_address.bytes(), ETH_ADDR_LEN);
1371909SN/A
1381909SN/A    memset(&rxDesc32, 0, sizeof(rxDesc32));
1391909SN/A    memset(&txDesc32, 0, sizeof(txDesc32));
1401909SN/A    memset(&rxDesc64, 0, sizeof(rxDesc64));
1411909SN/A    memset(&txDesc64, 0, sizeof(txDesc64));
142837SN/A}
143837SN/A
144879SN/ANSGigE::~NSGigE()
1459086SN/A{
1469086SN/A    delete interface;
1479086SN/A}
148837SN/A
149855SN/A/**
150855SN/A * This is to write to the PCI general configuration registers
151855SN/A */
1522846SN/ATick
1533349SN/ANSGigE::writeConfig(PacketPtr pkt)
154837SN/A{
1552846SN/A    int offset = pkt->getAddr() & PCI_CONFIG_SIZE;
156837SN/A    if (offset < PCI_DEVICE_SPECIFIC)
1579807SN/A        PciDevice::writeConfig(pkt);
158837SN/A    else
159897SN/A        panic("Device specific PCI config space not implemented!\n");
160897SN/A
161897SN/A    switch (offset) {
1621027SN/A        // seems to work fine without all these PCI settings, but i
1631027SN/A        // put in the IO to double check, an assertion will fail if we
1641027SN/A        // need to properly implement it
165917SN/A      case PCI_COMMAND:
166917SN/A        if (config.data[offset] & PCI_CMD_IOSE)
167927SN/A            ioEnable = true;
168917SN/A        else
169927SN/A            ioEnable = false;
170897SN/A        break;
171897SN/A    }
1724875SN/A
1732846SN/A    return configDelay;
174837SN/A}
175837SN/A
17613784Sgabeblack@google.comPort &
17713784Sgabeblack@google.comNSGigE::getPort(const std::string &if_name, PortID idx)
1784981SN/A{
17913784Sgabeblack@google.com    if (if_name == "interface")
18013784Sgabeblack@google.com       return *interface;
18113784Sgabeblack@google.com    return EtherDevBase::getPort(if_name, idx);
1824981SN/A}
1834981SN/A
184855SN/A/**
185855SN/A * This reads the device registers, which are detailed in the NS83820
186855SN/A * spec sheet
187855SN/A */
1882566SN/ATick
1893349SN/ANSGigE::read(PacketPtr pkt)
190837SN/A{
191927SN/A    assert(ioEnable);
192917SN/A
193855SN/A    //The mask is to give you only the offset into the device register file
1942641SN/A    Addr daddr = pkt->getAddr() & 0xfff;
1952566SN/A    DPRINTF(EthernetPIO, "read  da=%#x pa=%#x size=%d\n",
1962641SN/A            daddr, pkt->getAddr(), pkt->getSize());
197837SN/A
198855SN/A
1991027SN/A    // there are some reserved registers, you can see ns_gige_reg.h and
2001027SN/A    // the spec sheet for details
201854SN/A    if (daddr > LAST && daddr <=  RESERVED) {
202837SN/A        panic("Accessing reserved register");
203854SN/A    } else if (daddr > RESERVED && daddr <= 0x3FC) {
2042846SN/A        return readConfig(pkt);
205854SN/A    } else if (daddr >= MIB_START && daddr <= MIB_END) {
206854SN/A        // don't implement all the MIB's.  hopefully the kernel
207854SN/A        // doesn't actually DEPEND upon their values
208855SN/A        // MIB are just hardware stats keepers
20913342Sgabeblack@google.com        pkt->setLE<uint32_t>(0);
2104870SN/A        pkt->makeAtomicResponse();
2112566SN/A        return pioDelay;
212854SN/A    } else if (daddr > 0x3FC)
213854SN/A        panic("Something is messed up!\n");
214837SN/A
2152641SN/A    assert(pkt->getSize() == sizeof(uint32_t));
2162630SN/A        uint32_t &reg = *pkt->getPtr<uint32_t>();
2172566SN/A        uint16_t rfaddr;
2182566SN/A
2192566SN/A        switch (daddr) {
2202566SN/A          case CR:
2212566SN/A            reg = regs.command;
2222566SN/A            //these are supposed to be cleared on a read
2232566SN/A            reg &= ~(CR_RXD | CR_TXD | CR_TXR | CR_RXR);
2242566SN/A            break;
2252566SN/A
2262566SN/A          case CFGR:
2272566SN/A            reg = regs.config;
2282566SN/A            break;
2292566SN/A
2302566SN/A          case MEAR:
2312566SN/A            reg = regs.mear;
2322566SN/A            break;
2332566SN/A
2342566SN/A          case PTSCR:
2352566SN/A            reg = regs.ptscr;
2362566SN/A            break;
2372566SN/A
2382566SN/A          case ISR:
2392566SN/A            reg = regs.isr;
2402566SN/A            devIntrClear(ISR_ALL);
2412566SN/A            break;
2422566SN/A
2432566SN/A          case IMR:
2442566SN/A            reg = regs.imr;
2452566SN/A            break;
2462566SN/A
2472566SN/A          case IER:
2482566SN/A            reg = regs.ier;
2492566SN/A            break;
2502566SN/A
2512566SN/A          case IHR:
2522566SN/A            reg = regs.ihr;
2532566SN/A            break;
2542566SN/A
2552566SN/A          case TXDP:
2562566SN/A            reg = regs.txdp;
2572566SN/A            break;
2582566SN/A
2592566SN/A          case TXDP_HI:
2602566SN/A            reg = regs.txdp_hi;
2612566SN/A            break;
2622566SN/A
2632566SN/A          case TX_CFG:
2642566SN/A            reg = regs.txcfg;
2652566SN/A            break;
2662566SN/A
2672566SN/A          case GPIOR:
2682566SN/A            reg = regs.gpior;
2692566SN/A            break;
2702566SN/A
2712566SN/A          case RXDP:
2722566SN/A            reg = regs.rxdp;
2732566SN/A            break;
2742566SN/A
2752566SN/A          case RXDP_HI:
2762566SN/A            reg = regs.rxdp_hi;
2772566SN/A            break;
2782566SN/A
2792566SN/A          case RX_CFG:
2802566SN/A            reg = regs.rxcfg;
2812566SN/A            break;
2822566SN/A
2832566SN/A          case PQCR:
2842566SN/A            reg = regs.pqcr;
2852566SN/A            break;
2862566SN/A
2872566SN/A          case WCSR:
2882566SN/A            reg = regs.wcsr;
2892566SN/A            break;
2902566SN/A
2912566SN/A          case PCR:
2922566SN/A            reg = regs.pcr;
2932566SN/A            break;
2942566SN/A
2952566SN/A            // see the spec sheet for how RFCR and RFDR work
2962566SN/A            // basically, you write to RFCR to tell the machine
2972566SN/A            // what you want to do next, then you act upon RFDR,
2982566SN/A            // and the device will be prepared b/c of what you
2992566SN/A            // wrote to RFCR
3002566SN/A          case RFCR:
3012566SN/A            reg = regs.rfcr;
3022566SN/A            break;
3032566SN/A
3042566SN/A          case RFDR:
3052566SN/A            rfaddr = (uint16_t)(regs.rfcr & RFCR_RFADDR);
3062566SN/A            switch (rfaddr) {
3072566SN/A              // Read from perfect match ROM octets
3082566SN/A              case 0x000:
3092566SN/A                reg = rom.perfectMatch[1];
3102566SN/A                reg = reg << 8;
3112566SN/A                reg += rom.perfectMatch[0];
312837SN/A                break;
3132566SN/A              case 0x002:
3142566SN/A                reg = rom.perfectMatch[3] << 8;
3152566SN/A                reg += rom.perfectMatch[2];
316837SN/A                break;
3172566SN/A              case 0x004:
3182566SN/A                reg = rom.perfectMatch[5] << 8;
3192566SN/A                reg += rom.perfectMatch[4];
320837SN/A                break;
3212566SN/A              default:
3222566SN/A                // Read filter hash table
3232566SN/A                if (rfaddr >= FHASH_ADDR &&
3242566SN/A                    rfaddr < FHASH_ADDR + FHASH_SIZE) {
3252566SN/A
3262566SN/A                    // Only word-aligned reads supported
3272566SN/A                    if (rfaddr % 2)
3282566SN/A                        panic("unaligned read from filter hash table!");
3292566SN/A
3302566SN/A                    reg = rom.filterHash[rfaddr - FHASH_ADDR + 1] << 8;
3312566SN/A                    reg += rom.filterHash[rfaddr - FHASH_ADDR];
332837SN/A                    break;
333837SN/A                }
3342566SN/A
3352566SN/A                panic("reading RFDR for something other than pattern"
3362566SN/A                      " matching or hashing! %#x\n", rfaddr);
337837SN/A            }
3382566SN/A            break;
3392566SN/A
3402566SN/A          case SRR:
3412566SN/A            reg = regs.srr;
3422566SN/A            break;
3432566SN/A
3442566SN/A          case MIBC:
3452566SN/A            reg = regs.mibc;
3462566SN/A            reg &= ~(MIBC_MIBS | MIBC_ACLR);
3472566SN/A            break;
3482566SN/A
3492566SN/A          case VRCR:
3502566SN/A            reg = regs.vrcr;
3512566SN/A            break;
3522566SN/A
3532566SN/A          case VTCR:
3542566SN/A            reg = regs.vtcr;
3552566SN/A            break;
3562566SN/A
3572566SN/A          case VDR:
3582566SN/A            reg = regs.vdr;
3592566SN/A            break;
3602566SN/A
3612566SN/A          case CCSR:
3622566SN/A            reg = regs.ccsr;
3632566SN/A            break;
3642566SN/A
3652566SN/A          case TBICR:
3662566SN/A            reg = regs.tbicr;
3672566SN/A            break;
3682566SN/A
3692566SN/A          case TBISR:
3702566SN/A            reg = regs.tbisr;
3712566SN/A            break;
3722566SN/A
3732566SN/A          case TANAR:
3742566SN/A            reg = regs.tanar;
3752566SN/A            break;
3762566SN/A
3772566SN/A          case TANLPAR:
3782566SN/A            reg = regs.tanlpar;
3792566SN/A            break;
3802566SN/A
3812566SN/A          case TANER:
3822566SN/A            reg = regs.taner;
3832566SN/A            break;
3842566SN/A
3852566SN/A          case TESR:
3862566SN/A            reg = regs.tesr;
3872566SN/A            break;
3882566SN/A
3892566SN/A          case M5REG:
3902566SN/A            reg = 0;
3912566SN/A            if (params()->rx_thread)
3922566SN/A                reg |= M5REG_RX_THREAD;
3932566SN/A            if (params()->tx_thread)
3942566SN/A                reg |= M5REG_TX_THREAD;
3952566SN/A            if (params()->rss)
3962566SN/A                reg |= M5REG_RSS;
3972566SN/A            break;
3982566SN/A
3992566SN/A          default:
4002566SN/A            panic("reading unimplemented register: addr=%#x", daddr);
401837SN/A        }
4022566SN/A
4032566SN/A        DPRINTF(EthernetPIO, "read from %#x: data=%d data=%#x\n",
4042566SN/A                daddr, reg, reg);
4052566SN/A
4064870SN/A    pkt->makeAtomicResponse();
4072566SN/A    return pioDelay;
408837SN/A}
409837SN/A
4102566SN/ATick
4113349SN/ANSGigE::write(PacketPtr pkt)
412837SN/A{
413927SN/A    assert(ioEnable);
414917SN/A
4152641SN/A    Addr daddr = pkt->getAddr() & 0xfff;
4162566SN/A    DPRINTF(EthernetPIO, "write da=%#x pa=%#x size=%d\n",
4172641SN/A            daddr, pkt->getAddr(), pkt->getSize());
4182630SN/A
419854SN/A    if (daddr > LAST && daddr <=  RESERVED) {
420837SN/A        panic("Accessing reserved register");
421854SN/A    } else if (daddr > RESERVED && daddr <= 0x3FC) {
4222846SN/A        return writeConfig(pkt);
423854SN/A    } else if (daddr > 0x3FC)
424854SN/A        panic("Something is messed up!\n");
425837SN/A
4262641SN/A    if (pkt->getSize() == sizeof(uint32_t)) {
42713342Sgabeblack@google.com        uint32_t reg = pkt->getLE<uint32_t>();
4281848SN/A        uint16_t rfaddr;
4291848SN/A
430854SN/A        DPRINTF(EthernetPIO, "write data=%d data=%#x\n", reg, reg);
431837SN/A
432837SN/A        switch (daddr) {
433837SN/A          case CR:
434837SN/A            regs.command = reg;
4351035SN/A            if (reg & CR_TXD) {
4361035SN/A                txEnable = false;
437837SN/A            } else if (reg & CR_TXE) {
4382126SN/A                txEnable = true;
4392126SN/A
4402126SN/A                // the kernel is enabling the transmit machine
4412126SN/A                if (txState == txIdle)
4422126SN/A                    txKick();
443837SN/A            }
444837SN/A
4451035SN/A            if (reg & CR_RXD) {
4461035SN/A                rxEnable = false;
447837SN/A            } else if (reg & CR_RXE) {
4482126SN/A                rxEnable = true;
4492126SN/A
4502126SN/A                if (rxState == rxIdle)
4512126SN/A                    rxKick();
452837SN/A            }
453837SN/A
454837SN/A            if (reg & CR_TXR)
455837SN/A                txReset();
456837SN/A
457837SN/A            if (reg & CR_RXR)
458837SN/A                rxReset();
459837SN/A
460837SN/A            if (reg & CR_SWI)
461837SN/A                devIntrPost(ISR_SWI);
462837SN/A
463837SN/A            if (reg & CR_RST) {
464837SN/A                txReset();
465837SN/A                rxReset();
466854SN/A
467837SN/A                regsReset();
468837SN/A            }
469837SN/A            break;
470837SN/A
4711690SN/A          case CFGR:
4721690SN/A            if (reg & CFGR_LNKSTS ||
4731690SN/A                reg & CFGR_SPDSTS ||
4741690SN/A                reg & CFGR_DUPSTS ||
4751690SN/A                reg & CFGR_RESERVED ||
4761690SN/A                reg & CFGR_T64ADDR ||
4778726SN/A                reg & CFGR_PCI64_DET) {
4788726SN/A                // First clear all writable bits
4798726SN/A                regs.config &= CFGR_LNKSTS | CFGR_SPDSTS | CFGR_DUPSTS |
4808726SN/A                    CFGR_RESERVED | CFGR_T64ADDR |
4818726SN/A                    CFGR_PCI64_DET;
4828726SN/A                // Now set the appropriate writable bits
4838726SN/A                regs.config |= reg & ~(CFGR_LNKSTS | CFGR_SPDSTS | CFGR_DUPSTS |
4848726SN/A                                       CFGR_RESERVED | CFGR_T64ADDR |
4858726SN/A                                       CFGR_PCI64_DET);
4868726SN/A            }
4871027SN/A
4888737SN/A            if (reg & CFGR_AUTO_1000)
4898737SN/A                panic("CFGR_AUTO_1000 not implemented!\n");
4908737SN/A
4918737SN/A            if (reg & CFGR_PCI64_DET)
4928737SN/A                panic("CFGR_PCI64_DET is read only register!\n");
4938737SN/A
4948737SN/A            if (reg & CFGR_EXTSTS_EN)
4958737SN/A                extstsEnable = true;
4968737SN/A            else
4978737SN/A                extstsEnable = false;
498837SN/A            break;
499837SN/A
500837SN/A          case MEAR:
5011843SN/A            // Clear writable bits
5021843SN/A            regs.mear &= MEAR_EEDO;
5031843SN/A            // Set appropriate writable bits
5041843SN/A            regs.mear |= reg & ~MEAR_EEDO;
5051843SN/A
5061843SN/A            // FreeBSD uses the EEPROM to read PMATCH (for the MAC address)
5071843SN/A            // even though it could get it through RFDR
5081843SN/A            if (reg & MEAR_EESEL) {
5091843SN/A                // Rising edge of clock
5101843SN/A                if (reg & MEAR_EECLK && !eepromClk)
5111843SN/A                    eepromKick();
5121843SN/A            }
5131843SN/A            else {
5141843SN/A                eepromState = eepromStart;
5151843SN/A                regs.mear &= ~MEAR_EEDI;
5161843SN/A            }
5171843SN/A
5181843SN/A            eepromClk = reg & MEAR_EECLK;
5191843SN/A
5201027SN/A            // since phy is completely faked, MEAR_MD* don't matter
521837SN/A            break;
522837SN/A
523837SN/A          case PTSCR:
524854SN/A            regs.ptscr = reg & ~(PTSCR_RBIST_RDONLY);
5251027SN/A            // these control BISTs for various parts of chip - we
5261027SN/A            // don't care or do just fake that the BIST is done
527854SN/A            if (reg & PTSCR_RBIST_EN)
528854SN/A                regs.ptscr |= PTSCR_RBIST_DONE;
529854SN/A            if (reg & PTSCR_EEBIST_EN)
530854SN/A                regs.ptscr &= ~PTSCR_EEBIST_EN;
531854SN/A            if (reg & PTSCR_EELOAD_EN)
532854SN/A                regs.ptscr &= ~PTSCR_EELOAD_EN;
533837SN/A            break;
534837SN/A
535837SN/A          case ISR: /* writing to the ISR has no effect */
536837SN/A            panic("ISR is a read only register!\n");
537837SN/A
538837SN/A          case IMR:
539837SN/A            regs.imr = reg;
540837SN/A            devIntrChangeMask();
541837SN/A            break;
542837SN/A
543837SN/A          case IER:
544837SN/A            regs.ier = reg;
545837SN/A            break;
546837SN/A
547837SN/A          case IHR:
548837SN/A            regs.ihr = reg;
549837SN/A            /* not going to implement real interrupt holdoff */
550837SN/A            break;
551837SN/A
552837SN/A          case TXDP:
553837SN/A            regs.txdp = (reg & 0xFFFFFFFC);
554837SN/A            assert(txState == txIdle);
555837SN/A            CTDD = false;
556837SN/A            break;
557837SN/A
558837SN/A          case TXDP_HI:
559837SN/A            regs.txdp_hi = reg;
560837SN/A            break;
561837SN/A
5621690SN/A          case TX_CFG:
563837SN/A            regs.txcfg = reg;
5641027SN/A
5651027SN/A            // also, we currently don't care about fill/drain
5661027SN/A            // thresholds though this may change in the future with
5671027SN/A            // more realistic networks or a driver which changes it
5681027SN/A            // according to feedback
569837SN/A
570837SN/A            break;
571837SN/A
572837SN/A          case GPIOR:
5731843SN/A            // Only write writable bits
5741843SN/A            regs.gpior &= GPIOR_UNUSED | GPIOR_GP5_IN | GPIOR_GP4_IN
5751843SN/A                        | GPIOR_GP3_IN | GPIOR_GP2_IN | GPIOR_GP1_IN;
5761843SN/A            regs.gpior |= reg & ~(GPIOR_UNUSED | GPIOR_GP5_IN | GPIOR_GP4_IN
5771843SN/A                                | GPIOR_GP3_IN | GPIOR_GP2_IN | GPIOR_GP1_IN);
578837SN/A            /* these just control general purpose i/o pins, don't matter */
579837SN/A            break;
580837SN/A
581854SN/A          case RXDP:
582854SN/A            regs.rxdp = reg;
5831035SN/A            CRDD = false;
584854SN/A            break;
585854SN/A
586854SN/A          case RXDP_HI:
587854SN/A            regs.rxdp_hi = reg;
588854SN/A            break;
589854SN/A
5901690SN/A          case RX_CFG:
591837SN/A            regs.rxcfg = reg;
592837SN/A            break;
593837SN/A
594837SN/A          case PQCR:
595837SN/A            /* there is no priority queueing used in the linux 2.6 driver */
596837SN/A            regs.pqcr = reg;
597837SN/A            break;
598837SN/A
599837SN/A          case WCSR:
600837SN/A            /* not going to implement wake on LAN */
601837SN/A            regs.wcsr = reg;
602837SN/A            break;
603837SN/A
604837SN/A          case PCR:
605837SN/A            /* not going to implement pause control */
606837SN/A            regs.pcr = reg;
607837SN/A            break;
608837SN/A
609837SN/A          case RFCR:
610837SN/A            regs.rfcr = reg;
611854SN/A
612837SN/A            rxFilterEnable = (reg & RFCR_RFEN) ? true : false;
613837SN/A            acceptBroadcast = (reg & RFCR_AAB) ? true : false;
614837SN/A            acceptMulticast = (reg & RFCR_AAM) ? true : false;
615837SN/A            acceptUnicast = (reg & RFCR_AAU) ? true : false;
616837SN/A            acceptPerfect = (reg & RFCR_APM) ? true : false;
617837SN/A            acceptArp = (reg & RFCR_AARP) ? true : false;
6181843SN/A            multicastHashEnable = (reg & RFCR_MHEN) ? true : false;
619837SN/A
6201843SN/A            if (reg & RFCR_UHEN)
6211843SN/A                panic("Unicast hash filtering not used by drivers!\n");
622837SN/A
623837SN/A            if (reg & RFCR_ULM)
624837SN/A                panic("RFCR_ULM not implemented!\n");
625837SN/A
626837SN/A            break;
627837SN/A
628837SN/A          case RFDR:
6291848SN/A            rfaddr = (uint16_t)(regs.rfcr & RFCR_RFADDR);
6301843SN/A            switch (rfaddr) {
6311843SN/A              case 0x000:
6321843SN/A                rom.perfectMatch[0] = (uint8_t)reg;
6331843SN/A                rom.perfectMatch[1] = (uint8_t)(reg >> 8);
6341843SN/A                break;
6351843SN/A              case 0x002:
6361843SN/A                rom.perfectMatch[2] = (uint8_t)reg;
6371843SN/A                rom.perfectMatch[3] = (uint8_t)(reg >> 8);
6381843SN/A                break;
6391843SN/A              case 0x004:
6401843SN/A                rom.perfectMatch[4] = (uint8_t)reg;
6411843SN/A                rom.perfectMatch[5] = (uint8_t)(reg >> 8);
6421843SN/A                break;
6431843SN/A              default:
6441843SN/A
6451843SN/A                if (rfaddr >= FHASH_ADDR &&
6461843SN/A                    rfaddr < FHASH_ADDR + FHASH_SIZE) {
6471843SN/A
6481843SN/A                    // Only word-aligned writes supported
6491843SN/A                    if (rfaddr % 2)
6501843SN/A                        panic("unaligned write to filter hash table!");
6511843SN/A
6521843SN/A                    rom.filterHash[rfaddr - FHASH_ADDR] = (uint8_t)reg;
6531843SN/A                    rom.filterHash[rfaddr - FHASH_ADDR + 1]
6541843SN/A                        = (uint8_t)(reg >> 8);
6551843SN/A                    break;
6561843SN/A                }
65710367SN/A                panic("writing RFDR for something other than pattern matching "
65810367SN/A                    "or hashing! %#x\n", rfaddr);
6591843SN/A            }
66012561Ssiddhesh.poyarekar@gmail.com            break;
661837SN/A
662837SN/A          case BRAR:
6631843SN/A            regs.brar = reg;
6641843SN/A            break;
665837SN/A
666837SN/A          case BRDR:
667837SN/A            panic("the driver never uses BRDR, something is wrong!\n");
668837SN/A
669837SN/A          case SRR:
670837SN/A            panic("SRR is read only register!\n");
671837SN/A
672837SN/A          case MIBC:
673837SN/A            panic("the driver never uses MIBC, something is wrong!\n");
674837SN/A
675837SN/A          case VRCR:
676837SN/A            regs.vrcr = reg;
677837SN/A            break;
678837SN/A
679837SN/A          case VTCR:
680837SN/A            regs.vtcr = reg;
681837SN/A            break;
682837SN/A
683837SN/A          case VDR:
684837SN/A            panic("the driver never uses VDR, something is wrong!\n");
685837SN/A
686837SN/A          case CCSR:
687837SN/A            /* not going to implement clockrun stuff */
688837SN/A            regs.ccsr = reg;
689837SN/A            break;
690837SN/A
691837SN/A          case TBICR:
692837SN/A            regs.tbicr = reg;
693837SN/A            if (reg & TBICR_MR_LOOPBACK)
694837SN/A                panic("TBICR_MR_LOOPBACK never used, something wrong!\n");
695837SN/A
696837SN/A            if (reg & TBICR_MR_AN_ENABLE) {
697837SN/A                regs.tanlpar = regs.tanar;
698837SN/A                regs.tbisr |= (TBISR_MR_AN_COMPLETE | TBISR_MR_LINK_STATUS);
699837SN/A            }
700837SN/A
701837SN/A            break;
702837SN/A
703837SN/A          case TBISR:
704837SN/A            panic("TBISR is read only register!\n");
705837SN/A
706837SN/A          case TANAR:
7071843SN/A            // Only write the writable bits
7081843SN/A            regs.tanar &= TANAR_RF1 | TANAR_RF2 | TANAR_UNUSED;
7091843SN/A            regs.tanar |= reg & ~(TANAR_RF1 | TANAR_RF2 | TANAR_UNUSED);
7101843SN/A
7111843SN/A            // Pause capability unimplemented
712837SN/A            break;
713837SN/A
714837SN/A          case TANLPAR:
715837SN/A            panic("this should only be written to by the fake phy!\n");
716837SN/A
717837SN/A          case TANER:
718837SN/A            panic("TANER is read only register!\n");
719837SN/A
720837SN/A          case TESR:
721837SN/A            regs.tesr = reg;
722837SN/A            break;
723837SN/A
724837SN/A          default:
7251027SN/A            panic("invalid register access daddr=%#x", daddr);
726837SN/A        }
7271027SN/A    } else {
728837SN/A        panic("Invalid Request Size");
7291027SN/A    }
7304870SN/A    pkt->makeAtomicResponse();
7312566SN/A    return pioDelay;
732837SN/A}
733837SN/A
734837SN/Avoid
735879SN/ANSGigE::devIntrPost(uint32_t interrupts)
736837SN/A{
737854SN/A    if (interrupts & ISR_RESERVE)
738854SN/A        panic("Cannot set a reserved interrupt");
739837SN/A
7401057SN/A    if (interrupts & ISR_NOIMPL)
7411057SN/A        warn("interrupt not implemented %#x\n", interrupts);
7421057SN/A
7431883SN/A    interrupts &= ISR_IMPL;
7441057SN/A    regs.isr |= interrupts;
7451057SN/A
7461263SN/A    if (interrupts & regs.imr) {
7471263SN/A        if (interrupts & ISR_SWI) {
7481263SN/A            totalSwi++;
7491263SN/A        }
7501263SN/A        if (interrupts & ISR_RXIDLE) {
7511263SN/A            totalRxIdle++;
7521263SN/A        }
7531263SN/A        if (interrupts & ISR_RXOK) {
7541263SN/A            totalRxOk++;
7551263SN/A        }
7561263SN/A        if (interrupts & ISR_RXDESC) {
7571263SN/A            totalRxDesc++;
7581263SN/A        }
7591263SN/A        if (interrupts & ISR_TXOK) {
7601263SN/A            totalTxOk++;
7611263SN/A        }
7621263SN/A        if (interrupts & ISR_TXIDLE) {
7631263SN/A            totalTxIdle++;
7641263SN/A        }
7651263SN/A        if (interrupts & ISR_TXDESC) {
7661263SN/A            totalTxDesc++;
7671263SN/A        }
7681263SN/A        if (interrupts & ISR_RXORN) {
7691263SN/A            totalRxOrn++;
7701263SN/A        }
7711263SN/A    }
7721263SN/A
7731057SN/A    DPRINTF(EthernetIntr,
7741057SN/A            "interrupt written to ISR: intr=%#x isr=%#x imr=%#x\n",
7751057SN/A            interrupts, regs.isr, regs.imr);
776837SN/A
777854SN/A    if ((regs.isr & regs.imr)) {
7787823SN/A        Tick when = curTick();
7791883SN/A        if ((regs.isr & regs.imr & ISR_NODELAY) == 0)
780854SN/A            when += intrDelay;
7815485SN/A        postedInterrupts++;
782854SN/A        cpuIntrPost(when);
783854SN/A    }
784837SN/A}
785837SN/A
7861263SN/A/* writing this interrupt counting stats inside this means that this function
7871263SN/A   is now limited to being used to clear all interrupts upon the kernel
7881263SN/A   reading isr and servicing.  just telling you in case you were thinking
7891263SN/A   of expanding use.
7901263SN/A*/
791837SN/Avoid
792879SN/ANSGigE::devIntrClear(uint32_t interrupts)
793837SN/A{
794837SN/A    if (interrupts & ISR_RESERVE)
795837SN/A        panic("Cannot clear a reserved interrupt");
796837SN/A
7971263SN/A    if (regs.isr & regs.imr & ISR_SWI) {
7981263SN/A        postedSwi++;
7991263SN/A    }
8001263SN/A    if (regs.isr & regs.imr & ISR_RXIDLE) {
8011263SN/A        postedRxIdle++;
8021263SN/A    }
8031263SN/A    if (regs.isr & regs.imr & ISR_RXOK) {
8041263SN/A        postedRxOk++;
8051263SN/A    }
8061263SN/A    if (regs.isr & regs.imr & ISR_RXDESC) {
8071263SN/A            postedRxDesc++;
8081263SN/A    }
8091263SN/A    if (regs.isr & regs.imr & ISR_TXOK) {
8101263SN/A        postedTxOk++;
8111263SN/A    }
8121263SN/A    if (regs.isr & regs.imr & ISR_TXIDLE) {
8131263SN/A        postedTxIdle++;
8141263SN/A    }
8151263SN/A    if (regs.isr & regs.imr & ISR_TXDESC) {
8161263SN/A        postedTxDesc++;
8171263SN/A    }
8181263SN/A    if (regs.isr & regs.imr & ISR_RXORN) {
8191263SN/A        postedRxOrn++;
8201263SN/A    }
8211263SN/A
8221057SN/A    interrupts &= ~ISR_NOIMPL;
8231057SN/A    regs.isr &= ~interrupts;
824837SN/A
8251027SN/A    DPRINTF(EthernetIntr,
8261027SN/A            "interrupt cleared from ISR: intr=%x isr=%x imr=%x\n",
827881SN/A            interrupts, regs.isr, regs.imr);
8281036SN/A
8291036SN/A    if (!(regs.isr & regs.imr))
8301036SN/A        cpuIntrClear();
831837SN/A}
832837SN/A
833837SN/Avoid
834879SN/ANSGigE::devIntrChangeMask()
835837SN/A{
8361036SN/A    DPRINTF(EthernetIntr, "interrupt mask changed: isr=%x imr=%x masked=%x\n",
8371036SN/A            regs.isr, regs.imr, regs.isr & regs.imr);
838837SN/A
839837SN/A    if (regs.isr & regs.imr)
8407823SN/A        cpuIntrPost(curTick());
841837SN/A    else
842837SN/A        cpuIntrClear();
843837SN/A}
844837SN/A
845837SN/Avoid
846879SN/ANSGigE::cpuIntrPost(Tick when)
847837SN/A{
8481027SN/A    // If the interrupt you want to post is later than an interrupt
8491027SN/A    // already scheduled, just let it post in the coming one and don't
8501027SN/A    // schedule another.
8511027SN/A    // HOWEVER, must be sure that the scheduled intrTick is in the
8521027SN/A    // future (this was formerly the source of a bug)
8531035SN/A    /**
8541035SN/A     * @todo this warning should be removed and the intrTick code should
8551035SN/A     * be fixed.
8561035SN/A     */
8577823SN/A    assert(when >= curTick());
8587823SN/A    assert(intrTick >= curTick() || intrTick == 0);
8591072SN/A    if (when > intrTick && intrTick != 0) {
8601072SN/A        DPRINTF(EthernetIntr, "don't need to schedule event...intrTick=%d\n",
8611072SN/A                intrTick);
8621072SN/A        return;
8631035SN/A    }
864854SN/A
865854SN/A    intrTick = when;
8667823SN/A    if (intrTick < curTick()) {
8677823SN/A        intrTick = curTick();
8681072SN/A    }
8691072SN/A
8701072SN/A    DPRINTF(EthernetIntr, "going to schedule an interrupt for intrTick=%d\n",
8711072SN/A            intrTick);
8721072SN/A
8731072SN/A    if (intrEvent)
874854SN/A        intrEvent->squash();
87512087Sspwilson2@wisc.edu
87612087Sspwilson2@wisc.edu    intrEvent = new EventFunctionWrapper([this]{ cpuInterrupt(); },
87712087Sspwilson2@wisc.edu                                         name(), true);
8785606SN/A    schedule(intrEvent, intrTick);
879854SN/A}
880854SN/A
881854SN/Avoid
882879SN/ANSGigE::cpuInterrupt()
883854SN/A{
8847823SN/A    assert(intrTick == curTick());
8851072SN/A
8861072SN/A    // Whether or not there's a pending interrupt, we don't care about
8871072SN/A    // it anymore
8881072SN/A    intrEvent = 0;
8891072SN/A    intrTick = 0;
8901072SN/A
891854SN/A    // Don't send an interrupt if there's already one
892927SN/A    if (cpuPendingIntr) {
893927SN/A        DPRINTF(EthernetIntr,
894927SN/A                "would send an interrupt now, but there's already pending\n");
8951072SN/A    } else {
8961072SN/A        // Send interrupt
8971072SN/A        cpuPendingIntr = true;
8981072SN/A
8991149SN/A        DPRINTF(EthernetIntr, "posting interrupt\n");
9001149SN/A        intrPost();
901927SN/A    }
902837SN/A}
903837SN/A
904837SN/Avoid
905879SN/ANSGigE::cpuIntrClear()
906837SN/A{
9071027SN/A    if (!cpuPendingIntr)
9081027SN/A        return;
9091027SN/A
9101072SN/A    if (intrEvent) {
9111072SN/A        intrEvent->squash();
9121072SN/A        intrEvent = 0;
9131072SN/A    }
9141072SN/A
9151072SN/A    intrTick = 0;
9161072SN/A
9171027SN/A    cpuPendingIntr = false;
9181057SN/A
9191149SN/A    DPRINTF(EthernetIntr, "clearing interrupt\n");
9201149SN/A    intrClear();
921837SN/A}
922837SN/A
923837SN/Abool
924879SN/ANSGigE::cpuIntrPending() const
925837SN/A{ return cpuPendingIntr; }
926837SN/A
927837SN/Avoid
928879SN/ANSGigE::txReset()
929837SN/A{
930837SN/A
931837SN/A    DPRINTF(Ethernet, "transmit reset\n");
932837SN/A
933837SN/A    CTDD = false;
9341035SN/A    txEnable = false;;
935854SN/A    txFragPtr = 0;
936854SN/A    assert(txDescCnt == 0);
937837SN/A    txFifo.clear();
938837SN/A    txState = txIdle;
939854SN/A    assert(txDmaState == dmaIdle);
940837SN/A}
941837SN/A
942837SN/Avoid
943879SN/ANSGigE::rxReset()
944837SN/A{
945837SN/A    DPRINTF(Ethernet, "receive reset\n");
946837SN/A
947837SN/A    CRDD = false;
948854SN/A    assert(rxPktBytes == 0);
9491035SN/A    rxEnable = false;
950854SN/A    rxFragPtr = 0;
951854SN/A    assert(rxDescCnt == 0);
952854SN/A    assert(rxDmaState == dmaIdle);
953837SN/A    rxFifo.clear();
954837SN/A    rxState = rxIdle;
955837SN/A}
956837SN/A
9571036SN/Avoid
9581036SN/ANSGigE::regsReset()
959915SN/A{
960915SN/A    memset(&regs, 0, sizeof(regs));
9611817SN/A    regs.config = (CFGR_LNKSTS | CFGR_TBI_EN | CFGR_MODE_1000);
9621843SN/A    regs.mear = 0x12;
9631057SN/A    regs.txcfg = 0x120; // set drain threshold to 1024 bytes and
9641057SN/A                        // fill threshold to 32 bytes
9651057SN/A    regs.rxcfg = 0x4;   // set drain threshold to 16 bytes
9661057SN/A    regs.srr = 0x0103;  // set the silicon revision to rev B or 0x103
9671057SN/A    regs.mibc = MIBC_FRZ;
9681057SN/A    regs.vdr = 0x81;    // set the vlan tag type to 802.1q
9691057SN/A    regs.tesr = 0xc000; // TBI capable of both full and half duplex
9701843SN/A    regs.brar = 0xffffffff;
971927SN/A
972927SN/A    extstsEnable = false;
973927SN/A    acceptBroadcast = false;
974927SN/A    acceptMulticast = false;
975927SN/A    acceptUnicast = false;
976927SN/A    acceptPerfect = false;
977927SN/A    acceptArp = false;
978915SN/A}
979915SN/A
980854SN/Abool
981879SN/ANSGigE::doRxDmaRead()
982854SN/A{
983854SN/A    assert(rxDmaState == dmaIdle || rxDmaState == dmaReadWaiting);
984854SN/A    rxDmaState = dmaReading;
985854SN/A
98610913SN/A    if (dmaPending() || drainState() != DrainState::Running)
9872566SN/A        rxDmaState = dmaReadWaiting;
9882566SN/A    else
9892566SN/A        dmaRead(rxDmaAddr, rxDmaLen, &rxDmaReadEvent, (uint8_t*)rxDmaData);
9902566SN/A
991854SN/A    return true;
992854SN/A}
993854SN/A
994854SN/Avoid
995879SN/ANSGigE::rxDmaReadDone()
996854SN/A{
997854SN/A    assert(rxDmaState == dmaReading);
9982566SN/A    rxDmaState = dmaIdle;
9992566SN/A
10002566SN/A    DPRINTF(EthernetDMA, "rx dma read  paddr=%#x len=%d\n",
10012566SN/A            rxDmaAddr, rxDmaLen);
10022566SN/A    DDUMP(EthernetDMA, rxDmaData, rxDmaLen);
1003854SN/A
1004854SN/A    // If the transmit state machine has a pending DMA, let it go first
1005854SN/A    if (txDmaState == dmaReadWaiting || txDmaState == dmaWriteWaiting)
1006854SN/A        txKick();
1007854SN/A
1008854SN/A    rxKick();
1009854SN/A}
1010854SN/A
1011854SN/Abool
1012879SN/ANSGigE::doRxDmaWrite()
1013854SN/A{
1014854SN/A    assert(rxDmaState == dmaIdle || rxDmaState == dmaWriteWaiting);
1015854SN/A    rxDmaState = dmaWriting;
1016854SN/A
101710913SN/A    if (dmaPending() || drainState() != DrainState::Running)
10182566SN/A        rxDmaState = dmaWriteWaiting;
10192566SN/A    else
10202566SN/A        dmaWrite(rxDmaAddr, rxDmaLen, &rxDmaWriteEvent, (uint8_t*)rxDmaData);
1021854SN/A    return true;
1022854SN/A}
1023854SN/A
1024854SN/Avoid
1025879SN/ANSGigE::rxDmaWriteDone()
1026854SN/A{
1027854SN/A    assert(rxDmaState == dmaWriting);
10282566SN/A    rxDmaState = dmaIdle;
10292566SN/A
10302566SN/A    DPRINTF(EthernetDMA, "rx dma write paddr=%#x len=%d\n",
10312566SN/A            rxDmaAddr, rxDmaLen);
10322566SN/A    DDUMP(EthernetDMA, rxDmaData, rxDmaLen);
1033854SN/A
1034854SN/A    // If the transmit state machine has a pending DMA, let it go first
1035854SN/A    if (txDmaState == dmaReadWaiting || txDmaState == dmaWriteWaiting)
1036854SN/A        txKick();
1037854SN/A
1038854SN/A    rxKick();
1039837SN/A}
1040837SN/A
1041837SN/Avoid
1042879SN/ANSGigE::rxKick()
1043837SN/A{
10441909SN/A    bool is64bit = (bool)(regs.config & CFGR_M64ADDR);
10451909SN/A
10461909SN/A    DPRINTF(EthernetSM,
10471909SN/A            "receive kick rxState=%s (rxBuf.size=%d) %d-bit\n",
10481909SN/A            NsRxStateStrings[rxState], rxFifo.size(), is64bit ? 64 : 32);
10491909SN/A
10501909SN/A    Addr link, bufptr;
10511909SN/A    uint32_t &cmdsts = is64bit ? rxDesc64.cmdsts : rxDesc32.cmdsts;
10521909SN/A    uint32_t &extsts = is64bit ? rxDesc64.extsts : rxDesc32.extsts;
1053837SN/A
10541801SN/A  next:
10559417SN/A    if (rxKickTick > curTick()) {
10569417SN/A        DPRINTF(EthernetSM, "receive kick exiting, can't run till %d\n",
10579417SN/A                rxKickTick);
10581801SN/A
10599417SN/A        goto exit;
10609417SN/A    }
10611801SN/A
10629417SN/A    // Go to the next state machine clock tick.
10639417SN/A    rxKickTick = clockEdge(Cycles(1));
1064837SN/A
1065854SN/A    switch(rxDmaState) {
1066854SN/A      case dmaReadWaiting:
1067854SN/A        if (doRxDmaRead())
1068854SN/A            goto exit;
1069854SN/A        break;
1070854SN/A      case dmaWriteWaiting:
1071854SN/A        if (doRxDmaWrite())
1072854SN/A            goto exit;
1073854SN/A        break;
1074854SN/A      default:
1075854SN/A        break;
1076854SN/A    }
1077837SN/A
10781909SN/A    link = is64bit ? (Addr)rxDesc64.link : (Addr)rxDesc32.link;
10791909SN/A    bufptr = is64bit ? (Addr)rxDesc64.bufptr : (Addr)rxDesc32.bufptr;
10801909SN/A
1081855SN/A    // see state machine from spec for details
10821027SN/A    // the way this works is, if you finish work on one state and can
10831027SN/A    // go directly to another, you do that through jumping to the
10841027SN/A    // label "next".  however, if you have intermediate work, like DMA
10851027SN/A    // so that you can't go to the next state yet, you go to exit and
10861027SN/A    // exit the loop.  however, when the DMA is done it will trigger
10871027SN/A    // an event and come back to this loop.
1088854SN/A    switch (rxState) {
1089854SN/A      case rxIdle:
10901035SN/A        if (!rxEnable) {
1091927SN/A            DPRINTF(EthernetSM, "Receive Disabled! Nothing to do.\n");
1092854SN/A            goto exit;
1093854SN/A        }
1094837SN/A
1095854SN/A        if (CRDD) {
1096854SN/A            rxState = rxDescRefr;
1097837SN/A
1098854SN/A            rxDmaAddr = regs.rxdp & 0x3fffffff;
10991909SN/A            rxDmaData =
11001909SN/A                is64bit ? (void *)&rxDesc64.link : (void *)&rxDesc32.link;
11011909SN/A            rxDmaLen = is64bit ? sizeof(rxDesc64.link) : sizeof(rxDesc32.link);
1102854SN/A            rxDmaFree = dmaDescFree;
1103854SN/A
1104961SN/A            descDmaReads++;
1105961SN/A            descDmaRdBytes += rxDmaLen;
1106961SN/A
1107854SN/A            if (doRxDmaRead())
1108854SN/A                goto exit;
1109837SN/A        } else {
1110837SN/A            rxState = rxDescRead;
1111854SN/A
1112854SN/A            rxDmaAddr = regs.rxdp & 0x3fffffff;
11131909SN/A            rxDmaData = is64bit ? (void *)&rxDesc64 : (void *)&rxDesc32;
11141909SN/A            rxDmaLen = is64bit ? sizeof(rxDesc64) : sizeof(rxDesc32);
1115854SN/A            rxDmaFree = dmaDescFree;
1116854SN/A
1117961SN/A            descDmaReads++;
1118961SN/A            descDmaRdBytes += rxDmaLen;
1119961SN/A
1120854SN/A            if (doRxDmaRead())
1121854SN/A                goto exit;
1122837SN/A        }
1123854SN/A        break;
1124854SN/A
1125854SN/A      case rxDescRefr:
1126854SN/A        if (rxDmaState != dmaIdle)
1127854SN/A            goto exit;
1128854SN/A
1129854SN/A        rxState = rxAdvance;
1130854SN/A        break;
1131854SN/A
1132854SN/A     case rxDescRead:
1133854SN/A        if (rxDmaState != dmaIdle)
1134854SN/A            goto exit;
1135854SN/A
11361909SN/A        DPRINTF(EthernetDesc, "rxDesc: addr=%08x read descriptor\n",
11371036SN/A                regs.rxdp & 0x3fffffff);
11381036SN/A        DPRINTF(EthernetDesc,
11391909SN/A                "rxDesc: link=%#x bufptr=%#x cmdsts=%08x extsts=%08x\n",
11401909SN/A                link, bufptr, cmdsts, extsts);
11411909SN/A
11421909SN/A        if (cmdsts & CMDSTS_OWN) {
11431035SN/A            devIntrPost(ISR_RXIDLE);
1144837SN/A            rxState = rxIdle;
11451035SN/A            goto exit;
1146837SN/A        } else {
1147837SN/A            rxState = rxFifoBlock;
11481909SN/A            rxFragPtr = bufptr;
11491909SN/A            rxDescCnt = cmdsts & CMDSTS_LEN_MASK;
1150854SN/A        }
1151854SN/A        break;
1152837SN/A
1153854SN/A      case rxFifoBlock:
1154854SN/A        if (!rxPacket) {
1155854SN/A            /**
1156854SN/A             * @todo in reality, we should be able to start processing
1157854SN/A             * the packet as it arrives, and not have to wait for the
1158854SN/A             * full packet ot be in the receive fifo.
1159854SN/A             */
1160854SN/A            if (rxFifo.empty())
1161854SN/A                goto exit;
1162854SN/A
11631036SN/A            DPRINTF(EthernetSM, "****processing receive of new packet****\n");
1164927SN/A
1165854SN/A            // If we don't have a packet, grab a new one from the fifo.
1166854SN/A            rxPacket = rxFifo.front();
1167854SN/A            rxPktBytes = rxPacket->length;
1168854SN/A            rxPacketBufPtr = rxPacket->data;
1169854SN/A
11701011SN/A#if TRACING_ON
1171927SN/A            if (DTRACE(Ethernet)) {
11721114SN/A                IpPtr ip(rxPacket);
11731078SN/A                if (ip) {
11741078SN/A                    DPRINTF(Ethernet, "ID is %d\n", ip->id());
11751114SN/A                    TcpPtr tcp(ip);
11761078SN/A                    if (tcp) {
11771561SN/A                        DPRINTF(Ethernet,
11781561SN/A                                "Src Port=%d, Dest Port=%d, Seq=%d, Ack=%d\n",
11791561SN/A                                tcp->sport(), tcp->dport(), tcp->seq(),
11801561SN/A                                tcp->ack());
1181927SN/A                    }
1182927SN/A                }
1183927SN/A            }
11841011SN/A#endif
1185927SN/A
1186854SN/A            // sanity check - i think the driver behaves like this
1187854SN/A            assert(rxDescCnt >= rxPktBytes);
11881154SN/A            rxFifo.pop();
1189837SN/A        }
1190837SN/A
1191837SN/A
11921027SN/A        // dont' need the && rxDescCnt > 0 if driver sanity check
11931027SN/A        // above holds
1194854SN/A        if (rxPktBytes > 0) {
1195854SN/A            rxState = rxFragWrite;
11961027SN/A            // don't need min<>(rxPktBytes,rxDescCnt) if above sanity
11971027SN/A            // check holds
1198854SN/A            rxXferLen = rxPktBytes;
1199854SN/A
1200854SN/A            rxDmaAddr = rxFragPtr & 0x3fffffff;
1201854SN/A            rxDmaData = rxPacketBufPtr;
1202854SN/A            rxDmaLen = rxXferLen;
1203854SN/A            rxDmaFree = dmaDataFree;
1204854SN/A
1205854SN/A            if (doRxDmaWrite())
1206854SN/A                goto exit;
1207854SN/A
1208837SN/A        } else {
1209854SN/A            rxState = rxDescWrite;
1210837SN/A
1211854SN/A            //if (rxPktBytes == 0) {  /* packet is done */
1212854SN/A            assert(rxPktBytes == 0);
1213927SN/A            DPRINTF(EthernetSM, "done with receiving packet\n");
1214837SN/A
12151909SN/A            cmdsts |= CMDSTS_OWN;
12161909SN/A            cmdsts &= ~CMDSTS_MORE;
12171909SN/A            cmdsts |= CMDSTS_OK;
12181909SN/A            cmdsts &= 0xffff0000;
12191909SN/A            cmdsts += rxPacket->length;   //i.e. set CMDSTS_SIZE
1220837SN/A
12211114SN/A            IpPtr ip(rxPacket);
12221114SN/A            if (extstsEnable && ip) {
12231909SN/A                extsts |= EXTSTS_IPPKT;
12241078SN/A                rxIpChecksums++;
12251114SN/A                if (cksum(ip) != 0) {
1226927SN/A                    DPRINTF(EthernetCksum, "Rx IP Checksum Error\n");
12271909SN/A                    extsts |= EXTSTS_IPERR;
1228927SN/A                }
12291114SN/A                TcpPtr tcp(ip);
12301114SN/A                UdpPtr udp(ip);
12311114SN/A                if (tcp) {
12321909SN/A                    extsts |= EXTSTS_TCPPKT;
12331078SN/A                    rxTcpChecksums++;
12341114SN/A                    if (cksum(tcp) != 0) {
1235927SN/A                        DPRINTF(EthernetCksum, "Rx TCP Checksum Error\n");
12361909SN/A                        extsts |= EXTSTS_TCPERR;
1237961SN/A
1238927SN/A                    }
12391114SN/A                } else if (udp) {
12401909SN/A                    extsts |= EXTSTS_UDPPKT;
12411078SN/A                    rxUdpChecksums++;
12421114SN/A                    if (cksum(udp) != 0) {
1243927SN/A                        DPRINTF(EthernetCksum, "Rx UDP Checksum Error\n");
12441909SN/A                        extsts |= EXTSTS_UDPERR;
1245927SN/A                    }
1246837SN/A                }
1247837SN/A            }
1248881SN/A            rxPacket = 0;
1249881SN/A
12501027SN/A            /*
12511027SN/A             * the driver seems to always receive into desc buffers
12521027SN/A             * of size 1514, so you never have a pkt that is split
12531027SN/A             * into multiple descriptors on the receive side, so
12541027SN/A             * i don't implement that case, hence the assert above.
12551027SN/A             */
12561027SN/A
12571027SN/A            DPRINTF(EthernetDesc,
12581909SN/A                    "rxDesc: addr=%08x writeback cmdsts extsts\n",
12591036SN/A                    regs.rxdp & 0x3fffffff);
12601036SN/A            DPRINTF(EthernetDesc,
12611909SN/A                    "rxDesc: link=%#x bufptr=%#x cmdsts=%08x extsts=%08x\n",
12621909SN/A                    link, bufptr, cmdsts, extsts);
12631909SN/A
12641909SN/A            rxDmaAddr = regs.rxdp & 0x3fffffff;
12651909SN/A            rxDmaData = &cmdsts;
12661909SN/A            if (is64bit) {
12671909SN/A                rxDmaAddr += offsetof(ns_desc64, cmdsts);
12681909SN/A                rxDmaLen = sizeof(rxDesc64.cmdsts) + sizeof(rxDesc64.extsts);
12691909SN/A            } else {
12701909SN/A                rxDmaAddr += offsetof(ns_desc32, cmdsts);
12711909SN/A                rxDmaLen = sizeof(rxDesc32.cmdsts) + sizeof(rxDesc32.extsts);
12721909SN/A            }
1273854SN/A            rxDmaFree = dmaDescFree;
1274854SN/A
1275961SN/A            descDmaWrites++;
1276961SN/A            descDmaWrBytes += rxDmaLen;
1277961SN/A
1278854SN/A            if (doRxDmaWrite())
1279854SN/A                goto exit;
1280837SN/A        }
1281854SN/A        break;
1282837SN/A
1283854SN/A      case rxFragWrite:
1284854SN/A        if (rxDmaState != dmaIdle)
1285854SN/A            goto exit;
1286854SN/A
1287854SN/A        rxPacketBufPtr += rxXferLen;
1288854SN/A        rxFragPtr += rxXferLen;
1289854SN/A        rxPktBytes -= rxXferLen;
1290854SN/A
1291854SN/A        rxState = rxFifoBlock;
1292854SN/A        break;
1293854SN/A
1294854SN/A      case rxDescWrite:
1295854SN/A        if (rxDmaState != dmaIdle)
1296854SN/A            goto exit;
1297854SN/A
12981909SN/A        assert(cmdsts & CMDSTS_OWN);
1299854SN/A
1300854SN/A        assert(rxPacket == 0);
1301854SN/A        devIntrPost(ISR_RXOK);
1302854SN/A
13031909SN/A        if (cmdsts & CMDSTS_INTR)
1304854SN/A            devIntrPost(ISR_RXDESC);
1305854SN/A
13061035SN/A        if (!rxEnable) {
1307927SN/A            DPRINTF(EthernetSM, "Halting the RX state machine\n");
1308854SN/A            rxState = rxIdle;
13091035SN/A            goto exit;
1310854SN/A        } else
1311854SN/A            rxState = rxAdvance;
1312854SN/A        break;
1313854SN/A
1314854SN/A      case rxAdvance:
13151909SN/A        if (link == 0) {
13161035SN/A            devIntrPost(ISR_RXIDLE);
1317854SN/A            rxState = rxIdle;
13181035SN/A            CRDD = true;
13191035SN/A            goto exit;
1320854SN/A        } else {
13211893SN/A            if (rxDmaState != dmaIdle)
13221893SN/A                goto exit;
1323854SN/A            rxState = rxDescRead;
13241909SN/A            regs.rxdp = link;
1325854SN/A            CRDD = false;
1326854SN/A
1327854SN/A            rxDmaAddr = regs.rxdp & 0x3fffffff;
13281909SN/A            rxDmaData = is64bit ? (void *)&rxDesc64 : (void *)&rxDesc32;
13291909SN/A            rxDmaLen = is64bit ? sizeof(rxDesc64) : sizeof(rxDesc32);
1330854SN/A            rxDmaFree = dmaDescFree;
1331854SN/A
1332854SN/A            if (doRxDmaRead())
1333854SN/A                goto exit;
1334854SN/A        }
1335854SN/A        break;
1336854SN/A
1337854SN/A      default:
1338854SN/A        panic("Invalid rxState!");
1339837SN/A    }
1340837SN/A
13411036SN/A    DPRINTF(EthernetSM, "entering next rxState=%s\n",
1342854SN/A            NsRxStateStrings[rxState]);
1343854SN/A    goto next;
1344837SN/A
1345854SN/A  exit:
1346854SN/A    /**
1347854SN/A     * @todo do we want to schedule a future kick?
1348854SN/A     */
13491036SN/A    DPRINTF(EthernetSM, "rx state machine exited rxState=%s\n",
1350854SN/A            NsRxStateStrings[rxState]);
13511801SN/A
13529417SN/A    if (!rxKickEvent.scheduled())
13535606SN/A        schedule(rxKickEvent, rxKickTick);
1354837SN/A}
1355837SN/A
1356837SN/Avoid
1357879SN/ANSGigE::transmit()
1358837SN/A{
1359837SN/A    if (txFifo.empty()) {
1360837SN/A        DPRINTF(Ethernet, "nothing to transmit\n");
1361837SN/A        return;
1362837SN/A    }
1363837SN/A
13641036SN/A    DPRINTF(Ethernet, "Attempt Pkt Transmit: txFifo length=%d\n",
13651154SN/A            txFifo.size());
1366927SN/A    if (interface->sendPacket(txFifo.front())) {
13671011SN/A#if TRACING_ON
1368927SN/A        if (DTRACE(Ethernet)) {
13691114SN/A            IpPtr ip(txFifo.front());
13701078SN/A            if (ip) {
13711078SN/A                DPRINTF(Ethernet, "ID is %d\n", ip->id());
13721114SN/A                TcpPtr tcp(ip);
13731078SN/A                if (tcp) {
13741561SN/A                    DPRINTF(Ethernet,
13751561SN/A                            "Src Port=%d, Dest Port=%d, Seq=%d, Ack=%d\n",
13761909SN/A                            tcp->sport(), tcp->dport(), tcp->seq(),
13771909SN/A                            tcp->ack());
1378927SN/A                }
1379927SN/A            }
1380927SN/A        }
13811011SN/A#endif
1382927SN/A
13831561SN/A        DDUMP(EthernetData, txFifo.front()->data, txFifo.front()->length);
1384837SN/A        txBytes += txFifo.front()->length;
1385837SN/A        txPackets++;
1386837SN/A
13871027SN/A        DPRINTF(Ethernet, "Successful Xmit! now txFifoAvail is %d\n",
13881154SN/A                txFifo.avail());
13891154SN/A        txFifo.pop();
1390837SN/A
13911027SN/A        /*
13921027SN/A         * normally do a writeback of the descriptor here, and ONLY
13931027SN/A         * after that is done, send this interrupt.  but since our
13941027SN/A         * stuff never actually fails, just do this interrupt here,
13951027SN/A         * otherwise the code has to stray from this nice format.
13961027SN/A         * besides, it's functionally the same.
13971027SN/A         */
1398854SN/A        devIntrPost(ISR_TXOK);
13991027SN/A    }
1400854SN/A
1401854SN/A   if (!txFifo.empty() && !txEvent.scheduled()) {
1402854SN/A       DPRINTF(Ethernet, "reschedule transmit\n");
14037823SN/A       schedule(txEvent, curTick() + retryTime);
1404854SN/A   }
1405854SN/A}
1406854SN/A
1407854SN/Abool
1408879SN/ANSGigE::doTxDmaRead()
1409854SN/A{
1410854SN/A    assert(txDmaState == dmaIdle || txDmaState == dmaReadWaiting);
1411854SN/A    txDmaState = dmaReading;
1412854SN/A
141310913SN/A    if (dmaPending() || drainState() != DrainState::Running)
14142566SN/A        txDmaState = dmaReadWaiting;
14152566SN/A    else
14162566SN/A        dmaRead(txDmaAddr, txDmaLen, &txDmaReadEvent, (uint8_t*)txDmaData);
14172566SN/A
1418854SN/A    return true;
1419854SN/A}
1420837SN/A
1421854SN/Avoid
1422879SN/ANSGigE::txDmaReadDone()
1423854SN/A{
1424854SN/A    assert(txDmaState == dmaReading);
14252566SN/A    txDmaState = dmaIdle;
14262566SN/A
14272566SN/A    DPRINTF(EthernetDMA, "tx dma read  paddr=%#x len=%d\n",
14282566SN/A            txDmaAddr, txDmaLen);
14292566SN/A    DDUMP(EthernetDMA, txDmaData, txDmaLen);
1430837SN/A
1431854SN/A    // If the receive state machine  has a pending DMA, let it go first
1432854SN/A    if (rxDmaState == dmaReadWaiting || rxDmaState == dmaWriteWaiting)
1433854SN/A        rxKick();
1434837SN/A
1435854SN/A    txKick();
1436854SN/A}
1437837SN/A
1438854SN/Abool
1439879SN/ANSGigE::doTxDmaWrite()
1440854SN/A{
1441854SN/A    assert(txDmaState == dmaIdle || txDmaState == dmaWriteWaiting);
1442854SN/A    txDmaState = dmaWriting;
1443854SN/A
144410913SN/A    if (dmaPending() || drainState() != DrainState::Running)
14452566SN/A        txDmaState = dmaWriteWaiting;
14462566SN/A    else
14472566SN/A        dmaWrite(txDmaAddr, txDmaLen, &txDmaWriteEvent, (uint8_t*)txDmaData);
1448854SN/A    return true;
1449854SN/A}
1450854SN/A
1451854SN/Avoid
1452879SN/ANSGigE::txDmaWriteDone()
1453854SN/A{
1454854SN/A    assert(txDmaState == dmaWriting);
14552566SN/A    txDmaState = dmaIdle;
14562566SN/A
14572566SN/A    DPRINTF(EthernetDMA, "tx dma write paddr=%#x len=%d\n",
14582566SN/A            txDmaAddr, txDmaLen);
14592566SN/A    DDUMP(EthernetDMA, txDmaData, txDmaLen);
1460854SN/A
1461854SN/A    // If the receive state machine  has a pending DMA, let it go first
1462854SN/A    if (rxDmaState == dmaReadWaiting || rxDmaState == dmaWriteWaiting)
1463854SN/A        rxKick();
1464854SN/A
1465854SN/A    txKick();
1466837SN/A}
1467837SN/A
1468837SN/Avoid
1469879SN/ANSGigE::txKick()
1470837SN/A{
14711909SN/A    bool is64bit = (bool)(regs.config & CFGR_M64ADDR);
14721909SN/A
14731909SN/A    DPRINTF(EthernetSM, "transmit kick txState=%s %d-bit\n",
14741909SN/A            NsTxStateStrings[txState], is64bit ? 64 : 32);
14751909SN/A
14761909SN/A    Addr link, bufptr;
14771909SN/A    uint32_t &cmdsts = is64bit ? txDesc64.cmdsts : txDesc32.cmdsts;
14781909SN/A    uint32_t &extsts = is64bit ? txDesc64.extsts : txDesc32.extsts;
1479927SN/A
14801801SN/A  next:
14819417SN/A    if (txKickTick > curTick()) {
14829417SN/A        DPRINTF(EthernetSM, "transmit kick exiting, can't run till %d\n",
14839417SN/A                txKickTick);
14849417SN/A        goto exit;
14859417SN/A    }
14861801SN/A
14879417SN/A    // Go to the next state machine clock tick.
14889417SN/A    txKickTick = clockEdge(Cycles(1));
1489837SN/A
1490854SN/A    switch(txDmaState) {
1491854SN/A      case dmaReadWaiting:
1492854SN/A        if (doTxDmaRead())
1493854SN/A            goto exit;
1494854SN/A        break;
1495854SN/A      case dmaWriteWaiting:
1496854SN/A        if (doTxDmaWrite())
1497854SN/A            goto exit;
1498854SN/A        break;
1499854SN/A      default:
1500854SN/A        break;
1501854SN/A    }
1502837SN/A
15031909SN/A    link = is64bit ? (Addr)txDesc64.link : (Addr)txDesc32.link;
15041909SN/A    bufptr = is64bit ? (Addr)txDesc64.bufptr : (Addr)txDesc32.bufptr;
1505854SN/A    switch (txState) {
1506854SN/A      case txIdle:
15071035SN/A        if (!txEnable) {
1508927SN/A            DPRINTF(EthernetSM, "Transmit disabled.  Nothing to do.\n");
1509854SN/A            goto exit;
1510854SN/A        }
1511837SN/A
1512854SN/A        if (CTDD) {
1513854SN/A            txState = txDescRefr;
1514837SN/A
1515881SN/A            txDmaAddr = regs.txdp & 0x3fffffff;
15161909SN/A            txDmaData =
15171909SN/A                is64bit ? (void *)&txDesc64.link : (void *)&txDesc32.link;
15181909SN/A            txDmaLen = is64bit ? sizeof(txDesc64.link) : sizeof(txDesc32.link);
1519854SN/A            txDmaFree = dmaDescFree;
1520837SN/A
1521961SN/A            descDmaReads++;
1522961SN/A            descDmaRdBytes += txDmaLen;
1523961SN/A
1524854SN/A            if (doTxDmaRead())
1525854SN/A                goto exit;
1526854SN/A
1527854SN/A        } else {
1528854SN/A            txState = txDescRead;
1529854SN/A
1530854SN/A            txDmaAddr = regs.txdp & 0x3fffffff;
15311909SN/A            txDmaData = is64bit ? (void *)&txDesc64 : (void *)&txDesc32;
15321909SN/A            txDmaLen = is64bit ? sizeof(txDesc64) : sizeof(txDesc32);
1533854SN/A            txDmaFree = dmaDescFree;
1534854SN/A
1535961SN/A            descDmaReads++;
1536961SN/A            descDmaRdBytes += txDmaLen;
1537961SN/A
1538854SN/A            if (doTxDmaRead())
1539854SN/A                goto exit;
1540837SN/A        }
1541854SN/A        break;
1542837SN/A
1543854SN/A      case txDescRefr:
1544854SN/A        if (txDmaState != dmaIdle)
1545854SN/A            goto exit;
1546854SN/A
1547854SN/A        txState = txAdvance;
1548854SN/A        break;
1549854SN/A
1550854SN/A      case txDescRead:
1551854SN/A        if (txDmaState != dmaIdle)
1552854SN/A            goto exit;
1553854SN/A
15541909SN/A        DPRINTF(EthernetDesc, "txDesc: addr=%08x read descriptor\n",
15551801SN/A                regs.txdp & 0x3fffffff);
1556927SN/A        DPRINTF(EthernetDesc,
15571909SN/A                "txDesc: link=%#x bufptr=%#x cmdsts=%#08x extsts=%#08x\n",
15581909SN/A                link, bufptr, cmdsts, extsts);
15591909SN/A
15601909SN/A        if (cmdsts & CMDSTS_OWN) {
1561854SN/A            txState = txFifoBlock;
15621909SN/A            txFragPtr = bufptr;
15631909SN/A            txDescCnt = cmdsts & CMDSTS_LEN_MASK;
1564854SN/A        } else {
15651035SN/A            devIntrPost(ISR_TXIDLE);
1566854SN/A            txState = txIdle;
15671035SN/A            goto exit;
1568854SN/A        }
1569854SN/A        break;
1570854SN/A
1571854SN/A      case txFifoBlock:
1572854SN/A        if (!txPacket) {
15731036SN/A            DPRINTF(EthernetSM, "****starting the tx of a new packet****\n");
157410469SN/A            txPacket = make_shared<EthPacketData>(16384);
1575854SN/A            txPacketBufPtr = txPacket->data;
1576854SN/A        }
1577854SN/A
1578854SN/A        if (txDescCnt == 0) {
1579927SN/A            DPRINTF(EthernetSM, "the txDescCnt == 0, done with descriptor\n");
15801909SN/A            if (cmdsts & CMDSTS_MORE) {
1581927SN/A                DPRINTF(EthernetSM, "there are more descriptors to come\n");
1582854SN/A                txState = txDescWrite;
1583854SN/A
15841909SN/A                cmdsts &= ~CMDSTS_OWN;
15851909SN/A
15861909SN/A                txDmaAddr = regs.txdp & 0x3fffffff;
15871909SN/A                txDmaData = &cmdsts;
15881909SN/A                if (is64bit) {
15891909SN/A                    txDmaAddr += offsetof(ns_desc64, cmdsts);
15901909SN/A                    txDmaLen = sizeof(txDesc64.cmdsts);
15911909SN/A                } else {
15921909SN/A                    txDmaAddr += offsetof(ns_desc32, cmdsts);
15931909SN/A                    txDmaLen = sizeof(txDesc32.cmdsts);
15941909SN/A                }
1595854SN/A                txDmaFree = dmaDescFree;
1596854SN/A
1597854SN/A                if (doTxDmaWrite())
1598854SN/A                    goto exit;
1599854SN/A
1600854SN/A            } else { /* this packet is totally done */
1601927SN/A                DPRINTF(EthernetSM, "This packet is done, let's wrap it up\n");
1602854SN/A                /* deal with the the packet that just finished */
1603854SN/A                if ((regs.vtcr & VTCR_PPCHK) && extstsEnable) {
16041114SN/A                    IpPtr ip(txPacket);
16051909SN/A                    if (extsts & EXTSTS_UDPPKT) {
16061114SN/A                        UdpPtr udp(ip);
16075484SN/A                        if (udp) {
16085484SN/A                            udp->sum(0);
16095484SN/A                            udp->sum(cksum(udp));
16105484SN/A                            txUdpChecksums++;
16115484SN/A                        } else {
16128231SN/A                            Debug::breakpoint();
16135484SN/A                            warn_once("UDPPKT set, but not UDP!\n");
16145484SN/A                        }
16151909SN/A                    } else if (extsts & EXTSTS_TCPPKT) {
16161114SN/A                        TcpPtr tcp(ip);
16175484SN/A                        if (tcp) {
16185484SN/A                            tcp->sum(0);
16195484SN/A                            tcp->sum(cksum(tcp));
16205484SN/A                            txTcpChecksums++;
16215484SN/A                        } else {
16225484SN/A                            warn_once("TCPPKT set, but not UDP!\n");
16235484SN/A                        }
1624944SN/A                    }
16251909SN/A                    if (extsts & EXTSTS_IPPKT) {
16265484SN/A                        if (ip) {
16275484SN/A                            ip->sum(0);
16285484SN/A                            ip->sum(cksum(ip));
16295484SN/A                            txIpChecksums++;
16305484SN/A                        } else {
16315484SN/A                            warn_once("IPPKT set, but not UDP!\n");
16325484SN/A                        }
1633854SN/A                    }
1634854SN/A                }
1635854SN/A
163611701Smichael.lebeane@amd.com                txPacket->simLength = txPacketBufPtr - txPacket->data;
1637854SN/A                txPacket->length = txPacketBufPtr - txPacket->data;
16381027SN/A                // this is just because the receive can't handle a
16391027SN/A                // packet bigger want to make sure
16401909SN/A                if (txPacket->length > 1514)
16411909SN/A                    panic("transmit packet too large, %s > 1514\n",
16421909SN/A                          txPacket->length);
16431909SN/A
16441205SN/A#ifndef NDEBUG
16451205SN/A                bool success =
16461205SN/A#endif
16471205SN/A                    txFifo.push(txPacket);
16481205SN/A                assert(success);
1649854SN/A
16501027SN/A                /*
16511027SN/A                 * this following section is not tqo spec, but
16521027SN/A                 * functionally shouldn't be any different.  normally,
16531027SN/A                 * the chip will wait til the transmit has occurred
16541027SN/A                 * before writing back the descriptor because it has
16551027SN/A                 * to wait to see that it was successfully transmitted
16561027SN/A                 * to decide whether to set CMDSTS_OK or not.
16571027SN/A                 * however, in the simulator since it is always
16581027SN/A                 * successfully transmitted, and writing it exactly to
16591027SN/A                 * spec would complicate the code, we just do it here
16601027SN/A                 */
1661927SN/A
16621909SN/A                cmdsts &= ~CMDSTS_OWN;
16631909SN/A                cmdsts |= CMDSTS_OK;
1664854SN/A
1665927SN/A                DPRINTF(EthernetDesc,
16661036SN/A                        "txDesc writeback: cmdsts=%08x extsts=%08x\n",
16671909SN/A                        cmdsts, extsts);
16681909SN/A
1669854SN/A                txDmaFree = dmaDescFree;
16701909SN/A                txDmaAddr = regs.txdp & 0x3fffffff;
16711909SN/A                txDmaData = &cmdsts;
16721909SN/A                if (is64bit) {
16731909SN/A                    txDmaAddr += offsetof(ns_desc64, cmdsts);
16741909SN/A                    txDmaLen =
16751909SN/A                        sizeof(txDesc64.cmdsts) + sizeof(txDesc64.extsts);
16761909SN/A                } else {
16771909SN/A                    txDmaAddr += offsetof(ns_desc32, cmdsts);
16781909SN/A                    txDmaLen =
16791909SN/A                        sizeof(txDesc32.cmdsts) + sizeof(txDesc32.extsts);
16801909SN/A                }
1681854SN/A
1682961SN/A                descDmaWrites++;
1683961SN/A                descDmaWrBytes += txDmaLen;
1684961SN/A
1685927SN/A                transmit();
1686854SN/A                txPacket = 0;
1687854SN/A
16881035SN/A                if (!txEnable) {
1689927SN/A                    DPRINTF(EthernetSM, "halting TX state machine\n");
1690854SN/A                    txState = txIdle;
16911035SN/A                    goto exit;
1692854SN/A                } else
1693854SN/A                    txState = txAdvance;
1694986SN/A
1695986SN/A                if (doTxDmaWrite())
1696986SN/A                    goto exit;
1697854SN/A            }
1698854SN/A        } else {
1699927SN/A            DPRINTF(EthernetSM, "this descriptor isn't done yet\n");
17001154SN/A            if (!txFifo.full()) {
1701992SN/A                txState = txFragRead;
1702992SN/A
17031027SN/A                /*
17041027SN/A                 * The number of bytes transferred is either whatever
17051027SN/A                 * is left in the descriptor (txDescCnt), or if there
17061027SN/A                 * is not enough room in the fifo, just whatever room
17071027SN/A                 * is left in the fifo
17081027SN/A                 */
17091154SN/A                txXferLen = min<uint32_t>(txDescCnt, txFifo.avail());
1710992SN/A
1711992SN/A                txDmaAddr = txFragPtr & 0x3fffffff;
1712992SN/A                txDmaData = txPacketBufPtr;
1713992SN/A                txDmaLen = txXferLen;
1714992SN/A                txDmaFree = dmaDataFree;
1715992SN/A
1716992SN/A                if (doTxDmaRead())
1717992SN/A                    goto exit;
1718992SN/A            } else {
1719992SN/A                txState = txFifoBlock;
1720992SN/A                transmit();
1721992SN/A
1722998SN/A                goto exit;
1723992SN/A            }
1724992SN/A
1725854SN/A        }
1726854SN/A        break;
1727854SN/A
1728854SN/A      case txFragRead:
1729854SN/A        if (txDmaState != dmaIdle)
1730854SN/A            goto exit;
1731854SN/A
1732854SN/A        txPacketBufPtr += txXferLen;
1733854SN/A        txFragPtr += txXferLen;
1734854SN/A        txDescCnt -= txXferLen;
17351205SN/A        txFifo.reserve(txXferLen);
1736854SN/A
1737854SN/A        txState = txFifoBlock;
1738854SN/A        break;
1739854SN/A
1740854SN/A      case txDescWrite:
1741854SN/A        if (txDmaState != dmaIdle)
1742854SN/A            goto exit;
1743854SN/A
17441909SN/A        if (cmdsts & CMDSTS_INTR)
1745854SN/A            devIntrPost(ISR_TXDESC);
1746854SN/A
17471801SN/A        if (!txEnable) {
17481801SN/A            DPRINTF(EthernetSM, "halting TX state machine\n");
17491801SN/A            txState = txIdle;
17501801SN/A            goto exit;
17511801SN/A        } else
17521801SN/A            txState = txAdvance;
1753854SN/A        break;
1754854SN/A
1755854SN/A      case txAdvance:
17561909SN/A        if (link == 0) {
17571035SN/A            devIntrPost(ISR_TXIDLE);
1758837SN/A            txState = txIdle;
17591035SN/A            goto exit;
1760837SN/A        } else {
17611893SN/A            if (txDmaState != dmaIdle)
17621893SN/A                goto exit;
1763837SN/A            txState = txDescRead;
17641909SN/A            regs.txdp = link;
1765837SN/A            CTDD = false;
1766854SN/A
17671909SN/A            txDmaAddr = link & 0x3fffffff;
17681909SN/A            txDmaData = is64bit ? (void *)&txDesc64 : (void *)&txDesc32;
17691909SN/A            txDmaLen = is64bit ? sizeof(txDesc64) : sizeof(txDesc32);
1770854SN/A            txDmaFree = dmaDescFree;
1771854SN/A
1772854SN/A            if (doTxDmaRead())
1773854SN/A                goto exit;
1774837SN/A        }
1775854SN/A        break;
1776837SN/A
1777854SN/A      default:
1778854SN/A        panic("invalid state");
1779837SN/A    }
1780837SN/A
17811036SN/A    DPRINTF(EthernetSM, "entering next txState=%s\n",
1782854SN/A            NsTxStateStrings[txState]);
1783854SN/A    goto next;
1784837SN/A
1785854SN/A  exit:
1786854SN/A    /**
1787854SN/A     * @todo do we want to schedule a future kick?
1788854SN/A     */
17891036SN/A    DPRINTF(EthernetSM, "tx state machine exited txState=%s\n",
1790854SN/A            NsTxStateStrings[txState]);
17911801SN/A
17929417SN/A    if (!txKickEvent.scheduled())
17935606SN/A        schedule(txKickEvent, txKickTick);
1794837SN/A}
1795837SN/A
17961843SN/A/**
17971843SN/A * Advance the EEPROM state machine
17981843SN/A * Called on rising edge of EEPROM clock bit in MEAR
17991843SN/A */
18001843SN/Avoid
18011843SN/ANSGigE::eepromKick()
18021843SN/A{
18031843SN/A    switch (eepromState) {
18041843SN/A
18051843SN/A      case eepromStart:
18061843SN/A
18071843SN/A        // Wait for start bit
18081843SN/A        if (regs.mear & MEAR_EEDI) {
18091843SN/A            // Set up to get 2 opcode bits
18101843SN/A            eepromState = eepromGetOpcode;
18111843SN/A            eepromBitsToRx = 2;
18121843SN/A            eepromOpcode = 0;
18131843SN/A        }
18141843SN/A        break;
18151843SN/A
18161843SN/A      case eepromGetOpcode:
18171843SN/A        eepromOpcode <<= 1;
18181843SN/A        eepromOpcode += (regs.mear & MEAR_EEDI) ? 1 : 0;
18191843SN/A        --eepromBitsToRx;
18201843SN/A
18211843SN/A        // Done getting opcode
18221843SN/A        if (eepromBitsToRx == 0) {
18231843SN/A            if (eepromOpcode != EEPROM_READ)
18241843SN/A                panic("only EEPROM reads are implemented!");
18251843SN/A
18261843SN/A            // Set up to get address
18271843SN/A            eepromState = eepromGetAddress;
18281843SN/A            eepromBitsToRx = 6;
18291843SN/A            eepromAddress = 0;
18301843SN/A        }
18311843SN/A        break;
18321843SN/A
18331843SN/A      case eepromGetAddress:
18341843SN/A        eepromAddress <<= 1;
18351843SN/A        eepromAddress += (regs.mear & MEAR_EEDI) ? 1 : 0;
18361843SN/A        --eepromBitsToRx;
18371843SN/A
18381843SN/A        // Done getting address
18391843SN/A        if (eepromBitsToRx == 0) {
18401843SN/A
18411843SN/A            if (eepromAddress >= EEPROM_SIZE)
18421843SN/A                panic("EEPROM read access out of range!");
18431843SN/A
18441843SN/A            switch (eepromAddress) {
18451843SN/A
18461843SN/A              case EEPROM_PMATCH2_ADDR:
18471843SN/A                eepromData = rom.perfectMatch[5];
18481843SN/A                eepromData <<= 8;
18491843SN/A                eepromData += rom.perfectMatch[4];
18501843SN/A                break;
18511843SN/A
18521843SN/A              case EEPROM_PMATCH1_ADDR:
18531843SN/A                eepromData = rom.perfectMatch[3];
18541843SN/A                eepromData <<= 8;
18551843SN/A                eepromData += rom.perfectMatch[2];
18561843SN/A                break;
18571843SN/A
18581843SN/A              case EEPROM_PMATCH0_ADDR:
18591843SN/A                eepromData = rom.perfectMatch[1];
18601843SN/A                eepromData <<= 8;
18611843SN/A                eepromData += rom.perfectMatch[0];
18621843SN/A                break;
18631843SN/A
18641843SN/A              default:
18651843SN/A                panic("FreeBSD driver only uses EEPROM to read PMATCH!");
18661843SN/A            }
18671843SN/A            // Set up to read data
18681843SN/A            eepromState = eepromRead;
18691843SN/A            eepromBitsToRx = 16;
18701843SN/A
18711843SN/A            // Clear data in bit
18721843SN/A            regs.mear &= ~MEAR_EEDI;
18731843SN/A        }
18741843SN/A        break;
18751843SN/A
18761843SN/A      case eepromRead:
18771843SN/A        // Clear Data Out bit
18781843SN/A        regs.mear &= ~MEAR_EEDO;
18791843SN/A        // Set bit to value of current EEPROM bit
18801843SN/A        regs.mear |= (eepromData & 0x8000) ? MEAR_EEDO : 0x0;
18811843SN/A
18821843SN/A        eepromData <<= 1;
18831843SN/A        --eepromBitsToRx;
18841843SN/A
18851843SN/A        // All done
18861843SN/A        if (eepromBitsToRx == 0) {
18871843SN/A            eepromState = eepromStart;
18881843SN/A        }
18891843SN/A        break;
18901843SN/A
18911843SN/A      default:
18921843SN/A        panic("invalid EEPROM state");
18931843SN/A    }
18941843SN/A
18951843SN/A}
18961843SN/A
1897837SN/Avoid
1898879SN/ANSGigE::transferDone()
1899837SN/A{
19001036SN/A    if (txFifo.empty()) {
19011036SN/A        DPRINTF(Ethernet, "transfer complete: txFifo empty...nothing to do\n");
1902837SN/A        return;
19031036SN/A    }
19041036SN/A
19051036SN/A    DPRINTF(Ethernet, "transfer complete: data in txFifo...schedule xmit\n");
1906837SN/A
19079417SN/A    reschedule(txEvent, clockEdge(Cycles(1)), true);
1908837SN/A}
1909837SN/A
1910837SN/Abool
19112566SN/ANSGigE::rxFilter(const EthPacketPtr &packet)
1912837SN/A{
19131114SN/A    EthPtr eth = packet;
1914837SN/A    bool drop = true;
1915837SN/A    string type;
1916837SN/A
19171114SN/A    const EthAddr &dst = eth->dst();
19181114SN/A    if (dst.unicast()) {
1919837SN/A        // If we're accepting all unicast addresses
1920837SN/A        if (acceptUnicast)
1921837SN/A            drop = false;
1922837SN/A
1923837SN/A        // If we make a perfect match
19241114SN/A        if (acceptPerfect && dst == rom.perfectMatch)
1925837SN/A            drop = false;
1926837SN/A
19271078SN/A        if (acceptArp && eth->type() == ETH_TYPE_ARP)
1928837SN/A            drop = false;
1929837SN/A
19301114SN/A    } else if (dst.broadcast()) {
1931837SN/A        // if we're accepting broadcasts
1932837SN/A        if (acceptBroadcast)
1933837SN/A            drop = false;
1934837SN/A
19351114SN/A    } else if (dst.multicast()) {
1936837SN/A        // if we're accepting all multicasts
1937837SN/A        if (acceptMulticast)
1938837SN/A            drop = false;
1939837SN/A
19401843SN/A        // Multicast hashing faked - all packets accepted
19411843SN/A        if (multicastHashEnable)
19421843SN/A            drop = false;
1943837SN/A    }
1944837SN/A
1945837SN/A    if (drop) {
1946837SN/A        DPRINTF(Ethernet, "rxFilter drop\n");
1947837SN/A        DDUMP(EthernetData, packet->data, packet->length);
1948837SN/A    }
1949837SN/A
1950837SN/A    return drop;
1951837SN/A}
1952837SN/A
1953837SN/Abool
19542566SN/ANSGigE::recvPacket(EthPacketPtr packet)
1955837SN/A{
1956837SN/A    rxBytes += packet->length;
1957837SN/A    rxPackets++;
1958837SN/A
19591036SN/A    DPRINTF(Ethernet, "Receiving packet from wire, rxFifoAvail=%d\n",
19601154SN/A            rxFifo.avail());
1961927SN/A
19621035SN/A    if (!rxEnable) {
1963837SN/A        DPRINTF(Ethernet, "receive disabled...packet dropped\n");
1964837SN/A        return true;
1965837SN/A    }
1966837SN/A
19671843SN/A    if (!rxFilterEnable) {
19681843SN/A        DPRINTF(Ethernet,
19691843SN/A            "receive packet filtering disabled . . . packet dropped\n");
19701843SN/A        return true;
19711843SN/A    }
19721843SN/A
19731843SN/A    if (rxFilter(packet)) {
1974837SN/A        DPRINTF(Ethernet, "packet filtered...dropped\n");
1975837SN/A        return true;
1976837SN/A    }
1977837SN/A
19781154SN/A    if (rxFifo.avail() < packet->length) {
19791561SN/A#if TRACING_ON
19801561SN/A        IpPtr ip(packet);
19811561SN/A        TcpPtr tcp(ip);
19821561SN/A        if (ip) {
19831561SN/A            DPRINTF(Ethernet,
19841561SN/A                    "packet won't fit in receive buffer...pkt ID %d dropped\n",
19851561SN/A                    ip->id());
19861561SN/A            if (tcp) {
19871561SN/A                DPRINTF(Ethernet, "Seq=%d\n", tcp->seq());
19881561SN/A            }
19891561SN/A        }
19901561SN/A#endif
19911263SN/A        droppedPackets++;
1992837SN/A        devIntrPost(ISR_RXORN);
1993837SN/A        return false;
1994837SN/A    }
1995837SN/A
19961154SN/A    rxFifo.push(packet);
1997837SN/A
1998854SN/A    rxKick();
1999837SN/A    return true;
2000837SN/A}
2001837SN/A
20022901SN/A
20032901SN/Avoid
20049342SN/ANSGigE::drainResume()
20052901SN/A{
20069342SN/A    Drainable::drainResume();
20072901SN/A
20082901SN/A    // During drain we could have left the state machines in a waiting state and
20092901SN/A    // they wouldn't get out until some other event occured to kick them.
20102901SN/A    // This way they'll get out immediately
20112901SN/A    txKick();
20122901SN/A    rxKick();
20132901SN/A}
20142901SN/A
20152901SN/A
2016837SN/A//=====================================================================
2017837SN/A//
2018837SN/A//
2019837SN/Avoid
202010905SN/ANSGigE::serialize(CheckpointOut &cp) const
2021837SN/A{
20229807SN/A    // Serialize the PciDevice base class
202310905SN/A    PciDevice::serialize(cp);
2024897SN/A
2025854SN/A    /*
2026854SN/A     * Finalize any DMA events now.
2027854SN/A     */
20282566SN/A    // @todo will mem system save pending dma?
2029837SN/A
2030854SN/A    /*
2031854SN/A     * Serialize the device registers
2032854SN/A     */
2033854SN/A    SERIALIZE_SCALAR(regs.command);
2034854SN/A    SERIALIZE_SCALAR(regs.config);
2035854SN/A    SERIALIZE_SCALAR(regs.mear);
2036854SN/A    SERIALIZE_SCALAR(regs.ptscr);
2037854SN/A    SERIALIZE_SCALAR(regs.isr);
2038854SN/A    SERIALIZE_SCALAR(regs.imr);
2039854SN/A    SERIALIZE_SCALAR(regs.ier);
2040854SN/A    SERIALIZE_SCALAR(regs.ihr);
2041854SN/A    SERIALIZE_SCALAR(regs.txdp);
2042854SN/A    SERIALIZE_SCALAR(regs.txdp_hi);
2043854SN/A    SERIALIZE_SCALAR(regs.txcfg);
2044854SN/A    SERIALIZE_SCALAR(regs.gpior);
2045854SN/A    SERIALIZE_SCALAR(regs.rxdp);
2046854SN/A    SERIALIZE_SCALAR(regs.rxdp_hi);
2047854SN/A    SERIALIZE_SCALAR(regs.rxcfg);
2048854SN/A    SERIALIZE_SCALAR(regs.pqcr);
2049854SN/A    SERIALIZE_SCALAR(regs.wcsr);
2050854SN/A    SERIALIZE_SCALAR(regs.pcr);
2051854SN/A    SERIALIZE_SCALAR(regs.rfcr);
2052854SN/A    SERIALIZE_SCALAR(regs.rfdr);
20531843SN/A    SERIALIZE_SCALAR(regs.brar);
20541843SN/A    SERIALIZE_SCALAR(regs.brdr);
2055854SN/A    SERIALIZE_SCALAR(regs.srr);
2056854SN/A    SERIALIZE_SCALAR(regs.mibc);
2057854SN/A    SERIALIZE_SCALAR(regs.vrcr);
2058854SN/A    SERIALIZE_SCALAR(regs.vtcr);
2059854SN/A    SERIALIZE_SCALAR(regs.vdr);
2060854SN/A    SERIALIZE_SCALAR(regs.ccsr);
2061854SN/A    SERIALIZE_SCALAR(regs.tbicr);
2062854SN/A    SERIALIZE_SCALAR(regs.tbisr);
2063854SN/A    SERIALIZE_SCALAR(regs.tanar);
2064854SN/A    SERIALIZE_SCALAR(regs.tanlpar);
2065854SN/A    SERIALIZE_SCALAR(regs.taner);
2066854SN/A    SERIALIZE_SCALAR(regs.tesr);
2067837SN/A
20681114SN/A    SERIALIZE_ARRAY(rom.perfectMatch, ETH_ADDR_LEN);
20691843SN/A    SERIALIZE_ARRAY(rom.filterHash, FHASH_SIZE);
2070837SN/A
2071927SN/A    SERIALIZE_SCALAR(ioEnable);
2072917SN/A
2073854SN/A    /*
2074915SN/A     * Serialize the data Fifos
2075915SN/A     */
207610905SN/A    rxFifo.serialize("rxFifo", cp);
207710905SN/A    txFifo.serialize("txFifo", cp);
2078915SN/A
2079915SN/A    /*
2080854SN/A     * Serialize the various helper variables
2081854SN/A     */
208210469SN/A    bool txPacketExists = txPacket != nullptr;
2083915SN/A    SERIALIZE_SCALAR(txPacketExists);
2084915SN/A    if (txPacketExists) {
208511701Smichael.lebeane@amd.com        txPacket->simLength = txPacketBufPtr - txPacket->data;
20861337SN/A        txPacket->length = txPacketBufPtr - txPacket->data;
208710905SN/A        txPacket->serialize("txPacket", cp);
2088915SN/A        uint32_t txPktBufPtr = (uint32_t) (txPacketBufPtr - txPacket->data);
2089915SN/A        SERIALIZE_SCALAR(txPktBufPtr);
2090915SN/A    }
2091915SN/A
209210469SN/A    bool rxPacketExists = rxPacket != nullptr;
2093915SN/A    SERIALIZE_SCALAR(rxPacketExists);
2094915SN/A    if (rxPacketExists) {
209510905SN/A        rxPacket->serialize("rxPacket", cp);
2096915SN/A        uint32_t rxPktBufPtr = (uint32_t) (rxPacketBufPtr - rxPacket->data);
2097915SN/A        SERIALIZE_SCALAR(rxPktBufPtr);
2098915SN/A    }
2099915SN/A
2100854SN/A    SERIALIZE_SCALAR(txXferLen);
2101854SN/A    SERIALIZE_SCALAR(rxXferLen);
2102837SN/A
2103854SN/A    /*
21041909SN/A     * Serialize Cached Descriptors
2105854SN/A     */
21061909SN/A    SERIALIZE_SCALAR(rxDesc64.link);
21071909SN/A    SERIALIZE_SCALAR(rxDesc64.bufptr);
21081909SN/A    SERIALIZE_SCALAR(rxDesc64.cmdsts);
21091909SN/A    SERIALIZE_SCALAR(rxDesc64.extsts);
21101909SN/A    SERIALIZE_SCALAR(txDesc64.link);
21111909SN/A    SERIALIZE_SCALAR(txDesc64.bufptr);
21121909SN/A    SERIALIZE_SCALAR(txDesc64.cmdsts);
21131909SN/A    SERIALIZE_SCALAR(txDesc64.extsts);
21141909SN/A    SERIALIZE_SCALAR(rxDesc32.link);
21151909SN/A    SERIALIZE_SCALAR(rxDesc32.bufptr);
21161909SN/A    SERIALIZE_SCALAR(rxDesc32.cmdsts);
21171909SN/A    SERIALIZE_SCALAR(rxDesc32.extsts);
21181909SN/A    SERIALIZE_SCALAR(txDesc32.link);
21191909SN/A    SERIALIZE_SCALAR(txDesc32.bufptr);
21201909SN/A    SERIALIZE_SCALAR(txDesc32.cmdsts);
21211909SN/A    SERIALIZE_SCALAR(txDesc32.extsts);
21221801SN/A    SERIALIZE_SCALAR(extstsEnable);
2123837SN/A
2124854SN/A    /*
2125854SN/A     * Serialize tx state machine
2126854SN/A     */
2127854SN/A    int txState = this->txState;
2128854SN/A    SERIALIZE_SCALAR(txState);
21291035SN/A    SERIALIZE_SCALAR(txEnable);
2130854SN/A    SERIALIZE_SCALAR(CTDD);
2131854SN/A    SERIALIZE_SCALAR(txFragPtr);
2132854SN/A    SERIALIZE_SCALAR(txDescCnt);
2133854SN/A    int txDmaState = this->txDmaState;
2134854SN/A    SERIALIZE_SCALAR(txDmaState);
21351801SN/A    SERIALIZE_SCALAR(txKickTick);
2136854SN/A
2137854SN/A    /*
2138854SN/A     * Serialize rx state machine
2139854SN/A     */
2140854SN/A    int rxState = this->rxState;
2141854SN/A    SERIALIZE_SCALAR(rxState);
21421035SN/A    SERIALIZE_SCALAR(rxEnable);
2143854SN/A    SERIALIZE_SCALAR(CRDD);
2144854SN/A    SERIALIZE_SCALAR(rxPktBytes);
21451224SN/A    SERIALIZE_SCALAR(rxFragPtr);
2146854SN/A    SERIALIZE_SCALAR(rxDescCnt);
2147854SN/A    int rxDmaState = this->rxDmaState;
2148854SN/A    SERIALIZE_SCALAR(rxDmaState);
21491801SN/A    SERIALIZE_SCALAR(rxKickTick);
2150854SN/A
2151915SN/A    /*
21521843SN/A     * Serialize EEPROM state machine
21531843SN/A     */
21541843SN/A    int eepromState = this->eepromState;
21551843SN/A    SERIALIZE_SCALAR(eepromState);
21561843SN/A    SERIALIZE_SCALAR(eepromClk);
21571843SN/A    SERIALIZE_SCALAR(eepromBitsToRx);
21581843SN/A    SERIALIZE_SCALAR(eepromOpcode);
21591843SN/A    SERIALIZE_SCALAR(eepromAddress);
21601843SN/A    SERIALIZE_SCALAR(eepromData);
21611843SN/A
21621843SN/A    /*
2163854SN/A     * If there's a pending transmit, store the time so we can
2164854SN/A     * reschedule it later
2165854SN/A     */
21667823SN/A    Tick transmitTick = txEvent.scheduled() ? txEvent.when() - curTick() : 0;
2167854SN/A    SERIALIZE_SCALAR(transmitTick);
2168854SN/A
2169854SN/A    /*
2170915SN/A     * receive address filter settings
2171915SN/A     */
2172915SN/A    SERIALIZE_SCALAR(rxFilterEnable);
2173915SN/A    SERIALIZE_SCALAR(acceptBroadcast);
2174915SN/A    SERIALIZE_SCALAR(acceptMulticast);
2175915SN/A    SERIALIZE_SCALAR(acceptUnicast);
2176915SN/A    SERIALIZE_SCALAR(acceptPerfect);
2177915SN/A    SERIALIZE_SCALAR(acceptArp);
21781843SN/A    SERIALIZE_SCALAR(multicastHashEnable);
2179915SN/A
2180915SN/A    /*
2181854SN/A     * Keep track of pending interrupt status.
2182854SN/A     */
2183854SN/A    SERIALIZE_SCALAR(intrTick);
2184854SN/A    SERIALIZE_SCALAR(cpuPendingIntr);
2185854SN/A    Tick intrEventTick = 0;
2186854SN/A    if (intrEvent)
2187854SN/A        intrEventTick = intrEvent->when();
2188854SN/A    SERIALIZE_SCALAR(intrEventTick);
2189854SN/A
2190837SN/A}
2191837SN/A
2192837SN/Avoid
219310905SN/ANSGigE::unserialize(CheckpointIn &cp)
2194837SN/A{
21959807SN/A    // Unserialize the PciDevice base class
219610905SN/A    PciDevice::unserialize(cp);
2197897SN/A
2198854SN/A    UNSERIALIZE_SCALAR(regs.command);
2199854SN/A    UNSERIALIZE_SCALAR(regs.config);
2200854SN/A    UNSERIALIZE_SCALAR(regs.mear);
2201854SN/A    UNSERIALIZE_SCALAR(regs.ptscr);
2202854SN/A    UNSERIALIZE_SCALAR(regs.isr);
2203854SN/A    UNSERIALIZE_SCALAR(regs.imr);
2204854SN/A    UNSERIALIZE_SCALAR(regs.ier);
2205854SN/A    UNSERIALIZE_SCALAR(regs.ihr);
2206854SN/A    UNSERIALIZE_SCALAR(regs.txdp);
2207854SN/A    UNSERIALIZE_SCALAR(regs.txdp_hi);
2208854SN/A    UNSERIALIZE_SCALAR(regs.txcfg);
2209854SN/A    UNSERIALIZE_SCALAR(regs.gpior);
2210854SN/A    UNSERIALIZE_SCALAR(regs.rxdp);
2211854SN/A    UNSERIALIZE_SCALAR(regs.rxdp_hi);
2212854SN/A    UNSERIALIZE_SCALAR(regs.rxcfg);
2213854SN/A    UNSERIALIZE_SCALAR(regs.pqcr);
2214854SN/A    UNSERIALIZE_SCALAR(regs.wcsr);
2215854SN/A    UNSERIALIZE_SCALAR(regs.pcr);
2216854SN/A    UNSERIALIZE_SCALAR(regs.rfcr);
2217854SN/A    UNSERIALIZE_SCALAR(regs.rfdr);
22181843SN/A    UNSERIALIZE_SCALAR(regs.brar);
22191843SN/A    UNSERIALIZE_SCALAR(regs.brdr);
2220854SN/A    UNSERIALIZE_SCALAR(regs.srr);
2221854SN/A    UNSERIALIZE_SCALAR(regs.mibc);
2222854SN/A    UNSERIALIZE_SCALAR(regs.vrcr);
2223854SN/A    UNSERIALIZE_SCALAR(regs.vtcr);
2224854SN/A    UNSERIALIZE_SCALAR(regs.vdr);
2225854SN/A    UNSERIALIZE_SCALAR(regs.ccsr);
2226854SN/A    UNSERIALIZE_SCALAR(regs.tbicr);
2227854SN/A    UNSERIALIZE_SCALAR(regs.tbisr);
2228854SN/A    UNSERIALIZE_SCALAR(regs.tanar);
2229854SN/A    UNSERIALIZE_SCALAR(regs.tanlpar);
2230854SN/A    UNSERIALIZE_SCALAR(regs.taner);
2231854SN/A    UNSERIALIZE_SCALAR(regs.tesr);
2232837SN/A
22331114SN/A    UNSERIALIZE_ARRAY(rom.perfectMatch, ETH_ADDR_LEN);
22341843SN/A    UNSERIALIZE_ARRAY(rom.filterHash, FHASH_SIZE);
2235837SN/A
2236927SN/A    UNSERIALIZE_SCALAR(ioEnable);
2237917SN/A
2238854SN/A    /*
2239915SN/A     * unserialize the data fifos
2240915SN/A     */
224110905SN/A    rxFifo.unserialize("rxFifo", cp);
224210905SN/A    txFifo.unserialize("txFifo", cp);
2243915SN/A
2244915SN/A    /*
2245854SN/A     * unserialize the various helper variables
2246854SN/A     */
2247915SN/A    bool txPacketExists;
2248915SN/A    UNSERIALIZE_SCALAR(txPacketExists);
2249915SN/A    if (txPacketExists) {
225011719Smichael.lebeane@amd.com        txPacket = make_shared<EthPacketData>(16384);
225110905SN/A        txPacket->unserialize("txPacket", cp);
2252915SN/A        uint32_t txPktBufPtr;
2253915SN/A        UNSERIALIZE_SCALAR(txPktBufPtr);
2254915SN/A        txPacketBufPtr = (uint8_t *) txPacket->data + txPktBufPtr;
2255915SN/A    } else
2256915SN/A        txPacket = 0;
2257915SN/A
2258915SN/A    bool rxPacketExists;
2259915SN/A    UNSERIALIZE_SCALAR(rxPacketExists);
2260915SN/A    rxPacket = 0;
2261915SN/A    if (rxPacketExists) {
226211701Smichael.lebeane@amd.com        rxPacket = make_shared<EthPacketData>();
226310905SN/A        rxPacket->unserialize("rxPacket", cp);
2264915SN/A        uint32_t rxPktBufPtr;
2265915SN/A        UNSERIALIZE_SCALAR(rxPktBufPtr);
2266915SN/A        rxPacketBufPtr = (uint8_t *) rxPacket->data + rxPktBufPtr;
2267915SN/A    } else
2268915SN/A        rxPacket = 0;
2269915SN/A
2270854SN/A    UNSERIALIZE_SCALAR(txXferLen);
2271854SN/A    UNSERIALIZE_SCALAR(rxXferLen);
2272837SN/A
2273854SN/A    /*
22741909SN/A     * Unserialize Cached Descriptors
2275854SN/A     */
22761909SN/A    UNSERIALIZE_SCALAR(rxDesc64.link);
22771909SN/A    UNSERIALIZE_SCALAR(rxDesc64.bufptr);
22781909SN/A    UNSERIALIZE_SCALAR(rxDesc64.cmdsts);
22791909SN/A    UNSERIALIZE_SCALAR(rxDesc64.extsts);
22801909SN/A    UNSERIALIZE_SCALAR(txDesc64.link);
22811909SN/A    UNSERIALIZE_SCALAR(txDesc64.bufptr);
22821909SN/A    UNSERIALIZE_SCALAR(txDesc64.cmdsts);
22831909SN/A    UNSERIALIZE_SCALAR(txDesc64.extsts);
22841909SN/A    UNSERIALIZE_SCALAR(rxDesc32.link);
22851909SN/A    UNSERIALIZE_SCALAR(rxDesc32.bufptr);
22861909SN/A    UNSERIALIZE_SCALAR(rxDesc32.cmdsts);
22871909SN/A    UNSERIALIZE_SCALAR(rxDesc32.extsts);
22881909SN/A    UNSERIALIZE_SCALAR(txDesc32.link);
22891909SN/A    UNSERIALIZE_SCALAR(txDesc32.bufptr);
22901909SN/A    UNSERIALIZE_SCALAR(txDesc32.cmdsts);
22911909SN/A    UNSERIALIZE_SCALAR(txDesc32.extsts);
22921801SN/A    UNSERIALIZE_SCALAR(extstsEnable);
2293854SN/A
2294854SN/A    /*
2295854SN/A     * unserialize tx state machine
2296854SN/A     */
2297854SN/A    int txState;
2298854SN/A    UNSERIALIZE_SCALAR(txState);
2299854SN/A    this->txState = (TxState) txState;
23001035SN/A    UNSERIALIZE_SCALAR(txEnable);
2301854SN/A    UNSERIALIZE_SCALAR(CTDD);
2302854SN/A    UNSERIALIZE_SCALAR(txFragPtr);
2303854SN/A    UNSERIALIZE_SCALAR(txDescCnt);
2304854SN/A    int txDmaState;
2305854SN/A    UNSERIALIZE_SCALAR(txDmaState);
2306854SN/A    this->txDmaState = (DmaState) txDmaState;
23071801SN/A    UNSERIALIZE_SCALAR(txKickTick);
23081801SN/A    if (txKickTick)
23095606SN/A        schedule(txKickEvent, txKickTick);
2310854SN/A
2311854SN/A    /*
2312854SN/A     * unserialize rx state machine
2313854SN/A     */
2314854SN/A    int rxState;
2315854SN/A    UNSERIALIZE_SCALAR(rxState);
2316854SN/A    this->rxState = (RxState) rxState;
23171035SN/A    UNSERIALIZE_SCALAR(rxEnable);
2318854SN/A    UNSERIALIZE_SCALAR(CRDD);
2319854SN/A    UNSERIALIZE_SCALAR(rxPktBytes);
23201224SN/A    UNSERIALIZE_SCALAR(rxFragPtr);
2321854SN/A    UNSERIALIZE_SCALAR(rxDescCnt);
2322854SN/A    int rxDmaState;
2323854SN/A    UNSERIALIZE_SCALAR(rxDmaState);
2324854SN/A    this->rxDmaState = (DmaState) rxDmaState;
23251801SN/A    UNSERIALIZE_SCALAR(rxKickTick);
23261801SN/A    if (rxKickTick)
23275606SN/A        schedule(rxKickEvent, rxKickTick);
2328854SN/A
23291843SN/A    /*
23301843SN/A     * Unserialize EEPROM state machine
23311843SN/A     */
23321843SN/A    int eepromState;
23331843SN/A    UNSERIALIZE_SCALAR(eepromState);
23341843SN/A    this->eepromState = (EEPROMState) eepromState;
23351843SN/A    UNSERIALIZE_SCALAR(eepromClk);
23361843SN/A    UNSERIALIZE_SCALAR(eepromBitsToRx);
23371843SN/A    UNSERIALIZE_SCALAR(eepromOpcode);
23381843SN/A    UNSERIALIZE_SCALAR(eepromAddress);
23391843SN/A    UNSERIALIZE_SCALAR(eepromData);
23401843SN/A
23411843SN/A    /*
2342915SN/A     * If there's a pending transmit, reschedule it now
2343854SN/A     */
2344854SN/A    Tick transmitTick;
2345854SN/A    UNSERIALIZE_SCALAR(transmitTick);
2346854SN/A    if (transmitTick)
23477823SN/A        schedule(txEvent, curTick() + transmitTick);
2348854SN/A
2349854SN/A    /*
2350915SN/A     * unserialize receive address filter settings
2351915SN/A     */
2352915SN/A    UNSERIALIZE_SCALAR(rxFilterEnable);
2353915SN/A    UNSERIALIZE_SCALAR(acceptBroadcast);
2354915SN/A    UNSERIALIZE_SCALAR(acceptMulticast);
2355915SN/A    UNSERIALIZE_SCALAR(acceptUnicast);
2356915SN/A    UNSERIALIZE_SCALAR(acceptPerfect);
2357915SN/A    UNSERIALIZE_SCALAR(acceptArp);
23581843SN/A    UNSERIALIZE_SCALAR(multicastHashEnable);
2359915SN/A
2360915SN/A    /*
2361854SN/A     * Keep track of pending interrupt status.
2362854SN/A     */
2363854SN/A    UNSERIALIZE_SCALAR(intrTick);
2364854SN/A    UNSERIALIZE_SCALAR(cpuPendingIntr);
2365854SN/A    Tick intrEventTick;
2366854SN/A    UNSERIALIZE_SCALAR(intrEventTick);
2367854SN/A    if (intrEventTick) {
236812087Sspwilson2@wisc.edu        intrEvent = new EventFunctionWrapper([this]{ cpuInterrupt(); },
236912087Sspwilson2@wisc.edu                                             name(), true);
23705606SN/A        schedule(intrEvent, intrEventTick);
2371854SN/A    }
2372854SN/A}
2373927SN/A
23744762SN/ANSGigE *
23754762SN/ANSGigEParams::create()
2376837SN/A{
23774762SN/A    return new NSGigE(this);
2378837SN/A}
2379