ns_gige.cc revision 6216
16657Snate@binkert.org/* 26657Snate@binkert.org * Copyright (c) 2004-2005 The Regents of The University of Michigan 310972Sdavid.hashe@amd.com * 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 * 286657Snate@binkert.org * Authors: Nathan Binkert 2913672Sandreas.sandberg@arm.com * Lisa Hsu 306657Snate@binkert.org */ 316657Snate@binkert.org 326657Snate@binkert.org/** @file 336657Snate@binkert.org * Device module for modelling the National Semiconductor 348189SLisa.Hsu@amd.com * DP83820 ethernet controller. Does not support priority queueing 356657Snate@binkert.org */ 369499Snilay@cs.wisc.edu#include <deque> 379499Snilay@cs.wisc.edu#include <string> 3811308Santhony.gutierrez@amd.com 399364Snilay@cs.wisc.edu#include "base/debug.hh" 407055Snate@binkert.org#include "base/inet.hh" 416882SBrad.Beckmann@amd.com#include "base/types.hh" 426882SBrad.Beckmann@amd.com#include "cpu/thread_context.hh" 438191SLisa.Hsu@amd.com#include "dev/etherlink.hh" 446882SBrad.Beckmann@amd.com#include "dev/ns_gige.hh" 4511308Santhony.gutierrez@amd.com#include "dev/pciconfigall.hh" 4611308Santhony.gutierrez@amd.com#include "mem/packet.hh" 476882SBrad.Beckmann@amd.com#include "mem/packet_access.hh" 4811308Santhony.gutierrez@amd.com#include "params/NSGigE.hh" 499102SNuwan.Jayasena@amd.com#include "sim/system.hh" 5011084Snilay@cs.wisc.edu 519366Snilay@cs.wisc.educonst char *NsRxStateStrings[] = 529499Snilay@cs.wisc.edu{ 539499Snilay@cs.wisc.edu "rxIdle", 549499Snilay@cs.wisc.edu "rxDescRefr", 556882SBrad.Beckmann@amd.com "rxDescRead", 566657Snate@binkert.org "rxFifoBlock", 576657Snate@binkert.org "rxFragWrite", 586657Snate@binkert.org "rxDescWrite", 596657Snate@binkert.org "rxAdvance" 6010311Snilay@cs.wisc.edu}; 6110311Snilay@cs.wisc.edu 6210311Snilay@cs.wisc.educonst char *NsTxStateStrings[] = 6310311Snilay@cs.wisc.edu{ 646657Snate@binkert.org "txIdle", 6510311Snilay@cs.wisc.edu "txDescRefr", 669366Snilay@cs.wisc.edu "txDescRead", 677839Snilay@cs.wisc.edu "txFifoBlock", 686657Snate@binkert.org "txFragRead", 696882SBrad.Beckmann@amd.com "txDescWrite", 7010308Snilay@cs.wisc.edu "txAdvance" 7110308Snilay@cs.wisc.edu}; 726882SBrad.Beckmann@amd.com 7310308Snilay@cs.wisc.educonst char *NsDmaState[] = 7410308Snilay@cs.wisc.edu{ 7510308Snilay@cs.wisc.edu "dmaIdle", 7610308Snilay@cs.wisc.edu "dmaReading", 7710308Snilay@cs.wisc.edu "dmaWriting", 789366Snilay@cs.wisc.edu "dmaReadWaiting", 799366Snilay@cs.wisc.edu "dmaWriteWaiting" 806657Snate@binkert.org}; 8113672Sandreas.sandberg@arm.com 8213672Sandreas.sandberg@arm.comusing namespace std; 8313672Sandreas.sandberg@arm.comusing namespace Net; 8413672Sandreas.sandberg@arm.comusing namespace TheISA; 856657Snate@binkert.org 866657Snate@binkert.org/////////////////////////////////////////////////////////////////////// 876657Snate@binkert.org// 8810311Snilay@cs.wisc.edu// NSGigE PCI Device 8910311Snilay@cs.wisc.edu// 9010311Snilay@cs.wisc.eduNSGigE::NSGigE(Params *p) 9110311Snilay@cs.wisc.edu : EtherDevice(p), ioEnable(false), 926657Snate@binkert.org txFifo(p->tx_fifo_size), rxFifo(p->rx_fifo_size), 937839Snilay@cs.wisc.edu txPacket(0), rxPacket(0), txPacketBufPtr(NULL), rxPacketBufPtr(NULL), 947839Snilay@cs.wisc.edu txXferLen(0), rxXferLen(0), rxDmaFree(false), txDmaFree(false), 9510972Sdavid.hashe@amd.com clock(p->clock), 9610972Sdavid.hashe@amd.com txState(txIdle), txEnable(false), CTDD(false), txHalt(false), 9710972Sdavid.hashe@amd.com txFragPtr(0), txDescCnt(0), txDmaState(dmaIdle), rxState(rxIdle), 986657Snate@binkert.org rxEnable(false), CRDD(false), rxPktBytes(0), rxHalt(false), 996657Snate@binkert.org rxFragPtr(0), rxDescCnt(0), rxDmaState(dmaIdle), extstsEnable(false), 1006657Snate@binkert.org eepromState(eepromStart), eepromClk(false), eepromBitsToRx(0), 1016657Snate@binkert.org eepromOpcode(0), eepromAddress(0), eepromData(0), 1026657Snate@binkert.org dmaReadDelay(p->dma_read_delay), dmaWriteDelay(p->dma_write_delay), 1036657Snate@binkert.org dmaReadFactor(p->dma_read_factor), dmaWriteFactor(p->dma_write_factor), 1046657Snate@binkert.org rxDmaData(NULL), rxDmaAddr(0), rxDmaLen(0), 1056657Snate@binkert.org txDmaData(NULL), txDmaAddr(0), txDmaLen(0), 1066657Snate@binkert.org rxDmaReadEvent(this), rxDmaWriteEvent(this), 1076657Snate@binkert.org txDmaReadEvent(this), txDmaWriteEvent(this), 1086657Snate@binkert.org dmaDescFree(p->dma_desc_free), dmaDataFree(p->dma_data_free), 1096657Snate@binkert.org txDelay(p->tx_delay), rxDelay(p->rx_delay), 1106657Snate@binkert.org rxKickTick(0), rxKickEvent(this), txKickTick(0), txKickEvent(this), 1116657Snate@binkert.org txEvent(this), rxFilterEnable(p->rx_filter), 1126657Snate@binkert.org acceptBroadcast(false), acceptMulticast(false), acceptUnicast(false), 1136657Snate@binkert.org acceptPerfect(false), acceptArp(false), multicastHashEnable(false), 1146657Snate@binkert.org intrDelay(p->intr_delay), intrTick(0), cpuPendingIntr(false), 1156657Snate@binkert.org intrEvent(0), interface(0) 1166779SBrad.Beckmann@amd.com{ 1176657Snate@binkert.org 1186657Snate@binkert.org 1196657Snate@binkert.org interface = new NSGigEInt(name() + ".int0", this); 1206657Snate@binkert.org 1216657Snate@binkert.org regsReset(); 1226657Snate@binkert.org memcpy(&rom.perfectMatch, p->hardware_address.bytes(), ETH_ADDR_LEN); 1236657Snate@binkert.org 1246657Snate@binkert.org memset(&rxDesc32, 0, sizeof(rxDesc32)); 1256657Snate@binkert.org memset(&txDesc32, 0, sizeof(txDesc32)); 12610972Sdavid.hashe@amd.com memset(&rxDesc64, 0, sizeof(rxDesc64)); 12710972Sdavid.hashe@amd.com memset(&txDesc64, 0, sizeof(txDesc64)); 12810972Sdavid.hashe@amd.com} 1299104Shestness@cs.utexas.edu 1309104Shestness@cs.utexas.eduNSGigE::~NSGigE() 1319104Shestness@cs.utexas.edu{} 1329104Shestness@cs.utexas.edu 1336657Snate@binkert.org/** 1346657Snate@binkert.org * This is to write to the PCI general configuration registers 1356657Snate@binkert.org */ 1366657Snate@binkert.orgTick 1376657Snate@binkert.orgNSGigE::writeConfig(PacketPtr pkt) 1386657Snate@binkert.org{ 1396657Snate@binkert.org int offset = pkt->getAddr() & PCI_CONFIG_SIZE; 1406657Snate@binkert.org if (offset < PCI_DEVICE_SPECIFIC) 1416657Snate@binkert.org PciDev::writeConfig(pkt); 1426657Snate@binkert.org else 1436657Snate@binkert.org panic("Device specific PCI config space not implemented!\n"); 1446657Snate@binkert.org 1456657Snate@binkert.org switch (offset) { 14610307Snilay@cs.wisc.edu // seems to work fine without all these PCI settings, but i 1476657Snate@binkert.org // put in the IO to double check, an assertion will fail if we 1486657Snate@binkert.org // need to properly implement it 1497839Snilay@cs.wisc.edu case PCI_COMMAND: 1507839Snilay@cs.wisc.edu if (config.data[offset] & PCI_CMD_IOSE) 1517839Snilay@cs.wisc.edu ioEnable = true; 1527839Snilay@cs.wisc.edu else 1537839Snilay@cs.wisc.edu ioEnable = false; 1547839Snilay@cs.wisc.edu break; 1557839Snilay@cs.wisc.edu } 1567839Snilay@cs.wisc.edu 1577839Snilay@cs.wisc.edu return configDelay; 1587839Snilay@cs.wisc.edu} 15910968Sdavid.hashe@amd.com 16010968Sdavid.hashe@amd.comEtherInt* 16110968Sdavid.hashe@amd.comNSGigE::getEthPort(const std::string &if_name, int idx) 16210968Sdavid.hashe@amd.com{ 16310968Sdavid.hashe@amd.com if (if_name == "interface") { 16410968Sdavid.hashe@amd.com if (interface->getPeer()) 16510968Sdavid.hashe@amd.com panic("interface already connected to\n"); 1667839Snilay@cs.wisc.edu return interface; 1676657Snate@binkert.org } 1686657Snate@binkert.org return NULL; 1696657Snate@binkert.org} 1706657Snate@binkert.org 1716657Snate@binkert.org/** 1726657Snate@binkert.org * This reads the device registers, which are detailed in the NS83820 1736657Snate@binkert.org * spec sheet 1746657Snate@binkert.org */ 1756657Snate@binkert.orgTick 1766657Snate@binkert.orgNSGigE::read(PacketPtr pkt) 1776657Snate@binkert.org{ 1786657Snate@binkert.org assert(ioEnable); 1796657Snate@binkert.org 1806657Snate@binkert.org pkt->allocate(); 1816657Snate@binkert.org 1826657Snate@binkert.org //The mask is to give you only the offset into the device register file 1836657Snate@binkert.org Addr daddr = pkt->getAddr() & 0xfff; 1846657Snate@binkert.org DPRINTF(EthernetPIO, "read da=%#x pa=%#x size=%d\n", 1856657Snate@binkert.org daddr, pkt->getAddr(), pkt->getSize()); 1866657Snate@binkert.org 1876657Snate@binkert.org 1886657Snate@binkert.org // there are some reserved registers, you can see ns_gige_reg.h and 1896657Snate@binkert.org // the spec sheet for details 1906657Snate@binkert.org if (daddr > LAST && daddr <= RESERVED) { 1916657Snate@binkert.org panic("Accessing reserved register"); 1926657Snate@binkert.org } else if (daddr > RESERVED && daddr <= 0x3FC) { 1936657Snate@binkert.org return readConfig(pkt); 1946657Snate@binkert.org } else if (daddr >= MIB_START && daddr <= MIB_END) { 1956657Snate@binkert.org // don't implement all the MIB's. hopefully the kernel 1966657Snate@binkert.org // doesn't actually DEPEND upon their values 19710963Sdavid.hashe@amd.com // MIB are just hardware stats keepers 19810963Sdavid.hashe@amd.com pkt->set<uint32_t>(0); 19910963Sdavid.hashe@amd.com pkt->makeAtomicResponse(); 20010963Sdavid.hashe@amd.com return pioDelay; 20110963Sdavid.hashe@amd.com } else if (daddr > 0x3FC) 20210963Sdavid.hashe@amd.com panic("Something is messed up!\n"); 20311095Snilay@cs.wisc.edu 20410963Sdavid.hashe@amd.com assert(pkt->getSize() == sizeof(uint32_t)); 20510963Sdavid.hashe@amd.com uint32_t ® = *pkt->getPtr<uint32_t>(); 20610963Sdavid.hashe@amd.com uint16_t rfaddr; 20710963Sdavid.hashe@amd.com 20810963Sdavid.hashe@amd.com switch (daddr) { 20910963Sdavid.hashe@amd.com case CR: 21010963Sdavid.hashe@amd.com reg = regs.command; 21110963Sdavid.hashe@amd.com //these are supposed to be cleared on a read 2129219Spower.jg@gmail.com reg &= ~(CR_RXD | CR_TXD | CR_TXR | CR_RXR); 2136877Ssteve.reinhardt@amd.com break; 2146657Snate@binkert.org 2159219Spower.jg@gmail.com case CFGR: 2166657Snate@binkert.org reg = regs.config; 2179219Spower.jg@gmail.com break; 2186657Snate@binkert.org 2196877Ssteve.reinhardt@amd.com case MEAR: 2206999Snate@binkert.org reg = regs.mear; 2216877Ssteve.reinhardt@amd.com break; 22210308Snilay@cs.wisc.edu 2236877Ssteve.reinhardt@amd.com case PTSCR: 2246877Ssteve.reinhardt@amd.com reg = regs.ptscr; 22510308Snilay@cs.wisc.edu break; 2266877Ssteve.reinhardt@amd.com 2276877Ssteve.reinhardt@amd.com case ISR: 2286877Ssteve.reinhardt@amd.com reg = regs.isr; 22913665Sandreas.sandberg@arm.com devIntrClear(ISR_ALL); 2306877Ssteve.reinhardt@amd.com break; 2316877Ssteve.reinhardt@amd.com 2326877Ssteve.reinhardt@amd.com case IMR: 2339338SAndreas.Sandberg@arm.com reg = regs.imr; 2346877Ssteve.reinhardt@amd.com break; 2356877Ssteve.reinhardt@amd.com 2366877Ssteve.reinhardt@amd.com case IER: 2376877Ssteve.reinhardt@amd.com reg = regs.ier; 23810308Snilay@cs.wisc.edu break; 23910308Snilay@cs.wisc.edu 24010308Snilay@cs.wisc.edu case IHR: 24110308Snilay@cs.wisc.edu reg = regs.ihr; 24213675Sandreas.sandberg@arm.com break; 2436882SBrad.Beckmann@amd.com 24410308Snilay@cs.wisc.edu case TXDP: 24510308Snilay@cs.wisc.edu reg = regs.txdp; 2466882SBrad.Beckmann@amd.com break; 2476882SBrad.Beckmann@amd.com 2486882SBrad.Beckmann@amd.com case TXDP_HI: 2496882SBrad.Beckmann@amd.com reg = regs.txdp_hi; 25011021Sjthestness@gmail.com break; 2516877Ssteve.reinhardt@amd.com 2526877Ssteve.reinhardt@amd.com case TX_CFG: 25310917Sbrandon.potter@amd.com reg = regs.txcfg; 2546877Ssteve.reinhardt@amd.com break; 2556657Snate@binkert.org 2566657Snate@binkert.org case GPIOR: 2576999Snate@binkert.org reg = regs.gpior; 2586657Snate@binkert.org break; 2596657Snate@binkert.org 2606657Snate@binkert.org case RXDP: 2616657Snate@binkert.org reg = regs.rxdp; 2627007Snate@binkert.org break; 2636657Snate@binkert.org 2646657Snate@binkert.org case RXDP_HI: 2656657Snate@binkert.org reg = regs.rxdp_hi; 2666657Snate@binkert.org break; 2676657Snate@binkert.org 2687007Snate@binkert.org case RX_CFG: 2697007Snate@binkert.org reg = regs.rxcfg; 2706657Snate@binkert.org break; 2717002Snate@binkert.org 2727002Snate@binkert.org case PQCR: 2737002Snate@binkert.org reg = regs.pqcr; 2747002Snate@binkert.org break; 2756657Snate@binkert.org 2766657Snate@binkert.org case WCSR: 2778229Snate@binkert.org reg = regs.wcsr; 2788229Snate@binkert.org break; 2798229Snate@binkert.org 28010972Sdavid.hashe@amd.com case PCR: 2816657Snate@binkert.org reg = regs.pcr; 2826657Snate@binkert.org break; 2836657Snate@binkert.org 2846657Snate@binkert.org // see the spec sheet for how RFCR and RFDR work 2856793SBrad.Beckmann@amd.com // basically, you write to RFCR to tell the machine 2866657Snate@binkert.org // what you want to do next, then you act upon RFDR, 28710311Snilay@cs.wisc.edu // and the device will be prepared b/c of what you 2886657Snate@binkert.org // wrote to RFCR 2896657Snate@binkert.org case RFCR: 2906657Snate@binkert.org reg = regs.rfcr; 2917002Snate@binkert.org break; 2926657Snate@binkert.org 2937007Snate@binkert.org case RFDR: 2947007Snate@binkert.org rfaddr = (uint16_t)(regs.rfcr & RFCR_RFADDR); 2959271Snilay@cs.wisc.edu switch (rfaddr) { 2966877Ssteve.reinhardt@amd.com // Read from perfect match ROM octets 2976877Ssteve.reinhardt@amd.com case 0x000: 2986657Snate@binkert.org reg = rom.perfectMatch[1]; 2996877Ssteve.reinhardt@amd.com reg = reg << 8; 30010311Snilay@cs.wisc.edu reg += rom.perfectMatch[0]; 30111084Snilay@cs.wisc.edu break; 30211084Snilay@cs.wisc.edu case 0x002: 30311021Sjthestness@gmail.com reg = rom.perfectMatch[3] << 8; 3049745Snilay@cs.wisc.edu reg += rom.perfectMatch[2]; 3057002Snate@binkert.org break; 3066657Snate@binkert.org case 0x004: 30710012Snilay@cs.wisc.edu reg = rom.perfectMatch[5] << 8; 3089745Snilay@cs.wisc.edu reg += rom.perfectMatch[4]; 3099745Snilay@cs.wisc.edu break; 3109745Snilay@cs.wisc.edu default: 3118683Snilay@cs.wisc.edu // Read filter hash table 31211308Santhony.gutierrez@amd.com if (rfaddr >= FHASH_ADDR && 31311309Sdavid.hashe@amd.com rfaddr < FHASH_ADDR + FHASH_SIZE) { 3147007Snate@binkert.org 31510524Snilay@cs.wisc.edu // Only word-aligned reads supported 3169302Snilay@cs.wisc.edu if (rfaddr % 2) 3179745Snilay@cs.wisc.edu panic("unaligned read from filter hash table!"); 3189745Snilay@cs.wisc.edu 31911061Snilay@cs.wisc.edu reg = rom.filterHash[rfaddr - FHASH_ADDR + 1] << 8; 3209745Snilay@cs.wisc.edu reg += rom.filterHash[rfaddr - FHASH_ADDR]; 32111061Snilay@cs.wisc.edu break; 3229745Snilay@cs.wisc.edu } 3236657Snate@binkert.org 3246657Snate@binkert.org panic("reading RFDR for something other than pattern" 3256657Snate@binkert.org " matching or hashing! %#x\n", rfaddr); 3266657Snate@binkert.org } 3276657Snate@binkert.org break; 3286657Snate@binkert.org 3296882SBrad.Beckmann@amd.com case SRR: 3306882SBrad.Beckmann@amd.com reg = regs.srr; 3316882SBrad.Beckmann@amd.com break; 3326882SBrad.Beckmann@amd.com 3336657Snate@binkert.org case MIBC: 3346657Snate@binkert.org reg = regs.mibc; 3357007Snate@binkert.org reg &= ~(MIBC_MIBS | MIBC_ACLR); 3367839Snilay@cs.wisc.edu break; 3377839Snilay@cs.wisc.edu 3387839Snilay@cs.wisc.edu case VRCR: 3397839Snilay@cs.wisc.edu reg = regs.vrcr; 3407839Snilay@cs.wisc.edu break; 3417839Snilay@cs.wisc.edu 3427839Snilay@cs.wisc.edu case VTCR: 3437839Snilay@cs.wisc.edu reg = regs.vtcr; 3447839Snilay@cs.wisc.edu break; 3457839Snilay@cs.wisc.edu 3467839Snilay@cs.wisc.edu case VDR: 3477839Snilay@cs.wisc.edu reg = regs.vdr; 34811025Snilay@cs.wisc.edu break; 3497007Snate@binkert.org 3507007Snate@binkert.org case CCSR: 3517007Snate@binkert.org reg = regs.ccsr; 3527007Snate@binkert.org break; 3537839Snilay@cs.wisc.edu 3547839Snilay@cs.wisc.edu case TBICR: 3557839Snilay@cs.wisc.edu reg = regs.tbicr; 3567839Snilay@cs.wisc.edu break; 3577839Snilay@cs.wisc.edu 3587839Snilay@cs.wisc.edu case TBISR: 3597839Snilay@cs.wisc.edu reg = regs.tbisr; 3607839Snilay@cs.wisc.edu break; 3617839Snilay@cs.wisc.edu 3627839Snilay@cs.wisc.edu case TANAR: 3637839Snilay@cs.wisc.edu reg = regs.tanar; 3647839Snilay@cs.wisc.edu break; 36511025Snilay@cs.wisc.edu 3667007Snate@binkert.org case TANLPAR: 3679745Snilay@cs.wisc.edu reg = regs.tanlpar; 3689745Snilay@cs.wisc.edu break; 3699745Snilay@cs.wisc.edu 3709745Snilay@cs.wisc.edu case TANER: 3719745Snilay@cs.wisc.edu reg = regs.taner; 3729745Snilay@cs.wisc.edu break; 3736657Snate@binkert.org 3747007Snate@binkert.org case TESR: 3756657Snate@binkert.org reg = regs.tesr; 3766657Snate@binkert.org break; 3776657Snate@binkert.org 3786657Snate@binkert.org case M5REG: 3796657Snate@binkert.org reg = 0; 3806657Snate@binkert.org if (params()->rx_thread) 3816657Snate@binkert.org reg |= M5REG_RX_THREAD; 3826657Snate@binkert.org if (params()->tx_thread) 3837839Snilay@cs.wisc.edu reg |= M5REG_TX_THREAD; 3847839Snilay@cs.wisc.edu if (params()->rss) 3857839Snilay@cs.wisc.edu reg |= M5REG_RSS; 3867839Snilay@cs.wisc.edu break; 3877839Snilay@cs.wisc.edu 3887839Snilay@cs.wisc.edu default: 3897839Snilay@cs.wisc.edu panic("reading unimplemented register: addr=%#x", daddr); 3907839Snilay@cs.wisc.edu } 3917839Snilay@cs.wisc.edu 3927839Snilay@cs.wisc.edu DPRINTF(EthernetPIO, "read from %#x: data=%d data=%#x\n", 3937839Snilay@cs.wisc.edu daddr, reg, reg); 3947839Snilay@cs.wisc.edu 3957839Snilay@cs.wisc.edu pkt->makeAtomicResponse(); 3967839Snilay@cs.wisc.edu return pioDelay; 3977839Snilay@cs.wisc.edu} 3987839Snilay@cs.wisc.edu 39910121Snilay@cs.wisc.eduTick 4006657Snate@binkert.orgNSGigE::write(PacketPtr pkt) 4016657Snate@binkert.org{ 4026657Snate@binkert.org assert(ioEnable); 4036657Snate@binkert.org 4047839Snilay@cs.wisc.edu Addr daddr = pkt->getAddr() & 0xfff; 4057839Snilay@cs.wisc.edu DPRINTF(EthernetPIO, "write da=%#x pa=%#x size=%d\n", 4067839Snilay@cs.wisc.edu daddr, pkt->getAddr(), pkt->getSize()); 40710121Snilay@cs.wisc.edu 40810121Snilay@cs.wisc.edu if (daddr > LAST && daddr <= RESERVED) { 40911025Snilay@cs.wisc.edu panic("Accessing reserved register"); 4107839Snilay@cs.wisc.edu } else if (daddr > RESERVED && daddr <= 0x3FC) { 4117839Snilay@cs.wisc.edu return writeConfig(pkt); 4127839Snilay@cs.wisc.edu } else if (daddr > 0x3FC) 41310121Snilay@cs.wisc.edu panic("Something is messed up!\n"); 41411025Snilay@cs.wisc.edu 4157839Snilay@cs.wisc.edu if (pkt->getSize() == sizeof(uint32_t)) { 4167839Snilay@cs.wisc.edu uint32_t reg = pkt->get<uint32_t>(); 4177839Snilay@cs.wisc.edu uint16_t rfaddr; 41810121Snilay@cs.wisc.edu 41911025Snilay@cs.wisc.edu DPRINTF(EthernetPIO, "write data=%d data=%#x\n", reg, reg); 4207839Snilay@cs.wisc.edu 4217839Snilay@cs.wisc.edu switch (daddr) { 4227839Snilay@cs.wisc.edu case CR: 42311025Snilay@cs.wisc.edu regs.command = reg; 4246657Snate@binkert.org if (reg & CR_TXD) { 4256657Snate@binkert.org txEnable = false; 4266657Snate@binkert.org } else if (reg & CR_TXE) { 4276657Snate@binkert.org txEnable = true; 4287007Snate@binkert.org 4296657Snate@binkert.org // the kernel is enabling the transmit machine 4306657Snate@binkert.org if (txState == txIdle) 4319273Snilay@cs.wisc.edu txKick(); 43210305Snilay@cs.wisc.edu } 4336657Snate@binkert.org 4346657Snate@binkert.org if (reg & CR_RXD) { 4356657Snate@binkert.org rxEnable = false; 4367007Snate@binkert.org } else if (reg & CR_RXE) { 4376657Snate@binkert.org rxEnable = true; 4386657Snate@binkert.org 4399219Spower.jg@gmail.com if (rxState == rxIdle) 4406657Snate@binkert.org rxKick(); 4416657Snate@binkert.org } 4426999Snate@binkert.org 4436657Snate@binkert.org if (reg & CR_TXR) 4446657Snate@binkert.org txReset(); 4456657Snate@binkert.org 4466657Snate@binkert.org if (reg & CR_RXR) 4477007Snate@binkert.org rxReset(); 4486657Snate@binkert.org 4496657Snate@binkert.org if (reg & CR_SWI) 4506657Snate@binkert.org devIntrPost(ISR_SWI); 4516657Snate@binkert.org 4526657Snate@binkert.org if (reg & CR_RST) { 4538946Sandreas.hansson@arm.com txReset(); 4548946Sandreas.hansson@arm.com rxReset(); 4558946Sandreas.hansson@arm.com 4567832Snate@binkert.org regsReset(); 4577002Snate@binkert.org } 4587002Snate@binkert.org break; 45910972Sdavid.hashe@amd.com 4607002Snate@binkert.org case CFGR: 4618641Snate@binkert.org if (reg & CFGR_LNKSTS || 46211704Santhony.gutierrez@amd.com reg & CFGR_SPDSTS || 4637056Snate@binkert.org reg & CFGR_DUPSTS || 46410972Sdavid.hashe@amd.com reg & CFGR_RESERVED || 46510972Sdavid.hashe@amd.com reg & CFGR_T64ADDR || 46610972Sdavid.hashe@amd.com reg & CFGR_PCI64_DET) 46710972Sdavid.hashe@amd.com 46810972Sdavid.hashe@amd.com // First clear all writable bits 4696657Snate@binkert.org regs.config &= CFGR_LNKSTS | CFGR_SPDSTS | CFGR_DUPSTS | 4708229Snate@binkert.org CFGR_RESERVED | CFGR_T64ADDR | 4716657Snate@binkert.org CFGR_PCI64_DET; 4726657Snate@binkert.org // Now set the appropriate writable bits 47311793Sbrandon.potter@amd.com regs.config |= reg & ~(CFGR_LNKSTS | CFGR_SPDSTS | CFGR_DUPSTS | 47411108Sdavid.hashe@amd.com CFGR_RESERVED | CFGR_T64ADDR | 47510972Sdavid.hashe@amd.com CFGR_PCI64_DET); 4769219Spower.jg@gmail.com 4779219Spower.jg@gmail.com// all these #if 0's are because i don't THINK the kernel needs to 4789219Spower.jg@gmail.com// have these implemented. if there is a problem relating to one of 4799219Spower.jg@gmail.com// these, you may need to add functionality in. 4809219Spower.jg@gmail.com if (reg & CFGR_TBI_EN) ; 4817002Snate@binkert.org if (reg & CFGR_MODE_1000) ; 4827002Snate@binkert.org 4836657Snate@binkert.org if (reg & CFGR_AUTO_1000) 4846657Snate@binkert.org panic("CFGR_AUTO_1000 not implemented!\n"); 4856657Snate@binkert.org 4866657Snate@binkert.org if (reg & CFGR_PINT_DUPSTS || 4876657Snate@binkert.org reg & CFGR_PINT_LNKSTS || 4886793SBrad.Beckmann@amd.com reg & CFGR_PINT_SPDSTS) 4896657Snate@binkert.org ; 4906657Snate@binkert.org 4916657Snate@binkert.org if (reg & CFGR_TMRTEST) ; 49210121Snilay@cs.wisc.edu if (reg & CFGR_MRM_DIS) ; 49310121Snilay@cs.wisc.edu if (reg & CFGR_MWI_DIS) ; 4946657Snate@binkert.org 4956877Ssteve.reinhardt@amd.com if (reg & CFGR_T64ADDR) ; 4966877Ssteve.reinhardt@amd.com // panic("CFGR_T64ADDR is read only register!\n"); 4976877Ssteve.reinhardt@amd.com 4986877Ssteve.reinhardt@amd.com if (reg & CFGR_PCI64_DET) 4996877Ssteve.reinhardt@amd.com panic("CFGR_PCI64_DET is read only register!\n"); 5006877Ssteve.reinhardt@amd.com 5016657Snate@binkert.org if (reg & CFGR_DATA64_EN) ; 5029745Snilay@cs.wisc.edu if (reg & CFGR_M64ADDR) ; 5039745Snilay@cs.wisc.edu if (reg & CFGR_PHY_RST) ; 5046657Snate@binkert.org if (reg & CFGR_PHY_DIS) ; 5057007Snate@binkert.org 5066657Snate@binkert.org if (reg & CFGR_EXTSTS_EN) 5079801Snilay@cs.wisc.edu extstsEnable = true; 5089801Snilay@cs.wisc.edu else 5096657Snate@binkert.org extstsEnable = false; 5109801Snilay@cs.wisc.edu 5119801Snilay@cs.wisc.edu if (reg & CFGR_REQALG) ; 5129801Snilay@cs.wisc.edu if (reg & CFGR_SB) ; 5137007Snate@binkert.org if (reg & CFGR_POW) ; 5146657Snate@binkert.org if (reg & CFGR_EXD) ; 5156877Ssteve.reinhardt@amd.com if (reg & CFGR_PESEL) ; 5166877Ssteve.reinhardt@amd.com if (reg & CFGR_BROM_DIS) ; 5176657Snate@binkert.org if (reg & CFGR_EXT_125) ; 51810078Snilay@cs.wisc.edu if (reg & CFGR_BEM) ; 51910078Snilay@cs.wisc.edu break; 52010121Snilay@cs.wisc.edu 52110121Snilay@cs.wisc.edu case MEAR: 52210121Snilay@cs.wisc.edu // Clear writable bits 5236657Snate@binkert.org regs.mear &= MEAR_EEDO; 5246657Snate@binkert.org // Set appropriate writable bits 5256882SBrad.Beckmann@amd.com regs.mear |= reg & ~MEAR_EEDO; 5266882SBrad.Beckmann@amd.com 5276882SBrad.Beckmann@amd.com // FreeBSD uses the EEPROM to read PMATCH (for the MAC address) 52810121Snilay@cs.wisc.edu // even though it could get it through RFDR 52910121Snilay@cs.wisc.edu if (reg & MEAR_EESEL) { 5306882SBrad.Beckmann@amd.com // Rising edge of clock 5316877Ssteve.reinhardt@amd.com if (reg & MEAR_EECLK && !eepromClk) 5326882SBrad.Beckmann@amd.com eepromKick(); 53310308Snilay@cs.wisc.edu } 5346882SBrad.Beckmann@amd.com else { 53510308Snilay@cs.wisc.edu eepromState = eepromStart; 53610311Snilay@cs.wisc.edu regs.mear &= ~MEAR_EEDI; 53711308Santhony.gutierrez@amd.com } 53811308Santhony.gutierrez@amd.com 53911308Santhony.gutierrez@amd.com eepromClk = reg & MEAR_EECLK; 54011308Santhony.gutierrez@amd.com 54111308Santhony.gutierrez@amd.com // since phy is completely faked, MEAR_MD* don't matter 54211308Santhony.gutierrez@amd.com if (reg & MEAR_MDIO) ; 54311308Santhony.gutierrez@amd.com if (reg & MEAR_MDDIR) ; 54411308Santhony.gutierrez@amd.com if (reg & MEAR_MDC) ; 54510917Sbrandon.potter@amd.com break; 5469595Snilay@cs.wisc.edu 5479745Snilay@cs.wisc.edu case PTSCR: 5489745Snilay@cs.wisc.edu regs.ptscr = reg & ~(PTSCR_RBIST_RDONLY); 5499745Snilay@cs.wisc.edu // these control BISTs for various parts of chip - we 5509745Snilay@cs.wisc.edu // don't care or do just fake that the BIST is done 5519745Snilay@cs.wisc.edu if (reg & PTSCR_RBIST_EN) 5529745Snilay@cs.wisc.edu regs.ptscr |= PTSCR_RBIST_DONE; 5539745Snilay@cs.wisc.edu if (reg & PTSCR_EEBIST_EN) 5549745Snilay@cs.wisc.edu regs.ptscr &= ~PTSCR_EEBIST_EN; 5559745Snilay@cs.wisc.edu if (reg & PTSCR_EELOAD_EN) 5569745Snilay@cs.wisc.edu regs.ptscr &= ~PTSCR_EELOAD_EN; 5579595Snilay@cs.wisc.edu break; 5586657Snate@binkert.org 5596657Snate@binkert.org case ISR: /* writing to the ISR has no effect */ 5606657Snate@binkert.org panic("ISR is a read only register!\n"); 5616657Snate@binkert.org 5627007Snate@binkert.org case IMR: 56311021Sjthestness@gmail.com regs.imr = reg; 56410311Snilay@cs.wisc.edu devIntrChangeMask(); 56510311Snilay@cs.wisc.edu break; 56610311Snilay@cs.wisc.edu 56710311Snilay@cs.wisc.edu case IER: 56810311Snilay@cs.wisc.edu regs.ier = reg; 56910311Snilay@cs.wisc.edu break; 57010311Snilay@cs.wisc.edu 57110311Snilay@cs.wisc.edu case IHR: 57210311Snilay@cs.wisc.edu regs.ihr = reg; 57310311Snilay@cs.wisc.edu /* not going to implement real interrupt holdoff */ 57410311Snilay@cs.wisc.edu break; 57510311Snilay@cs.wisc.edu 57610311Snilay@cs.wisc.edu case TXDP: 57711084Snilay@cs.wisc.edu regs.txdp = (reg & 0xFFFFFFFC); 57810311Snilay@cs.wisc.edu assert(txState == txIdle); 57910311Snilay@cs.wisc.edu CTDD = false; 58011021Sjthestness@gmail.com break; 58111021Sjthestness@gmail.com 58210311Snilay@cs.wisc.edu case TXDP_HI: 58310311Snilay@cs.wisc.edu regs.txdp_hi = reg; 58410311Snilay@cs.wisc.edu break; 58510311Snilay@cs.wisc.edu 58610311Snilay@cs.wisc.edu case TX_CFG: 58710311Snilay@cs.wisc.edu regs.txcfg = reg; 58810311Snilay@cs.wisc.edu#if 0 58910311Snilay@cs.wisc.edu if (reg & TX_CFG_CSI) ; 59010311Snilay@cs.wisc.edu if (reg & TX_CFG_HBI) ; 59110311Snilay@cs.wisc.edu if (reg & TX_CFG_MLB) ; 59210311Snilay@cs.wisc.edu if (reg & TX_CFG_ATP) ; 59311021Sjthestness@gmail.com if (reg & TX_CFG_ECRETRY) { 59411021Sjthestness@gmail.com /* 59510311Snilay@cs.wisc.edu * this could easily be implemented, but considering 59610311Snilay@cs.wisc.edu * the network is just a fake pipe, wouldn't make 59710311Snilay@cs.wisc.edu * sense to do this 59810311Snilay@cs.wisc.edu */ 59910311Snilay@cs.wisc.edu } 60010311Snilay@cs.wisc.edu 60110311Snilay@cs.wisc.edu if (reg & TX_CFG_BRST_DIS) ; 60210311Snilay@cs.wisc.edu#endif 60310311Snilay@cs.wisc.edu 60410311Snilay@cs.wisc.edu#if 0 6057007Snate@binkert.org /* we handle our own DMA, ignore the kernel's exhortations */ 6066657Snate@binkert.org if (reg & TX_CFG_MXDMA) ; 6077007Snate@binkert.org#endif 6086657Snate@binkert.org 6096657Snate@binkert.org // also, we currently don't care about fill/drain 6106657Snate@binkert.org // thresholds though this may change in the future with 61110311Snilay@cs.wisc.edu // more realistic networks or a driver which changes it 6126657Snate@binkert.org // according to feedback 6136657Snate@binkert.org 61410305Snilay@cs.wisc.edu break; 6156657Snate@binkert.org 6166657Snate@binkert.org case GPIOR: 6176657Snate@binkert.org // Only write writable bits 6186657Snate@binkert.org regs.gpior &= GPIOR_UNUSED | GPIOR_GP5_IN | GPIOR_GP4_IN 6196657Snate@binkert.org | GPIOR_GP3_IN | GPIOR_GP2_IN | GPIOR_GP1_IN; 6206657Snate@binkert.org regs.gpior |= reg & ~(GPIOR_UNUSED | GPIOR_GP5_IN | GPIOR_GP4_IN 6216657Snate@binkert.org | GPIOR_GP3_IN | GPIOR_GP2_IN | GPIOR_GP1_IN); 6226657Snate@binkert.org /* these just control general purpose i/o pins, don't matter */ 62311084Snilay@cs.wisc.edu break; 62411084Snilay@cs.wisc.edu 62511084Snilay@cs.wisc.edu case RXDP: 62611084Snilay@cs.wisc.edu regs.rxdp = reg; 62711084Snilay@cs.wisc.edu CRDD = false; 6286657Snate@binkert.org break; 62911084Snilay@cs.wisc.edu 6306657Snate@binkert.org case RXDP_HI: 6316657Snate@binkert.org regs.rxdp_hi = reg; 6326657Snate@binkert.org break; 6337007Snate@binkert.org 6346657Snate@binkert.org case RX_CFG: 6357007Snate@binkert.org regs.rxcfg = reg; 6367007Snate@binkert.org#if 0 6376657Snate@binkert.org if (reg & RX_CFG_AEP) ; 6389366Snilay@cs.wisc.edu if (reg & RX_CFG_ARP) ; 6399366Snilay@cs.wisc.edu if (reg & RX_CFG_STRIPCRC) ; 6409366Snilay@cs.wisc.edu if (reg & RX_CFG_RX_RD) ; 6419366Snilay@cs.wisc.edu if (reg & RX_CFG_ALP) ; 6427566SBrad.Beckmann@amd.com if (reg & RX_CFG_AIRL) ; 6437672Snate@binkert.org 6446657Snate@binkert.org /* we handle our own DMA, ignore what kernel says about it */ 6459465Snilay@cs.wisc.edu if (reg & RX_CFG_MXDMA) ; 6466657Snate@binkert.org 6476657Snate@binkert.org //also, we currently don't care about fill/drain thresholds 6486657Snate@binkert.org //though this may change in the future with more realistic 6497672Snate@binkert.org //networks or a driver which changes it according to feedback 6506657Snate@binkert.org if (reg & (RX_CFG_DRTH | RX_CFG_DRTH0)) ; 6516657Snate@binkert.org#endif 6526657Snate@binkert.org break; 6536657Snate@binkert.org 6546657Snate@binkert.org case PQCR: 6556657Snate@binkert.org /* there is no priority queueing used in the linux 2.6 driver */ 6566657Snate@binkert.org regs.pqcr = reg; 6576657Snate@binkert.org break; 6586657Snate@binkert.org 6596657Snate@binkert.org case WCSR: 6606657Snate@binkert.org /* not going to implement wake on LAN */ 6619745Snilay@cs.wisc.edu regs.wcsr = reg; 6626657Snate@binkert.org break; 6636657Snate@binkert.org 6649496Snilay@cs.wisc.edu case PCR: 6659496Snilay@cs.wisc.edu /* not going to implement pause control */ 66610012Snilay@cs.wisc.edu regs.pcr = reg; 6679496Snilay@cs.wisc.edu break; 6689496Snilay@cs.wisc.edu 6696657Snate@binkert.org case RFCR: 67010121Snilay@cs.wisc.edu regs.rfcr = reg; 6716657Snate@binkert.org 6726657Snate@binkert.org rxFilterEnable = (reg & RFCR_RFEN) ? true : false; 67310305Snilay@cs.wisc.edu acceptBroadcast = (reg & RFCR_AAB) ? true : false; 6746657Snate@binkert.org acceptMulticast = (reg & RFCR_AAM) ? true : false; 67511021Sjthestness@gmail.com acceptUnicast = (reg & RFCR_AAU) ? true : false; 67611021Sjthestness@gmail.com acceptPerfect = (reg & RFCR_APM) ? true : false; 67711021Sjthestness@gmail.com acceptArp = (reg & RFCR_AARP) ? true : false; 67811021Sjthestness@gmail.com multicastHashEnable = (reg & RFCR_MHEN) ? true : false; 67911021Sjthestness@gmail.com 6808683Snilay@cs.wisc.edu#if 0 6818683Snilay@cs.wisc.edu if (reg & RFCR_APAT) 68210308Snilay@cs.wisc.edu panic("RFCR_APAT not implemented!\n"); 6838683Snilay@cs.wisc.edu#endif 68410308Snilay@cs.wisc.edu if (reg & RFCR_UHEN) 6858683Snilay@cs.wisc.edu panic("Unicast hash filtering not used by drivers!\n"); 68611309Sdavid.hashe@amd.com 68711309Sdavid.hashe@amd.com if (reg & RFCR_ULM) 68811309Sdavid.hashe@amd.com panic("RFCR_ULM not implemented!\n"); 68911309Sdavid.hashe@amd.com 69011309Sdavid.hashe@amd.com break; 69111309Sdavid.hashe@amd.com 69211308Santhony.gutierrez@amd.com case RFDR: 69311308Santhony.gutierrez@amd.com rfaddr = (uint16_t)(regs.rfcr & RFCR_RFADDR); 69411308Santhony.gutierrez@amd.com switch (rfaddr) { 69511308Santhony.gutierrez@amd.com case 0x000: 69611308Santhony.gutierrez@amd.com rom.perfectMatch[0] = (uint8_t)reg; 69711308Santhony.gutierrez@amd.com rom.perfectMatch[1] = (uint8_t)(reg >> 8); 69811308Santhony.gutierrez@amd.com break; 69911308Santhony.gutierrez@amd.com case 0x002: 70011308Santhony.gutierrez@amd.com rom.perfectMatch[2] = (uint8_t)reg; 70111308Santhony.gutierrez@amd.com rom.perfectMatch[3] = (uint8_t)(reg >> 8); 70211308Santhony.gutierrez@amd.com break; 70311308Santhony.gutierrez@amd.com case 0x004: 70411308Santhony.gutierrez@amd.com rom.perfectMatch[4] = (uint8_t)reg; 70511308Santhony.gutierrez@amd.com rom.perfectMatch[5] = (uint8_t)(reg >> 8); 70611308Santhony.gutierrez@amd.com break; 70711308Santhony.gutierrez@amd.com default: 70811308Santhony.gutierrez@amd.com 70911308Santhony.gutierrez@amd.com if (rfaddr >= FHASH_ADDR && 71011308Santhony.gutierrez@amd.com rfaddr < FHASH_ADDR + FHASH_SIZE) { 71111308Santhony.gutierrez@amd.com 71211308Santhony.gutierrez@amd.com // Only word-aligned writes supported 71311308Santhony.gutierrez@amd.com if (rfaddr % 2) 71411309Sdavid.hashe@amd.com panic("unaligned write to filter hash table!"); 71511309Sdavid.hashe@amd.com 71611309Sdavid.hashe@amd.com rom.filterHash[rfaddr - FHASH_ADDR] = (uint8_t)reg; 71711309Sdavid.hashe@amd.com rom.filterHash[rfaddr - FHASH_ADDR + 1] 71811309Sdavid.hashe@amd.com = (uint8_t)(reg >> 8); 71911309Sdavid.hashe@amd.com break; 72011309Sdavid.hashe@amd.com } 72111309Sdavid.hashe@amd.com panic("writing RFDR for something other than pattern matching\ 72211309Sdavid.hashe@amd.com or hashing! %#x\n", rfaddr); 72311309Sdavid.hashe@amd.com } 72411309Sdavid.hashe@amd.com 72511309Sdavid.hashe@amd.com case BRAR: 72611309Sdavid.hashe@amd.com regs.brar = reg; 72711309Sdavid.hashe@amd.com break; 72811309Sdavid.hashe@amd.com 72911309Sdavid.hashe@amd.com case BRDR: 73011309Sdavid.hashe@amd.com panic("the driver never uses BRDR, something is wrong!\n"); 73111309Sdavid.hashe@amd.com 73211309Sdavid.hashe@amd.com case SRR: 73311309Sdavid.hashe@amd.com panic("SRR is read only register!\n"); 73411309Sdavid.hashe@amd.com 73511309Sdavid.hashe@amd.com case MIBC: 7366657Snate@binkert.org panic("the driver never uses MIBC, something is wrong!\n"); 7379745Snilay@cs.wisc.edu 7389745Snilay@cs.wisc.edu case VRCR: 7399745Snilay@cs.wisc.edu regs.vrcr = reg; 7409745Snilay@cs.wisc.edu break; 74110012Snilay@cs.wisc.edu 74210012Snilay@cs.wisc.edu case VTCR: 7439745Snilay@cs.wisc.edu regs.vtcr = reg; 7449745Snilay@cs.wisc.edu break; 7459745Snilay@cs.wisc.edu 7469745Snilay@cs.wisc.edu case VDR: 7479745Snilay@cs.wisc.edu panic("the driver never uses VDR, something is wrong!\n"); 74810919Sbrandon.potter@amd.com 74910012Snilay@cs.wisc.edu case CCSR: 7509745Snilay@cs.wisc.edu /* not going to implement clockrun stuff */ 7519745Snilay@cs.wisc.edu regs.ccsr = reg; 7529745Snilay@cs.wisc.edu break; 7539745Snilay@cs.wisc.edu 7549745Snilay@cs.wisc.edu case TBICR: 7559745Snilay@cs.wisc.edu regs.tbicr = reg; 7569745Snilay@cs.wisc.edu if (reg & TBICR_MR_LOOPBACK) 7579745Snilay@cs.wisc.edu panic("TBICR_MR_LOOPBACK never used, something wrong!\n"); 7589745Snilay@cs.wisc.edu 7599745Snilay@cs.wisc.edu if (reg & TBICR_MR_AN_ENABLE) { 7609745Snilay@cs.wisc.edu regs.tanlpar = regs.tanar; 7619745Snilay@cs.wisc.edu regs.tbisr |= (TBISR_MR_AN_COMPLETE | TBISR_MR_LINK_STATUS); 7629745Snilay@cs.wisc.edu } 7639745Snilay@cs.wisc.edu 7649745Snilay@cs.wisc.edu#if 0 7659745Snilay@cs.wisc.edu if (reg & TBICR_MR_RESTART_AN) ; 76610919Sbrandon.potter@amd.com#endif 76710012Snilay@cs.wisc.edu 7689745Snilay@cs.wisc.edu break; 7699745Snilay@cs.wisc.edu 7709745Snilay@cs.wisc.edu case TBISR: 7719745Snilay@cs.wisc.edu panic("TBISR is read only register!\n"); 7729745Snilay@cs.wisc.edu 7739745Snilay@cs.wisc.edu case TANAR: 7749745Snilay@cs.wisc.edu // Only write the writable bits 7759745Snilay@cs.wisc.edu regs.tanar &= TANAR_RF1 | TANAR_RF2 | TANAR_UNUSED; 7769745Snilay@cs.wisc.edu regs.tanar |= reg & ~(TANAR_RF1 | TANAR_RF2 | TANAR_UNUSED); 7779745Snilay@cs.wisc.edu 7789745Snilay@cs.wisc.edu // Pause capability unimplemented 7799745Snilay@cs.wisc.edu#if 0 7809745Snilay@cs.wisc.edu if (reg & TANAR_PS2) ; 7819745Snilay@cs.wisc.edu if (reg & TANAR_PS1) ; 7829745Snilay@cs.wisc.edu#endif 7839745Snilay@cs.wisc.edu 78410920Sbrandon.potter@amd.com break; 7859745Snilay@cs.wisc.edu 78610920Sbrandon.potter@amd.com case TANLPAR: 78710920Sbrandon.potter@amd.com panic("this should only be written to by the fake phy!\n"); 7889745Snilay@cs.wisc.edu 7899745Snilay@cs.wisc.edu case TANER: 7909745Snilay@cs.wisc.edu panic("TANER is read only register!\n"); 7919745Snilay@cs.wisc.edu 7929745Snilay@cs.wisc.edu case TESR: 7939745Snilay@cs.wisc.edu regs.tesr = reg; 7949745Snilay@cs.wisc.edu break; 7959745Snilay@cs.wisc.edu 7969745Snilay@cs.wisc.edu default: 7979745Snilay@cs.wisc.edu panic("invalid register access daddr=%#x", daddr); 7989745Snilay@cs.wisc.edu } 7999745Snilay@cs.wisc.edu } else { 80010920Sbrandon.potter@amd.com panic("Invalid Request Size"); 8019745Snilay@cs.wisc.edu } 80210920Sbrandon.potter@amd.com pkt->makeAtomicResponse(); 80310920Sbrandon.potter@amd.com return pioDelay; 8049745Snilay@cs.wisc.edu} 8059745Snilay@cs.wisc.edu 8069745Snilay@cs.wisc.eduvoid 8079745Snilay@cs.wisc.eduNSGigE::devIntrPost(uint32_t interrupts) 8089745Snilay@cs.wisc.edu{ 8099745Snilay@cs.wisc.edu if (interrupts & ISR_RESERVE) 8109745Snilay@cs.wisc.edu panic("Cannot set a reserved interrupt"); 8119745Snilay@cs.wisc.edu 8129745Snilay@cs.wisc.edu if (interrupts & ISR_NOIMPL) 8139745Snilay@cs.wisc.edu warn("interrupt not implemented %#x\n", interrupts); 8149745Snilay@cs.wisc.edu 8159745Snilay@cs.wisc.edu interrupts &= ISR_IMPL; 8169745Snilay@cs.wisc.edu regs.isr |= interrupts; 8179745Snilay@cs.wisc.edu 8189745Snilay@cs.wisc.edu if (interrupts & regs.imr) { 8199745Snilay@cs.wisc.edu if (interrupts & ISR_SWI) { 8209745Snilay@cs.wisc.edu totalSwi++; 8219745Snilay@cs.wisc.edu } 8229745Snilay@cs.wisc.edu if (interrupts & ISR_RXIDLE) { 8239745Snilay@cs.wisc.edu totalRxIdle++; 8249745Snilay@cs.wisc.edu } 82511061Snilay@cs.wisc.edu if (interrupts & ISR_RXOK) { 8269745Snilay@cs.wisc.edu totalRxOk++; 8279745Snilay@cs.wisc.edu } 8289745Snilay@cs.wisc.edu if (interrupts & ISR_RXDESC) { 8299745Snilay@cs.wisc.edu totalRxDesc++; 8309745Snilay@cs.wisc.edu } 8319745Snilay@cs.wisc.edu if (interrupts & ISR_TXOK) { 8329745Snilay@cs.wisc.edu totalTxOk++; 8339745Snilay@cs.wisc.edu } 8349745Snilay@cs.wisc.edu if (interrupts & ISR_TXIDLE) { 8359745Snilay@cs.wisc.edu totalTxIdle++; 8369745Snilay@cs.wisc.edu } 83711061Snilay@cs.wisc.edu if (interrupts & ISR_TXDESC) { 8389745Snilay@cs.wisc.edu totalTxDesc++; 8399745Snilay@cs.wisc.edu } 8409745Snilay@cs.wisc.edu if (interrupts & ISR_RXORN) { 8419745Snilay@cs.wisc.edu totalRxOrn++; 8429745Snilay@cs.wisc.edu } 8439745Snilay@cs.wisc.edu } 8447007Snate@binkert.org 8457007Snate@binkert.org DPRINTF(EthernetIntr, 8467007Snate@binkert.org "interrupt written to ISR: intr=%#x isr=%#x imr=%#x\n", 8476657Snate@binkert.org interrupts, regs.isr, regs.imr); 8486657Snate@binkert.org 8496657Snate@binkert.org if ((regs.isr & regs.imr)) { 8507007Snate@binkert.org Tick when = curTick; 8517007Snate@binkert.org if ((regs.isr & regs.imr & ISR_NODELAY) == 0) 8527007Snate@binkert.org when += intrDelay; 8536657Snate@binkert.org postedInterrupts++; 8546657Snate@binkert.org cpuIntrPost(when); 8556657Snate@binkert.org } 85611021Sjthestness@gmail.com} 85711021Sjthestness@gmail.com 85811021Sjthestness@gmail.com/* writing this interrupt counting stats inside this means that this function 85911021Sjthestness@gmail.com is now limited to being used to clear all interrupts upon the kernel 86011021Sjthestness@gmail.com reading isr and servicing. just telling you in case you were thinking 86111021Sjthestness@gmail.com of expanding use. 8627007Snate@binkert.org*/ 8637007Snate@binkert.orgvoid 8647007Snate@binkert.orgNSGigE::devIntrClear(uint32_t interrupts) 8657007Snate@binkert.org{ 8667007Snate@binkert.org if (interrupts & ISR_RESERVE) 8676657Snate@binkert.org panic("Cannot clear a reserved interrupt"); 86810012Snilay@cs.wisc.edu 8699745Snilay@cs.wisc.edu if (regs.isr & regs.imr & ISR_SWI) { 8709745Snilay@cs.wisc.edu postedSwi++; 8719745Snilay@cs.wisc.edu } 8729745Snilay@cs.wisc.edu if (regs.isr & regs.imr & ISR_RXIDLE) { 8739745Snilay@cs.wisc.edu postedRxIdle++; 8749745Snilay@cs.wisc.edu } 8756902SBrad.Beckmann@amd.com if (regs.isr & regs.imr & ISR_RXOK) { 8769745Snilay@cs.wisc.edu postedRxOk++; 8779745Snilay@cs.wisc.edu } 8789745Snilay@cs.wisc.edu if (regs.isr & regs.imr & ISR_RXDESC) { 8799745Snilay@cs.wisc.edu postedRxDesc++; 88010012Snilay@cs.wisc.edu } 8816902SBrad.Beckmann@amd.com if (regs.isr & regs.imr & ISR_TXOK) { 8827839Snilay@cs.wisc.edu postedTxOk++; 8837839Snilay@cs.wisc.edu } 8847839Snilay@cs.wisc.edu if (regs.isr & regs.imr & ISR_TXIDLE) { 8857839Snilay@cs.wisc.edu postedTxIdle++; 8867839Snilay@cs.wisc.edu } 8877839Snilay@cs.wisc.edu if (regs.isr & regs.imr & ISR_TXDESC) { 8887839Snilay@cs.wisc.edu postedTxDesc++; 8897839Snilay@cs.wisc.edu } 8907839Snilay@cs.wisc.edu if (regs.isr & regs.imr & ISR_RXORN) { 8917839Snilay@cs.wisc.edu postedRxOrn++; 8927839Snilay@cs.wisc.edu } 8937839Snilay@cs.wisc.edu 8947839Snilay@cs.wisc.edu interrupts &= ~ISR_NOIMPL; 8957839Snilay@cs.wisc.edu regs.isr &= ~interrupts; 8967839Snilay@cs.wisc.edu 8977839Snilay@cs.wisc.edu DPRINTF(EthernetIntr, 8987839Snilay@cs.wisc.edu "interrupt cleared from ISR: intr=%x isr=%x imr=%x\n", 8997839Snilay@cs.wisc.edu interrupts, regs.isr, regs.imr); 9007839Snilay@cs.wisc.edu 9017839Snilay@cs.wisc.edu if (!(regs.isr & regs.imr)) 9027839Snilay@cs.wisc.edu cpuIntrClear(); 9037839Snilay@cs.wisc.edu} 9047839Snilay@cs.wisc.edu 9057839Snilay@cs.wisc.eduvoid 9067839Snilay@cs.wisc.eduNSGigE::devIntrChangeMask() 9077839Snilay@cs.wisc.edu{ 9087839Snilay@cs.wisc.edu DPRINTF(EthernetIntr, "interrupt mask changed: isr=%x imr=%x masked=%x\n", 9097839Snilay@cs.wisc.edu regs.isr, regs.imr, regs.isr & regs.imr); 9107839Snilay@cs.wisc.edu 9117839Snilay@cs.wisc.edu if (regs.isr & regs.imr) 9127839Snilay@cs.wisc.edu cpuIntrPost(curTick); 9137839Snilay@cs.wisc.edu else 9147839Snilay@cs.wisc.edu cpuIntrClear(); 9157839Snilay@cs.wisc.edu} 9167839Snilay@cs.wisc.edu 9177839Snilay@cs.wisc.eduvoid 9187839Snilay@cs.wisc.eduNSGigE::cpuIntrPost(Tick when) 9196902SBrad.Beckmann@amd.com{ 9208683Snilay@cs.wisc.edu // If the interrupt you want to post is later than an interrupt 9218683Snilay@cs.wisc.edu // already scheduled, just let it post in the coming one and don't 9228683Snilay@cs.wisc.edu // schedule another. 9238683Snilay@cs.wisc.edu // HOWEVER, must be sure that the scheduled intrTick is in the 9248683Snilay@cs.wisc.edu // future (this was formerly the source of a bug) 9258683Snilay@cs.wisc.edu /** 9268683Snilay@cs.wisc.edu * @todo this warning should be removed and the intrTick code should 9278683Snilay@cs.wisc.edu * be fixed. 9288683Snilay@cs.wisc.edu */ 9298683Snilay@cs.wisc.edu assert(when >= curTick); 9308683Snilay@cs.wisc.edu assert(intrTick >= curTick || intrTick == 0); 9318683Snilay@cs.wisc.edu if (when > intrTick && intrTick != 0) { 9328683Snilay@cs.wisc.edu DPRINTF(EthernetIntr, "don't need to schedule event...intrTick=%d\n", 9338683Snilay@cs.wisc.edu intrTick); 9348683Snilay@cs.wisc.edu return; 9358683Snilay@cs.wisc.edu } 9368683Snilay@cs.wisc.edu 9376657Snate@binkert.org intrTick = when; 9386657Snate@binkert.org if (intrTick < curTick) { 9397839Snilay@cs.wisc.edu debug_break(); 9407839Snilay@cs.wisc.edu intrTick = curTick; 9417839Snilay@cs.wisc.edu } 9427839Snilay@cs.wisc.edu 9436657Snate@binkert.org DPRINTF(EthernetIntr, "going to schedule an interrupt for intrTick=%d\n", 9447839Snilay@cs.wisc.edu intrTick); 9457839Snilay@cs.wisc.edu 9467839Snilay@cs.wisc.edu if (intrEvent) 94711025Snilay@cs.wisc.edu intrEvent->squash(); 9487839Snilay@cs.wisc.edu intrEvent = new IntrEvent(this, true); 9498055Sksewell@umich.edu schedule(intrEvent, intrTick); 95010963Sdavid.hashe@amd.com} 95110963Sdavid.hashe@amd.com 95210963Sdavid.hashe@amd.comvoid 95310963Sdavid.hashe@amd.comNSGigE::cpuInterrupt() 95410963Sdavid.hashe@amd.com{ 95510963Sdavid.hashe@amd.com assert(intrTick == curTick); 95610963Sdavid.hashe@amd.com 9577839Snilay@cs.wisc.edu // Whether or not there's a pending interrupt, we don't care about 9586657Snate@binkert.org // it anymore 9597839Snilay@cs.wisc.edu intrEvent = 0; 9607839Snilay@cs.wisc.edu intrTick = 0; 9617839Snilay@cs.wisc.edu 9627839Snilay@cs.wisc.edu // Don't send an interrupt if there's already one 9637839Snilay@cs.wisc.edu if (cpuPendingIntr) { 9647839Snilay@cs.wisc.edu DPRINTF(EthernetIntr, 9657839Snilay@cs.wisc.edu "would send an interrupt now, but there's already pending\n"); 9667839Snilay@cs.wisc.edu } else { 9677839Snilay@cs.wisc.edu // Send interrupt 96811025Snilay@cs.wisc.edu cpuPendingIntr = true; 9697839Snilay@cs.wisc.edu 9708055Sksewell@umich.edu DPRINTF(EthernetIntr, "posting interrupt\n"); 9717839Snilay@cs.wisc.edu intrPost(); 9727839Snilay@cs.wisc.edu } 9737839Snilay@cs.wisc.edu} 9747839Snilay@cs.wisc.edu 9757839Snilay@cs.wisc.eduvoid 9767839Snilay@cs.wisc.eduNSGigE::cpuIntrClear() 9777839Snilay@cs.wisc.edu{ 9787839Snilay@cs.wisc.edu if (!cpuPendingIntr) 9797839Snilay@cs.wisc.edu return; 9807839Snilay@cs.wisc.edu 9817839Snilay@cs.wisc.edu if (intrEvent) { 9827839Snilay@cs.wisc.edu intrEvent->squash(); 98311025Snilay@cs.wisc.edu intrEvent = 0; 9847839Snilay@cs.wisc.edu } 9858055Sksewell@umich.edu 9867839Snilay@cs.wisc.edu intrTick = 0; 9877839Snilay@cs.wisc.edu 9887839Snilay@cs.wisc.edu cpuPendingIntr = false; 9897839Snilay@cs.wisc.edu 9907839Snilay@cs.wisc.edu DPRINTF(EthernetIntr, "clearing interrupt\n"); 9917839Snilay@cs.wisc.edu intrClear(); 9927839Snilay@cs.wisc.edu} 9937839Snilay@cs.wisc.edu 9947839Snilay@cs.wisc.edubool 9957839Snilay@cs.wisc.eduNSGigE::cpuIntrPending() const 9966657Snate@binkert.org{ return cpuPendingIntr; } 9977007Snate@binkert.org 99811025Snilay@cs.wisc.eduvoid 9996657Snate@binkert.orgNSGigE::txReset() 10008055Sksewell@umich.edu{ 10016657Snate@binkert.org 10026657Snate@binkert.org DPRINTF(Ethernet, "transmit reset\n"); 10036657Snate@binkert.org 10046657Snate@binkert.org CTDD = false; 10058478Snilay@cs.wisc.edu txEnable = false;; 10068478Snilay@cs.wisc.edu txFragPtr = 0; 10078478Snilay@cs.wisc.edu assert(txDescCnt == 0); 10089302Snilay@cs.wisc.edu txFifo.clear(); 10099302Snilay@cs.wisc.edu txState = txIdle; 101010524Snilay@cs.wisc.edu assert(txDmaState == dmaIdle); 10119302Snilay@cs.wisc.edu} 10129302Snilay@cs.wisc.edu 101310524Snilay@cs.wisc.eduvoid 10149302Snilay@cs.wisc.eduNSGigE::rxReset() 10159302Snilay@cs.wisc.edu{ 10169302Snilay@cs.wisc.edu DPRINTF(Ethernet, "receive reset\n"); 10179302Snilay@cs.wisc.edu 101810305Snilay@cs.wisc.edu CRDD = false; 10199302Snilay@cs.wisc.edu assert(rxPktBytes == 0); 102010311Snilay@cs.wisc.edu rxEnable = false; 102110311Snilay@cs.wisc.edu rxFragPtr = 0; 102210311Snilay@cs.wisc.edu assert(rxDescCnt == 0); 102310311Snilay@cs.wisc.edu assert(rxDmaState == dmaIdle); 102410311Snilay@cs.wisc.edu rxFifo.clear(); 102510311Snilay@cs.wisc.edu rxState = rxIdle; 102610311Snilay@cs.wisc.edu} 10279302Snilay@cs.wisc.edu 10289302Snilay@cs.wisc.eduvoid 10299302Snilay@cs.wisc.eduNSGigE::regsReset() 10309302Snilay@cs.wisc.edu{ 10319302Snilay@cs.wisc.edu memset(®s, 0, sizeof(regs)); 10326657Snate@binkert.org regs.config = (CFGR_LNKSTS | CFGR_TBI_EN | CFGR_MODE_1000); 10336657Snate@binkert.org regs.mear = 0x12; 10349219Spower.jg@gmail.com regs.txcfg = 0x120; // set drain threshold to 1024 bytes and 10356657Snate@binkert.org // fill threshold to 32 bytes 10366657Snate@binkert.org regs.rxcfg = 0x4; // set drain threshold to 16 bytes 10376999Snate@binkert.org regs.srr = 0x0103; // set the silicon revision to rev B or 0x103 10386657Snate@binkert.org regs.mibc = MIBC_FRZ; 10396657Snate@binkert.org regs.vdr = 0x81; // set the vlan tag type to 802.1q 10409104Shestness@cs.utexas.edu regs.tesr = 0xc000; // TBI capable of both full and half duplex 10419104Shestness@cs.utexas.edu regs.brar = 0xffffffff; 10429104Shestness@cs.utexas.edu 10439104Shestness@cs.utexas.edu extstsEnable = false; 10446657Snate@binkert.org acceptBroadcast = false; 10456657Snate@binkert.org acceptMulticast = false; 10466657Snate@binkert.org acceptUnicast = false; 10476657Snate@binkert.org acceptPerfect = false; 10488946Sandreas.hansson@arm.com acceptArp = false; 10498946Sandreas.hansson@arm.com} 10508946Sandreas.hansson@arm.com 10517832Snate@binkert.orgbool 105210972Sdavid.hashe@amd.comNSGigE::doRxDmaRead() 10537832Snate@binkert.org{ 105412334Sgabeblack@google.com assert(rxDmaState == dmaIdle || rxDmaState == dmaReadWaiting); 105510972Sdavid.hashe@amd.com rxDmaState = dmaReading; 105610972Sdavid.hashe@amd.com 105710972Sdavid.hashe@amd.com if (dmaPending() || getState() != Running) 105810972Sdavid.hashe@amd.com rxDmaState = dmaReadWaiting; 105910972Sdavid.hashe@amd.com else 10608229Snate@binkert.org dmaRead(rxDmaAddr, rxDmaLen, &rxDmaReadEvent, (uint8_t*)rxDmaData); 10618229Snate@binkert.org 10628229Snate@binkert.org return true; 106310972Sdavid.hashe@amd.com} 10649104Shestness@cs.utexas.edu 10659104Shestness@cs.utexas.eduvoid 10669104Shestness@cs.utexas.eduNSGigE::rxDmaReadDone() 10679104Shestness@cs.utexas.edu{ 10689104Shestness@cs.utexas.edu assert(rxDmaState == dmaReading); 10699104Shestness@cs.utexas.edu rxDmaState = dmaIdle; 10708229Snate@binkert.org 107111108Sdavid.hashe@amd.com DPRINTF(EthernetDMA, "rx dma read paddr=%#x len=%d\n", 107210972Sdavid.hashe@amd.com rxDmaAddr, rxDmaLen); 10739219Spower.jg@gmail.com DDUMP(EthernetDMA, rxDmaData, rxDmaLen); 10749219Spower.jg@gmail.com 10759219Spower.jg@gmail.com // If the transmit state machine has a pending DMA, let it go first 10769219Spower.jg@gmail.com if (txDmaState == dmaReadWaiting || txDmaState == dmaWriteWaiting) 10779219Spower.jg@gmail.com txKick(); 10789219Spower.jg@gmail.com 107910963Sdavid.hashe@amd.com rxKick(); 108010963Sdavid.hashe@amd.com} 10819219Spower.jg@gmail.com 10826657Snate@binkert.orgbool 10837055Snate@binkert.orgNSGigE::doRxDmaWrite() 10847055Snate@binkert.org{ 10857007Snate@binkert.org assert(rxDmaState == dmaIdle || rxDmaState == dmaWriteWaiting); 10867007Snate@binkert.org rxDmaState = dmaWriting; 10876657Snate@binkert.org 10886657Snate@binkert.org if (dmaPending() || getState() != Running) 10896657Snate@binkert.org rxDmaState = dmaWriteWaiting; 109010963Sdavid.hashe@amd.com else 109110963Sdavid.hashe@amd.com dmaWrite(rxDmaAddr, rxDmaLen, &rxDmaWriteEvent, (uint8_t*)rxDmaData); 10926657Snate@binkert.org return true; 10936657Snate@binkert.org} 10946657Snate@binkert.org 10957007Snate@binkert.orgvoid 10969496Snilay@cs.wisc.eduNSGigE::rxDmaWriteDone() 10977007Snate@binkert.org{ 10987007Snate@binkert.org assert(rxDmaState == dmaWriting); 10999499Snilay@cs.wisc.edu rxDmaState = dmaIdle; 11006657Snate@binkert.org 11016657Snate@binkert.org DPRINTF(EthernetDMA, "rx dma write paddr=%#x len=%d\n", 11026657Snate@binkert.org rxDmaAddr, rxDmaLen); 11036657Snate@binkert.org DDUMP(EthernetDMA, rxDmaData, rxDmaLen); 11046657Snate@binkert.org 11056657Snate@binkert.org // If the transmit state machine has a pending DMA, let it go first 11066657Snate@binkert.org if (txDmaState == dmaReadWaiting || txDmaState == dmaWriteWaiting) 11076657Snate@binkert.org txKick(); 11086657Snate@binkert.org 11096657Snate@binkert.org rxKick(); 11106657Snate@binkert.org} 11116657Snate@binkert.org 111213675Sandreas.sandberg@arm.comvoid 11139996Snilay@cs.wisc.eduNSGigE::rxKick() 11147567SBrad.Beckmann@amd.com{ 11159996Snilay@cs.wisc.edu bool is64bit = (bool)(regs.config & CFGR_M64ADDR); 111610963Sdavid.hashe@amd.com 111710963Sdavid.hashe@amd.com DPRINTF(EthernetSM, 111810963Sdavid.hashe@amd.com "receive kick rxState=%s (rxBuf.size=%d) %d-bit\n", 11196657Snate@binkert.org NsRxStateStrings[rxState], rxFifo.size(), is64bit ? 64 : 32); 112010963Sdavid.hashe@amd.com 112110963Sdavid.hashe@amd.com Addr link, bufptr; 112210963Sdavid.hashe@amd.com uint32_t &cmdsts = is64bit ? rxDesc64.cmdsts : rxDesc32.cmdsts; 112310963Sdavid.hashe@amd.com uint32_t &extsts = is64bit ? rxDesc64.extsts : rxDesc32.extsts; 112410963Sdavid.hashe@amd.com 112510963Sdavid.hashe@amd.com next: 112610963Sdavid.hashe@amd.com if (clock) { 112710963Sdavid.hashe@amd.com if (rxKickTick > curTick) { 11286657Snate@binkert.org DPRINTF(EthernetSM, "receive kick exiting, can't run till %d\n", 11296657Snate@binkert.org rxKickTick); 11306657Snate@binkert.org 11316657Snate@binkert.org goto exit; 11326657Snate@binkert.org } 11336657Snate@binkert.org 113410963Sdavid.hashe@amd.com // Go to the next state machine clock tick. 113510963Sdavid.hashe@amd.com rxKickTick = curTick + ticks(1); 113610963Sdavid.hashe@amd.com } 113710963Sdavid.hashe@amd.com 113810963Sdavid.hashe@amd.com switch(rxDmaState) { 113910963Sdavid.hashe@amd.com case dmaReadWaiting: 114011116Santhony.gutierrez@amd.com if (doRxDmaRead()) 114110963Sdavid.hashe@amd.com goto exit; 114210963Sdavid.hashe@amd.com break; 114310963Sdavid.hashe@amd.com case dmaWriteWaiting: 114410963Sdavid.hashe@amd.com if (doRxDmaWrite()) 114510963Sdavid.hashe@amd.com goto exit; 114610963Sdavid.hashe@amd.com break; 114710963Sdavid.hashe@amd.com default: 114810963Sdavid.hashe@amd.com break; 114910963Sdavid.hashe@amd.com } 115010963Sdavid.hashe@amd.com 115110963Sdavid.hashe@amd.com link = is64bit ? (Addr)rxDesc64.link : (Addr)rxDesc32.link; 115210963Sdavid.hashe@amd.com bufptr = is64bit ? (Addr)rxDesc64.bufptr : (Addr)rxDesc32.bufptr; 11536657Snate@binkert.org 11546657Snate@binkert.org // see state machine from spec for details 11556657Snate@binkert.org // the way this works is, if you finish work on one state and can 11566657Snate@binkert.org // go directly to another, you do that through jumping to the 11576657Snate@binkert.org // label "next". however, if you have intermediate work, like DMA 11586657Snate@binkert.org // so that you can't go to the next state yet, you go to exit and 11596657Snate@binkert.org // exit the loop. however, when the DMA is done it will trigger 11606657Snate@binkert.org // an event and come back to this loop. 11616657Snate@binkert.org switch (rxState) { 11626999Snate@binkert.org case rxIdle: 11636657Snate@binkert.org if (!rxEnable) { 11646657Snate@binkert.org DPRINTF(EthernetSM, "Receive Disabled! Nothing to do.\n"); 11656657Snate@binkert.org goto exit; 11666657Snate@binkert.org } 11676657Snate@binkert.org 11686657Snate@binkert.org if (CRDD) { 11697832Snate@binkert.org rxState = rxDescRefr; 11707832Snate@binkert.org 117112334Sgabeblack@google.com rxDmaAddr = regs.rxdp & 0x3fffffff; 11727832Snate@binkert.org rxDmaData = 11738232Snate@binkert.org is64bit ? (void *)&rxDesc64.link : (void *)&rxDesc32.link; 11748232Snate@binkert.org rxDmaLen = is64bit ? sizeof(rxDesc64.link) : sizeof(rxDesc32.link); 11758229Snate@binkert.org rxDmaFree = dmaDescFree; 11768229Snate@binkert.org 11778229Snate@binkert.org descDmaReads++; 11788229Snate@binkert.org descDmaRdBytes += rxDmaLen; 117911108Sdavid.hashe@amd.com 11806657Snate@binkert.org if (doRxDmaRead()) 11816657Snate@binkert.org goto exit; 11826657Snate@binkert.org } else { 11836657Snate@binkert.org rxState = rxDescRead; 11846657Snate@binkert.org 11856657Snate@binkert.org rxDmaAddr = regs.rxdp & 0x3fffffff; 11867007Snate@binkert.org rxDmaData = is64bit ? (void *)&rxDesc64 : (void *)&rxDesc32; 11877007Snate@binkert.org rxDmaLen = is64bit ? sizeof(rxDesc64) : sizeof(rxDesc32); 11887839Snilay@cs.wisc.edu rxDmaFree = dmaDescFree; 11897839Snilay@cs.wisc.edu 11907839Snilay@cs.wisc.edu descDmaReads++; 11917839Snilay@cs.wisc.edu descDmaRdBytes += rxDmaLen; 11927839Snilay@cs.wisc.edu 11937839Snilay@cs.wisc.edu if (doRxDmaRead()) 11947839Snilay@cs.wisc.edu goto exit; 11957839Snilay@cs.wisc.edu } 11967839Snilay@cs.wisc.edu break; 11977839Snilay@cs.wisc.edu 119811025Snilay@cs.wisc.edu case rxDescRefr: 11996657Snate@binkert.org if (rxDmaState != dmaIdle) 12007839Snilay@cs.wisc.edu goto exit; 120110305Snilay@cs.wisc.edu 120210305Snilay@cs.wisc.edu rxState = rxAdvance; 12037839Snilay@cs.wisc.edu break; 12048337Snilay@cs.wisc.edu 12057839Snilay@cs.wisc.edu case rxDescRead: 12068337Snilay@cs.wisc.edu if (rxDmaState != dmaIdle) 12077839Snilay@cs.wisc.edu goto exit; 12088337Snilay@cs.wisc.edu 12097839Snilay@cs.wisc.edu DPRINTF(EthernetDesc, "rxDesc: addr=%08x read descriptor\n", 12108337Snilay@cs.wisc.edu regs.rxdp & 0x3fffffff); 12117839Snilay@cs.wisc.edu DPRINTF(EthernetDesc, 12127839Snilay@cs.wisc.edu "rxDesc: link=%#x bufptr=%#x cmdsts=%08x extsts=%08x\n", 121310305Snilay@cs.wisc.edu link, bufptr, cmdsts, extsts); 12146657Snate@binkert.org 121511118Snilay@cs.wisc.edu if (cmdsts & CMDSTS_OWN) { 121610305Snilay@cs.wisc.edu devIntrPost(ISR_RXIDLE); 121710305Snilay@cs.wisc.edu rxState = rxIdle; 12186657Snate@binkert.org goto exit; 121910305Snilay@cs.wisc.edu } else { 12207839Snilay@cs.wisc.edu rxState = rxFifoBlock; 12217839Snilay@cs.wisc.edu rxFragPtr = bufptr; 12227839Snilay@cs.wisc.edu rxDescCnt = cmdsts & CMDSTS_LEN_MASK; 12237839Snilay@cs.wisc.edu } 12247839Snilay@cs.wisc.edu break; 12257839Snilay@cs.wisc.edu 12267839Snilay@cs.wisc.edu case rxFifoBlock: 12277839Snilay@cs.wisc.edu if (!rxPacket) { 12287839Snilay@cs.wisc.edu /** 12296657Snate@binkert.org * @todo in reality, we should be able to start processing 123011049Snilay@cs.wisc.edu * the packet as it arrives, and not have to wait for the 123111049Snilay@cs.wisc.edu * full packet ot be in the receive fifo. 12327839Snilay@cs.wisc.edu */ 12336657Snate@binkert.org if (rxFifo.empty()) 123410305Snilay@cs.wisc.edu goto exit; 123510305Snilay@cs.wisc.edu 123610305Snilay@cs.wisc.edu DPRINTF(EthernetSM, "****processing receive of new packet****\n"); 123710305Snilay@cs.wisc.edu 123810305Snilay@cs.wisc.edu // If we don't have a packet, grab a new one from the fifo. 123911025Snilay@cs.wisc.edu rxPacket = rxFifo.front(); 124010305Snilay@cs.wisc.edu rxPktBytes = rxPacket->length; 124110305Snilay@cs.wisc.edu rxPacketBufPtr = rxPacket->data; 124210305Snilay@cs.wisc.edu 124310305Snilay@cs.wisc.edu#if TRACING_ON 124411118Snilay@cs.wisc.edu if (DTRACE(Ethernet)) { 124510305Snilay@cs.wisc.edu IpPtr ip(rxPacket); 124610305Snilay@cs.wisc.edu if (ip) { 12477839Snilay@cs.wisc.edu DPRINTF(Ethernet, "ID is %d\n", ip->id()); 12487839Snilay@cs.wisc.edu TcpPtr tcp(ip); 12498337Snilay@cs.wisc.edu if (tcp) { 12508341Snilay@cs.wisc.edu DPRINTF(Ethernet, 12517839Snilay@cs.wisc.edu "Src Port=%d, Dest Port=%d, Seq=%d, Ack=%d\n", 12528337Snilay@cs.wisc.edu tcp->sport(), tcp->dport(), tcp->seq(), 12538341Snilay@cs.wisc.edu tcp->ack()); 12547839Snilay@cs.wisc.edu } 12558337Snilay@cs.wisc.edu } 12568341Snilay@cs.wisc.edu } 12577839Snilay@cs.wisc.edu#endif 12588337Snilay@cs.wisc.edu 12598341Snilay@cs.wisc.edu // sanity check - i think the driver behaves like this 12607839Snilay@cs.wisc.edu assert(rxDescCnt >= rxPktBytes); 12617839Snilay@cs.wisc.edu rxFifo.pop(); 126210305Snilay@cs.wisc.edu } 126311025Snilay@cs.wisc.edu 126410305Snilay@cs.wisc.edu 126510305Snilay@cs.wisc.edu // dont' need the && rxDescCnt > 0 if driver sanity check 126610305Snilay@cs.wisc.edu // above holds 126710305Snilay@cs.wisc.edu if (rxPktBytes > 0) { 126811118Snilay@cs.wisc.edu rxState = rxFragWrite; 126910305Snilay@cs.wisc.edu // don't need min<>(rxPktBytes,rxDescCnt) if above sanity 127010305Snilay@cs.wisc.edu // check holds 127111025Snilay@cs.wisc.edu rxXferLen = rxPktBytes; 127210305Snilay@cs.wisc.edu 127310305Snilay@cs.wisc.edu rxDmaAddr = rxFragPtr & 0x3fffffff; 127410305Snilay@cs.wisc.edu rxDmaData = rxPacketBufPtr; 127510305Snilay@cs.wisc.edu rxDmaLen = rxXferLen; 127611118Snilay@cs.wisc.edu rxDmaFree = dmaDataFree; 127710305Snilay@cs.wisc.edu 12786657Snate@binkert.org if (doRxDmaWrite()) 127910305Snilay@cs.wisc.edu goto exit; 128010305Snilay@cs.wisc.edu 128110305Snilay@cs.wisc.edu } else { 128210305Snilay@cs.wisc.edu rxState = rxDescWrite; 12836657Snate@binkert.org 12846657Snate@binkert.org //if (rxPktBytes == 0) { /* packet is done */ 12857007Snate@binkert.org assert(rxPktBytes == 0); 12867007Snate@binkert.org DPRINTF(EthernetSM, "done with receiving packet\n"); 12877007Snate@binkert.org 12887007Snate@binkert.org cmdsts |= CMDSTS_OWN; 12897839Snilay@cs.wisc.edu cmdsts &= ~CMDSTS_MORE; 12907839Snilay@cs.wisc.edu cmdsts |= CMDSTS_OK; 12917839Snilay@cs.wisc.edu cmdsts &= 0xffff0000; 12927839Snilay@cs.wisc.edu cmdsts += rxPacket->length; //i.e. set CMDSTS_SIZE 12937839Snilay@cs.wisc.edu 12947839Snilay@cs.wisc.edu#if 0 12957839Snilay@cs.wisc.edu /* 12967839Snilay@cs.wisc.edu * all the driver uses these are for its own stats keeping 12977839Snilay@cs.wisc.edu * which we don't care about, aren't necessary for 12987839Snilay@cs.wisc.edu * functionality and doing this would just slow us down. 12997839Snilay@cs.wisc.edu * if they end up using this in a later version for 130011025Snilay@cs.wisc.edu * functional purposes, just undef 13016657Snate@binkert.org */ 13026657Snate@binkert.org if (rxFilterEnable) { 13036657Snate@binkert.org cmdsts &= ~CMDSTS_DEST_MASK; 13046657Snate@binkert.org const EthAddr &dst = rxFifoFront()->dst(); 13056657Snate@binkert.org if (dst->unicast()) 130613672Sandreas.sandberg@arm.com cmdsts |= CMDSTS_DEST_SELF; 13076657Snate@binkert.org if (dst->multicast()) 13086657Snate@binkert.org cmdsts |= CMDSTS_DEST_MULTI; 13096657Snate@binkert.org if (dst->broadcast()) 13106657Snate@binkert.org cmdsts |= CMDSTS_DEST_MASK; 13116657Snate@binkert.org } 13126999Snate@binkert.org#endif 13136657Snate@binkert.org 13146657Snate@binkert.org IpPtr ip(rxPacket); 131510964Sdavid.hashe@amd.com if (extstsEnable && ip) { 131610964Sdavid.hashe@amd.com extsts |= EXTSTS_IPPKT; 131710964Sdavid.hashe@amd.com rxIpChecksums++; 131810964Sdavid.hashe@amd.com if (cksum(ip) != 0) { 131910964Sdavid.hashe@amd.com DPRINTF(EthernetCksum, "Rx IP Checksum Error\n"); 132010964Sdavid.hashe@amd.com extsts |= EXTSTS_IPERR; 132110964Sdavid.hashe@amd.com } 132210964Sdavid.hashe@amd.com TcpPtr tcp(ip); 132310964Sdavid.hashe@amd.com UdpPtr udp(ip); 132410964Sdavid.hashe@amd.com if (tcp) { 132510964Sdavid.hashe@amd.com extsts |= EXTSTS_TCPPKT; 13266657Snate@binkert.org rxTcpChecksums++; 13276657Snate@binkert.org if (cksum(tcp) != 0) { 13289104Shestness@cs.utexas.edu DPRINTF(EthernetCksum, "Rx TCP Checksum Error\n"); 13296657Snate@binkert.org extsts |= EXTSTS_TCPERR; 13306657Snate@binkert.org 13316657Snate@binkert.org } 13326657Snate@binkert.org } else if (udp) { 13336657Snate@binkert.org extsts |= EXTSTS_UDPPKT; 133410228Snilay@cs.wisc.edu rxUdpChecksums++; 133511111Snilay@cs.wisc.edu if (cksum(udp) != 0) { 13366657Snate@binkert.org DPRINTF(EthernetCksum, "Rx UDP Checksum Error\n"); 13376657Snate@binkert.org extsts |= EXTSTS_UDPERR; 13386657Snate@binkert.org } 13396657Snate@binkert.org } 13409105SBrad.Beckmann@amd.com } 13419105SBrad.Beckmann@amd.com rxPacket = 0; 13429105SBrad.Beckmann@amd.com 13439105SBrad.Beckmann@amd.com /* 13449105SBrad.Beckmann@amd.com * the driver seems to always receive into desc buffers 13459105SBrad.Beckmann@amd.com * of size 1514, so you never have a pkt that is split 13469105SBrad.Beckmann@amd.com * into multiple descriptors on the receive side, so 13479105SBrad.Beckmann@amd.com * i don't implement that case, hence the assert above. 13486657Snate@binkert.org */ 13496657Snate@binkert.org 13506657Snate@binkert.org DPRINTF(EthernetDesc, 13516657Snate@binkert.org "rxDesc: addr=%08x writeback cmdsts extsts\n", 13526657Snate@binkert.org regs.rxdp & 0x3fffffff); 13536657Snate@binkert.org DPRINTF(EthernetDesc, 13546657Snate@binkert.org "rxDesc: link=%#x bufptr=%#x cmdsts=%08x extsts=%08x\n", 13559104Shestness@cs.utexas.edu link, bufptr, cmdsts, extsts); 13569104Shestness@cs.utexas.edu 13579104Shestness@cs.utexas.edu rxDmaAddr = regs.rxdp & 0x3fffffff; 13589104Shestness@cs.utexas.edu rxDmaData = &cmdsts; 13596657Snate@binkert.org if (is64bit) { 13606657Snate@binkert.org rxDmaAddr += offsetof(ns_desc64, cmdsts); 13616657Snate@binkert.org rxDmaLen = sizeof(rxDesc64.cmdsts) + sizeof(rxDesc64.extsts); 13626657Snate@binkert.org } else { 13636657Snate@binkert.org rxDmaAddr += offsetof(ns_desc32, cmdsts); 13646657Snate@binkert.org rxDmaLen = sizeof(rxDesc32.cmdsts) + sizeof(rxDesc32.extsts); 13656657Snate@binkert.org } 13666657Snate@binkert.org rxDmaFree = dmaDescFree; 13676657Snate@binkert.org 13686657Snate@binkert.org descDmaWrites++; 13697839Snilay@cs.wisc.edu descDmaWrBytes += rxDmaLen; 13707839Snilay@cs.wisc.edu 13717839Snilay@cs.wisc.edu if (doRxDmaWrite()) 13727839Snilay@cs.wisc.edu goto exit; 13737839Snilay@cs.wisc.edu } 13747839Snilay@cs.wisc.edu break; 13757839Snilay@cs.wisc.edu 13767839Snilay@cs.wisc.edu case rxFragWrite: 13777839Snilay@cs.wisc.edu if (rxDmaState != dmaIdle) 13787839Snilay@cs.wisc.edu goto exit; 13797839Snilay@cs.wisc.edu 13807839Snilay@cs.wisc.edu rxPacketBufPtr += rxXferLen; 13816657Snate@binkert.org rxFragPtr += rxXferLen; 13826657Snate@binkert.org rxPktBytes -= rxXferLen; 13836657Snate@binkert.org 13846657Snate@binkert.org rxState = rxFifoBlock; 13856657Snate@binkert.org break; 13866657Snate@binkert.org 13876657Snate@binkert.org case rxDescWrite: 13886657Snate@binkert.org if (rxDmaState != dmaIdle) 13896657Snate@binkert.org goto exit; 13906657Snate@binkert.org 13916657Snate@binkert.org assert(cmdsts & CMDSTS_OWN); 13926657Snate@binkert.org 13936657Snate@binkert.org assert(rxPacket == 0); 13946657Snate@binkert.org devIntrPost(ISR_RXOK); 13956657Snate@binkert.org 13966657Snate@binkert.org if (cmdsts & CMDSTS_INTR) 13976657Snate@binkert.org devIntrPost(ISR_RXDESC); 139810305Snilay@cs.wisc.edu 13996657Snate@binkert.org if (!rxEnable) { 14006657Snate@binkert.org DPRINTF(EthernetSM, "Halting the RX state machine\n"); 14016657Snate@binkert.org rxState = rxIdle; 140210962SBrad.Beckmann@amd.com goto exit; 140312612Sjason@lowepower.com } else 14049465Snilay@cs.wisc.edu rxState = rxAdvance; 14056657Snate@binkert.org break; 140610305Snilay@cs.wisc.edu 14076657Snate@binkert.org case rxAdvance: 14086657Snate@binkert.org if (link == 0) { 14096657Snate@binkert.org devIntrPost(ISR_RXIDLE); 14106657Snate@binkert.org rxState = rxIdle; 14116657Snate@binkert.org CRDD = true; 14126657Snate@binkert.org goto exit; 14136657Snate@binkert.org } else { 14146657Snate@binkert.org if (rxDmaState != dmaIdle) 14156657Snate@binkert.org goto exit; 14167007Snate@binkert.org rxState = rxDescRead; 14176999Snate@binkert.org regs.rxdp = link; 14187007Snate@binkert.org CRDD = false; 14197007Snate@binkert.org 14207007Snate@binkert.org rxDmaAddr = regs.rxdp & 0x3fffffff; 14217007Snate@binkert.org rxDmaData = is64bit ? (void *)&rxDesc64 : (void *)&rxDesc32; 14227007Snate@binkert.org rxDmaLen = is64bit ? sizeof(rxDesc64) : sizeof(rxDesc32); 14237007Snate@binkert.org rxDmaFree = dmaDescFree; 14246657Snate@binkert.org 14256657Snate@binkert.org if (doRxDmaRead()) 14266657Snate@binkert.org goto exit; 14276657Snate@binkert.org } 14286657Snate@binkert.org break; 14296657Snate@binkert.org 14306657Snate@binkert.org default: 14316657Snate@binkert.org panic("Invalid rxState!"); 14326657Snate@binkert.org } 14336657Snate@binkert.org 14346657Snate@binkert.org DPRINTF(EthernetSM, "entering next rxState=%s\n", 14356657Snate@binkert.org NsRxStateStrings[rxState]); 14366657Snate@binkert.org goto next; 14376657Snate@binkert.org 14386657Snate@binkert.org exit: 14396657Snate@binkert.org /** 14406657Snate@binkert.org * @todo do we want to schedule a future kick? 14416657Snate@binkert.org */ 14426657Snate@binkert.org DPRINTF(EthernetSM, "rx state machine exited rxState=%s\n", 14436657Snate@binkert.org NsRxStateStrings[rxState]); 14446657Snate@binkert.org 14456657Snate@binkert.org if (clock && !rxKickEvent.scheduled()) 14466657Snate@binkert.org schedule(rxKickEvent, rxKickTick); 14476657Snate@binkert.org} 14486657Snate@binkert.org 14496657Snate@binkert.orgvoid 14506657Snate@binkert.orgNSGigE::transmit() 14516657Snate@binkert.org{ 14526657Snate@binkert.org if (txFifo.empty()) { 14536999Snate@binkert.org DPRINTF(Ethernet, "nothing to transmit\n"); 14546657Snate@binkert.org return; 14556657Snate@binkert.org } 14567007Snate@binkert.org 14577007Snate@binkert.org DPRINTF(Ethernet, "Attempt Pkt Transmit: txFifo length=%d\n", 14586657Snate@binkert.org txFifo.size()); 14596657Snate@binkert.org if (interface->sendPacket(txFifo.front())) { 14606657Snate@binkert.org#if TRACING_ON 14616657Snate@binkert.org if (DTRACE(Ethernet)) { 14626657Snate@binkert.org IpPtr ip(txFifo.front()); 14636657Snate@binkert.org if (ip) { 14646657Snate@binkert.org DPRINTF(Ethernet, "ID is %d\n", ip->id()); 14656657Snate@binkert.org TcpPtr tcp(ip); 14666657Snate@binkert.org if (tcp) { 14676657Snate@binkert.org DPRINTF(Ethernet, 14686657Snate@binkert.org "Src Port=%d, Dest Port=%d, Seq=%d, Ack=%d\n", 14696657Snate@binkert.org tcp->sport(), tcp->dport(), tcp->seq(), 14706657Snate@binkert.org tcp->ack()); 14716657Snate@binkert.org } 14726657Snate@binkert.org } 14736657Snate@binkert.org } 14746657Snate@binkert.org#endif 14756657Snate@binkert.org 14766657Snate@binkert.org DDUMP(EthernetData, txFifo.front()->data, txFifo.front()->length); 14776657Snate@binkert.org txBytes += txFifo.front()->length; 14786657Snate@binkert.org txPackets++; 14796657Snate@binkert.org 14806657Snate@binkert.org DPRINTF(Ethernet, "Successful Xmit! now txFifoAvail is %d\n", 14816657Snate@binkert.org txFifo.avail()); 14826657Snate@binkert.org txFifo.pop(); 14836657Snate@binkert.org 14846657Snate@binkert.org /* 14856657Snate@binkert.org * normally do a writeback of the descriptor here, and ONLY 14866657Snate@binkert.org * after that is done, send this interrupt. but since our 14876657Snate@binkert.org * stuff never actually fails, just do this interrupt here, 14886657Snate@binkert.org * otherwise the code has to stray from this nice format. 14896657Snate@binkert.org * besides, it's functionally the same. 14906657Snate@binkert.org */ 14916657Snate@binkert.org devIntrPost(ISR_TXOK); 14926657Snate@binkert.org } 14936657Snate@binkert.org 14946657Snate@binkert.org if (!txFifo.empty() && !txEvent.scheduled()) { 14956657Snate@binkert.org DPRINTF(Ethernet, "reschedule transmit\n"); 14966657Snate@binkert.org schedule(txEvent, curTick + retryTime); 14976657Snate@binkert.org } 14986657Snate@binkert.org} 14996657Snate@binkert.org 15006657Snate@binkert.orgbool 15016657Snate@binkert.orgNSGigE::doTxDmaRead() 15026657Snate@binkert.org{ 15036657Snate@binkert.org assert(txDmaState == dmaIdle || txDmaState == dmaReadWaiting); 15046657Snate@binkert.org txDmaState = dmaReading; 15056657Snate@binkert.org 15066657Snate@binkert.org if (dmaPending() || getState() != Running) 15076657Snate@binkert.org txDmaState = dmaReadWaiting; 15086657Snate@binkert.org else 15096657Snate@binkert.org dmaRead(txDmaAddr, txDmaLen, &txDmaReadEvent, (uint8_t*)txDmaData); 15106657Snate@binkert.org 15116657Snate@binkert.org return true; 15126657Snate@binkert.org} 15136657Snate@binkert.org 15146657Snate@binkert.orgvoid 15156657Snate@binkert.orgNSGigE::txDmaReadDone() 15166657Snate@binkert.org{ 15176657Snate@binkert.org assert(txDmaState == dmaReading); 15186657Snate@binkert.org txDmaState = dmaIdle; 15196657Snate@binkert.org 15206657Snate@binkert.org DPRINTF(EthernetDMA, "tx dma read paddr=%#x len=%d\n", 15216657Snate@binkert.org txDmaAddr, txDmaLen); 15226657Snate@binkert.org DDUMP(EthernetDMA, txDmaData, txDmaLen); 15236657Snate@binkert.org 15246657Snate@binkert.org // If the receive state machine has a pending DMA, let it go first 15256657Snate@binkert.org if (rxDmaState == dmaReadWaiting || rxDmaState == dmaWriteWaiting) 15266657Snate@binkert.org rxKick(); 15276657Snate@binkert.org 15286657Snate@binkert.org txKick(); 15296657Snate@binkert.org} 15306657Snate@binkert.org 15316657Snate@binkert.orgbool 15326657Snate@binkert.orgNSGigE::doTxDmaWrite() 15336657Snate@binkert.org{ 15346657Snate@binkert.org assert(txDmaState == dmaIdle || txDmaState == dmaWriteWaiting); 15356657Snate@binkert.org txDmaState = dmaWriting; 15366657Snate@binkert.org 15376657Snate@binkert.org if (dmaPending() || getState() != Running) 15386657Snate@binkert.org txDmaState = dmaWriteWaiting; 15396657Snate@binkert.org else 15406657Snate@binkert.org dmaWrite(txDmaAddr, txDmaLen, &txDmaWriteEvent, (uint8_t*)txDmaData); 15416657Snate@binkert.org return true; 15426657Snate@binkert.org} 15436657Snate@binkert.org 15446657Snate@binkert.orgvoid 15456657Snate@binkert.orgNSGigE::txDmaWriteDone() 15467007Snate@binkert.org{ 15476657Snate@binkert.org assert(txDmaState == dmaWriting); 15486657Snate@binkert.org txDmaState = dmaIdle; 15496657Snate@binkert.org 15506657Snate@binkert.org DPRINTF(EthernetDMA, "tx dma write paddr=%#x len=%d\n", 15516657Snate@binkert.org txDmaAddr, txDmaLen); 15526657Snate@binkert.org DDUMP(EthernetDMA, txDmaData, txDmaLen); 15536657Snate@binkert.org 15547007Snate@binkert.org // If the receive state machine has a pending DMA, let it go first 15556657Snate@binkert.org if (rxDmaState == dmaReadWaiting || rxDmaState == dmaWriteWaiting) 15566657Snate@binkert.org rxKick(); 15576657Snate@binkert.org 15586657Snate@binkert.org txKick(); 15596657Snate@binkert.org} 15606657Snate@binkert.org 15616657Snate@binkert.orgvoid 15626657Snate@binkert.orgNSGigE::txKick() 15636657Snate@binkert.org{ 15646657Snate@binkert.org bool is64bit = (bool)(regs.config & CFGR_M64ADDR); 15656657Snate@binkert.org 15666657Snate@binkert.org DPRINTF(EthernetSM, "transmit kick txState=%s %d-bit\n", 15676657Snate@binkert.org NsTxStateStrings[txState], is64bit ? 64 : 32); 15686657Snate@binkert.org 15696657Snate@binkert.org Addr link, bufptr; 157010917Sbrandon.potter@amd.com uint32_t &cmdsts = is64bit ? txDesc64.cmdsts : txDesc32.cmdsts; 15716657Snate@binkert.org uint32_t &extsts = is64bit ? txDesc64.extsts : txDesc32.extsts; 15726657Snate@binkert.org 15736657Snate@binkert.org next: 15746657Snate@binkert.org if (clock) { 15756657Snate@binkert.org if (txKickTick > curTick) { 15766657Snate@binkert.org DPRINTF(EthernetSM, "transmit kick exiting, can't run till %d\n", 15776657Snate@binkert.org txKickTick); 15786657Snate@binkert.org goto exit; 15796657Snate@binkert.org } 15806657Snate@binkert.org 15816657Snate@binkert.org // Go to the next state machine clock tick. 15826657Snate@binkert.org txKickTick = curTick + ticks(1); 15836657Snate@binkert.org } 15846657Snate@binkert.org 15856657Snate@binkert.org switch(txDmaState) { 15866657Snate@binkert.org case dmaReadWaiting: 15876657Snate@binkert.org if (doTxDmaRead()) 15886657Snate@binkert.org goto exit; 15896657Snate@binkert.org break; 15906657Snate@binkert.org case dmaWriteWaiting: 15916657Snate@binkert.org if (doTxDmaWrite()) 15926657Snate@binkert.org goto exit; 1593 break; 1594 default: 1595 break; 1596 } 1597 1598 link = is64bit ? (Addr)txDesc64.link : (Addr)txDesc32.link; 1599 bufptr = is64bit ? (Addr)txDesc64.bufptr : (Addr)txDesc32.bufptr; 1600 switch (txState) { 1601 case txIdle: 1602 if (!txEnable) { 1603 DPRINTF(EthernetSM, "Transmit disabled. Nothing to do.\n"); 1604 goto exit; 1605 } 1606 1607 if (CTDD) { 1608 txState = txDescRefr; 1609 1610 txDmaAddr = regs.txdp & 0x3fffffff; 1611 txDmaData = 1612 is64bit ? (void *)&txDesc64.link : (void *)&txDesc32.link; 1613 txDmaLen = is64bit ? sizeof(txDesc64.link) : sizeof(txDesc32.link); 1614 txDmaFree = dmaDescFree; 1615 1616 descDmaReads++; 1617 descDmaRdBytes += txDmaLen; 1618 1619 if (doTxDmaRead()) 1620 goto exit; 1621 1622 } else { 1623 txState = txDescRead; 1624 1625 txDmaAddr = regs.txdp & 0x3fffffff; 1626 txDmaData = is64bit ? (void *)&txDesc64 : (void *)&txDesc32; 1627 txDmaLen = is64bit ? sizeof(txDesc64) : sizeof(txDesc32); 1628 txDmaFree = dmaDescFree; 1629 1630 descDmaReads++; 1631 descDmaRdBytes += txDmaLen; 1632 1633 if (doTxDmaRead()) 1634 goto exit; 1635 } 1636 break; 1637 1638 case txDescRefr: 1639 if (txDmaState != dmaIdle) 1640 goto exit; 1641 1642 txState = txAdvance; 1643 break; 1644 1645 case txDescRead: 1646 if (txDmaState != dmaIdle) 1647 goto exit; 1648 1649 DPRINTF(EthernetDesc, "txDesc: addr=%08x read descriptor\n", 1650 regs.txdp & 0x3fffffff); 1651 DPRINTF(EthernetDesc, 1652 "txDesc: link=%#x bufptr=%#x cmdsts=%#08x extsts=%#08x\n", 1653 link, bufptr, cmdsts, extsts); 1654 1655 if (cmdsts & CMDSTS_OWN) { 1656 txState = txFifoBlock; 1657 txFragPtr = bufptr; 1658 txDescCnt = cmdsts & CMDSTS_LEN_MASK; 1659 } else { 1660 devIntrPost(ISR_TXIDLE); 1661 txState = txIdle; 1662 goto exit; 1663 } 1664 break; 1665 1666 case txFifoBlock: 1667 if (!txPacket) { 1668 DPRINTF(EthernetSM, "****starting the tx of a new packet****\n"); 1669 txPacket = new EthPacketData(16384); 1670 txPacketBufPtr = txPacket->data; 1671 } 1672 1673 if (txDescCnt == 0) { 1674 DPRINTF(EthernetSM, "the txDescCnt == 0, done with descriptor\n"); 1675 if (cmdsts & CMDSTS_MORE) { 1676 DPRINTF(EthernetSM, "there are more descriptors to come\n"); 1677 txState = txDescWrite; 1678 1679 cmdsts &= ~CMDSTS_OWN; 1680 1681 txDmaAddr = regs.txdp & 0x3fffffff; 1682 txDmaData = &cmdsts; 1683 if (is64bit) { 1684 txDmaAddr += offsetof(ns_desc64, cmdsts); 1685 txDmaLen = sizeof(txDesc64.cmdsts); 1686 } else { 1687 txDmaAddr += offsetof(ns_desc32, cmdsts); 1688 txDmaLen = sizeof(txDesc32.cmdsts); 1689 } 1690 txDmaFree = dmaDescFree; 1691 1692 if (doTxDmaWrite()) 1693 goto exit; 1694 1695 } else { /* this packet is totally done */ 1696 DPRINTF(EthernetSM, "This packet is done, let's wrap it up\n"); 1697 /* deal with the the packet that just finished */ 1698 if ((regs.vtcr & VTCR_PPCHK) && extstsEnable) { 1699 IpPtr ip(txPacket); 1700 if (extsts & EXTSTS_UDPPKT) { 1701 UdpPtr udp(ip); 1702 if (udp) { 1703 udp->sum(0); 1704 udp->sum(cksum(udp)); 1705 txUdpChecksums++; 1706 } else { 1707 debug_break(); 1708 warn_once("UDPPKT set, but not UDP!\n"); 1709 } 1710 } else if (extsts & EXTSTS_TCPPKT) { 1711 TcpPtr tcp(ip); 1712 if (tcp) { 1713 tcp->sum(0); 1714 tcp->sum(cksum(tcp)); 1715 txTcpChecksums++; 1716 } else { 1717 debug_break(); 1718 warn_once("TCPPKT set, but not UDP!\n"); 1719 } 1720 } 1721 if (extsts & EXTSTS_IPPKT) { 1722 if (ip) { 1723 ip->sum(0); 1724 ip->sum(cksum(ip)); 1725 txIpChecksums++; 1726 } else { 1727 debug_break(); 1728 warn_once("IPPKT set, but not UDP!\n"); 1729 } 1730 } 1731 } 1732 1733 txPacket->length = txPacketBufPtr - txPacket->data; 1734 // this is just because the receive can't handle a 1735 // packet bigger want to make sure 1736 if (txPacket->length > 1514) 1737 panic("transmit packet too large, %s > 1514\n", 1738 txPacket->length); 1739 1740#ifndef NDEBUG 1741 bool success = 1742#endif 1743 txFifo.push(txPacket); 1744 assert(success); 1745 1746 /* 1747 * this following section is not tqo spec, but 1748 * functionally shouldn't be any different. normally, 1749 * the chip will wait til the transmit has occurred 1750 * before writing back the descriptor because it has 1751 * to wait to see that it was successfully transmitted 1752 * to decide whether to set CMDSTS_OK or not. 1753 * however, in the simulator since it is always 1754 * successfully transmitted, and writing it exactly to 1755 * spec would complicate the code, we just do it here 1756 */ 1757 1758 cmdsts &= ~CMDSTS_OWN; 1759 cmdsts |= CMDSTS_OK; 1760 1761 DPRINTF(EthernetDesc, 1762 "txDesc writeback: cmdsts=%08x extsts=%08x\n", 1763 cmdsts, extsts); 1764 1765 txDmaFree = dmaDescFree; 1766 txDmaAddr = regs.txdp & 0x3fffffff; 1767 txDmaData = &cmdsts; 1768 if (is64bit) { 1769 txDmaAddr += offsetof(ns_desc64, cmdsts); 1770 txDmaLen = 1771 sizeof(txDesc64.cmdsts) + sizeof(txDesc64.extsts); 1772 } else { 1773 txDmaAddr += offsetof(ns_desc32, cmdsts); 1774 txDmaLen = 1775 sizeof(txDesc32.cmdsts) + sizeof(txDesc32.extsts); 1776 } 1777 1778 descDmaWrites++; 1779 descDmaWrBytes += txDmaLen; 1780 1781 transmit(); 1782 txPacket = 0; 1783 1784 if (!txEnable) { 1785 DPRINTF(EthernetSM, "halting TX state machine\n"); 1786 txState = txIdle; 1787 goto exit; 1788 } else 1789 txState = txAdvance; 1790 1791 if (doTxDmaWrite()) 1792 goto exit; 1793 } 1794 } else { 1795 DPRINTF(EthernetSM, "this descriptor isn't done yet\n"); 1796 if (!txFifo.full()) { 1797 txState = txFragRead; 1798 1799 /* 1800 * The number of bytes transferred is either whatever 1801 * is left in the descriptor (txDescCnt), or if there 1802 * is not enough room in the fifo, just whatever room 1803 * is left in the fifo 1804 */ 1805 txXferLen = min<uint32_t>(txDescCnt, txFifo.avail()); 1806 1807 txDmaAddr = txFragPtr & 0x3fffffff; 1808 txDmaData = txPacketBufPtr; 1809 txDmaLen = txXferLen; 1810 txDmaFree = dmaDataFree; 1811 1812 if (doTxDmaRead()) 1813 goto exit; 1814 } else { 1815 txState = txFifoBlock; 1816 transmit(); 1817 1818 goto exit; 1819 } 1820 1821 } 1822 break; 1823 1824 case txFragRead: 1825 if (txDmaState != dmaIdle) 1826 goto exit; 1827 1828 txPacketBufPtr += txXferLen; 1829 txFragPtr += txXferLen; 1830 txDescCnt -= txXferLen; 1831 txFifo.reserve(txXferLen); 1832 1833 txState = txFifoBlock; 1834 break; 1835 1836 case txDescWrite: 1837 if (txDmaState != dmaIdle) 1838 goto exit; 1839 1840 if (cmdsts & CMDSTS_INTR) 1841 devIntrPost(ISR_TXDESC); 1842 1843 if (!txEnable) { 1844 DPRINTF(EthernetSM, "halting TX state machine\n"); 1845 txState = txIdle; 1846 goto exit; 1847 } else 1848 txState = txAdvance; 1849 break; 1850 1851 case txAdvance: 1852 if (link == 0) { 1853 devIntrPost(ISR_TXIDLE); 1854 txState = txIdle; 1855 goto exit; 1856 } else { 1857 if (txDmaState != dmaIdle) 1858 goto exit; 1859 txState = txDescRead; 1860 regs.txdp = link; 1861 CTDD = false; 1862 1863 txDmaAddr = link & 0x3fffffff; 1864 txDmaData = is64bit ? (void *)&txDesc64 : (void *)&txDesc32; 1865 txDmaLen = is64bit ? sizeof(txDesc64) : sizeof(txDesc32); 1866 txDmaFree = dmaDescFree; 1867 1868 if (doTxDmaRead()) 1869 goto exit; 1870 } 1871 break; 1872 1873 default: 1874 panic("invalid state"); 1875 } 1876 1877 DPRINTF(EthernetSM, "entering next txState=%s\n", 1878 NsTxStateStrings[txState]); 1879 goto next; 1880 1881 exit: 1882 /** 1883 * @todo do we want to schedule a future kick? 1884 */ 1885 DPRINTF(EthernetSM, "tx state machine exited txState=%s\n", 1886 NsTxStateStrings[txState]); 1887 1888 if (clock && !txKickEvent.scheduled()) 1889 schedule(txKickEvent, txKickTick); 1890} 1891 1892/** 1893 * Advance the EEPROM state machine 1894 * Called on rising edge of EEPROM clock bit in MEAR 1895 */ 1896void 1897NSGigE::eepromKick() 1898{ 1899 switch (eepromState) { 1900 1901 case eepromStart: 1902 1903 // Wait for start bit 1904 if (regs.mear & MEAR_EEDI) { 1905 // Set up to get 2 opcode bits 1906 eepromState = eepromGetOpcode; 1907 eepromBitsToRx = 2; 1908 eepromOpcode = 0; 1909 } 1910 break; 1911 1912 case eepromGetOpcode: 1913 eepromOpcode <<= 1; 1914 eepromOpcode += (regs.mear & MEAR_EEDI) ? 1 : 0; 1915 --eepromBitsToRx; 1916 1917 // Done getting opcode 1918 if (eepromBitsToRx == 0) { 1919 if (eepromOpcode != EEPROM_READ) 1920 panic("only EEPROM reads are implemented!"); 1921 1922 // Set up to get address 1923 eepromState = eepromGetAddress; 1924 eepromBitsToRx = 6; 1925 eepromAddress = 0; 1926 } 1927 break; 1928 1929 case eepromGetAddress: 1930 eepromAddress <<= 1; 1931 eepromAddress += (regs.mear & MEAR_EEDI) ? 1 : 0; 1932 --eepromBitsToRx; 1933 1934 // Done getting address 1935 if (eepromBitsToRx == 0) { 1936 1937 if (eepromAddress >= EEPROM_SIZE) 1938 panic("EEPROM read access out of range!"); 1939 1940 switch (eepromAddress) { 1941 1942 case EEPROM_PMATCH2_ADDR: 1943 eepromData = rom.perfectMatch[5]; 1944 eepromData <<= 8; 1945 eepromData += rom.perfectMatch[4]; 1946 break; 1947 1948 case EEPROM_PMATCH1_ADDR: 1949 eepromData = rom.perfectMatch[3]; 1950 eepromData <<= 8; 1951 eepromData += rom.perfectMatch[2]; 1952 break; 1953 1954 case EEPROM_PMATCH0_ADDR: 1955 eepromData = rom.perfectMatch[1]; 1956 eepromData <<= 8; 1957 eepromData += rom.perfectMatch[0]; 1958 break; 1959 1960 default: 1961 panic("FreeBSD driver only uses EEPROM to read PMATCH!"); 1962 } 1963 // Set up to read data 1964 eepromState = eepromRead; 1965 eepromBitsToRx = 16; 1966 1967 // Clear data in bit 1968 regs.mear &= ~MEAR_EEDI; 1969 } 1970 break; 1971 1972 case eepromRead: 1973 // Clear Data Out bit 1974 regs.mear &= ~MEAR_EEDO; 1975 // Set bit to value of current EEPROM bit 1976 regs.mear |= (eepromData & 0x8000) ? MEAR_EEDO : 0x0; 1977 1978 eepromData <<= 1; 1979 --eepromBitsToRx; 1980 1981 // All done 1982 if (eepromBitsToRx == 0) { 1983 eepromState = eepromStart; 1984 } 1985 break; 1986 1987 default: 1988 panic("invalid EEPROM state"); 1989 } 1990 1991} 1992 1993void 1994NSGigE::transferDone() 1995{ 1996 if (txFifo.empty()) { 1997 DPRINTF(Ethernet, "transfer complete: txFifo empty...nothing to do\n"); 1998 return; 1999 } 2000 2001 DPRINTF(Ethernet, "transfer complete: data in txFifo...schedule xmit\n"); 2002 2003 reschedule(txEvent, curTick + ticks(1), true); 2004} 2005 2006bool 2007NSGigE::rxFilter(const EthPacketPtr &packet) 2008{ 2009 EthPtr eth = packet; 2010 bool drop = true; 2011 string type; 2012 2013 const EthAddr &dst = eth->dst(); 2014 if (dst.unicast()) { 2015 // If we're accepting all unicast addresses 2016 if (acceptUnicast) 2017 drop = false; 2018 2019 // If we make a perfect match 2020 if (acceptPerfect && dst == rom.perfectMatch) 2021 drop = false; 2022 2023 if (acceptArp && eth->type() == ETH_TYPE_ARP) 2024 drop = false; 2025 2026 } else if (dst.broadcast()) { 2027 // if we're accepting broadcasts 2028 if (acceptBroadcast) 2029 drop = false; 2030 2031 } else if (dst.multicast()) { 2032 // if we're accepting all multicasts 2033 if (acceptMulticast) 2034 drop = false; 2035 2036 // Multicast hashing faked - all packets accepted 2037 if (multicastHashEnable) 2038 drop = false; 2039 } 2040 2041 if (drop) { 2042 DPRINTF(Ethernet, "rxFilter drop\n"); 2043 DDUMP(EthernetData, packet->data, packet->length); 2044 } 2045 2046 return drop; 2047} 2048 2049bool 2050NSGigE::recvPacket(EthPacketPtr packet) 2051{ 2052 rxBytes += packet->length; 2053 rxPackets++; 2054 2055 DPRINTF(Ethernet, "Receiving packet from wire, rxFifoAvail=%d\n", 2056 rxFifo.avail()); 2057 2058 if (!rxEnable) { 2059 DPRINTF(Ethernet, "receive disabled...packet dropped\n"); 2060 return true; 2061 } 2062 2063 if (!rxFilterEnable) { 2064 DPRINTF(Ethernet, 2065 "receive packet filtering disabled . . . packet dropped\n"); 2066 return true; 2067 } 2068 2069 if (rxFilter(packet)) { 2070 DPRINTF(Ethernet, "packet filtered...dropped\n"); 2071 return true; 2072 } 2073 2074 if (rxFifo.avail() < packet->length) { 2075#if TRACING_ON 2076 IpPtr ip(packet); 2077 TcpPtr tcp(ip); 2078 if (ip) { 2079 DPRINTF(Ethernet, 2080 "packet won't fit in receive buffer...pkt ID %d dropped\n", 2081 ip->id()); 2082 if (tcp) { 2083 DPRINTF(Ethernet, "Seq=%d\n", tcp->seq()); 2084 } 2085 } 2086#endif 2087 droppedPackets++; 2088 devIntrPost(ISR_RXORN); 2089 return false; 2090 } 2091 2092 rxFifo.push(packet); 2093 2094 rxKick(); 2095 return true; 2096} 2097 2098 2099void 2100NSGigE::resume() 2101{ 2102 SimObject::resume(); 2103 2104 // During drain we could have left the state machines in a waiting state and 2105 // they wouldn't get out until some other event occured to kick them. 2106 // This way they'll get out immediately 2107 txKick(); 2108 rxKick(); 2109} 2110 2111 2112//===================================================================== 2113// 2114// 2115void 2116NSGigE::serialize(ostream &os) 2117{ 2118 // Serialize the PciDev base class 2119 PciDev::serialize(os); 2120 2121 /* 2122 * Finalize any DMA events now. 2123 */ 2124 // @todo will mem system save pending dma? 2125 2126 /* 2127 * Serialize the device registers 2128 */ 2129 SERIALIZE_SCALAR(regs.command); 2130 SERIALIZE_SCALAR(regs.config); 2131 SERIALIZE_SCALAR(regs.mear); 2132 SERIALIZE_SCALAR(regs.ptscr); 2133 SERIALIZE_SCALAR(regs.isr); 2134 SERIALIZE_SCALAR(regs.imr); 2135 SERIALIZE_SCALAR(regs.ier); 2136 SERIALIZE_SCALAR(regs.ihr); 2137 SERIALIZE_SCALAR(regs.txdp); 2138 SERIALIZE_SCALAR(regs.txdp_hi); 2139 SERIALIZE_SCALAR(regs.txcfg); 2140 SERIALIZE_SCALAR(regs.gpior); 2141 SERIALIZE_SCALAR(regs.rxdp); 2142 SERIALIZE_SCALAR(regs.rxdp_hi); 2143 SERIALIZE_SCALAR(regs.rxcfg); 2144 SERIALIZE_SCALAR(regs.pqcr); 2145 SERIALIZE_SCALAR(regs.wcsr); 2146 SERIALIZE_SCALAR(regs.pcr); 2147 SERIALIZE_SCALAR(regs.rfcr); 2148 SERIALIZE_SCALAR(regs.rfdr); 2149 SERIALIZE_SCALAR(regs.brar); 2150 SERIALIZE_SCALAR(regs.brdr); 2151 SERIALIZE_SCALAR(regs.srr); 2152 SERIALIZE_SCALAR(regs.mibc); 2153 SERIALIZE_SCALAR(regs.vrcr); 2154 SERIALIZE_SCALAR(regs.vtcr); 2155 SERIALIZE_SCALAR(regs.vdr); 2156 SERIALIZE_SCALAR(regs.ccsr); 2157 SERIALIZE_SCALAR(regs.tbicr); 2158 SERIALIZE_SCALAR(regs.tbisr); 2159 SERIALIZE_SCALAR(regs.tanar); 2160 SERIALIZE_SCALAR(regs.tanlpar); 2161 SERIALIZE_SCALAR(regs.taner); 2162 SERIALIZE_SCALAR(regs.tesr); 2163 2164 SERIALIZE_ARRAY(rom.perfectMatch, ETH_ADDR_LEN); 2165 SERIALIZE_ARRAY(rom.filterHash, FHASH_SIZE); 2166 2167 SERIALIZE_SCALAR(ioEnable); 2168 2169 /* 2170 * Serialize the data Fifos 2171 */ 2172 rxFifo.serialize("rxFifo", os); 2173 txFifo.serialize("txFifo", os); 2174 2175 /* 2176 * Serialize the various helper variables 2177 */ 2178 bool txPacketExists = txPacket; 2179 SERIALIZE_SCALAR(txPacketExists); 2180 if (txPacketExists) { 2181 txPacket->length = txPacketBufPtr - txPacket->data; 2182 txPacket->serialize("txPacket", os); 2183 uint32_t txPktBufPtr = (uint32_t) (txPacketBufPtr - txPacket->data); 2184 SERIALIZE_SCALAR(txPktBufPtr); 2185 } 2186 2187 bool rxPacketExists = rxPacket; 2188 SERIALIZE_SCALAR(rxPacketExists); 2189 if (rxPacketExists) { 2190 rxPacket->serialize("rxPacket", os); 2191 uint32_t rxPktBufPtr = (uint32_t) (rxPacketBufPtr - rxPacket->data); 2192 SERIALIZE_SCALAR(rxPktBufPtr); 2193 } 2194 2195 SERIALIZE_SCALAR(txXferLen); 2196 SERIALIZE_SCALAR(rxXferLen); 2197 2198 /* 2199 * Serialize Cached Descriptors 2200 */ 2201 SERIALIZE_SCALAR(rxDesc64.link); 2202 SERIALIZE_SCALAR(rxDesc64.bufptr); 2203 SERIALIZE_SCALAR(rxDesc64.cmdsts); 2204 SERIALIZE_SCALAR(rxDesc64.extsts); 2205 SERIALIZE_SCALAR(txDesc64.link); 2206 SERIALIZE_SCALAR(txDesc64.bufptr); 2207 SERIALIZE_SCALAR(txDesc64.cmdsts); 2208 SERIALIZE_SCALAR(txDesc64.extsts); 2209 SERIALIZE_SCALAR(rxDesc32.link); 2210 SERIALIZE_SCALAR(rxDesc32.bufptr); 2211 SERIALIZE_SCALAR(rxDesc32.cmdsts); 2212 SERIALIZE_SCALAR(rxDesc32.extsts); 2213 SERIALIZE_SCALAR(txDesc32.link); 2214 SERIALIZE_SCALAR(txDesc32.bufptr); 2215 SERIALIZE_SCALAR(txDesc32.cmdsts); 2216 SERIALIZE_SCALAR(txDesc32.extsts); 2217 SERIALIZE_SCALAR(extstsEnable); 2218 2219 /* 2220 * Serialize tx state machine 2221 */ 2222 int txState = this->txState; 2223 SERIALIZE_SCALAR(txState); 2224 SERIALIZE_SCALAR(txEnable); 2225 SERIALIZE_SCALAR(CTDD); 2226 SERIALIZE_SCALAR(txFragPtr); 2227 SERIALIZE_SCALAR(txDescCnt); 2228 int txDmaState = this->txDmaState; 2229 SERIALIZE_SCALAR(txDmaState); 2230 SERIALIZE_SCALAR(txKickTick); 2231 2232 /* 2233 * Serialize rx state machine 2234 */ 2235 int rxState = this->rxState; 2236 SERIALIZE_SCALAR(rxState); 2237 SERIALIZE_SCALAR(rxEnable); 2238 SERIALIZE_SCALAR(CRDD); 2239 SERIALIZE_SCALAR(rxPktBytes); 2240 SERIALIZE_SCALAR(rxFragPtr); 2241 SERIALIZE_SCALAR(rxDescCnt); 2242 int rxDmaState = this->rxDmaState; 2243 SERIALIZE_SCALAR(rxDmaState); 2244 SERIALIZE_SCALAR(rxKickTick); 2245 2246 /* 2247 * Serialize EEPROM state machine 2248 */ 2249 int eepromState = this->eepromState; 2250 SERIALIZE_SCALAR(eepromState); 2251 SERIALIZE_SCALAR(eepromClk); 2252 SERIALIZE_SCALAR(eepromBitsToRx); 2253 SERIALIZE_SCALAR(eepromOpcode); 2254 SERIALIZE_SCALAR(eepromAddress); 2255 SERIALIZE_SCALAR(eepromData); 2256 2257 /* 2258 * If there's a pending transmit, store the time so we can 2259 * reschedule it later 2260 */ 2261 Tick transmitTick = txEvent.scheduled() ? txEvent.when() - curTick : 0; 2262 SERIALIZE_SCALAR(transmitTick); 2263 2264 /* 2265 * receive address filter settings 2266 */ 2267 SERIALIZE_SCALAR(rxFilterEnable); 2268 SERIALIZE_SCALAR(acceptBroadcast); 2269 SERIALIZE_SCALAR(acceptMulticast); 2270 SERIALIZE_SCALAR(acceptUnicast); 2271 SERIALIZE_SCALAR(acceptPerfect); 2272 SERIALIZE_SCALAR(acceptArp); 2273 SERIALIZE_SCALAR(multicastHashEnable); 2274 2275 /* 2276 * Keep track of pending interrupt status. 2277 */ 2278 SERIALIZE_SCALAR(intrTick); 2279 SERIALIZE_SCALAR(cpuPendingIntr); 2280 Tick intrEventTick = 0; 2281 if (intrEvent) 2282 intrEventTick = intrEvent->when(); 2283 SERIALIZE_SCALAR(intrEventTick); 2284 2285} 2286 2287void 2288NSGigE::unserialize(Checkpoint *cp, const std::string §ion) 2289{ 2290 // Unserialize the PciDev base class 2291 PciDev::unserialize(cp, section); 2292 2293 UNSERIALIZE_SCALAR(regs.command); 2294 UNSERIALIZE_SCALAR(regs.config); 2295 UNSERIALIZE_SCALAR(regs.mear); 2296 UNSERIALIZE_SCALAR(regs.ptscr); 2297 UNSERIALIZE_SCALAR(regs.isr); 2298 UNSERIALIZE_SCALAR(regs.imr); 2299 UNSERIALIZE_SCALAR(regs.ier); 2300 UNSERIALIZE_SCALAR(regs.ihr); 2301 UNSERIALIZE_SCALAR(regs.txdp); 2302 UNSERIALIZE_SCALAR(regs.txdp_hi); 2303 UNSERIALIZE_SCALAR(regs.txcfg); 2304 UNSERIALIZE_SCALAR(regs.gpior); 2305 UNSERIALIZE_SCALAR(regs.rxdp); 2306 UNSERIALIZE_SCALAR(regs.rxdp_hi); 2307 UNSERIALIZE_SCALAR(regs.rxcfg); 2308 UNSERIALIZE_SCALAR(regs.pqcr); 2309 UNSERIALIZE_SCALAR(regs.wcsr); 2310 UNSERIALIZE_SCALAR(regs.pcr); 2311 UNSERIALIZE_SCALAR(regs.rfcr); 2312 UNSERIALIZE_SCALAR(regs.rfdr); 2313 UNSERIALIZE_SCALAR(regs.brar); 2314 UNSERIALIZE_SCALAR(regs.brdr); 2315 UNSERIALIZE_SCALAR(regs.srr); 2316 UNSERIALIZE_SCALAR(regs.mibc); 2317 UNSERIALIZE_SCALAR(regs.vrcr); 2318 UNSERIALIZE_SCALAR(regs.vtcr); 2319 UNSERIALIZE_SCALAR(regs.vdr); 2320 UNSERIALIZE_SCALAR(regs.ccsr); 2321 UNSERIALIZE_SCALAR(regs.tbicr); 2322 UNSERIALIZE_SCALAR(regs.tbisr); 2323 UNSERIALIZE_SCALAR(regs.tanar); 2324 UNSERIALIZE_SCALAR(regs.tanlpar); 2325 UNSERIALIZE_SCALAR(regs.taner); 2326 UNSERIALIZE_SCALAR(regs.tesr); 2327 2328 UNSERIALIZE_ARRAY(rom.perfectMatch, ETH_ADDR_LEN); 2329 UNSERIALIZE_ARRAY(rom.filterHash, FHASH_SIZE); 2330 2331 UNSERIALIZE_SCALAR(ioEnable); 2332 2333 /* 2334 * unserialize the data fifos 2335 */ 2336 rxFifo.unserialize("rxFifo", cp, section); 2337 txFifo.unserialize("txFifo", cp, section); 2338 2339 /* 2340 * unserialize the various helper variables 2341 */ 2342 bool txPacketExists; 2343 UNSERIALIZE_SCALAR(txPacketExists); 2344 if (txPacketExists) { 2345 txPacket = new EthPacketData(16384); 2346 txPacket->unserialize("txPacket", cp, section); 2347 uint32_t txPktBufPtr; 2348 UNSERIALIZE_SCALAR(txPktBufPtr); 2349 txPacketBufPtr = (uint8_t *) txPacket->data + txPktBufPtr; 2350 } else 2351 txPacket = 0; 2352 2353 bool rxPacketExists; 2354 UNSERIALIZE_SCALAR(rxPacketExists); 2355 rxPacket = 0; 2356 if (rxPacketExists) { 2357 rxPacket = new EthPacketData(16384); 2358 rxPacket->unserialize("rxPacket", cp, section); 2359 uint32_t rxPktBufPtr; 2360 UNSERIALIZE_SCALAR(rxPktBufPtr); 2361 rxPacketBufPtr = (uint8_t *) rxPacket->data + rxPktBufPtr; 2362 } else 2363 rxPacket = 0; 2364 2365 UNSERIALIZE_SCALAR(txXferLen); 2366 UNSERIALIZE_SCALAR(rxXferLen); 2367 2368 /* 2369 * Unserialize Cached Descriptors 2370 */ 2371 UNSERIALIZE_SCALAR(rxDesc64.link); 2372 UNSERIALIZE_SCALAR(rxDesc64.bufptr); 2373 UNSERIALIZE_SCALAR(rxDesc64.cmdsts); 2374 UNSERIALIZE_SCALAR(rxDesc64.extsts); 2375 UNSERIALIZE_SCALAR(txDesc64.link); 2376 UNSERIALIZE_SCALAR(txDesc64.bufptr); 2377 UNSERIALIZE_SCALAR(txDesc64.cmdsts); 2378 UNSERIALIZE_SCALAR(txDesc64.extsts); 2379 UNSERIALIZE_SCALAR(rxDesc32.link); 2380 UNSERIALIZE_SCALAR(rxDesc32.bufptr); 2381 UNSERIALIZE_SCALAR(rxDesc32.cmdsts); 2382 UNSERIALIZE_SCALAR(rxDesc32.extsts); 2383 UNSERIALIZE_SCALAR(txDesc32.link); 2384 UNSERIALIZE_SCALAR(txDesc32.bufptr); 2385 UNSERIALIZE_SCALAR(txDesc32.cmdsts); 2386 UNSERIALIZE_SCALAR(txDesc32.extsts); 2387 UNSERIALIZE_SCALAR(extstsEnable); 2388 2389 /* 2390 * unserialize tx state machine 2391 */ 2392 int txState; 2393 UNSERIALIZE_SCALAR(txState); 2394 this->txState = (TxState) txState; 2395 UNSERIALIZE_SCALAR(txEnable); 2396 UNSERIALIZE_SCALAR(CTDD); 2397 UNSERIALIZE_SCALAR(txFragPtr); 2398 UNSERIALIZE_SCALAR(txDescCnt); 2399 int txDmaState; 2400 UNSERIALIZE_SCALAR(txDmaState); 2401 this->txDmaState = (DmaState) txDmaState; 2402 UNSERIALIZE_SCALAR(txKickTick); 2403 if (txKickTick) 2404 schedule(txKickEvent, txKickTick); 2405 2406 /* 2407 * unserialize rx state machine 2408 */ 2409 int rxState; 2410 UNSERIALIZE_SCALAR(rxState); 2411 this->rxState = (RxState) rxState; 2412 UNSERIALIZE_SCALAR(rxEnable); 2413 UNSERIALIZE_SCALAR(CRDD); 2414 UNSERIALIZE_SCALAR(rxPktBytes); 2415 UNSERIALIZE_SCALAR(rxFragPtr); 2416 UNSERIALIZE_SCALAR(rxDescCnt); 2417 int rxDmaState; 2418 UNSERIALIZE_SCALAR(rxDmaState); 2419 this->rxDmaState = (DmaState) rxDmaState; 2420 UNSERIALIZE_SCALAR(rxKickTick); 2421 if (rxKickTick) 2422 schedule(rxKickEvent, rxKickTick); 2423 2424 /* 2425 * Unserialize EEPROM state machine 2426 */ 2427 int eepromState; 2428 UNSERIALIZE_SCALAR(eepromState); 2429 this->eepromState = (EEPROMState) eepromState; 2430 UNSERIALIZE_SCALAR(eepromClk); 2431 UNSERIALIZE_SCALAR(eepromBitsToRx); 2432 UNSERIALIZE_SCALAR(eepromOpcode); 2433 UNSERIALIZE_SCALAR(eepromAddress); 2434 UNSERIALIZE_SCALAR(eepromData); 2435 2436 /* 2437 * If there's a pending transmit, reschedule it now 2438 */ 2439 Tick transmitTick; 2440 UNSERIALIZE_SCALAR(transmitTick); 2441 if (transmitTick) 2442 schedule(txEvent, curTick + transmitTick); 2443 2444 /* 2445 * unserialize receive address filter settings 2446 */ 2447 UNSERIALIZE_SCALAR(rxFilterEnable); 2448 UNSERIALIZE_SCALAR(acceptBroadcast); 2449 UNSERIALIZE_SCALAR(acceptMulticast); 2450 UNSERIALIZE_SCALAR(acceptUnicast); 2451 UNSERIALIZE_SCALAR(acceptPerfect); 2452 UNSERIALIZE_SCALAR(acceptArp); 2453 UNSERIALIZE_SCALAR(multicastHashEnable); 2454 2455 /* 2456 * Keep track of pending interrupt status. 2457 */ 2458 UNSERIALIZE_SCALAR(intrTick); 2459 UNSERIALIZE_SCALAR(cpuPendingIntr); 2460 Tick intrEventTick; 2461 UNSERIALIZE_SCALAR(intrEventTick); 2462 if (intrEventTick) { 2463 intrEvent = new IntrEvent(this, true); 2464 schedule(intrEvent, intrEventTick); 2465 } 2466} 2467 2468NSGigE * 2469NSGigEParams::create() 2470{ 2471 return new NSGigE(this); 2472} 2473