ns_gige.cc revision 13342
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
1764981SN/AEtherInt*
1774981SN/ANSGigE::getEthPort(const std::string &if_name, int idx)
1784981SN/A{
1794981SN/A    if (if_name == "interface") {
1804981SN/A       if (interface->getPeer())
1814981SN/A           panic("interface already connected to\n");
1824981SN/A       return interface;
1834981SN/A    }
1844981SN/A    return NULL;
1854981SN/A}
1864981SN/A
187855SN/A/**
188855SN/A * This reads the device registers, which are detailed in the NS83820
189855SN/A * spec sheet
190855SN/A */
1912566SN/ATick
1923349SN/ANSGigE::read(PacketPtr pkt)
193837SN/A{
194927SN/A    assert(ioEnable);
195917SN/A
196855SN/A    //The mask is to give you only the offset into the device register file
1972641SN/A    Addr daddr = pkt->getAddr() & 0xfff;
1982566SN/A    DPRINTF(EthernetPIO, "read  da=%#x pa=%#x size=%d\n",
1992641SN/A            daddr, pkt->getAddr(), pkt->getSize());
200837SN/A
201855SN/A
2021027SN/A    // there are some reserved registers, you can see ns_gige_reg.h and
2031027SN/A    // the spec sheet for details
204854SN/A    if (daddr > LAST && daddr <=  RESERVED) {
205837SN/A        panic("Accessing reserved register");
206854SN/A    } else if (daddr > RESERVED && daddr <= 0x3FC) {
2072846SN/A        return readConfig(pkt);
208854SN/A    } else if (daddr >= MIB_START && daddr <= MIB_END) {
209854SN/A        // don't implement all the MIB's.  hopefully the kernel
210854SN/A        // doesn't actually DEPEND upon their values
211855SN/A        // MIB are just hardware stats keepers
21213342Sgabeblack@google.com        pkt->setLE<uint32_t>(0);
2134870SN/A        pkt->makeAtomicResponse();
2142566SN/A        return pioDelay;
215854SN/A    } else if (daddr > 0x3FC)
216854SN/A        panic("Something is messed up!\n");
217837SN/A
2182641SN/A    assert(pkt->getSize() == sizeof(uint32_t));
2192630SN/A        uint32_t &reg = *pkt->getPtr<uint32_t>();
2202566SN/A        uint16_t rfaddr;
2212566SN/A
2222566SN/A        switch (daddr) {
2232566SN/A          case CR:
2242566SN/A            reg = regs.command;
2252566SN/A            //these are supposed to be cleared on a read
2262566SN/A            reg &= ~(CR_RXD | CR_TXD | CR_TXR | CR_RXR);
2272566SN/A            break;
2282566SN/A
2292566SN/A          case CFGR:
2302566SN/A            reg = regs.config;
2312566SN/A            break;
2322566SN/A
2332566SN/A          case MEAR:
2342566SN/A            reg = regs.mear;
2352566SN/A            break;
2362566SN/A
2372566SN/A          case PTSCR:
2382566SN/A            reg = regs.ptscr;
2392566SN/A            break;
2402566SN/A
2412566SN/A          case ISR:
2422566SN/A            reg = regs.isr;
2432566SN/A            devIntrClear(ISR_ALL);
2442566SN/A            break;
2452566SN/A
2462566SN/A          case IMR:
2472566SN/A            reg = regs.imr;
2482566SN/A            break;
2492566SN/A
2502566SN/A          case IER:
2512566SN/A            reg = regs.ier;
2522566SN/A            break;
2532566SN/A
2542566SN/A          case IHR:
2552566SN/A            reg = regs.ihr;
2562566SN/A            break;
2572566SN/A
2582566SN/A          case TXDP:
2592566SN/A            reg = regs.txdp;
2602566SN/A            break;
2612566SN/A
2622566SN/A          case TXDP_HI:
2632566SN/A            reg = regs.txdp_hi;
2642566SN/A            break;
2652566SN/A
2662566SN/A          case TX_CFG:
2672566SN/A            reg = regs.txcfg;
2682566SN/A            break;
2692566SN/A
2702566SN/A          case GPIOR:
2712566SN/A            reg = regs.gpior;
2722566SN/A            break;
2732566SN/A
2742566SN/A          case RXDP:
2752566SN/A            reg = regs.rxdp;
2762566SN/A            break;
2772566SN/A
2782566SN/A          case RXDP_HI:
2792566SN/A            reg = regs.rxdp_hi;
2802566SN/A            break;
2812566SN/A
2822566SN/A          case RX_CFG:
2832566SN/A            reg = regs.rxcfg;
2842566SN/A            break;
2852566SN/A
2862566SN/A          case PQCR:
2872566SN/A            reg = regs.pqcr;
2882566SN/A            break;
2892566SN/A
2902566SN/A          case WCSR:
2912566SN/A            reg = regs.wcsr;
2922566SN/A            break;
2932566SN/A
2942566SN/A          case PCR:
2952566SN/A            reg = regs.pcr;
2962566SN/A            break;
2972566SN/A
2982566SN/A            // see the spec sheet for how RFCR and RFDR work
2992566SN/A            // basically, you write to RFCR to tell the machine
3002566SN/A            // what you want to do next, then you act upon RFDR,
3012566SN/A            // and the device will be prepared b/c of what you
3022566SN/A            // wrote to RFCR
3032566SN/A          case RFCR:
3042566SN/A            reg = regs.rfcr;
3052566SN/A            break;
3062566SN/A
3072566SN/A          case RFDR:
3082566SN/A            rfaddr = (uint16_t)(regs.rfcr & RFCR_RFADDR);
3092566SN/A            switch (rfaddr) {
3102566SN/A              // Read from perfect match ROM octets
3112566SN/A              case 0x000:
3122566SN/A                reg = rom.perfectMatch[1];
3132566SN/A                reg = reg << 8;
3142566SN/A                reg += rom.perfectMatch[0];
315837SN/A                break;
3162566SN/A              case 0x002:
3172566SN/A                reg = rom.perfectMatch[3] << 8;
3182566SN/A                reg += rom.perfectMatch[2];
319837SN/A                break;
3202566SN/A              case 0x004:
3212566SN/A                reg = rom.perfectMatch[5] << 8;
3222566SN/A                reg += rom.perfectMatch[4];
323837SN/A                break;
3242566SN/A              default:
3252566SN/A                // Read filter hash table
3262566SN/A                if (rfaddr >= FHASH_ADDR &&
3272566SN/A                    rfaddr < FHASH_ADDR + FHASH_SIZE) {
3282566SN/A
3292566SN/A                    // Only word-aligned reads supported
3302566SN/A                    if (rfaddr % 2)
3312566SN/A                        panic("unaligned read from filter hash table!");
3322566SN/A
3332566SN/A                    reg = rom.filterHash[rfaddr - FHASH_ADDR + 1] << 8;
3342566SN/A                    reg += rom.filterHash[rfaddr - FHASH_ADDR];
335837SN/A                    break;
336837SN/A                }
3372566SN/A
3382566SN/A                panic("reading RFDR for something other than pattern"
3392566SN/A                      " matching or hashing! %#x\n", rfaddr);
340837SN/A            }
3412566SN/A            break;
3422566SN/A
3432566SN/A          case SRR:
3442566SN/A            reg = regs.srr;
3452566SN/A            break;
3462566SN/A
3472566SN/A          case MIBC:
3482566SN/A            reg = regs.mibc;
3492566SN/A            reg &= ~(MIBC_MIBS | MIBC_ACLR);
3502566SN/A            break;
3512566SN/A
3522566SN/A          case VRCR:
3532566SN/A            reg = regs.vrcr;
3542566SN/A            break;
3552566SN/A
3562566SN/A          case VTCR:
3572566SN/A            reg = regs.vtcr;
3582566SN/A            break;
3592566SN/A
3602566SN/A          case VDR:
3612566SN/A            reg = regs.vdr;
3622566SN/A            break;
3632566SN/A
3642566SN/A          case CCSR:
3652566SN/A            reg = regs.ccsr;
3662566SN/A            break;
3672566SN/A
3682566SN/A          case TBICR:
3692566SN/A            reg = regs.tbicr;
3702566SN/A            break;
3712566SN/A
3722566SN/A          case TBISR:
3732566SN/A            reg = regs.tbisr;
3742566SN/A            break;
3752566SN/A
3762566SN/A          case TANAR:
3772566SN/A            reg = regs.tanar;
3782566SN/A            break;
3792566SN/A
3802566SN/A          case TANLPAR:
3812566SN/A            reg = regs.tanlpar;
3822566SN/A            break;
3832566SN/A
3842566SN/A          case TANER:
3852566SN/A            reg = regs.taner;
3862566SN/A            break;
3872566SN/A
3882566SN/A          case TESR:
3892566SN/A            reg = regs.tesr;
3902566SN/A            break;
3912566SN/A
3922566SN/A          case M5REG:
3932566SN/A            reg = 0;
3942566SN/A            if (params()->rx_thread)
3952566SN/A                reg |= M5REG_RX_THREAD;
3962566SN/A            if (params()->tx_thread)
3972566SN/A                reg |= M5REG_TX_THREAD;
3982566SN/A            if (params()->rss)
3992566SN/A                reg |= M5REG_RSS;
4002566SN/A            break;
4012566SN/A
4022566SN/A          default:
4032566SN/A            panic("reading unimplemented register: addr=%#x", daddr);
404837SN/A        }
4052566SN/A
4062566SN/A        DPRINTF(EthernetPIO, "read from %#x: data=%d data=%#x\n",
4072566SN/A                daddr, reg, reg);
4082566SN/A
4094870SN/A    pkt->makeAtomicResponse();
4102566SN/A    return pioDelay;
411837SN/A}
412837SN/A
4132566SN/ATick
4143349SN/ANSGigE::write(PacketPtr pkt)
415837SN/A{
416927SN/A    assert(ioEnable);
417917SN/A
4182641SN/A    Addr daddr = pkt->getAddr() & 0xfff;
4192566SN/A    DPRINTF(EthernetPIO, "write da=%#x pa=%#x size=%d\n",
4202641SN/A            daddr, pkt->getAddr(), pkt->getSize());
4212630SN/A
422854SN/A    if (daddr > LAST && daddr <=  RESERVED) {
423837SN/A        panic("Accessing reserved register");
424854SN/A    } else if (daddr > RESERVED && daddr <= 0x3FC) {
4252846SN/A        return writeConfig(pkt);
426854SN/A    } else if (daddr > 0x3FC)
427854SN/A        panic("Something is messed up!\n");
428837SN/A
4292641SN/A    if (pkt->getSize() == sizeof(uint32_t)) {
43013342Sgabeblack@google.com        uint32_t reg = pkt->getLE<uint32_t>();
4311848SN/A        uint16_t rfaddr;
4321848SN/A
433854SN/A        DPRINTF(EthernetPIO, "write data=%d data=%#x\n", reg, reg);
434837SN/A
435837SN/A        switch (daddr) {
436837SN/A          case CR:
437837SN/A            regs.command = reg;
4381035SN/A            if (reg & CR_TXD) {
4391035SN/A                txEnable = false;
440837SN/A            } else if (reg & CR_TXE) {
4412126SN/A                txEnable = true;
4422126SN/A
4432126SN/A                // the kernel is enabling the transmit machine
4442126SN/A                if (txState == txIdle)
4452126SN/A                    txKick();
446837SN/A            }
447837SN/A
4481035SN/A            if (reg & CR_RXD) {
4491035SN/A                rxEnable = false;
450837SN/A            } else if (reg & CR_RXE) {
4512126SN/A                rxEnable = true;
4522126SN/A
4532126SN/A                if (rxState == rxIdle)
4542126SN/A                    rxKick();
455837SN/A            }
456837SN/A
457837SN/A            if (reg & CR_TXR)
458837SN/A                txReset();
459837SN/A
460837SN/A            if (reg & CR_RXR)
461837SN/A                rxReset();
462837SN/A
463837SN/A            if (reg & CR_SWI)
464837SN/A                devIntrPost(ISR_SWI);
465837SN/A
466837SN/A            if (reg & CR_RST) {
467837SN/A                txReset();
468837SN/A                rxReset();
469854SN/A
470837SN/A                regsReset();
471837SN/A            }
472837SN/A            break;
473837SN/A
4741690SN/A          case CFGR:
4751690SN/A            if (reg & CFGR_LNKSTS ||
4761690SN/A                reg & CFGR_SPDSTS ||
4771690SN/A                reg & CFGR_DUPSTS ||
4781690SN/A                reg & CFGR_RESERVED ||
4791690SN/A                reg & CFGR_T64ADDR ||
4808726SN/A                reg & CFGR_PCI64_DET) {
4818726SN/A                // First clear all writable bits
4828726SN/A                regs.config &= CFGR_LNKSTS | CFGR_SPDSTS | CFGR_DUPSTS |
4838726SN/A                    CFGR_RESERVED | CFGR_T64ADDR |
4848726SN/A                    CFGR_PCI64_DET;
4858726SN/A                // Now set the appropriate writable bits
4868726SN/A                regs.config |= reg & ~(CFGR_LNKSTS | CFGR_SPDSTS | CFGR_DUPSTS |
4878726SN/A                                       CFGR_RESERVED | CFGR_T64ADDR |
4888726SN/A                                       CFGR_PCI64_DET);
4898726SN/A            }
4901027SN/A
4911027SN/A// all these #if 0's are because i don't THINK the kernel needs to
4921027SN/A// have these implemented. if there is a problem relating to one of
4931027SN/A// these, you may need to add functionality in.
4948737SN/A
4958737SN/A// grouped together and #if 0'ed to avoid empty if body and make clang happy
4968737SN/A#if 0
4971690SN/A            if (reg & CFGR_TBI_EN) ;
4981690SN/A            if (reg & CFGR_MODE_1000) ;
499837SN/A
5001690SN/A            if (reg & CFGR_PINT_DUPSTS ||
5011690SN/A                reg & CFGR_PINT_LNKSTS ||
5021690SN/A                reg & CFGR_PINT_SPDSTS)
5031027SN/A                ;
5041027SN/A
5051690SN/A            if (reg & CFGR_TMRTEST) ;
5061690SN/A            if (reg & CFGR_MRM_DIS) ;
5071690SN/A            if (reg & CFGR_MWI_DIS) ;
5081690SN/A
5091690SN/A            if (reg & CFGR_DATA64_EN) ;
5101690SN/A            if (reg & CFGR_M64ADDR) ;
5111690SN/A            if (reg & CFGR_PHY_RST) ;
5121690SN/A            if (reg & CFGR_PHY_DIS) ;
513837SN/A
5141909SN/A            if (reg & CFGR_REQALG) ;
5151909SN/A            if (reg & CFGR_SB) ;
5161909SN/A            if (reg & CFGR_POW) ;
5171909SN/A            if (reg & CFGR_EXD) ;
5181909SN/A            if (reg & CFGR_PESEL) ;
5191909SN/A            if (reg & CFGR_BROM_DIS) ;
5201909SN/A            if (reg & CFGR_EXT_125) ;
5211909SN/A            if (reg & CFGR_BEM) ;
5228737SN/A
5238737SN/A            if (reg & CFGR_T64ADDR) ;
5248737SN/A            // panic("CFGR_T64ADDR is read only register!\n");
5258737SN/A#endif
5268737SN/A            if (reg & CFGR_AUTO_1000)
5278737SN/A                panic("CFGR_AUTO_1000 not implemented!\n");
5288737SN/A
5298737SN/A            if (reg & CFGR_PCI64_DET)
5308737SN/A                panic("CFGR_PCI64_DET is read only register!\n");
5318737SN/A
5328737SN/A            if (reg & CFGR_EXTSTS_EN)
5338737SN/A                extstsEnable = true;
5348737SN/A            else
5358737SN/A                extstsEnable = false;
536837SN/A            break;
537837SN/A
538837SN/A          case MEAR:
5391843SN/A            // Clear writable bits
5401843SN/A            regs.mear &= MEAR_EEDO;
5411843SN/A            // Set appropriate writable bits
5421843SN/A            regs.mear |= reg & ~MEAR_EEDO;
5431843SN/A
5441843SN/A            // FreeBSD uses the EEPROM to read PMATCH (for the MAC address)
5451843SN/A            // even though it could get it through RFDR
5461843SN/A            if (reg & MEAR_EESEL) {
5471843SN/A                // Rising edge of clock
5481843SN/A                if (reg & MEAR_EECLK && !eepromClk)
5491843SN/A                    eepromKick();
5501843SN/A            }
5511843SN/A            else {
5521843SN/A                eepromState = eepromStart;
5531843SN/A                regs.mear &= ~MEAR_EEDI;
5541843SN/A            }
5551843SN/A
5561843SN/A            eepromClk = reg & MEAR_EECLK;
5571843SN/A
5581027SN/A            // since phy is completely faked, MEAR_MD* don't matter
5598737SN/A
5608737SN/A// grouped together and #if 0'ed to avoid empty if body and make clang happy
5618737SN/A#if 0
562837SN/A            if (reg & MEAR_MDIO) ;
563837SN/A            if (reg & MEAR_MDDIR) ;
564837SN/A            if (reg & MEAR_MDC) ;
5658737SN/A#endif
566837SN/A            break;
567837SN/A
568837SN/A          case PTSCR:
569854SN/A            regs.ptscr = reg & ~(PTSCR_RBIST_RDONLY);
5701027SN/A            // these control BISTs for various parts of chip - we
5711027SN/A            // don't care or do just fake that the BIST is done
572854SN/A            if (reg & PTSCR_RBIST_EN)
573854SN/A                regs.ptscr |= PTSCR_RBIST_DONE;
574854SN/A            if (reg & PTSCR_EEBIST_EN)
575854SN/A                regs.ptscr &= ~PTSCR_EEBIST_EN;
576854SN/A            if (reg & PTSCR_EELOAD_EN)
577854SN/A                regs.ptscr &= ~PTSCR_EELOAD_EN;
578837SN/A            break;
579837SN/A
580837SN/A          case ISR: /* writing to the ISR has no effect */
581837SN/A            panic("ISR is a read only register!\n");
582837SN/A
583837SN/A          case IMR:
584837SN/A            regs.imr = reg;
585837SN/A            devIntrChangeMask();
586837SN/A            break;
587837SN/A
588837SN/A          case IER:
589837SN/A            regs.ier = reg;
590837SN/A            break;
591837SN/A
592837SN/A          case IHR:
593837SN/A            regs.ihr = reg;
594837SN/A            /* not going to implement real interrupt holdoff */
595837SN/A            break;
596837SN/A
597837SN/A          case TXDP:
598837SN/A            regs.txdp = (reg & 0xFFFFFFFC);
599837SN/A            assert(txState == txIdle);
600837SN/A            CTDD = false;
601837SN/A            break;
602837SN/A
603837SN/A          case TXDP_HI:
604837SN/A            regs.txdp_hi = reg;
605837SN/A            break;
606837SN/A
6071690SN/A          case TX_CFG:
608837SN/A            regs.txcfg = reg;
609837SN/A#if 0
6101690SN/A            if (reg & TX_CFG_CSI) ;
6111690SN/A            if (reg & TX_CFG_HBI) ;
6121690SN/A            if (reg & TX_CFG_MLB) ;
6131690SN/A            if (reg & TX_CFG_ATP) ;
6141690SN/A            if (reg & TX_CFG_ECRETRY) {
6151027SN/A                /*
6161027SN/A                 * this could easily be implemented, but considering
6171027SN/A                 * the network is just a fake pipe, wouldn't make
6181027SN/A                 * sense to do this
6191027SN/A                 */
6201027SN/A            }
621837SN/A
6221690SN/A            if (reg & TX_CFG_BRST_DIS) ;
623837SN/A#endif
624837SN/A
6251027SN/A#if 0
626854SN/A            /* we handle our own DMA, ignore the kernel's exhortations */
6271690SN/A            if (reg & TX_CFG_MXDMA) ;
6281027SN/A#endif
6291027SN/A
6301027SN/A            // also, we currently don't care about fill/drain
6311027SN/A            // thresholds though this may change in the future with
6321027SN/A            // more realistic networks or a driver which changes it
6331027SN/A            // according to feedback
634837SN/A
635837SN/A            break;
636837SN/A
637837SN/A          case GPIOR:
6381843SN/A            // Only write writable bits
6391843SN/A            regs.gpior &= GPIOR_UNUSED | GPIOR_GP5_IN | GPIOR_GP4_IN
6401843SN/A                        | GPIOR_GP3_IN | GPIOR_GP2_IN | GPIOR_GP1_IN;
6411843SN/A            regs.gpior |= reg & ~(GPIOR_UNUSED | GPIOR_GP5_IN | GPIOR_GP4_IN
6421843SN/A                                | GPIOR_GP3_IN | GPIOR_GP2_IN | GPIOR_GP1_IN);
643837SN/A            /* these just control general purpose i/o pins, don't matter */
644837SN/A            break;
645837SN/A
646854SN/A          case RXDP:
647854SN/A            regs.rxdp = reg;
6481035SN/A            CRDD = false;
649854SN/A            break;
650854SN/A
651854SN/A          case RXDP_HI:
652854SN/A            regs.rxdp_hi = reg;
653854SN/A            break;
654854SN/A
6551690SN/A          case RX_CFG:
656837SN/A            regs.rxcfg = reg;
657837SN/A#if 0
6581690SN/A            if (reg & RX_CFG_AEP) ;
6591690SN/A            if (reg & RX_CFG_ARP) ;
6601690SN/A            if (reg & RX_CFG_STRIPCRC) ;
6611690SN/A            if (reg & RX_CFG_RX_RD) ;
6621690SN/A            if (reg & RX_CFG_ALP) ;
6631690SN/A            if (reg & RX_CFG_AIRL) ;
664837SN/A
665854SN/A            /* we handle our own DMA, ignore what kernel says about it */
6661690SN/A            if (reg & RX_CFG_MXDMA) ;
6671027SN/A
668927SN/A            //also, we currently don't care about fill/drain thresholds
669927SN/A            //though this may change in the future with more realistic
670927SN/A            //networks or a driver which changes it according to feedback
6711690SN/A            if (reg & (RX_CFG_DRTH | RX_CFG_DRTH0)) ;
672837SN/A#endif
673837SN/A            break;
674837SN/A
675837SN/A          case PQCR:
676837SN/A            /* there is no priority queueing used in the linux 2.6 driver */
677837SN/A            regs.pqcr = reg;
678837SN/A            break;
679837SN/A
680837SN/A          case WCSR:
681837SN/A            /* not going to implement wake on LAN */
682837SN/A            regs.wcsr = reg;
683837SN/A            break;
684837SN/A
685837SN/A          case PCR:
686837SN/A            /* not going to implement pause control */
687837SN/A            regs.pcr = reg;
688837SN/A            break;
689837SN/A
690837SN/A          case RFCR:
691837SN/A            regs.rfcr = reg;
692854SN/A
693837SN/A            rxFilterEnable = (reg & RFCR_RFEN) ? true : false;
694837SN/A            acceptBroadcast = (reg & RFCR_AAB) ? true : false;
695837SN/A            acceptMulticast = (reg & RFCR_AAM) ? true : false;
696837SN/A            acceptUnicast = (reg & RFCR_AAU) ? true : false;
697837SN/A            acceptPerfect = (reg & RFCR_APM) ? true : false;
698837SN/A            acceptArp = (reg & RFCR_AARP) ? true : false;
6991843SN/A            multicastHashEnable = (reg & RFCR_MHEN) ? true : false;
700837SN/A
7011027SN/A#if 0
7021027SN/A            if (reg & RFCR_APAT)
7031027SN/A                panic("RFCR_APAT not implemented!\n");
7041027SN/A#endif
7051843SN/A            if (reg & RFCR_UHEN)
7061843SN/A                panic("Unicast hash filtering not used by drivers!\n");
707837SN/A
708837SN/A            if (reg & RFCR_ULM)
709837SN/A                panic("RFCR_ULM not implemented!\n");
710837SN/A
711837SN/A            break;
712837SN/A
713837SN/A          case RFDR:
7141848SN/A            rfaddr = (uint16_t)(regs.rfcr & RFCR_RFADDR);
7151843SN/A            switch (rfaddr) {
7161843SN/A              case 0x000:
7171843SN/A                rom.perfectMatch[0] = (uint8_t)reg;
7181843SN/A                rom.perfectMatch[1] = (uint8_t)(reg >> 8);
7191843SN/A                break;
7201843SN/A              case 0x002:
7211843SN/A                rom.perfectMatch[2] = (uint8_t)reg;
7221843SN/A                rom.perfectMatch[3] = (uint8_t)(reg >> 8);
7231843SN/A                break;
7241843SN/A              case 0x004:
7251843SN/A                rom.perfectMatch[4] = (uint8_t)reg;
7261843SN/A                rom.perfectMatch[5] = (uint8_t)(reg >> 8);
7271843SN/A                break;
7281843SN/A              default:
7291843SN/A
7301843SN/A                if (rfaddr >= FHASH_ADDR &&
7311843SN/A                    rfaddr < FHASH_ADDR + FHASH_SIZE) {
7321843SN/A
7331843SN/A                    // Only word-aligned writes supported
7341843SN/A                    if (rfaddr % 2)
7351843SN/A                        panic("unaligned write to filter hash table!");
7361843SN/A
7371843SN/A                    rom.filterHash[rfaddr - FHASH_ADDR] = (uint8_t)reg;
7381843SN/A                    rom.filterHash[rfaddr - FHASH_ADDR + 1]
7391843SN/A                        = (uint8_t)(reg >> 8);
7401843SN/A                    break;
7411843SN/A                }
74210367SN/A                panic("writing RFDR for something other than pattern matching "
74310367SN/A                    "or hashing! %#x\n", rfaddr);
7441843SN/A            }
74512561Ssiddhesh.poyarekar@gmail.com            break;
746837SN/A
747837SN/A          case BRAR:
7481843SN/A            regs.brar = reg;
7491843SN/A            break;
750837SN/A
751837SN/A          case BRDR:
752837SN/A            panic("the driver never uses BRDR, something is wrong!\n");
753837SN/A
754837SN/A          case SRR:
755837SN/A            panic("SRR is read only register!\n");
756837SN/A
757837SN/A          case MIBC:
758837SN/A            panic("the driver never uses MIBC, something is wrong!\n");
759837SN/A
760837SN/A          case VRCR:
761837SN/A            regs.vrcr = reg;
762837SN/A            break;
763837SN/A
764837SN/A          case VTCR:
765837SN/A            regs.vtcr = reg;
766837SN/A            break;
767837SN/A
768837SN/A          case VDR:
769837SN/A            panic("the driver never uses VDR, something is wrong!\n");
770837SN/A
771837SN/A          case CCSR:
772837SN/A            /* not going to implement clockrun stuff */
773837SN/A            regs.ccsr = reg;
774837SN/A            break;
775837SN/A
776837SN/A          case TBICR:
777837SN/A            regs.tbicr = reg;
778837SN/A            if (reg & TBICR_MR_LOOPBACK)
779837SN/A                panic("TBICR_MR_LOOPBACK never used, something wrong!\n");
780837SN/A
781837SN/A            if (reg & TBICR_MR_AN_ENABLE) {
782837SN/A                regs.tanlpar = regs.tanar;
783837SN/A                regs.tbisr |= (TBISR_MR_AN_COMPLETE | TBISR_MR_LINK_STATUS);
784837SN/A            }
785837SN/A
786837SN/A#if 0
787837SN/A            if (reg & TBICR_MR_RESTART_AN) ;
788837SN/A#endif
789837SN/A
790837SN/A            break;
791837SN/A
792837SN/A          case TBISR:
793837SN/A            panic("TBISR is read only register!\n");
794837SN/A
795837SN/A          case TANAR:
7961843SN/A            // Only write the writable bits
7971843SN/A            regs.tanar &= TANAR_RF1 | TANAR_RF2 | TANAR_UNUSED;
7981843SN/A            regs.tanar |= reg & ~(TANAR_RF1 | TANAR_RF2 | TANAR_UNUSED);
7991843SN/A
8001843SN/A            // Pause capability unimplemented
8011843SN/A#if 0
8021843SN/A            if (reg & TANAR_PS2) ;
8031843SN/A            if (reg & TANAR_PS1) ;
8041843SN/A#endif
8051843SN/A
806837SN/A            break;
807837SN/A
808837SN/A          case TANLPAR:
809837SN/A            panic("this should only be written to by the fake phy!\n");
810837SN/A
811837SN/A          case TANER:
812837SN/A            panic("TANER is read only register!\n");
813837SN/A
814837SN/A          case TESR:
815837SN/A            regs.tesr = reg;
816837SN/A            break;
817837SN/A
818837SN/A          default:
8191027SN/A            panic("invalid register access daddr=%#x", daddr);
820837SN/A        }
8211027SN/A    } else {
822837SN/A        panic("Invalid Request Size");
8231027SN/A    }
8244870SN/A    pkt->makeAtomicResponse();
8252566SN/A    return pioDelay;
826837SN/A}
827837SN/A
828837SN/Avoid
829879SN/ANSGigE::devIntrPost(uint32_t interrupts)
830837SN/A{
831854SN/A    if (interrupts & ISR_RESERVE)
832854SN/A        panic("Cannot set a reserved interrupt");
833837SN/A
8341057SN/A    if (interrupts & ISR_NOIMPL)
8351057SN/A        warn("interrupt not implemented %#x\n", interrupts);
8361057SN/A
8371883SN/A    interrupts &= ISR_IMPL;
8381057SN/A    regs.isr |= interrupts;
8391057SN/A
8401263SN/A    if (interrupts & regs.imr) {
8411263SN/A        if (interrupts & ISR_SWI) {
8421263SN/A            totalSwi++;
8431263SN/A        }
8441263SN/A        if (interrupts & ISR_RXIDLE) {
8451263SN/A            totalRxIdle++;
8461263SN/A        }
8471263SN/A        if (interrupts & ISR_RXOK) {
8481263SN/A            totalRxOk++;
8491263SN/A        }
8501263SN/A        if (interrupts & ISR_RXDESC) {
8511263SN/A            totalRxDesc++;
8521263SN/A        }
8531263SN/A        if (interrupts & ISR_TXOK) {
8541263SN/A            totalTxOk++;
8551263SN/A        }
8561263SN/A        if (interrupts & ISR_TXIDLE) {
8571263SN/A            totalTxIdle++;
8581263SN/A        }
8591263SN/A        if (interrupts & ISR_TXDESC) {
8601263SN/A            totalTxDesc++;
8611263SN/A        }
8621263SN/A        if (interrupts & ISR_RXORN) {
8631263SN/A            totalRxOrn++;
8641263SN/A        }
8651263SN/A    }
8661263SN/A
8671057SN/A    DPRINTF(EthernetIntr,
8681057SN/A            "interrupt written to ISR: intr=%#x isr=%#x imr=%#x\n",
8691057SN/A            interrupts, regs.isr, regs.imr);
870837SN/A
871854SN/A    if ((regs.isr & regs.imr)) {
8727823SN/A        Tick when = curTick();
8731883SN/A        if ((regs.isr & regs.imr & ISR_NODELAY) == 0)
874854SN/A            when += intrDelay;
8755485SN/A        postedInterrupts++;
876854SN/A        cpuIntrPost(when);
877854SN/A    }
878837SN/A}
879837SN/A
8801263SN/A/* writing this interrupt counting stats inside this means that this function
8811263SN/A   is now limited to being used to clear all interrupts upon the kernel
8821263SN/A   reading isr and servicing.  just telling you in case you were thinking
8831263SN/A   of expanding use.
8841263SN/A*/
885837SN/Avoid
886879SN/ANSGigE::devIntrClear(uint32_t interrupts)
887837SN/A{
888837SN/A    if (interrupts & ISR_RESERVE)
889837SN/A        panic("Cannot clear a reserved interrupt");
890837SN/A
8911263SN/A    if (regs.isr & regs.imr & ISR_SWI) {
8921263SN/A        postedSwi++;
8931263SN/A    }
8941263SN/A    if (regs.isr & regs.imr & ISR_RXIDLE) {
8951263SN/A        postedRxIdle++;
8961263SN/A    }
8971263SN/A    if (regs.isr & regs.imr & ISR_RXOK) {
8981263SN/A        postedRxOk++;
8991263SN/A    }
9001263SN/A    if (regs.isr & regs.imr & ISR_RXDESC) {
9011263SN/A            postedRxDesc++;
9021263SN/A    }
9031263SN/A    if (regs.isr & regs.imr & ISR_TXOK) {
9041263SN/A        postedTxOk++;
9051263SN/A    }
9061263SN/A    if (regs.isr & regs.imr & ISR_TXIDLE) {
9071263SN/A        postedTxIdle++;
9081263SN/A    }
9091263SN/A    if (regs.isr & regs.imr & ISR_TXDESC) {
9101263SN/A        postedTxDesc++;
9111263SN/A    }
9121263SN/A    if (regs.isr & regs.imr & ISR_RXORN) {
9131263SN/A        postedRxOrn++;
9141263SN/A    }
9151263SN/A
9161057SN/A    interrupts &= ~ISR_NOIMPL;
9171057SN/A    regs.isr &= ~interrupts;
918837SN/A
9191027SN/A    DPRINTF(EthernetIntr,
9201027SN/A            "interrupt cleared from ISR: intr=%x isr=%x imr=%x\n",
921881SN/A            interrupts, regs.isr, regs.imr);
9221036SN/A
9231036SN/A    if (!(regs.isr & regs.imr))
9241036SN/A        cpuIntrClear();
925837SN/A}
926837SN/A
927837SN/Avoid
928879SN/ANSGigE::devIntrChangeMask()
929837SN/A{
9301036SN/A    DPRINTF(EthernetIntr, "interrupt mask changed: isr=%x imr=%x masked=%x\n",
9311036SN/A            regs.isr, regs.imr, regs.isr & regs.imr);
932837SN/A
933837SN/A    if (regs.isr & regs.imr)
9347823SN/A        cpuIntrPost(curTick());
935837SN/A    else
936837SN/A        cpuIntrClear();
937837SN/A}
938837SN/A
939837SN/Avoid
940879SN/ANSGigE::cpuIntrPost(Tick when)
941837SN/A{
9421027SN/A    // If the interrupt you want to post is later than an interrupt
9431027SN/A    // already scheduled, just let it post in the coming one and don't
9441027SN/A    // schedule another.
9451027SN/A    // HOWEVER, must be sure that the scheduled intrTick is in the
9461027SN/A    // future (this was formerly the source of a bug)
9471035SN/A    /**
9481035SN/A     * @todo this warning should be removed and the intrTick code should
9491035SN/A     * be fixed.
9501035SN/A     */
9517823SN/A    assert(when >= curTick());
9527823SN/A    assert(intrTick >= curTick() || intrTick == 0);
9531072SN/A    if (when > intrTick && intrTick != 0) {
9541072SN/A        DPRINTF(EthernetIntr, "don't need to schedule event...intrTick=%d\n",
9551072SN/A                intrTick);
9561072SN/A        return;
9571035SN/A    }
958854SN/A
959854SN/A    intrTick = when;
9607823SN/A    if (intrTick < curTick()) {
9617823SN/A        intrTick = curTick();
9621072SN/A    }
9631072SN/A
9641072SN/A    DPRINTF(EthernetIntr, "going to schedule an interrupt for intrTick=%d\n",
9651072SN/A            intrTick);
9661072SN/A
9671072SN/A    if (intrEvent)
968854SN/A        intrEvent->squash();
96912087Sspwilson2@wisc.edu
97012087Sspwilson2@wisc.edu    intrEvent = new EventFunctionWrapper([this]{ cpuInterrupt(); },
97112087Sspwilson2@wisc.edu                                         name(), true);
9725606SN/A    schedule(intrEvent, intrTick);
973854SN/A}
974854SN/A
975854SN/Avoid
976879SN/ANSGigE::cpuInterrupt()
977854SN/A{
9787823SN/A    assert(intrTick == curTick());
9791072SN/A
9801072SN/A    // Whether or not there's a pending interrupt, we don't care about
9811072SN/A    // it anymore
9821072SN/A    intrEvent = 0;
9831072SN/A    intrTick = 0;
9841072SN/A
985854SN/A    // Don't send an interrupt if there's already one
986927SN/A    if (cpuPendingIntr) {
987927SN/A        DPRINTF(EthernetIntr,
988927SN/A                "would send an interrupt now, but there's already pending\n");
9891072SN/A    } else {
9901072SN/A        // Send interrupt
9911072SN/A        cpuPendingIntr = true;
9921072SN/A
9931149SN/A        DPRINTF(EthernetIntr, "posting interrupt\n");
9941149SN/A        intrPost();
995927SN/A    }
996837SN/A}
997837SN/A
998837SN/Avoid
999879SN/ANSGigE::cpuIntrClear()
1000837SN/A{
10011027SN/A    if (!cpuPendingIntr)
10021027SN/A        return;
10031027SN/A
10041072SN/A    if (intrEvent) {
10051072SN/A        intrEvent->squash();
10061072SN/A        intrEvent = 0;
10071072SN/A    }
10081072SN/A
10091072SN/A    intrTick = 0;
10101072SN/A
10111027SN/A    cpuPendingIntr = false;
10121057SN/A
10131149SN/A    DPRINTF(EthernetIntr, "clearing interrupt\n");
10141149SN/A    intrClear();
1015837SN/A}
1016837SN/A
1017837SN/Abool
1018879SN/ANSGigE::cpuIntrPending() const
1019837SN/A{ return cpuPendingIntr; }
1020837SN/A
1021837SN/Avoid
1022879SN/ANSGigE::txReset()
1023837SN/A{
1024837SN/A
1025837SN/A    DPRINTF(Ethernet, "transmit reset\n");
1026837SN/A
1027837SN/A    CTDD = false;
10281035SN/A    txEnable = false;;
1029854SN/A    txFragPtr = 0;
1030854SN/A    assert(txDescCnt == 0);
1031837SN/A    txFifo.clear();
1032837SN/A    txState = txIdle;
1033854SN/A    assert(txDmaState == dmaIdle);
1034837SN/A}
1035837SN/A
1036837SN/Avoid
1037879SN/ANSGigE::rxReset()
1038837SN/A{
1039837SN/A    DPRINTF(Ethernet, "receive reset\n");
1040837SN/A
1041837SN/A    CRDD = false;
1042854SN/A    assert(rxPktBytes == 0);
10431035SN/A    rxEnable = false;
1044854SN/A    rxFragPtr = 0;
1045854SN/A    assert(rxDescCnt == 0);
1046854SN/A    assert(rxDmaState == dmaIdle);
1047837SN/A    rxFifo.clear();
1048837SN/A    rxState = rxIdle;
1049837SN/A}
1050837SN/A
10511036SN/Avoid
10521036SN/ANSGigE::regsReset()
1053915SN/A{
1054915SN/A    memset(&regs, 0, sizeof(regs));
10551817SN/A    regs.config = (CFGR_LNKSTS | CFGR_TBI_EN | CFGR_MODE_1000);
10561843SN/A    regs.mear = 0x12;
10571057SN/A    regs.txcfg = 0x120; // set drain threshold to 1024 bytes and
10581057SN/A                        // fill threshold to 32 bytes
10591057SN/A    regs.rxcfg = 0x4;   // set drain threshold to 16 bytes
10601057SN/A    regs.srr = 0x0103;  // set the silicon revision to rev B or 0x103
10611057SN/A    regs.mibc = MIBC_FRZ;
10621057SN/A    regs.vdr = 0x81;    // set the vlan tag type to 802.1q
10631057SN/A    regs.tesr = 0xc000; // TBI capable of both full and half duplex
10641843SN/A    regs.brar = 0xffffffff;
1065927SN/A
1066927SN/A    extstsEnable = false;
1067927SN/A    acceptBroadcast = false;
1068927SN/A    acceptMulticast = false;
1069927SN/A    acceptUnicast = false;
1070927SN/A    acceptPerfect = false;
1071927SN/A    acceptArp = false;
1072915SN/A}
1073915SN/A
1074854SN/Abool
1075879SN/ANSGigE::doRxDmaRead()
1076854SN/A{
1077854SN/A    assert(rxDmaState == dmaIdle || rxDmaState == dmaReadWaiting);
1078854SN/A    rxDmaState = dmaReading;
1079854SN/A
108010913SN/A    if (dmaPending() || drainState() != DrainState::Running)
10812566SN/A        rxDmaState = dmaReadWaiting;
10822566SN/A    else
10832566SN/A        dmaRead(rxDmaAddr, rxDmaLen, &rxDmaReadEvent, (uint8_t*)rxDmaData);
10842566SN/A
1085854SN/A    return true;
1086854SN/A}
1087854SN/A
1088854SN/Avoid
1089879SN/ANSGigE::rxDmaReadDone()
1090854SN/A{
1091854SN/A    assert(rxDmaState == dmaReading);
10922566SN/A    rxDmaState = dmaIdle;
10932566SN/A
10942566SN/A    DPRINTF(EthernetDMA, "rx dma read  paddr=%#x len=%d\n",
10952566SN/A            rxDmaAddr, rxDmaLen);
10962566SN/A    DDUMP(EthernetDMA, rxDmaData, rxDmaLen);
1097854SN/A
1098854SN/A    // If the transmit state machine has a pending DMA, let it go first
1099854SN/A    if (txDmaState == dmaReadWaiting || txDmaState == dmaWriteWaiting)
1100854SN/A        txKick();
1101854SN/A
1102854SN/A    rxKick();
1103854SN/A}
1104854SN/A
1105854SN/Abool
1106879SN/ANSGigE::doRxDmaWrite()
1107854SN/A{
1108854SN/A    assert(rxDmaState == dmaIdle || rxDmaState == dmaWriteWaiting);
1109854SN/A    rxDmaState = dmaWriting;
1110854SN/A
111110913SN/A    if (dmaPending() || drainState() != DrainState::Running)
11122566SN/A        rxDmaState = dmaWriteWaiting;
11132566SN/A    else
11142566SN/A        dmaWrite(rxDmaAddr, rxDmaLen, &rxDmaWriteEvent, (uint8_t*)rxDmaData);
1115854SN/A    return true;
1116854SN/A}
1117854SN/A
1118854SN/Avoid
1119879SN/ANSGigE::rxDmaWriteDone()
1120854SN/A{
1121854SN/A    assert(rxDmaState == dmaWriting);
11222566SN/A    rxDmaState = dmaIdle;
11232566SN/A
11242566SN/A    DPRINTF(EthernetDMA, "rx dma write paddr=%#x len=%d\n",
11252566SN/A            rxDmaAddr, rxDmaLen);
11262566SN/A    DDUMP(EthernetDMA, rxDmaData, rxDmaLen);
1127854SN/A
1128854SN/A    // If the transmit state machine has a pending DMA, let it go first
1129854SN/A    if (txDmaState == dmaReadWaiting || txDmaState == dmaWriteWaiting)
1130854SN/A        txKick();
1131854SN/A
1132854SN/A    rxKick();
1133837SN/A}
1134837SN/A
1135837SN/Avoid
1136879SN/ANSGigE::rxKick()
1137837SN/A{
11381909SN/A    bool is64bit = (bool)(regs.config & CFGR_M64ADDR);
11391909SN/A
11401909SN/A    DPRINTF(EthernetSM,
11411909SN/A            "receive kick rxState=%s (rxBuf.size=%d) %d-bit\n",
11421909SN/A            NsRxStateStrings[rxState], rxFifo.size(), is64bit ? 64 : 32);
11431909SN/A
11441909SN/A    Addr link, bufptr;
11451909SN/A    uint32_t &cmdsts = is64bit ? rxDesc64.cmdsts : rxDesc32.cmdsts;
11461909SN/A    uint32_t &extsts = is64bit ? rxDesc64.extsts : rxDesc32.extsts;
1147837SN/A
11481801SN/A  next:
11499417SN/A    if (rxKickTick > curTick()) {
11509417SN/A        DPRINTF(EthernetSM, "receive kick exiting, can't run till %d\n",
11519417SN/A                rxKickTick);
11521801SN/A
11539417SN/A        goto exit;
11549417SN/A    }
11551801SN/A
11569417SN/A    // Go to the next state machine clock tick.
11579417SN/A    rxKickTick = clockEdge(Cycles(1));
1158837SN/A
1159854SN/A    switch(rxDmaState) {
1160854SN/A      case dmaReadWaiting:
1161854SN/A        if (doRxDmaRead())
1162854SN/A            goto exit;
1163854SN/A        break;
1164854SN/A      case dmaWriteWaiting:
1165854SN/A        if (doRxDmaWrite())
1166854SN/A            goto exit;
1167854SN/A        break;
1168854SN/A      default:
1169854SN/A        break;
1170854SN/A    }
1171837SN/A
11721909SN/A    link = is64bit ? (Addr)rxDesc64.link : (Addr)rxDesc32.link;
11731909SN/A    bufptr = is64bit ? (Addr)rxDesc64.bufptr : (Addr)rxDesc32.bufptr;
11741909SN/A
1175855SN/A    // see state machine from spec for details
11761027SN/A    // the way this works is, if you finish work on one state and can
11771027SN/A    // go directly to another, you do that through jumping to the
11781027SN/A    // label "next".  however, if you have intermediate work, like DMA
11791027SN/A    // so that you can't go to the next state yet, you go to exit and
11801027SN/A    // exit the loop.  however, when the DMA is done it will trigger
11811027SN/A    // an event and come back to this loop.
1182854SN/A    switch (rxState) {
1183854SN/A      case rxIdle:
11841035SN/A        if (!rxEnable) {
1185927SN/A            DPRINTF(EthernetSM, "Receive Disabled! Nothing to do.\n");
1186854SN/A            goto exit;
1187854SN/A        }
1188837SN/A
1189854SN/A        if (CRDD) {
1190854SN/A            rxState = rxDescRefr;
1191837SN/A
1192854SN/A            rxDmaAddr = regs.rxdp & 0x3fffffff;
11931909SN/A            rxDmaData =
11941909SN/A                is64bit ? (void *)&rxDesc64.link : (void *)&rxDesc32.link;
11951909SN/A            rxDmaLen = is64bit ? sizeof(rxDesc64.link) : sizeof(rxDesc32.link);
1196854SN/A            rxDmaFree = dmaDescFree;
1197854SN/A
1198961SN/A            descDmaReads++;
1199961SN/A            descDmaRdBytes += rxDmaLen;
1200961SN/A
1201854SN/A            if (doRxDmaRead())
1202854SN/A                goto exit;
1203837SN/A        } else {
1204837SN/A            rxState = rxDescRead;
1205854SN/A
1206854SN/A            rxDmaAddr = regs.rxdp & 0x3fffffff;
12071909SN/A            rxDmaData = is64bit ? (void *)&rxDesc64 : (void *)&rxDesc32;
12081909SN/A            rxDmaLen = is64bit ? sizeof(rxDesc64) : sizeof(rxDesc32);
1209854SN/A            rxDmaFree = dmaDescFree;
1210854SN/A
1211961SN/A            descDmaReads++;
1212961SN/A            descDmaRdBytes += rxDmaLen;
1213961SN/A
1214854SN/A            if (doRxDmaRead())
1215854SN/A                goto exit;
1216837SN/A        }
1217854SN/A        break;
1218854SN/A
1219854SN/A      case rxDescRefr:
1220854SN/A        if (rxDmaState != dmaIdle)
1221854SN/A            goto exit;
1222854SN/A
1223854SN/A        rxState = rxAdvance;
1224854SN/A        break;
1225854SN/A
1226854SN/A     case rxDescRead:
1227854SN/A        if (rxDmaState != dmaIdle)
1228854SN/A            goto exit;
1229854SN/A
12301909SN/A        DPRINTF(EthernetDesc, "rxDesc: addr=%08x read descriptor\n",
12311036SN/A                regs.rxdp & 0x3fffffff);
12321036SN/A        DPRINTF(EthernetDesc,
12331909SN/A                "rxDesc: link=%#x bufptr=%#x cmdsts=%08x extsts=%08x\n",
12341909SN/A                link, bufptr, cmdsts, extsts);
12351909SN/A
12361909SN/A        if (cmdsts & CMDSTS_OWN) {
12371035SN/A            devIntrPost(ISR_RXIDLE);
1238837SN/A            rxState = rxIdle;
12391035SN/A            goto exit;
1240837SN/A        } else {
1241837SN/A            rxState = rxFifoBlock;
12421909SN/A            rxFragPtr = bufptr;
12431909SN/A            rxDescCnt = cmdsts & CMDSTS_LEN_MASK;
1244854SN/A        }
1245854SN/A        break;
1246837SN/A
1247854SN/A      case rxFifoBlock:
1248854SN/A        if (!rxPacket) {
1249854SN/A            /**
1250854SN/A             * @todo in reality, we should be able to start processing
1251854SN/A             * the packet as it arrives, and not have to wait for the
1252854SN/A             * full packet ot be in the receive fifo.
1253854SN/A             */
1254854SN/A            if (rxFifo.empty())
1255854SN/A                goto exit;
1256854SN/A
12571036SN/A            DPRINTF(EthernetSM, "****processing receive of new packet****\n");
1258927SN/A
1259854SN/A            // If we don't have a packet, grab a new one from the fifo.
1260854SN/A            rxPacket = rxFifo.front();
1261854SN/A            rxPktBytes = rxPacket->length;
1262854SN/A            rxPacketBufPtr = rxPacket->data;
1263854SN/A
12641011SN/A#if TRACING_ON
1265927SN/A            if (DTRACE(Ethernet)) {
12661114SN/A                IpPtr ip(rxPacket);
12671078SN/A                if (ip) {
12681078SN/A                    DPRINTF(Ethernet, "ID is %d\n", ip->id());
12691114SN/A                    TcpPtr tcp(ip);
12701078SN/A                    if (tcp) {
12711561SN/A                        DPRINTF(Ethernet,
12721561SN/A                                "Src Port=%d, Dest Port=%d, Seq=%d, Ack=%d\n",
12731561SN/A                                tcp->sport(), tcp->dport(), tcp->seq(),
12741561SN/A                                tcp->ack());
1275927SN/A                    }
1276927SN/A                }
1277927SN/A            }
12781011SN/A#endif
1279927SN/A
1280854SN/A            // sanity check - i think the driver behaves like this
1281854SN/A            assert(rxDescCnt >= rxPktBytes);
12821154SN/A            rxFifo.pop();
1283837SN/A        }
1284837SN/A
1285837SN/A
12861027SN/A        // dont' need the && rxDescCnt > 0 if driver sanity check
12871027SN/A        // above holds
1288854SN/A        if (rxPktBytes > 0) {
1289854SN/A            rxState = rxFragWrite;
12901027SN/A            // don't need min<>(rxPktBytes,rxDescCnt) if above sanity
12911027SN/A            // check holds
1292854SN/A            rxXferLen = rxPktBytes;
1293854SN/A
1294854SN/A            rxDmaAddr = rxFragPtr & 0x3fffffff;
1295854SN/A            rxDmaData = rxPacketBufPtr;
1296854SN/A            rxDmaLen = rxXferLen;
1297854SN/A            rxDmaFree = dmaDataFree;
1298854SN/A
1299854SN/A            if (doRxDmaWrite())
1300854SN/A                goto exit;
1301854SN/A
1302837SN/A        } else {
1303854SN/A            rxState = rxDescWrite;
1304837SN/A
1305854SN/A            //if (rxPktBytes == 0) {  /* packet is done */
1306854SN/A            assert(rxPktBytes == 0);
1307927SN/A            DPRINTF(EthernetSM, "done with receiving packet\n");
1308837SN/A
13091909SN/A            cmdsts |= CMDSTS_OWN;
13101909SN/A            cmdsts &= ~CMDSTS_MORE;
13111909SN/A            cmdsts |= CMDSTS_OK;
13121909SN/A            cmdsts &= 0xffff0000;
13131909SN/A            cmdsts += rxPacket->length;   //i.e. set CMDSTS_SIZE
1314837SN/A
1315854SN/A#if 0
13161027SN/A            /*
13171027SN/A             * all the driver uses these are for its own stats keeping
13181027SN/A             * which we don't care about, aren't necessary for
13191027SN/A             * functionality and doing this would just slow us down.
13201027SN/A             * if they end up using this in a later version for
13211027SN/A             * functional purposes, just undef
13221027SN/A             */
1323837SN/A            if (rxFilterEnable) {
13241909SN/A                cmdsts &= ~CMDSTS_DEST_MASK;
13251114SN/A                const EthAddr &dst = rxFifoFront()->dst();
13261114SN/A                if (dst->unicast())
13271909SN/A                    cmdsts |= CMDSTS_DEST_SELF;
13281114SN/A                if (dst->multicast())
13291909SN/A                    cmdsts |= CMDSTS_DEST_MULTI;
13301114SN/A                if (dst->broadcast())
13311909SN/A                    cmdsts |= CMDSTS_DEST_MASK;
1332837SN/A            }
1333854SN/A#endif
1334837SN/A
13351114SN/A            IpPtr ip(rxPacket);
13361114SN/A            if (extstsEnable && ip) {
13371909SN/A                extsts |= EXTSTS_IPPKT;
13381078SN/A                rxIpChecksums++;
13391114SN/A                if (cksum(ip) != 0) {
1340927SN/A                    DPRINTF(EthernetCksum, "Rx IP Checksum Error\n");
13411909SN/A                    extsts |= EXTSTS_IPERR;
1342927SN/A                }
13431114SN/A                TcpPtr tcp(ip);
13441114SN/A                UdpPtr udp(ip);
13451114SN/A                if (tcp) {
13461909SN/A                    extsts |= EXTSTS_TCPPKT;
13471078SN/A                    rxTcpChecksums++;
13481114SN/A                    if (cksum(tcp) != 0) {
1349927SN/A                        DPRINTF(EthernetCksum, "Rx TCP Checksum Error\n");
13501909SN/A                        extsts |= EXTSTS_TCPERR;
1351961SN/A
1352927SN/A                    }
13531114SN/A                } else if (udp) {
13541909SN/A                    extsts |= EXTSTS_UDPPKT;
13551078SN/A                    rxUdpChecksums++;
13561114SN/A                    if (cksum(udp) != 0) {
1357927SN/A                        DPRINTF(EthernetCksum, "Rx UDP Checksum Error\n");
13581909SN/A                        extsts |= EXTSTS_UDPERR;
1359927SN/A                    }
1360837SN/A                }
1361837SN/A            }
1362881SN/A            rxPacket = 0;
1363881SN/A
13641027SN/A            /*
13651027SN/A             * the driver seems to always receive into desc buffers
13661027SN/A             * of size 1514, so you never have a pkt that is split
13671027SN/A             * into multiple descriptors on the receive side, so
13681027SN/A             * i don't implement that case, hence the assert above.
13691027SN/A             */
13701027SN/A
13711027SN/A            DPRINTF(EthernetDesc,
13721909SN/A                    "rxDesc: addr=%08x writeback cmdsts extsts\n",
13731036SN/A                    regs.rxdp & 0x3fffffff);
13741036SN/A            DPRINTF(EthernetDesc,
13751909SN/A                    "rxDesc: link=%#x bufptr=%#x cmdsts=%08x extsts=%08x\n",
13761909SN/A                    link, bufptr, cmdsts, extsts);
13771909SN/A
13781909SN/A            rxDmaAddr = regs.rxdp & 0x3fffffff;
13791909SN/A            rxDmaData = &cmdsts;
13801909SN/A            if (is64bit) {
13811909SN/A                rxDmaAddr += offsetof(ns_desc64, cmdsts);
13821909SN/A                rxDmaLen = sizeof(rxDesc64.cmdsts) + sizeof(rxDesc64.extsts);
13831909SN/A            } else {
13841909SN/A                rxDmaAddr += offsetof(ns_desc32, cmdsts);
13851909SN/A                rxDmaLen = sizeof(rxDesc32.cmdsts) + sizeof(rxDesc32.extsts);
13861909SN/A            }
1387854SN/A            rxDmaFree = dmaDescFree;
1388854SN/A
1389961SN/A            descDmaWrites++;
1390961SN/A            descDmaWrBytes += rxDmaLen;
1391961SN/A
1392854SN/A            if (doRxDmaWrite())
1393854SN/A                goto exit;
1394837SN/A        }
1395854SN/A        break;
1396837SN/A
1397854SN/A      case rxFragWrite:
1398854SN/A        if (rxDmaState != dmaIdle)
1399854SN/A            goto exit;
1400854SN/A
1401854SN/A        rxPacketBufPtr += rxXferLen;
1402854SN/A        rxFragPtr += rxXferLen;
1403854SN/A        rxPktBytes -= rxXferLen;
1404854SN/A
1405854SN/A        rxState = rxFifoBlock;
1406854SN/A        break;
1407854SN/A
1408854SN/A      case rxDescWrite:
1409854SN/A        if (rxDmaState != dmaIdle)
1410854SN/A            goto exit;
1411854SN/A
14121909SN/A        assert(cmdsts & CMDSTS_OWN);
1413854SN/A
1414854SN/A        assert(rxPacket == 0);
1415854SN/A        devIntrPost(ISR_RXOK);
1416854SN/A
14171909SN/A        if (cmdsts & CMDSTS_INTR)
1418854SN/A            devIntrPost(ISR_RXDESC);
1419854SN/A
14201035SN/A        if (!rxEnable) {
1421927SN/A            DPRINTF(EthernetSM, "Halting the RX state machine\n");
1422854SN/A            rxState = rxIdle;
14231035SN/A            goto exit;
1424854SN/A        } else
1425854SN/A            rxState = rxAdvance;
1426854SN/A        break;
1427854SN/A
1428854SN/A      case rxAdvance:
14291909SN/A        if (link == 0) {
14301035SN/A            devIntrPost(ISR_RXIDLE);
1431854SN/A            rxState = rxIdle;
14321035SN/A            CRDD = true;
14331035SN/A            goto exit;
1434854SN/A        } else {
14351893SN/A            if (rxDmaState != dmaIdle)
14361893SN/A                goto exit;
1437854SN/A            rxState = rxDescRead;
14381909SN/A            regs.rxdp = link;
1439854SN/A            CRDD = false;
1440854SN/A
1441854SN/A            rxDmaAddr = regs.rxdp & 0x3fffffff;
14421909SN/A            rxDmaData = is64bit ? (void *)&rxDesc64 : (void *)&rxDesc32;
14431909SN/A            rxDmaLen = is64bit ? sizeof(rxDesc64) : sizeof(rxDesc32);
1444854SN/A            rxDmaFree = dmaDescFree;
1445854SN/A
1446854SN/A            if (doRxDmaRead())
1447854SN/A                goto exit;
1448854SN/A        }
1449854SN/A        break;
1450854SN/A
1451854SN/A      default:
1452854SN/A        panic("Invalid rxState!");
1453837SN/A    }
1454837SN/A
14551036SN/A    DPRINTF(EthernetSM, "entering next rxState=%s\n",
1456854SN/A            NsRxStateStrings[rxState]);
1457854SN/A    goto next;
1458837SN/A
1459854SN/A  exit:
1460854SN/A    /**
1461854SN/A     * @todo do we want to schedule a future kick?
1462854SN/A     */
14631036SN/A    DPRINTF(EthernetSM, "rx state machine exited rxState=%s\n",
1464854SN/A            NsRxStateStrings[rxState]);
14651801SN/A
14669417SN/A    if (!rxKickEvent.scheduled())
14675606SN/A        schedule(rxKickEvent, rxKickTick);
1468837SN/A}
1469837SN/A
1470837SN/Avoid
1471879SN/ANSGigE::transmit()
1472837SN/A{
1473837SN/A    if (txFifo.empty()) {
1474837SN/A        DPRINTF(Ethernet, "nothing to transmit\n");
1475837SN/A        return;
1476837SN/A    }
1477837SN/A
14781036SN/A    DPRINTF(Ethernet, "Attempt Pkt Transmit: txFifo length=%d\n",
14791154SN/A            txFifo.size());
1480927SN/A    if (interface->sendPacket(txFifo.front())) {
14811011SN/A#if TRACING_ON
1482927SN/A        if (DTRACE(Ethernet)) {
14831114SN/A            IpPtr ip(txFifo.front());
14841078SN/A            if (ip) {
14851078SN/A                DPRINTF(Ethernet, "ID is %d\n", ip->id());
14861114SN/A                TcpPtr tcp(ip);
14871078SN/A                if (tcp) {
14881561SN/A                    DPRINTF(Ethernet,
14891561SN/A                            "Src Port=%d, Dest Port=%d, Seq=%d, Ack=%d\n",
14901909SN/A                            tcp->sport(), tcp->dport(), tcp->seq(),
14911909SN/A                            tcp->ack());
1492927SN/A                }
1493927SN/A            }
1494927SN/A        }
14951011SN/A#endif
1496927SN/A
14971561SN/A        DDUMP(EthernetData, txFifo.front()->data, txFifo.front()->length);
1498837SN/A        txBytes += txFifo.front()->length;
1499837SN/A        txPackets++;
1500837SN/A
15011027SN/A        DPRINTF(Ethernet, "Successful Xmit! now txFifoAvail is %d\n",
15021154SN/A                txFifo.avail());
15031154SN/A        txFifo.pop();
1504837SN/A
15051027SN/A        /*
15061027SN/A         * normally do a writeback of the descriptor here, and ONLY
15071027SN/A         * after that is done, send this interrupt.  but since our
15081027SN/A         * stuff never actually fails, just do this interrupt here,
15091027SN/A         * otherwise the code has to stray from this nice format.
15101027SN/A         * besides, it's functionally the same.
15111027SN/A         */
1512854SN/A        devIntrPost(ISR_TXOK);
15131027SN/A    }
1514854SN/A
1515854SN/A   if (!txFifo.empty() && !txEvent.scheduled()) {
1516854SN/A       DPRINTF(Ethernet, "reschedule transmit\n");
15177823SN/A       schedule(txEvent, curTick() + retryTime);
1518854SN/A   }
1519854SN/A}
1520854SN/A
1521854SN/Abool
1522879SN/ANSGigE::doTxDmaRead()
1523854SN/A{
1524854SN/A    assert(txDmaState == dmaIdle || txDmaState == dmaReadWaiting);
1525854SN/A    txDmaState = dmaReading;
1526854SN/A
152710913SN/A    if (dmaPending() || drainState() != DrainState::Running)
15282566SN/A        txDmaState = dmaReadWaiting;
15292566SN/A    else
15302566SN/A        dmaRead(txDmaAddr, txDmaLen, &txDmaReadEvent, (uint8_t*)txDmaData);
15312566SN/A
1532854SN/A    return true;
1533854SN/A}
1534837SN/A
1535854SN/Avoid
1536879SN/ANSGigE::txDmaReadDone()
1537854SN/A{
1538854SN/A    assert(txDmaState == dmaReading);
15392566SN/A    txDmaState = dmaIdle;
15402566SN/A
15412566SN/A    DPRINTF(EthernetDMA, "tx dma read  paddr=%#x len=%d\n",
15422566SN/A            txDmaAddr, txDmaLen);
15432566SN/A    DDUMP(EthernetDMA, txDmaData, txDmaLen);
1544837SN/A
1545854SN/A    // If the receive state machine  has a pending DMA, let it go first
1546854SN/A    if (rxDmaState == dmaReadWaiting || rxDmaState == dmaWriteWaiting)
1547854SN/A        rxKick();
1548837SN/A
1549854SN/A    txKick();
1550854SN/A}
1551837SN/A
1552854SN/Abool
1553879SN/ANSGigE::doTxDmaWrite()
1554854SN/A{
1555854SN/A    assert(txDmaState == dmaIdle || txDmaState == dmaWriteWaiting);
1556854SN/A    txDmaState = dmaWriting;
1557854SN/A
155810913SN/A    if (dmaPending() || drainState() != DrainState::Running)
15592566SN/A        txDmaState = dmaWriteWaiting;
15602566SN/A    else
15612566SN/A        dmaWrite(txDmaAddr, txDmaLen, &txDmaWriteEvent, (uint8_t*)txDmaData);
1562854SN/A    return true;
1563854SN/A}
1564854SN/A
1565854SN/Avoid
1566879SN/ANSGigE::txDmaWriteDone()
1567854SN/A{
1568854SN/A    assert(txDmaState == dmaWriting);
15692566SN/A    txDmaState = dmaIdle;
15702566SN/A
15712566SN/A    DPRINTF(EthernetDMA, "tx dma write paddr=%#x len=%d\n",
15722566SN/A            txDmaAddr, txDmaLen);
15732566SN/A    DDUMP(EthernetDMA, txDmaData, txDmaLen);
1574854SN/A
1575854SN/A    // If the receive state machine  has a pending DMA, let it go first
1576854SN/A    if (rxDmaState == dmaReadWaiting || rxDmaState == dmaWriteWaiting)
1577854SN/A        rxKick();
1578854SN/A
1579854SN/A    txKick();
1580837SN/A}
1581837SN/A
1582837SN/Avoid
1583879SN/ANSGigE::txKick()
1584837SN/A{
15851909SN/A    bool is64bit = (bool)(regs.config & CFGR_M64ADDR);
15861909SN/A
15871909SN/A    DPRINTF(EthernetSM, "transmit kick txState=%s %d-bit\n",
15881909SN/A            NsTxStateStrings[txState], is64bit ? 64 : 32);
15891909SN/A
15901909SN/A    Addr link, bufptr;
15911909SN/A    uint32_t &cmdsts = is64bit ? txDesc64.cmdsts : txDesc32.cmdsts;
15921909SN/A    uint32_t &extsts = is64bit ? txDesc64.extsts : txDesc32.extsts;
1593927SN/A
15941801SN/A  next:
15959417SN/A    if (txKickTick > curTick()) {
15969417SN/A        DPRINTF(EthernetSM, "transmit kick exiting, can't run till %d\n",
15979417SN/A                txKickTick);
15989417SN/A        goto exit;
15999417SN/A    }
16001801SN/A
16019417SN/A    // Go to the next state machine clock tick.
16029417SN/A    txKickTick = clockEdge(Cycles(1));
1603837SN/A
1604854SN/A    switch(txDmaState) {
1605854SN/A      case dmaReadWaiting:
1606854SN/A        if (doTxDmaRead())
1607854SN/A            goto exit;
1608854SN/A        break;
1609854SN/A      case dmaWriteWaiting:
1610854SN/A        if (doTxDmaWrite())
1611854SN/A            goto exit;
1612854SN/A        break;
1613854SN/A      default:
1614854SN/A        break;
1615854SN/A    }
1616837SN/A
16171909SN/A    link = is64bit ? (Addr)txDesc64.link : (Addr)txDesc32.link;
16181909SN/A    bufptr = is64bit ? (Addr)txDesc64.bufptr : (Addr)txDesc32.bufptr;
1619854SN/A    switch (txState) {
1620854SN/A      case txIdle:
16211035SN/A        if (!txEnable) {
1622927SN/A            DPRINTF(EthernetSM, "Transmit disabled.  Nothing to do.\n");
1623854SN/A            goto exit;
1624854SN/A        }
1625837SN/A
1626854SN/A        if (CTDD) {
1627854SN/A            txState = txDescRefr;
1628837SN/A
1629881SN/A            txDmaAddr = regs.txdp & 0x3fffffff;
16301909SN/A            txDmaData =
16311909SN/A                is64bit ? (void *)&txDesc64.link : (void *)&txDesc32.link;
16321909SN/A            txDmaLen = is64bit ? sizeof(txDesc64.link) : sizeof(txDesc32.link);
1633854SN/A            txDmaFree = dmaDescFree;
1634837SN/A
1635961SN/A            descDmaReads++;
1636961SN/A            descDmaRdBytes += txDmaLen;
1637961SN/A
1638854SN/A            if (doTxDmaRead())
1639854SN/A                goto exit;
1640854SN/A
1641854SN/A        } else {
1642854SN/A            txState = txDescRead;
1643854SN/A
1644854SN/A            txDmaAddr = regs.txdp & 0x3fffffff;
16451909SN/A            txDmaData = is64bit ? (void *)&txDesc64 : (void *)&txDesc32;
16461909SN/A            txDmaLen = is64bit ? sizeof(txDesc64) : sizeof(txDesc32);
1647854SN/A            txDmaFree = dmaDescFree;
1648854SN/A
1649961SN/A            descDmaReads++;
1650961SN/A            descDmaRdBytes += txDmaLen;
1651961SN/A
1652854SN/A            if (doTxDmaRead())
1653854SN/A                goto exit;
1654837SN/A        }
1655854SN/A        break;
1656837SN/A
1657854SN/A      case txDescRefr:
1658854SN/A        if (txDmaState != dmaIdle)
1659854SN/A            goto exit;
1660854SN/A
1661854SN/A        txState = txAdvance;
1662854SN/A        break;
1663854SN/A
1664854SN/A      case txDescRead:
1665854SN/A        if (txDmaState != dmaIdle)
1666854SN/A            goto exit;
1667854SN/A
16681909SN/A        DPRINTF(EthernetDesc, "txDesc: addr=%08x read descriptor\n",
16691801SN/A                regs.txdp & 0x3fffffff);
1670927SN/A        DPRINTF(EthernetDesc,
16711909SN/A                "txDesc: link=%#x bufptr=%#x cmdsts=%#08x extsts=%#08x\n",
16721909SN/A                link, bufptr, cmdsts, extsts);
16731909SN/A
16741909SN/A        if (cmdsts & CMDSTS_OWN) {
1675854SN/A            txState = txFifoBlock;
16761909SN/A            txFragPtr = bufptr;
16771909SN/A            txDescCnt = cmdsts & CMDSTS_LEN_MASK;
1678854SN/A        } else {
16791035SN/A            devIntrPost(ISR_TXIDLE);
1680854SN/A            txState = txIdle;
16811035SN/A            goto exit;
1682854SN/A        }
1683854SN/A        break;
1684854SN/A
1685854SN/A      case txFifoBlock:
1686854SN/A        if (!txPacket) {
16871036SN/A            DPRINTF(EthernetSM, "****starting the tx of a new packet****\n");
168810469SN/A            txPacket = make_shared<EthPacketData>(16384);
1689854SN/A            txPacketBufPtr = txPacket->data;
1690854SN/A        }
1691854SN/A
1692854SN/A        if (txDescCnt == 0) {
1693927SN/A            DPRINTF(EthernetSM, "the txDescCnt == 0, done with descriptor\n");
16941909SN/A            if (cmdsts & CMDSTS_MORE) {
1695927SN/A                DPRINTF(EthernetSM, "there are more descriptors to come\n");
1696854SN/A                txState = txDescWrite;
1697854SN/A
16981909SN/A                cmdsts &= ~CMDSTS_OWN;
16991909SN/A
17001909SN/A                txDmaAddr = regs.txdp & 0x3fffffff;
17011909SN/A                txDmaData = &cmdsts;
17021909SN/A                if (is64bit) {
17031909SN/A                    txDmaAddr += offsetof(ns_desc64, cmdsts);
17041909SN/A                    txDmaLen = sizeof(txDesc64.cmdsts);
17051909SN/A                } else {
17061909SN/A                    txDmaAddr += offsetof(ns_desc32, cmdsts);
17071909SN/A                    txDmaLen = sizeof(txDesc32.cmdsts);
17081909SN/A                }
1709854SN/A                txDmaFree = dmaDescFree;
1710854SN/A
1711854SN/A                if (doTxDmaWrite())
1712854SN/A                    goto exit;
1713854SN/A
1714854SN/A            } else { /* this packet is totally done */
1715927SN/A                DPRINTF(EthernetSM, "This packet is done, let's wrap it up\n");
1716854SN/A                /* deal with the the packet that just finished */
1717854SN/A                if ((regs.vtcr & VTCR_PPCHK) && extstsEnable) {
17181114SN/A                    IpPtr ip(txPacket);
17191909SN/A                    if (extsts & EXTSTS_UDPPKT) {
17201114SN/A                        UdpPtr udp(ip);
17215484SN/A                        if (udp) {
17225484SN/A                            udp->sum(0);
17235484SN/A                            udp->sum(cksum(udp));
17245484SN/A                            txUdpChecksums++;
17255484SN/A                        } else {
17268231SN/A                            Debug::breakpoint();
17275484SN/A                            warn_once("UDPPKT set, but not UDP!\n");
17285484SN/A                        }
17291909SN/A                    } else if (extsts & EXTSTS_TCPPKT) {
17301114SN/A                        TcpPtr tcp(ip);
17315484SN/A                        if (tcp) {
17325484SN/A                            tcp->sum(0);
17335484SN/A                            tcp->sum(cksum(tcp));
17345484SN/A                            txTcpChecksums++;
17355484SN/A                        } else {
17365484SN/A                            warn_once("TCPPKT set, but not UDP!\n");
17375484SN/A                        }
1738944SN/A                    }
17391909SN/A                    if (extsts & EXTSTS_IPPKT) {
17405484SN/A                        if (ip) {
17415484SN/A                            ip->sum(0);
17425484SN/A                            ip->sum(cksum(ip));
17435484SN/A                            txIpChecksums++;
17445484SN/A                        } else {
17455484SN/A                            warn_once("IPPKT set, but not UDP!\n");
17465484SN/A                        }
1747854SN/A                    }
1748854SN/A                }
1749854SN/A
175011701Smichael.lebeane@amd.com                txPacket->simLength = txPacketBufPtr - txPacket->data;
1751854SN/A                txPacket->length = txPacketBufPtr - txPacket->data;
17521027SN/A                // this is just because the receive can't handle a
17531027SN/A                // packet bigger want to make sure
17541909SN/A                if (txPacket->length > 1514)
17551909SN/A                    panic("transmit packet too large, %s > 1514\n",
17561909SN/A                          txPacket->length);
17571909SN/A
17581205SN/A#ifndef NDEBUG
17591205SN/A                bool success =
17601205SN/A#endif
17611205SN/A                    txFifo.push(txPacket);
17621205SN/A                assert(success);
1763854SN/A
17641027SN/A                /*
17651027SN/A                 * this following section is not tqo spec, but
17661027SN/A                 * functionally shouldn't be any different.  normally,
17671027SN/A                 * the chip will wait til the transmit has occurred
17681027SN/A                 * before writing back the descriptor because it has
17691027SN/A                 * to wait to see that it was successfully transmitted
17701027SN/A                 * to decide whether to set CMDSTS_OK or not.
17711027SN/A                 * however, in the simulator since it is always
17721027SN/A                 * successfully transmitted, and writing it exactly to
17731027SN/A                 * spec would complicate the code, we just do it here
17741027SN/A                 */
1775927SN/A
17761909SN/A                cmdsts &= ~CMDSTS_OWN;
17771909SN/A                cmdsts |= CMDSTS_OK;
1778854SN/A
1779927SN/A                DPRINTF(EthernetDesc,
17801036SN/A                        "txDesc writeback: cmdsts=%08x extsts=%08x\n",
17811909SN/A                        cmdsts, extsts);
17821909SN/A
1783854SN/A                txDmaFree = dmaDescFree;
17841909SN/A                txDmaAddr = regs.txdp & 0x3fffffff;
17851909SN/A                txDmaData = &cmdsts;
17861909SN/A                if (is64bit) {
17871909SN/A                    txDmaAddr += offsetof(ns_desc64, cmdsts);
17881909SN/A                    txDmaLen =
17891909SN/A                        sizeof(txDesc64.cmdsts) + sizeof(txDesc64.extsts);
17901909SN/A                } else {
17911909SN/A                    txDmaAddr += offsetof(ns_desc32, cmdsts);
17921909SN/A                    txDmaLen =
17931909SN/A                        sizeof(txDesc32.cmdsts) + sizeof(txDesc32.extsts);
17941909SN/A                }
1795854SN/A
1796961SN/A                descDmaWrites++;
1797961SN/A                descDmaWrBytes += txDmaLen;
1798961SN/A
1799927SN/A                transmit();
1800854SN/A                txPacket = 0;
1801854SN/A
18021035SN/A                if (!txEnable) {
1803927SN/A                    DPRINTF(EthernetSM, "halting TX state machine\n");
1804854SN/A                    txState = txIdle;
18051035SN/A                    goto exit;
1806854SN/A                } else
1807854SN/A                    txState = txAdvance;
1808986SN/A
1809986SN/A                if (doTxDmaWrite())
1810986SN/A                    goto exit;
1811854SN/A            }
1812854SN/A        } else {
1813927SN/A            DPRINTF(EthernetSM, "this descriptor isn't done yet\n");
18141154SN/A            if (!txFifo.full()) {
1815992SN/A                txState = txFragRead;
1816992SN/A
18171027SN/A                /*
18181027SN/A                 * The number of bytes transferred is either whatever
18191027SN/A                 * is left in the descriptor (txDescCnt), or if there
18201027SN/A                 * is not enough room in the fifo, just whatever room
18211027SN/A                 * is left in the fifo
18221027SN/A                 */
18231154SN/A                txXferLen = min<uint32_t>(txDescCnt, txFifo.avail());
1824992SN/A
1825992SN/A                txDmaAddr = txFragPtr & 0x3fffffff;
1826992SN/A                txDmaData = txPacketBufPtr;
1827992SN/A                txDmaLen = txXferLen;
1828992SN/A                txDmaFree = dmaDataFree;
1829992SN/A
1830992SN/A                if (doTxDmaRead())
1831992SN/A                    goto exit;
1832992SN/A            } else {
1833992SN/A                txState = txFifoBlock;
1834992SN/A                transmit();
1835992SN/A
1836998SN/A                goto exit;
1837992SN/A            }
1838992SN/A
1839854SN/A        }
1840854SN/A        break;
1841854SN/A
1842854SN/A      case txFragRead:
1843854SN/A        if (txDmaState != dmaIdle)
1844854SN/A            goto exit;
1845854SN/A
1846854SN/A        txPacketBufPtr += txXferLen;
1847854SN/A        txFragPtr += txXferLen;
1848854SN/A        txDescCnt -= txXferLen;
18491205SN/A        txFifo.reserve(txXferLen);
1850854SN/A
1851854SN/A        txState = txFifoBlock;
1852854SN/A        break;
1853854SN/A
1854854SN/A      case txDescWrite:
1855854SN/A        if (txDmaState != dmaIdle)
1856854SN/A            goto exit;
1857854SN/A
18581909SN/A        if (cmdsts & CMDSTS_INTR)
1859854SN/A            devIntrPost(ISR_TXDESC);
1860854SN/A
18611801SN/A        if (!txEnable) {
18621801SN/A            DPRINTF(EthernetSM, "halting TX state machine\n");
18631801SN/A            txState = txIdle;
18641801SN/A            goto exit;
18651801SN/A        } else
18661801SN/A            txState = txAdvance;
1867854SN/A        break;
1868854SN/A
1869854SN/A      case txAdvance:
18701909SN/A        if (link == 0) {
18711035SN/A            devIntrPost(ISR_TXIDLE);
1872837SN/A            txState = txIdle;
18731035SN/A            goto exit;
1874837SN/A        } else {
18751893SN/A            if (txDmaState != dmaIdle)
18761893SN/A                goto exit;
1877837SN/A            txState = txDescRead;
18781909SN/A            regs.txdp = link;
1879837SN/A            CTDD = false;
1880854SN/A
18811909SN/A            txDmaAddr = link & 0x3fffffff;
18821909SN/A            txDmaData = is64bit ? (void *)&txDesc64 : (void *)&txDesc32;
18831909SN/A            txDmaLen = is64bit ? sizeof(txDesc64) : sizeof(txDesc32);
1884854SN/A            txDmaFree = dmaDescFree;
1885854SN/A
1886854SN/A            if (doTxDmaRead())
1887854SN/A                goto exit;
1888837SN/A        }
1889854SN/A        break;
1890837SN/A
1891854SN/A      default:
1892854SN/A        panic("invalid state");
1893837SN/A    }
1894837SN/A
18951036SN/A    DPRINTF(EthernetSM, "entering next txState=%s\n",
1896854SN/A            NsTxStateStrings[txState]);
1897854SN/A    goto next;
1898837SN/A
1899854SN/A  exit:
1900854SN/A    /**
1901854SN/A     * @todo do we want to schedule a future kick?
1902854SN/A     */
19031036SN/A    DPRINTF(EthernetSM, "tx state machine exited txState=%s\n",
1904854SN/A            NsTxStateStrings[txState]);
19051801SN/A
19069417SN/A    if (!txKickEvent.scheduled())
19075606SN/A        schedule(txKickEvent, txKickTick);
1908837SN/A}
1909837SN/A
19101843SN/A/**
19111843SN/A * Advance the EEPROM state machine
19121843SN/A * Called on rising edge of EEPROM clock bit in MEAR
19131843SN/A */
19141843SN/Avoid
19151843SN/ANSGigE::eepromKick()
19161843SN/A{
19171843SN/A    switch (eepromState) {
19181843SN/A
19191843SN/A      case eepromStart:
19201843SN/A
19211843SN/A        // Wait for start bit
19221843SN/A        if (regs.mear & MEAR_EEDI) {
19231843SN/A            // Set up to get 2 opcode bits
19241843SN/A            eepromState = eepromGetOpcode;
19251843SN/A            eepromBitsToRx = 2;
19261843SN/A            eepromOpcode = 0;
19271843SN/A        }
19281843SN/A        break;
19291843SN/A
19301843SN/A      case eepromGetOpcode:
19311843SN/A        eepromOpcode <<= 1;
19321843SN/A        eepromOpcode += (regs.mear & MEAR_EEDI) ? 1 : 0;
19331843SN/A        --eepromBitsToRx;
19341843SN/A
19351843SN/A        // Done getting opcode
19361843SN/A        if (eepromBitsToRx == 0) {
19371843SN/A            if (eepromOpcode != EEPROM_READ)
19381843SN/A                panic("only EEPROM reads are implemented!");
19391843SN/A
19401843SN/A            // Set up to get address
19411843SN/A            eepromState = eepromGetAddress;
19421843SN/A            eepromBitsToRx = 6;
19431843SN/A            eepromAddress = 0;
19441843SN/A        }
19451843SN/A        break;
19461843SN/A
19471843SN/A      case eepromGetAddress:
19481843SN/A        eepromAddress <<= 1;
19491843SN/A        eepromAddress += (regs.mear & MEAR_EEDI) ? 1 : 0;
19501843SN/A        --eepromBitsToRx;
19511843SN/A
19521843SN/A        // Done getting address
19531843SN/A        if (eepromBitsToRx == 0) {
19541843SN/A
19551843SN/A            if (eepromAddress >= EEPROM_SIZE)
19561843SN/A                panic("EEPROM read access out of range!");
19571843SN/A
19581843SN/A            switch (eepromAddress) {
19591843SN/A
19601843SN/A              case EEPROM_PMATCH2_ADDR:
19611843SN/A                eepromData = rom.perfectMatch[5];
19621843SN/A                eepromData <<= 8;
19631843SN/A                eepromData += rom.perfectMatch[4];
19641843SN/A                break;
19651843SN/A
19661843SN/A              case EEPROM_PMATCH1_ADDR:
19671843SN/A                eepromData = rom.perfectMatch[3];
19681843SN/A                eepromData <<= 8;
19691843SN/A                eepromData += rom.perfectMatch[2];
19701843SN/A                break;
19711843SN/A
19721843SN/A              case EEPROM_PMATCH0_ADDR:
19731843SN/A                eepromData = rom.perfectMatch[1];
19741843SN/A                eepromData <<= 8;
19751843SN/A                eepromData += rom.perfectMatch[0];
19761843SN/A                break;
19771843SN/A
19781843SN/A              default:
19791843SN/A                panic("FreeBSD driver only uses EEPROM to read PMATCH!");
19801843SN/A            }
19811843SN/A            // Set up to read data
19821843SN/A            eepromState = eepromRead;
19831843SN/A            eepromBitsToRx = 16;
19841843SN/A
19851843SN/A            // Clear data in bit
19861843SN/A            regs.mear &= ~MEAR_EEDI;
19871843SN/A        }
19881843SN/A        break;
19891843SN/A
19901843SN/A      case eepromRead:
19911843SN/A        // Clear Data Out bit
19921843SN/A        regs.mear &= ~MEAR_EEDO;
19931843SN/A        // Set bit to value of current EEPROM bit
19941843SN/A        regs.mear |= (eepromData & 0x8000) ? MEAR_EEDO : 0x0;
19951843SN/A
19961843SN/A        eepromData <<= 1;
19971843SN/A        --eepromBitsToRx;
19981843SN/A
19991843SN/A        // All done
20001843SN/A        if (eepromBitsToRx == 0) {
20011843SN/A            eepromState = eepromStart;
20021843SN/A        }
20031843SN/A        break;
20041843SN/A
20051843SN/A      default:
20061843SN/A        panic("invalid EEPROM state");
20071843SN/A    }
20081843SN/A
20091843SN/A}
20101843SN/A
2011837SN/Avoid
2012879SN/ANSGigE::transferDone()
2013837SN/A{
20141036SN/A    if (txFifo.empty()) {
20151036SN/A        DPRINTF(Ethernet, "transfer complete: txFifo empty...nothing to do\n");
2016837SN/A        return;
20171036SN/A    }
20181036SN/A
20191036SN/A    DPRINTF(Ethernet, "transfer complete: data in txFifo...schedule xmit\n");
2020837SN/A
20219417SN/A    reschedule(txEvent, clockEdge(Cycles(1)), true);
2022837SN/A}
2023837SN/A
2024837SN/Abool
20252566SN/ANSGigE::rxFilter(const EthPacketPtr &packet)
2026837SN/A{
20271114SN/A    EthPtr eth = packet;
2028837SN/A    bool drop = true;
2029837SN/A    string type;
2030837SN/A
20311114SN/A    const EthAddr &dst = eth->dst();
20321114SN/A    if (dst.unicast()) {
2033837SN/A        // If we're accepting all unicast addresses
2034837SN/A        if (acceptUnicast)
2035837SN/A            drop = false;
2036837SN/A
2037837SN/A        // If we make a perfect match
20381114SN/A        if (acceptPerfect && dst == rom.perfectMatch)
2039837SN/A            drop = false;
2040837SN/A
20411078SN/A        if (acceptArp && eth->type() == ETH_TYPE_ARP)
2042837SN/A            drop = false;
2043837SN/A
20441114SN/A    } else if (dst.broadcast()) {
2045837SN/A        // if we're accepting broadcasts
2046837SN/A        if (acceptBroadcast)
2047837SN/A            drop = false;
2048837SN/A
20491114SN/A    } else if (dst.multicast()) {
2050837SN/A        // if we're accepting all multicasts
2051837SN/A        if (acceptMulticast)
2052837SN/A            drop = false;
2053837SN/A
20541843SN/A        // Multicast hashing faked - all packets accepted
20551843SN/A        if (multicastHashEnable)
20561843SN/A            drop = false;
2057837SN/A    }
2058837SN/A
2059837SN/A    if (drop) {
2060837SN/A        DPRINTF(Ethernet, "rxFilter drop\n");
2061837SN/A        DDUMP(EthernetData, packet->data, packet->length);
2062837SN/A    }
2063837SN/A
2064837SN/A    return drop;
2065837SN/A}
2066837SN/A
2067837SN/Abool
20682566SN/ANSGigE::recvPacket(EthPacketPtr packet)
2069837SN/A{
2070837SN/A    rxBytes += packet->length;
2071837SN/A    rxPackets++;
2072837SN/A
20731036SN/A    DPRINTF(Ethernet, "Receiving packet from wire, rxFifoAvail=%d\n",
20741154SN/A            rxFifo.avail());
2075927SN/A
20761035SN/A    if (!rxEnable) {
2077837SN/A        DPRINTF(Ethernet, "receive disabled...packet dropped\n");
2078837SN/A        return true;
2079837SN/A    }
2080837SN/A
20811843SN/A    if (!rxFilterEnable) {
20821843SN/A        DPRINTF(Ethernet,
20831843SN/A            "receive packet filtering disabled . . . packet dropped\n");
20841843SN/A        return true;
20851843SN/A    }
20861843SN/A
20871843SN/A    if (rxFilter(packet)) {
2088837SN/A        DPRINTF(Ethernet, "packet filtered...dropped\n");
2089837SN/A        return true;
2090837SN/A    }
2091837SN/A
20921154SN/A    if (rxFifo.avail() < packet->length) {
20931561SN/A#if TRACING_ON
20941561SN/A        IpPtr ip(packet);
20951561SN/A        TcpPtr tcp(ip);
20961561SN/A        if (ip) {
20971561SN/A            DPRINTF(Ethernet,
20981561SN/A                    "packet won't fit in receive buffer...pkt ID %d dropped\n",
20991561SN/A                    ip->id());
21001561SN/A            if (tcp) {
21011561SN/A                DPRINTF(Ethernet, "Seq=%d\n", tcp->seq());
21021561SN/A            }
21031561SN/A        }
21041561SN/A#endif
21051263SN/A        droppedPackets++;
2106837SN/A        devIntrPost(ISR_RXORN);
2107837SN/A        return false;
2108837SN/A    }
2109837SN/A
21101154SN/A    rxFifo.push(packet);
2111837SN/A
2112854SN/A    rxKick();
2113837SN/A    return true;
2114837SN/A}
2115837SN/A
21162901SN/A
21172901SN/Avoid
21189342SN/ANSGigE::drainResume()
21192901SN/A{
21209342SN/A    Drainable::drainResume();
21212901SN/A
21222901SN/A    // During drain we could have left the state machines in a waiting state and
21232901SN/A    // they wouldn't get out until some other event occured to kick them.
21242901SN/A    // This way they'll get out immediately
21252901SN/A    txKick();
21262901SN/A    rxKick();
21272901SN/A}
21282901SN/A
21292901SN/A
2130837SN/A//=====================================================================
2131837SN/A//
2132837SN/A//
2133837SN/Avoid
213410905SN/ANSGigE::serialize(CheckpointOut &cp) const
2135837SN/A{
21369807SN/A    // Serialize the PciDevice base class
213710905SN/A    PciDevice::serialize(cp);
2138897SN/A
2139854SN/A    /*
2140854SN/A     * Finalize any DMA events now.
2141854SN/A     */
21422566SN/A    // @todo will mem system save pending dma?
2143837SN/A
2144854SN/A    /*
2145854SN/A     * Serialize the device registers
2146854SN/A     */
2147854SN/A    SERIALIZE_SCALAR(regs.command);
2148854SN/A    SERIALIZE_SCALAR(regs.config);
2149854SN/A    SERIALIZE_SCALAR(regs.mear);
2150854SN/A    SERIALIZE_SCALAR(regs.ptscr);
2151854SN/A    SERIALIZE_SCALAR(regs.isr);
2152854SN/A    SERIALIZE_SCALAR(regs.imr);
2153854SN/A    SERIALIZE_SCALAR(regs.ier);
2154854SN/A    SERIALIZE_SCALAR(regs.ihr);
2155854SN/A    SERIALIZE_SCALAR(regs.txdp);
2156854SN/A    SERIALIZE_SCALAR(regs.txdp_hi);
2157854SN/A    SERIALIZE_SCALAR(regs.txcfg);
2158854SN/A    SERIALIZE_SCALAR(regs.gpior);
2159854SN/A    SERIALIZE_SCALAR(regs.rxdp);
2160854SN/A    SERIALIZE_SCALAR(regs.rxdp_hi);
2161854SN/A    SERIALIZE_SCALAR(regs.rxcfg);
2162854SN/A    SERIALIZE_SCALAR(regs.pqcr);
2163854SN/A    SERIALIZE_SCALAR(regs.wcsr);
2164854SN/A    SERIALIZE_SCALAR(regs.pcr);
2165854SN/A    SERIALIZE_SCALAR(regs.rfcr);
2166854SN/A    SERIALIZE_SCALAR(regs.rfdr);
21671843SN/A    SERIALIZE_SCALAR(regs.brar);
21681843SN/A    SERIALIZE_SCALAR(regs.brdr);
2169854SN/A    SERIALIZE_SCALAR(regs.srr);
2170854SN/A    SERIALIZE_SCALAR(regs.mibc);
2171854SN/A    SERIALIZE_SCALAR(regs.vrcr);
2172854SN/A    SERIALIZE_SCALAR(regs.vtcr);
2173854SN/A    SERIALIZE_SCALAR(regs.vdr);
2174854SN/A    SERIALIZE_SCALAR(regs.ccsr);
2175854SN/A    SERIALIZE_SCALAR(regs.tbicr);
2176854SN/A    SERIALIZE_SCALAR(regs.tbisr);
2177854SN/A    SERIALIZE_SCALAR(regs.tanar);
2178854SN/A    SERIALIZE_SCALAR(regs.tanlpar);
2179854SN/A    SERIALIZE_SCALAR(regs.taner);
2180854SN/A    SERIALIZE_SCALAR(regs.tesr);
2181837SN/A
21821114SN/A    SERIALIZE_ARRAY(rom.perfectMatch, ETH_ADDR_LEN);
21831843SN/A    SERIALIZE_ARRAY(rom.filterHash, FHASH_SIZE);
2184837SN/A
2185927SN/A    SERIALIZE_SCALAR(ioEnable);
2186917SN/A
2187854SN/A    /*
2188915SN/A     * Serialize the data Fifos
2189915SN/A     */
219010905SN/A    rxFifo.serialize("rxFifo", cp);
219110905SN/A    txFifo.serialize("txFifo", cp);
2192915SN/A
2193915SN/A    /*
2194854SN/A     * Serialize the various helper variables
2195854SN/A     */
219610469SN/A    bool txPacketExists = txPacket != nullptr;
2197915SN/A    SERIALIZE_SCALAR(txPacketExists);
2198915SN/A    if (txPacketExists) {
219911701Smichael.lebeane@amd.com        txPacket->simLength = txPacketBufPtr - txPacket->data;
22001337SN/A        txPacket->length = txPacketBufPtr - txPacket->data;
220110905SN/A        txPacket->serialize("txPacket", cp);
2202915SN/A        uint32_t txPktBufPtr = (uint32_t) (txPacketBufPtr - txPacket->data);
2203915SN/A        SERIALIZE_SCALAR(txPktBufPtr);
2204915SN/A    }
2205915SN/A
220610469SN/A    bool rxPacketExists = rxPacket != nullptr;
2207915SN/A    SERIALIZE_SCALAR(rxPacketExists);
2208915SN/A    if (rxPacketExists) {
220910905SN/A        rxPacket->serialize("rxPacket", cp);
2210915SN/A        uint32_t rxPktBufPtr = (uint32_t) (rxPacketBufPtr - rxPacket->data);
2211915SN/A        SERIALIZE_SCALAR(rxPktBufPtr);
2212915SN/A    }
2213915SN/A
2214854SN/A    SERIALIZE_SCALAR(txXferLen);
2215854SN/A    SERIALIZE_SCALAR(rxXferLen);
2216837SN/A
2217854SN/A    /*
22181909SN/A     * Serialize Cached Descriptors
2219854SN/A     */
22201909SN/A    SERIALIZE_SCALAR(rxDesc64.link);
22211909SN/A    SERIALIZE_SCALAR(rxDesc64.bufptr);
22221909SN/A    SERIALIZE_SCALAR(rxDesc64.cmdsts);
22231909SN/A    SERIALIZE_SCALAR(rxDesc64.extsts);
22241909SN/A    SERIALIZE_SCALAR(txDesc64.link);
22251909SN/A    SERIALIZE_SCALAR(txDesc64.bufptr);
22261909SN/A    SERIALIZE_SCALAR(txDesc64.cmdsts);
22271909SN/A    SERIALIZE_SCALAR(txDesc64.extsts);
22281909SN/A    SERIALIZE_SCALAR(rxDesc32.link);
22291909SN/A    SERIALIZE_SCALAR(rxDesc32.bufptr);
22301909SN/A    SERIALIZE_SCALAR(rxDesc32.cmdsts);
22311909SN/A    SERIALIZE_SCALAR(rxDesc32.extsts);
22321909SN/A    SERIALIZE_SCALAR(txDesc32.link);
22331909SN/A    SERIALIZE_SCALAR(txDesc32.bufptr);
22341909SN/A    SERIALIZE_SCALAR(txDesc32.cmdsts);
22351909SN/A    SERIALIZE_SCALAR(txDesc32.extsts);
22361801SN/A    SERIALIZE_SCALAR(extstsEnable);
2237837SN/A
2238854SN/A    /*
2239854SN/A     * Serialize tx state machine
2240854SN/A     */
2241854SN/A    int txState = this->txState;
2242854SN/A    SERIALIZE_SCALAR(txState);
22431035SN/A    SERIALIZE_SCALAR(txEnable);
2244854SN/A    SERIALIZE_SCALAR(CTDD);
2245854SN/A    SERIALIZE_SCALAR(txFragPtr);
2246854SN/A    SERIALIZE_SCALAR(txDescCnt);
2247854SN/A    int txDmaState = this->txDmaState;
2248854SN/A    SERIALIZE_SCALAR(txDmaState);
22491801SN/A    SERIALIZE_SCALAR(txKickTick);
2250854SN/A
2251854SN/A    /*
2252854SN/A     * Serialize rx state machine
2253854SN/A     */
2254854SN/A    int rxState = this->rxState;
2255854SN/A    SERIALIZE_SCALAR(rxState);
22561035SN/A    SERIALIZE_SCALAR(rxEnable);
2257854SN/A    SERIALIZE_SCALAR(CRDD);
2258854SN/A    SERIALIZE_SCALAR(rxPktBytes);
22591224SN/A    SERIALIZE_SCALAR(rxFragPtr);
2260854SN/A    SERIALIZE_SCALAR(rxDescCnt);
2261854SN/A    int rxDmaState = this->rxDmaState;
2262854SN/A    SERIALIZE_SCALAR(rxDmaState);
22631801SN/A    SERIALIZE_SCALAR(rxKickTick);
2264854SN/A
2265915SN/A    /*
22661843SN/A     * Serialize EEPROM state machine
22671843SN/A     */
22681843SN/A    int eepromState = this->eepromState;
22691843SN/A    SERIALIZE_SCALAR(eepromState);
22701843SN/A    SERIALIZE_SCALAR(eepromClk);
22711843SN/A    SERIALIZE_SCALAR(eepromBitsToRx);
22721843SN/A    SERIALIZE_SCALAR(eepromOpcode);
22731843SN/A    SERIALIZE_SCALAR(eepromAddress);
22741843SN/A    SERIALIZE_SCALAR(eepromData);
22751843SN/A
22761843SN/A    /*
2277854SN/A     * If there's a pending transmit, store the time so we can
2278854SN/A     * reschedule it later
2279854SN/A     */
22807823SN/A    Tick transmitTick = txEvent.scheduled() ? txEvent.when() - curTick() : 0;
2281854SN/A    SERIALIZE_SCALAR(transmitTick);
2282854SN/A
2283854SN/A    /*
2284915SN/A     * receive address filter settings
2285915SN/A     */
2286915SN/A    SERIALIZE_SCALAR(rxFilterEnable);
2287915SN/A    SERIALIZE_SCALAR(acceptBroadcast);
2288915SN/A    SERIALIZE_SCALAR(acceptMulticast);
2289915SN/A    SERIALIZE_SCALAR(acceptUnicast);
2290915SN/A    SERIALIZE_SCALAR(acceptPerfect);
2291915SN/A    SERIALIZE_SCALAR(acceptArp);
22921843SN/A    SERIALIZE_SCALAR(multicastHashEnable);
2293915SN/A
2294915SN/A    /*
2295854SN/A     * Keep track of pending interrupt status.
2296854SN/A     */
2297854SN/A    SERIALIZE_SCALAR(intrTick);
2298854SN/A    SERIALIZE_SCALAR(cpuPendingIntr);
2299854SN/A    Tick intrEventTick = 0;
2300854SN/A    if (intrEvent)
2301854SN/A        intrEventTick = intrEvent->when();
2302854SN/A    SERIALIZE_SCALAR(intrEventTick);
2303854SN/A
2304837SN/A}
2305837SN/A
2306837SN/Avoid
230710905SN/ANSGigE::unserialize(CheckpointIn &cp)
2308837SN/A{
23099807SN/A    // Unserialize the PciDevice base class
231010905SN/A    PciDevice::unserialize(cp);
2311897SN/A
2312854SN/A    UNSERIALIZE_SCALAR(regs.command);
2313854SN/A    UNSERIALIZE_SCALAR(regs.config);
2314854SN/A    UNSERIALIZE_SCALAR(regs.mear);
2315854SN/A    UNSERIALIZE_SCALAR(regs.ptscr);
2316854SN/A    UNSERIALIZE_SCALAR(regs.isr);
2317854SN/A    UNSERIALIZE_SCALAR(regs.imr);
2318854SN/A    UNSERIALIZE_SCALAR(regs.ier);
2319854SN/A    UNSERIALIZE_SCALAR(regs.ihr);
2320854SN/A    UNSERIALIZE_SCALAR(regs.txdp);
2321854SN/A    UNSERIALIZE_SCALAR(regs.txdp_hi);
2322854SN/A    UNSERIALIZE_SCALAR(regs.txcfg);
2323854SN/A    UNSERIALIZE_SCALAR(regs.gpior);
2324854SN/A    UNSERIALIZE_SCALAR(regs.rxdp);
2325854SN/A    UNSERIALIZE_SCALAR(regs.rxdp_hi);
2326854SN/A    UNSERIALIZE_SCALAR(regs.rxcfg);
2327854SN/A    UNSERIALIZE_SCALAR(regs.pqcr);
2328854SN/A    UNSERIALIZE_SCALAR(regs.wcsr);
2329854SN/A    UNSERIALIZE_SCALAR(regs.pcr);
2330854SN/A    UNSERIALIZE_SCALAR(regs.rfcr);
2331854SN/A    UNSERIALIZE_SCALAR(regs.rfdr);
23321843SN/A    UNSERIALIZE_SCALAR(regs.brar);
23331843SN/A    UNSERIALIZE_SCALAR(regs.brdr);
2334854SN/A    UNSERIALIZE_SCALAR(regs.srr);
2335854SN/A    UNSERIALIZE_SCALAR(regs.mibc);
2336854SN/A    UNSERIALIZE_SCALAR(regs.vrcr);
2337854SN/A    UNSERIALIZE_SCALAR(regs.vtcr);
2338854SN/A    UNSERIALIZE_SCALAR(regs.vdr);
2339854SN/A    UNSERIALIZE_SCALAR(regs.ccsr);
2340854SN/A    UNSERIALIZE_SCALAR(regs.tbicr);
2341854SN/A    UNSERIALIZE_SCALAR(regs.tbisr);
2342854SN/A    UNSERIALIZE_SCALAR(regs.tanar);
2343854SN/A    UNSERIALIZE_SCALAR(regs.tanlpar);
2344854SN/A    UNSERIALIZE_SCALAR(regs.taner);
2345854SN/A    UNSERIALIZE_SCALAR(regs.tesr);
2346837SN/A
23471114SN/A    UNSERIALIZE_ARRAY(rom.perfectMatch, ETH_ADDR_LEN);
23481843SN/A    UNSERIALIZE_ARRAY(rom.filterHash, FHASH_SIZE);
2349837SN/A
2350927SN/A    UNSERIALIZE_SCALAR(ioEnable);
2351917SN/A
2352854SN/A    /*
2353915SN/A     * unserialize the data fifos
2354915SN/A     */
235510905SN/A    rxFifo.unserialize("rxFifo", cp);
235610905SN/A    txFifo.unserialize("txFifo", cp);
2357915SN/A
2358915SN/A    /*
2359854SN/A     * unserialize the various helper variables
2360854SN/A     */
2361915SN/A    bool txPacketExists;
2362915SN/A    UNSERIALIZE_SCALAR(txPacketExists);
2363915SN/A    if (txPacketExists) {
236411719Smichael.lebeane@amd.com        txPacket = make_shared<EthPacketData>(16384);
236510905SN/A        txPacket->unserialize("txPacket", cp);
2366915SN/A        uint32_t txPktBufPtr;
2367915SN/A        UNSERIALIZE_SCALAR(txPktBufPtr);
2368915SN/A        txPacketBufPtr = (uint8_t *) txPacket->data + txPktBufPtr;
2369915SN/A    } else
2370915SN/A        txPacket = 0;
2371915SN/A
2372915SN/A    bool rxPacketExists;
2373915SN/A    UNSERIALIZE_SCALAR(rxPacketExists);
2374915SN/A    rxPacket = 0;
2375915SN/A    if (rxPacketExists) {
237611701Smichael.lebeane@amd.com        rxPacket = make_shared<EthPacketData>();
237710905SN/A        rxPacket->unserialize("rxPacket", cp);
2378915SN/A        uint32_t rxPktBufPtr;
2379915SN/A        UNSERIALIZE_SCALAR(rxPktBufPtr);
2380915SN/A        rxPacketBufPtr = (uint8_t *) rxPacket->data + rxPktBufPtr;
2381915SN/A    } else
2382915SN/A        rxPacket = 0;
2383915SN/A
2384854SN/A    UNSERIALIZE_SCALAR(txXferLen);
2385854SN/A    UNSERIALIZE_SCALAR(rxXferLen);
2386837SN/A
2387854SN/A    /*
23881909SN/A     * Unserialize Cached Descriptors
2389854SN/A     */
23901909SN/A    UNSERIALIZE_SCALAR(rxDesc64.link);
23911909SN/A    UNSERIALIZE_SCALAR(rxDesc64.bufptr);
23921909SN/A    UNSERIALIZE_SCALAR(rxDesc64.cmdsts);
23931909SN/A    UNSERIALIZE_SCALAR(rxDesc64.extsts);
23941909SN/A    UNSERIALIZE_SCALAR(txDesc64.link);
23951909SN/A    UNSERIALIZE_SCALAR(txDesc64.bufptr);
23961909SN/A    UNSERIALIZE_SCALAR(txDesc64.cmdsts);
23971909SN/A    UNSERIALIZE_SCALAR(txDesc64.extsts);
23981909SN/A    UNSERIALIZE_SCALAR(rxDesc32.link);
23991909SN/A    UNSERIALIZE_SCALAR(rxDesc32.bufptr);
24001909SN/A    UNSERIALIZE_SCALAR(rxDesc32.cmdsts);
24011909SN/A    UNSERIALIZE_SCALAR(rxDesc32.extsts);
24021909SN/A    UNSERIALIZE_SCALAR(txDesc32.link);
24031909SN/A    UNSERIALIZE_SCALAR(txDesc32.bufptr);
24041909SN/A    UNSERIALIZE_SCALAR(txDesc32.cmdsts);
24051909SN/A    UNSERIALIZE_SCALAR(txDesc32.extsts);
24061801SN/A    UNSERIALIZE_SCALAR(extstsEnable);
2407854SN/A
2408854SN/A    /*
2409854SN/A     * unserialize tx state machine
2410854SN/A     */
2411854SN/A    int txState;
2412854SN/A    UNSERIALIZE_SCALAR(txState);
2413854SN/A    this->txState = (TxState) txState;
24141035SN/A    UNSERIALIZE_SCALAR(txEnable);
2415854SN/A    UNSERIALIZE_SCALAR(CTDD);
2416854SN/A    UNSERIALIZE_SCALAR(txFragPtr);
2417854SN/A    UNSERIALIZE_SCALAR(txDescCnt);
2418854SN/A    int txDmaState;
2419854SN/A    UNSERIALIZE_SCALAR(txDmaState);
2420854SN/A    this->txDmaState = (DmaState) txDmaState;
24211801SN/A    UNSERIALIZE_SCALAR(txKickTick);
24221801SN/A    if (txKickTick)
24235606SN/A        schedule(txKickEvent, txKickTick);
2424854SN/A
2425854SN/A    /*
2426854SN/A     * unserialize rx state machine
2427854SN/A     */
2428854SN/A    int rxState;
2429854SN/A    UNSERIALIZE_SCALAR(rxState);
2430854SN/A    this->rxState = (RxState) rxState;
24311035SN/A    UNSERIALIZE_SCALAR(rxEnable);
2432854SN/A    UNSERIALIZE_SCALAR(CRDD);
2433854SN/A    UNSERIALIZE_SCALAR(rxPktBytes);
24341224SN/A    UNSERIALIZE_SCALAR(rxFragPtr);
2435854SN/A    UNSERIALIZE_SCALAR(rxDescCnt);
2436854SN/A    int rxDmaState;
2437854SN/A    UNSERIALIZE_SCALAR(rxDmaState);
2438854SN/A    this->rxDmaState = (DmaState) rxDmaState;
24391801SN/A    UNSERIALIZE_SCALAR(rxKickTick);
24401801SN/A    if (rxKickTick)
24415606SN/A        schedule(rxKickEvent, rxKickTick);
2442854SN/A
24431843SN/A    /*
24441843SN/A     * Unserialize EEPROM state machine
24451843SN/A     */
24461843SN/A    int eepromState;
24471843SN/A    UNSERIALIZE_SCALAR(eepromState);
24481843SN/A    this->eepromState = (EEPROMState) eepromState;
24491843SN/A    UNSERIALIZE_SCALAR(eepromClk);
24501843SN/A    UNSERIALIZE_SCALAR(eepromBitsToRx);
24511843SN/A    UNSERIALIZE_SCALAR(eepromOpcode);
24521843SN/A    UNSERIALIZE_SCALAR(eepromAddress);
24531843SN/A    UNSERIALIZE_SCALAR(eepromData);
24541843SN/A
24551843SN/A    /*
2456915SN/A     * If there's a pending transmit, reschedule it now
2457854SN/A     */
2458854SN/A    Tick transmitTick;
2459854SN/A    UNSERIALIZE_SCALAR(transmitTick);
2460854SN/A    if (transmitTick)
24617823SN/A        schedule(txEvent, curTick() + transmitTick);
2462854SN/A
2463854SN/A    /*
2464915SN/A     * unserialize receive address filter settings
2465915SN/A     */
2466915SN/A    UNSERIALIZE_SCALAR(rxFilterEnable);
2467915SN/A    UNSERIALIZE_SCALAR(acceptBroadcast);
2468915SN/A    UNSERIALIZE_SCALAR(acceptMulticast);
2469915SN/A    UNSERIALIZE_SCALAR(acceptUnicast);
2470915SN/A    UNSERIALIZE_SCALAR(acceptPerfect);
2471915SN/A    UNSERIALIZE_SCALAR(acceptArp);
24721843SN/A    UNSERIALIZE_SCALAR(multicastHashEnable);
2473915SN/A
2474915SN/A    /*
2475854SN/A     * Keep track of pending interrupt status.
2476854SN/A     */
2477854SN/A    UNSERIALIZE_SCALAR(intrTick);
2478854SN/A    UNSERIALIZE_SCALAR(cpuPendingIntr);
2479854SN/A    Tick intrEventTick;
2480854SN/A    UNSERIALIZE_SCALAR(intrEventTick);
2481854SN/A    if (intrEventTick) {
248212087Sspwilson2@wisc.edu        intrEvent = new EventFunctionWrapper([this]{ cpuInterrupt(); },
248312087Sspwilson2@wisc.edu                                             name(), true);
24845606SN/A        schedule(intrEvent, intrEventTick);
2485854SN/A    }
2486854SN/A}
2487927SN/A
24884762SN/ANSGigE *
24894762SN/ANSGigEParams::create()
2490837SN/A{
24914762SN/A    return new NSGigE(this);
2492837SN/A}
2493