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