ns_gige.cc revision 5882
19793Sakash.bagdia@arm.com/* 27586SAli.Saidi@arm.com * Copyright (c) 2004-2005 The Regents of The University of Michigan 37586SAli.Saidi@arm.com * All rights reserved. 47586SAli.Saidi@arm.com * 57586SAli.Saidi@arm.com * Redistribution and use in source and binary forms, with or without 67586SAli.Saidi@arm.com * modification, are permitted provided that the following conditions are 77586SAli.Saidi@arm.com * met: redistributions of source code must retain the above copyright 87586SAli.Saidi@arm.com * notice, this list of conditions and the following disclaimer; 97586SAli.Saidi@arm.com * redistributions in binary form must reproduce the above copyright 107586SAli.Saidi@arm.com * notice, this list of conditions and the following disclaimer in the 117586SAli.Saidi@arm.com * documentation and/or other materials provided with the distribution; 127586SAli.Saidi@arm.com * neither the name of the copyright holders nor the names of its 1310118Snilay@cs.wisc.edu * contributors may be used to endorse or promote products derived from 1410118Snilay@cs.wisc.edu * this software without specific prior written permission. 153970Sgblack@eecs.umich.edu * 163005Sstever@eecs.umich.edu * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 173005Sstever@eecs.umich.edu * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 183005Sstever@eecs.umich.edu * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR 193005Sstever@eecs.umich.edu * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT 203005Sstever@eecs.umich.edu * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 213005Sstever@eecs.umich.edu * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT 223005Sstever@eecs.umich.edu * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 233005Sstever@eecs.umich.edu * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 243005Sstever@eecs.umich.edu * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 253005Sstever@eecs.umich.edu * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 263005Sstever@eecs.umich.edu * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 273005Sstever@eecs.umich.edu * 283005Sstever@eecs.umich.edu * Authors: Nathan Binkert 293005Sstever@eecs.umich.edu * Lisa Hsu 303005Sstever@eecs.umich.edu */ 313005Sstever@eecs.umich.edu 323005Sstever@eecs.umich.edu/** @file 333005Sstever@eecs.umich.edu * Device module for modelling the National Semiconductor 343005Sstever@eecs.umich.edu * DP83820 ethernet controller. Does not support priority queueing 353005Sstever@eecs.umich.edu */ 363005Sstever@eecs.umich.edu#include <deque> 373005Sstever@eecs.umich.edu#include <string> 383005Sstever@eecs.umich.edu 393005Sstever@eecs.umich.edu#include "base/debug.hh" 403005Sstever@eecs.umich.edu#include "base/inet.hh" 413005Sstever@eecs.umich.edu#include "cpu/thread_context.hh" 4210118Snilay@cs.wisc.edu#include "dev/etherlink.hh" 433005Sstever@eecs.umich.edu#include "dev/ns_gige.hh" 446654Snate@binkert.org#include "dev/pciconfigall.hh" 456654Snate@binkert.org#include "mem/packet.hh" 462889SN/A#include "mem/packet_access.hh" 472710SN/A#include "params/NSGigE.hh" 486654Snate@binkert.org#include "sim/host.hh" 496654Snate@binkert.org#include "sim/system.hh" 506654Snate@binkert.org 515457Ssaidi@eecs.umich.educonst char *NsRxStateStrings[] = 526654Snate@binkert.org{ 5310118Snilay@cs.wisc.edu "rxIdle", 5410118Snilay@cs.wisc.edu "rxDescRefr", 5510118Snilay@cs.wisc.edu "rxDescRead", 566654Snate@binkert.org "rxFifoBlock", 572934SN/A "rxFragWrite", 582549SN/A "rxDescWrite", 592995SN/A "rxAdvance" 603395Shsul@eecs.umich.edu}; 616981SLisa.Hsu@amd.com 629836Sandreas.hansson@arm.comconst char *NsTxStateStrings[] = 633448Shsul@eecs.umich.edu{ 648920Snilay@cs.wisc.edu "txIdle", 653444Sktlim@umich.edu "txDescRefr", 663304Sstever@eecs.umich.edu "txDescRead", 679653SAndreas.Sandberg@ARM.com "txFifoBlock", 689653SAndreas.Sandberg@ARM.com "txFragRead", 699653SAndreas.Sandberg@ARM.com "txDescWrite", 709653SAndreas.Sandberg@ARM.com "txAdvance" 719653SAndreas.Sandberg@ARM.com}; 729653SAndreas.Sandberg@ARM.com 739653SAndreas.Sandberg@ARM.comconst char *NsDmaState[] = 7410594Sgabeblack@google.com{ 7510594Sgabeblack@google.com "dmaIdle", 7610594Sgabeblack@google.com "dmaReading", 7710594Sgabeblack@google.com "dmaWriting", 7810594Sgabeblack@google.com "dmaReadWaiting", 7910594Sgabeblack@google.com "dmaWriteWaiting" 8010594Sgabeblack@google.com}; 8110594Sgabeblack@google.com 8210594Sgabeblack@google.comusing namespace std; 8310594Sgabeblack@google.comusing namespace Net; 8410594Sgabeblack@google.comusing namespace TheISA; 8510119Snilay@cs.wisc.edu 8610594Sgabeblack@google.com/////////////////////////////////////////////////////////////////////// 8710119Snilay@cs.wisc.edu// 8810594Sgabeblack@google.com// NSGigE PCI Device 8910594Sgabeblack@google.com// 9010119Snilay@cs.wisc.eduNSGigE::NSGigE(Params *p) 9110594Sgabeblack@google.com : EtherDevice(p), ioEnable(false), 9210119Snilay@cs.wisc.edu txFifo(p->tx_fifo_size), rxFifo(p->rx_fifo_size), 9310594Sgabeblack@google.com txPacket(0), rxPacket(0), txPacketBufPtr(NULL), rxPacketBufPtr(NULL), 9410119Snilay@cs.wisc.edu txXferLen(0), rxXferLen(0), rxDmaFree(false), txDmaFree(false), 9510119Snilay@cs.wisc.edu clock(p->clock), 9610594Sgabeblack@google.com txState(txIdle), txEnable(false), CTDD(false), txHalt(false), 9710119Snilay@cs.wisc.edu txFragPtr(0), txDescCnt(0), txDmaState(dmaIdle), rxState(rxIdle), 9810512SAli.Saidi@ARM.com rxEnable(false), CRDD(false), rxPktBytes(0), rxHalt(false), 9910512SAli.Saidi@ARM.com rxFragPtr(0), rxDescCnt(0), rxDmaState(dmaIdle), extstsEnable(false), 10010594Sgabeblack@google.com eepromState(eepromStart), eepromClk(false), eepromBitsToRx(0), 10110594Sgabeblack@google.com eepromOpcode(0), eepromAddress(0), eepromData(0), 10210119Snilay@cs.wisc.edu dmaReadDelay(p->dma_read_delay), dmaWriteDelay(p->dma_write_delay), 10310119Snilay@cs.wisc.edu dmaReadFactor(p->dma_read_factor), dmaWriteFactor(p->dma_write_factor), 10410119Snilay@cs.wisc.edu rxDmaData(NULL), rxDmaAddr(0), rxDmaLen(0), 10510119Snilay@cs.wisc.edu txDmaData(NULL), txDmaAddr(0), txDmaLen(0), 1062566SN/A rxDmaReadEvent(this), rxDmaWriteEvent(this), 10710119Snilay@cs.wisc.edu txDmaReadEvent(this), txDmaWriteEvent(this), 10810119Snilay@cs.wisc.edu dmaDescFree(p->dma_desc_free), dmaDataFree(p->dma_data_free), 1099665Sandreas.hansson@arm.com txDelay(p->tx_delay), rxDelay(p->rx_delay), 11010119Snilay@cs.wisc.edu rxKickTick(0), rxKickEvent(this), txKickTick(0), txKickEvent(this), 11110119Snilay@cs.wisc.edu txEvent(this), rxFilterEnable(p->rx_filter), 11210119Snilay@cs.wisc.edu acceptBroadcast(false), acceptMulticast(false), acceptUnicast(false), 11310119Snilay@cs.wisc.edu acceptPerfect(false), acceptArp(false), multicastHashEnable(false), 11410119Snilay@cs.wisc.edu intrDelay(p->intr_delay), intrTick(0), cpuPendingIntr(false), 11510119Snilay@cs.wisc.edu intrEvent(0), interface(0) 11610119Snilay@cs.wisc.edu{ 11710119Snilay@cs.wisc.edu 11810119Snilay@cs.wisc.edu 11910119Snilay@cs.wisc.edu interface = new NSGigEInt(name() + ".int0", this); 12010119Snilay@cs.wisc.edu 12110119Snilay@cs.wisc.edu regsReset(); 12210119Snilay@cs.wisc.edu memcpy(&rom.perfectMatch, p->hardware_address.bytes(), ETH_ADDR_LEN); 12310119Snilay@cs.wisc.edu 12410119Snilay@cs.wisc.edu memset(&rxDesc32, 0, sizeof(rxDesc32)); 12510119Snilay@cs.wisc.edu memset(&txDesc32, 0, sizeof(txDesc32)); 12610119Snilay@cs.wisc.edu memset(&rxDesc64, 0, sizeof(rxDesc64)); 12710119Snilay@cs.wisc.edu memset(&txDesc64, 0, sizeof(txDesc64)); 12810119Snilay@cs.wisc.edu} 12910119Snilay@cs.wisc.edu 13010119Snilay@cs.wisc.eduNSGigE::~NSGigE() 13110119Snilay@cs.wisc.edu{} 13210119Snilay@cs.wisc.edu 13310119Snilay@cs.wisc.edu/** 13410119Snilay@cs.wisc.edu * This is to write to the PCI general configuration registers 13510119Snilay@cs.wisc.edu */ 13610119Snilay@cs.wisc.eduTick 13710119Snilay@cs.wisc.eduNSGigE::writeConfig(PacketPtr pkt) 13810119Snilay@cs.wisc.edu{ 13910119Snilay@cs.wisc.edu int offset = pkt->getAddr() & PCI_CONFIG_SIZE; 14010119Snilay@cs.wisc.edu if (offset < PCI_DEVICE_SPECIFIC) 14110119Snilay@cs.wisc.edu PciDev::writeConfig(pkt); 14210119Snilay@cs.wisc.edu else 14310119Snilay@cs.wisc.edu panic("Device specific PCI config space not implemented!\n"); 14410119Snilay@cs.wisc.edu 14510119Snilay@cs.wisc.edu switch (offset) { 14610119Snilay@cs.wisc.edu // seems to work fine without all these PCI settings, but i 14710119Snilay@cs.wisc.edu // put in the IO to double check, an assertion will fail if we 14810119Snilay@cs.wisc.edu // need to properly implement it 14910119Snilay@cs.wisc.edu case PCI_COMMAND: 15010119Snilay@cs.wisc.edu if (config.data[offset] & PCI_CMD_IOSE) 15110119Snilay@cs.wisc.edu ioEnable = true; 15210519Snilay@cs.wisc.edu else 15310519Snilay@cs.wisc.edu ioEnable = false; 15410119Snilay@cs.wisc.edu break; 15510119Snilay@cs.wisc.edu } 15610119Snilay@cs.wisc.edu 15710119Snilay@cs.wisc.edu return configDelay; 15810119Snilay@cs.wisc.edu} 15910547Snilay@cs.wisc.edu 16010547Snilay@cs.wisc.eduEtherInt* 16110547Snilay@cs.wisc.eduNSGigE::getEthPort(const std::string &if_name, int idx) 16210547Snilay@cs.wisc.edu{ 16310119Snilay@cs.wisc.edu if (if_name == "interface") { 16410119Snilay@cs.wisc.edu if (interface->getPeer()) 16510119Snilay@cs.wisc.edu panic("interface already connected to\n"); 16610119Snilay@cs.wisc.edu return interface; 16710119Snilay@cs.wisc.edu } 16810119Snilay@cs.wisc.edu return NULL; 16910119Snilay@cs.wisc.edu} 17010119Snilay@cs.wisc.edu 17110120Snilay@cs.wisc.edu/** 17210120Snilay@cs.wisc.edu * This reads the device registers, which are detailed in the NS83820 17310119Snilay@cs.wisc.edu * spec sheet 17410119Snilay@cs.wisc.edu */ 17510120Snilay@cs.wisc.eduTick 17610120Snilay@cs.wisc.eduNSGigE::read(PacketPtr pkt) 17710119Snilay@cs.wisc.edu{ 17810120Snilay@cs.wisc.edu assert(ioEnable); 17910120Snilay@cs.wisc.edu 18010120Snilay@cs.wisc.edu pkt->allocate(); 18110119Snilay@cs.wisc.edu 1822995SN/A //The mask is to give you only the offset into the device register file 18310119Snilay@cs.wisc.edu Addr daddr = pkt->getAddr() & 0xfff; 18410119Snilay@cs.wisc.edu DPRINTF(EthernetPIO, "read da=%#x pa=%#x size=%d\n", 18510119Snilay@cs.wisc.edu daddr, pkt->getAddr(), pkt->getSize()); 18610119Snilay@cs.wisc.edu 18710119Snilay@cs.wisc.edu 18810119Snilay@cs.wisc.edu // there are some reserved registers, you can see ns_gige_reg.h and 18910119Snilay@cs.wisc.edu // the spec sheet for details 19010119Snilay@cs.wisc.edu if (daddr > LAST && daddr <= RESERVED) { 19110119Snilay@cs.wisc.edu panic("Accessing reserved register"); 1923304Sstever@eecs.umich.edu } else if (daddr > RESERVED && daddr <= 0x3FC) { 19310119Snilay@cs.wisc.edu return readConfig(pkt); 19410119Snilay@cs.wisc.edu } else if (daddr >= MIB_START && daddr <= MIB_END) { 19510119Snilay@cs.wisc.edu // don't implement all the MIB's. hopefully the kernel 19610119Snilay@cs.wisc.edu // doesn't actually DEPEND upon their values 19710119Snilay@cs.wisc.edu // MIB are just hardware stats keepers 19810119Snilay@cs.wisc.edu pkt->set<uint32_t>(0); 1996135Sgblack@eecs.umich.edu pkt->makeAtomicResponse(); 20010608Sdam.sunwoo@arm.com return pioDelay; 20110608Sdam.sunwoo@arm.com } else if (daddr > 0x3FC) 20210608Sdam.sunwoo@arm.com panic("Something is messed up!\n"); 20310608Sdam.sunwoo@arm.com 20410608Sdam.sunwoo@arm.com assert(pkt->getSize() == sizeof(uint32_t)); 20510608Sdam.sunwoo@arm.com uint32_t ® = *pkt->getPtr<uint32_t>(); 20610608Sdam.sunwoo@arm.com uint16_t rfaddr; 20710119Snilay@cs.wisc.edu 20810119Snilay@cs.wisc.edu switch (daddr) { 20910119Snilay@cs.wisc.edu case CR: 21010608Sdam.sunwoo@arm.com reg = regs.command; 21110608Sdam.sunwoo@arm.com //these are supposed to be cleared on a read 21210119Snilay@cs.wisc.edu reg &= ~(CR_RXD | CR_TXD | CR_TXR | CR_RXR); 21310119Snilay@cs.wisc.edu break; 21410119Snilay@cs.wisc.edu 2153819Shsul@eecs.umich.edu case CFGR: 21610119Snilay@cs.wisc.edu reg = regs.config; 21710119Snilay@cs.wisc.edu break; 21810118Snilay@cs.wisc.edu 21910119Snilay@cs.wisc.edu case MEAR: 2209827Sakash.bagdia@arm.com reg = regs.mear; 22110119Snilay@cs.wisc.edu break; 22210119Snilay@cs.wisc.edu 22310119Snilay@cs.wisc.edu case PTSCR: 22410119Snilay@cs.wisc.edu reg = regs.ptscr; 22510119Snilay@cs.wisc.edu break; 22610119Snilay@cs.wisc.edu 2279827Sakash.bagdia@arm.com case ISR: 22810594Sgabeblack@google.com reg = regs.isr; 2296654Snate@binkert.org devIntrClear(ISR_ALL); 23010594Sgabeblack@google.com break; 2316654Snate@binkert.org 23210594Sgabeblack@google.com case IMR: 2336654Snate@binkert.org reg = regs.imr; 23410594Sgabeblack@google.com break; 2356654Snate@binkert.org 23610594Sgabeblack@google.com case IER: 23710594Sgabeblack@google.com reg = regs.ier; 2387586SAli.Saidi@arm.com break; 23910635Satgutier@umich.edu 24010635Satgutier@umich.edu case IHR: 2418661SAli.Saidi@ARM.com reg = regs.ihr; 2429827Sakash.bagdia@arm.com break; 2439827Sakash.bagdia@arm.com 2449827Sakash.bagdia@arm.com case TXDP: 2459793Sakash.bagdia@arm.com reg = regs.txdp; 24610119Snilay@cs.wisc.edu break; 24710119Snilay@cs.wisc.edu 2489790Sakash.bagdia@arm.com case TXDP_HI: 2499827Sakash.bagdia@arm.com reg = regs.txdp_hi; 2509827Sakash.bagdia@arm.com break; 2519827Sakash.bagdia@arm.com 2529793Sakash.bagdia@arm.com case TX_CFG: 2539827Sakash.bagdia@arm.com reg = regs.txcfg; 2549827Sakash.bagdia@arm.com break; 2559827Sakash.bagdia@arm.com 2569793Sakash.bagdia@arm.com case GPIOR: 2579793Sakash.bagdia@arm.com reg = regs.gpior; 2589793Sakash.bagdia@arm.com break; 2599384SAndreas.Sandberg@arm.com 2608863Snilay@cs.wisc.edu case RXDP: 2617876Sgblack@eecs.umich.edu reg = regs.rxdp; 2624968Sacolyte@umich.edu break; 2638926Sandreas.hansson@arm.com 2644837Ssaidi@eecs.umich.edu case RXDP_HI: 2654837Ssaidi@eecs.umich.edu reg = regs.rxdp_hi; 2669408Sandreas.hansson@arm.com break; 2679653SAndreas.Sandberg@ARM.com 2689653SAndreas.Sandberg@ARM.com case RX_CFG: 2699653SAndreas.Sandberg@ARM.com reg = regs.rxcfg; 2709164Sandreas.hansson@arm.com break; 2719408Sandreas.hansson@arm.com 2728845Sandreas.hansson@arm.com case PQCR: 2738845Sandreas.hansson@arm.com reg = regs.pqcr; 2744837Ssaidi@eecs.umich.edu break; 2759826Sandreas.hansson@arm.com 2769826Sandreas.hansson@arm.com case WCSR: 2779835Sandreas.hansson@arm.com reg = regs.wcsr; 2789826Sandreas.hansson@arm.com break; 2799826Sandreas.hansson@arm.com 2809826Sandreas.hansson@arm.com case PCR: 2819826Sandreas.hansson@arm.com reg = regs.pcr; 2828659SAli.Saidi@ARM.com break; 28310119Snilay@cs.wisc.edu 28410119Snilay@cs.wisc.edu // see the spec sheet for how RFCR and RFDR work 28510119Snilay@cs.wisc.edu // basically, you write to RFCR to tell the machine 28610119Snilay@cs.wisc.edu // what you want to do next, then you act upon RFDR, 28710119Snilay@cs.wisc.edu // and the device will be prepared b/c of what you 28810119Snilay@cs.wisc.edu // wrote to RFCR 28910119Snilay@cs.wisc.edu case RFCR: 29010119Snilay@cs.wisc.edu reg = regs.rfcr; 29110119Snilay@cs.wisc.edu break; 29210119Snilay@cs.wisc.edu 29310119Snilay@cs.wisc.edu case RFDR: 29410119Snilay@cs.wisc.edu rfaddr = (uint16_t)(regs.rfcr & RFCR_RFADDR); 29510119Snilay@cs.wisc.edu switch (rfaddr) { 29610119Snilay@cs.wisc.edu // Read from perfect match ROM octets 29710119Snilay@cs.wisc.edu case 0x000: 29810119Snilay@cs.wisc.edu reg = rom.perfectMatch[1]; 29910119Snilay@cs.wisc.edu reg = reg << 8; 30010119Snilay@cs.wisc.edu reg += rom.perfectMatch[0]; 30110119Snilay@cs.wisc.edu break; 30210119Snilay@cs.wisc.edu case 0x002: 30310119Snilay@cs.wisc.edu reg = rom.perfectMatch[3] << 8; 30410119Snilay@cs.wisc.edu reg += rom.perfectMatch[2]; 30510119Snilay@cs.wisc.edu break; 30610119Snilay@cs.wisc.edu case 0x004: 30710119Snilay@cs.wisc.edu reg = rom.perfectMatch[5] << 8; 30810119Snilay@cs.wisc.edu reg += rom.perfectMatch[4]; 30910119Snilay@cs.wisc.edu break; 31010119Snilay@cs.wisc.edu default: 31110119Snilay@cs.wisc.edu // Read filter hash table 31210119Snilay@cs.wisc.edu if (rfaddr >= FHASH_ADDR && 31310119Snilay@cs.wisc.edu rfaddr < FHASH_ADDR + FHASH_SIZE) { 31410119Snilay@cs.wisc.edu 31510119Snilay@cs.wisc.edu // Only word-aligned reads supported 31610119Snilay@cs.wisc.edu if (rfaddr % 2) 31710119Snilay@cs.wisc.edu panic("unaligned read from filter hash table!"); 31810119Snilay@cs.wisc.edu 31910119Snilay@cs.wisc.edu reg = rom.filterHash[rfaddr - FHASH_ADDR + 1] << 8; 32010119Snilay@cs.wisc.edu reg += rom.filterHash[rfaddr - FHASH_ADDR]; 32110119Snilay@cs.wisc.edu break; 32210119Snilay@cs.wisc.edu } 32310119Snilay@cs.wisc.edu 32410119Snilay@cs.wisc.edu panic("reading RFDR for something other than pattern" 32510119Snilay@cs.wisc.edu " matching or hashing! %#x\n", rfaddr); 3268801Sgblack@eecs.umich.edu } 3273005Sstever@eecs.umich.edu break; 3288801Sgblack@eecs.umich.edu 3293005Sstever@eecs.umich.edu case SRR: 3303005Sstever@eecs.umich.edu reg = regs.srr; 3313005Sstever@eecs.umich.edu break; 3322566SN/A 3337861Sgblack@eecs.umich.edu case MIBC: 3347861Sgblack@eecs.umich.edu reg = regs.mibc; 3357861Sgblack@eecs.umich.edu reg &= ~(MIBC_MIBS | MIBC_ACLR); 3368635Schris.emmons@arm.com break; 3378635Schris.emmons@arm.com 3388635Schris.emmons@arm.com case VRCR: 3399061Snilay@cs.wisc.edu reg = regs.vrcr; 3403481Shsul@eecs.umich.edu break; 341 342 case VTCR: 343 reg = regs.vtcr; 344 break; 345 346 case VDR: 347 reg = regs.vdr; 348 break; 349 350 case CCSR: 351 reg = regs.ccsr; 352 break; 353 354 case TBICR: 355 reg = regs.tbicr; 356 break; 357 358 case TBISR: 359 reg = regs.tbisr; 360 break; 361 362 case TANAR: 363 reg = regs.tanar; 364 break; 365 366 case TANLPAR: 367 reg = regs.tanlpar; 368 break; 369 370 case TANER: 371 reg = regs.taner; 372 break; 373 374 case TESR: 375 reg = regs.tesr; 376 break; 377 378 case M5REG: 379 reg = 0; 380 if (params()->rx_thread) 381 reg |= M5REG_RX_THREAD; 382 if (params()->tx_thread) 383 reg |= M5REG_TX_THREAD; 384 if (params()->rss) 385 reg |= M5REG_RSS; 386 break; 387 388 default: 389 panic("reading unimplemented register: addr=%#x", daddr); 390 } 391 392 DPRINTF(EthernetPIO, "read from %#x: data=%d data=%#x\n", 393 daddr, reg, reg); 394 395 pkt->makeAtomicResponse(); 396 return pioDelay; 397} 398 399Tick 400NSGigE::write(PacketPtr pkt) 401{ 402 assert(ioEnable); 403 404 Addr daddr = pkt->getAddr() & 0xfff; 405 DPRINTF(EthernetPIO, "write da=%#x pa=%#x size=%d\n", 406 daddr, pkt->getAddr(), pkt->getSize()); 407 408 if (daddr > LAST && daddr <= RESERVED) { 409 panic("Accessing reserved register"); 410 } else if (daddr > RESERVED && daddr <= 0x3FC) { 411 return writeConfig(pkt); 412 } else if (daddr > 0x3FC) 413 panic("Something is messed up!\n"); 414 415 if (pkt->getSize() == sizeof(uint32_t)) { 416 uint32_t reg = pkt->get<uint32_t>(); 417 uint16_t rfaddr; 418 419 DPRINTF(EthernetPIO, "write data=%d data=%#x\n", reg, reg); 420 421 switch (daddr) { 422 case CR: 423 regs.command = reg; 424 if (reg & CR_TXD) { 425 txEnable = false; 426 } else if (reg & CR_TXE) { 427 txEnable = true; 428 429 // the kernel is enabling the transmit machine 430 if (txState == txIdle) 431 txKick(); 432 } 433 434 if (reg & CR_RXD) { 435 rxEnable = false; 436 } else if (reg & CR_RXE) { 437 rxEnable = true; 438 439 if (rxState == rxIdle) 440 rxKick(); 441 } 442 443 if (reg & CR_TXR) 444 txReset(); 445 446 if (reg & CR_RXR) 447 rxReset(); 448 449 if (reg & CR_SWI) 450 devIntrPost(ISR_SWI); 451 452 if (reg & CR_RST) { 453 txReset(); 454 rxReset(); 455 456 regsReset(); 457 } 458 break; 459 460 case CFGR: 461 if (reg & CFGR_LNKSTS || 462 reg & CFGR_SPDSTS || 463 reg & CFGR_DUPSTS || 464 reg & CFGR_RESERVED || 465 reg & CFGR_T64ADDR || 466 reg & CFGR_PCI64_DET) 467 468 // First clear all writable bits 469 regs.config &= CFGR_LNKSTS | CFGR_SPDSTS | CFGR_DUPSTS | 470 CFGR_RESERVED | CFGR_T64ADDR | 471 CFGR_PCI64_DET; 472 // Now set the appropriate writable bits 473 regs.config |= reg & ~(CFGR_LNKSTS | CFGR_SPDSTS | CFGR_DUPSTS | 474 CFGR_RESERVED | CFGR_T64ADDR | 475 CFGR_PCI64_DET); 476 477// all these #if 0's are because i don't THINK the kernel needs to 478// have these implemented. if there is a problem relating to one of 479// these, you may need to add functionality in. 480 if (reg & CFGR_TBI_EN) ; 481 if (reg & CFGR_MODE_1000) ; 482 483 if (reg & CFGR_AUTO_1000) 484 panic("CFGR_AUTO_1000 not implemented!\n"); 485 486 if (reg & CFGR_PINT_DUPSTS || 487 reg & CFGR_PINT_LNKSTS || 488 reg & CFGR_PINT_SPDSTS) 489 ; 490 491 if (reg & CFGR_TMRTEST) ; 492 if (reg & CFGR_MRM_DIS) ; 493 if (reg & CFGR_MWI_DIS) ; 494 495 if (reg & CFGR_T64ADDR) ; 496 // panic("CFGR_T64ADDR is read only register!\n"); 497 498 if (reg & CFGR_PCI64_DET) 499 panic("CFGR_PCI64_DET is read only register!\n"); 500 501 if (reg & CFGR_DATA64_EN) ; 502 if (reg & CFGR_M64ADDR) ; 503 if (reg & CFGR_PHY_RST) ; 504 if (reg & CFGR_PHY_DIS) ; 505 506 if (reg & CFGR_EXTSTS_EN) 507 extstsEnable = true; 508 else 509 extstsEnable = false; 510 511 if (reg & CFGR_REQALG) ; 512 if (reg & CFGR_SB) ; 513 if (reg & CFGR_POW) ; 514 if (reg & CFGR_EXD) ; 515 if (reg & CFGR_PESEL) ; 516 if (reg & CFGR_BROM_DIS) ; 517 if (reg & CFGR_EXT_125) ; 518 if (reg & CFGR_BEM) ; 519 break; 520 521 case MEAR: 522 // Clear writable bits 523 regs.mear &= MEAR_EEDO; 524 // Set appropriate writable bits 525 regs.mear |= reg & ~MEAR_EEDO; 526 527 // FreeBSD uses the EEPROM to read PMATCH (for the MAC address) 528 // even though it could get it through RFDR 529 if (reg & MEAR_EESEL) { 530 // Rising edge of clock 531 if (reg & MEAR_EECLK && !eepromClk) 532 eepromKick(); 533 } 534 else { 535 eepromState = eepromStart; 536 regs.mear &= ~MEAR_EEDI; 537 } 538 539 eepromClk = reg & MEAR_EECLK; 540 541 // since phy is completely faked, MEAR_MD* don't matter 542 if (reg & MEAR_MDIO) ; 543 if (reg & MEAR_MDDIR) ; 544 if (reg & MEAR_MDC) ; 545 break; 546 547 case PTSCR: 548 regs.ptscr = reg & ~(PTSCR_RBIST_RDONLY); 549 // these control BISTs for various parts of chip - we 550 // don't care or do just fake that the BIST is done 551 if (reg & PTSCR_RBIST_EN) 552 regs.ptscr |= PTSCR_RBIST_DONE; 553 if (reg & PTSCR_EEBIST_EN) 554 regs.ptscr &= ~PTSCR_EEBIST_EN; 555 if (reg & PTSCR_EELOAD_EN) 556 regs.ptscr &= ~PTSCR_EELOAD_EN; 557 break; 558 559 case ISR: /* writing to the ISR has no effect */ 560 panic("ISR is a read only register!\n"); 561 562 case IMR: 563 regs.imr = reg; 564 devIntrChangeMask(); 565 break; 566 567 case IER: 568 regs.ier = reg; 569 break; 570 571 case IHR: 572 regs.ihr = reg; 573 /* not going to implement real interrupt holdoff */ 574 break; 575 576 case TXDP: 577 regs.txdp = (reg & 0xFFFFFFFC); 578 assert(txState == txIdle); 579 CTDD = false; 580 break; 581 582 case TXDP_HI: 583 regs.txdp_hi = reg; 584 break; 585 586 case TX_CFG: 587 regs.txcfg = reg; 588#if 0 589 if (reg & TX_CFG_CSI) ; 590 if (reg & TX_CFG_HBI) ; 591 if (reg & TX_CFG_MLB) ; 592 if (reg & TX_CFG_ATP) ; 593 if (reg & TX_CFG_ECRETRY) { 594 /* 595 * this could easily be implemented, but considering 596 * the network is just a fake pipe, wouldn't make 597 * sense to do this 598 */ 599 } 600 601 if (reg & TX_CFG_BRST_DIS) ; 602#endif 603 604#if 0 605 /* we handle our own DMA, ignore the kernel's exhortations */ 606 if (reg & TX_CFG_MXDMA) ; 607#endif 608 609 // also, we currently don't care about fill/drain 610 // thresholds though this may change in the future with 611 // more realistic networks or a driver which changes it 612 // according to feedback 613 614 break; 615 616 case GPIOR: 617 // Only write writable bits 618 regs.gpior &= GPIOR_UNUSED | GPIOR_GP5_IN | GPIOR_GP4_IN 619 | GPIOR_GP3_IN | GPIOR_GP2_IN | GPIOR_GP1_IN; 620 regs.gpior |= reg & ~(GPIOR_UNUSED | GPIOR_GP5_IN | GPIOR_GP4_IN 621 | GPIOR_GP3_IN | GPIOR_GP2_IN | GPIOR_GP1_IN); 622 /* these just control general purpose i/o pins, don't matter */ 623 break; 624 625 case RXDP: 626 regs.rxdp = reg; 627 CRDD = false; 628 break; 629 630 case RXDP_HI: 631 regs.rxdp_hi = reg; 632 break; 633 634 case RX_CFG: 635 regs.rxcfg = reg; 636#if 0 637 if (reg & RX_CFG_AEP) ; 638 if (reg & RX_CFG_ARP) ; 639 if (reg & RX_CFG_STRIPCRC) ; 640 if (reg & RX_CFG_RX_RD) ; 641 if (reg & RX_CFG_ALP) ; 642 if (reg & RX_CFG_AIRL) ; 643 644 /* we handle our own DMA, ignore what kernel says about it */ 645 if (reg & RX_CFG_MXDMA) ; 646 647 //also, we currently don't care about fill/drain thresholds 648 //though this may change in the future with more realistic 649 //networks or a driver which changes it according to feedback 650 if (reg & (RX_CFG_DRTH | RX_CFG_DRTH0)) ; 651#endif 652 break; 653 654 case PQCR: 655 /* there is no priority queueing used in the linux 2.6 driver */ 656 regs.pqcr = reg; 657 break; 658 659 case WCSR: 660 /* not going to implement wake on LAN */ 661 regs.wcsr = reg; 662 break; 663 664 case PCR: 665 /* not going to implement pause control */ 666 regs.pcr = reg; 667 break; 668 669 case RFCR: 670 regs.rfcr = reg; 671 672 rxFilterEnable = (reg & RFCR_RFEN) ? true : false; 673 acceptBroadcast = (reg & RFCR_AAB) ? true : false; 674 acceptMulticast = (reg & RFCR_AAM) ? true : false; 675 acceptUnicast = (reg & RFCR_AAU) ? true : false; 676 acceptPerfect = (reg & RFCR_APM) ? true : false; 677 acceptArp = (reg & RFCR_AARP) ? true : false; 678 multicastHashEnable = (reg & RFCR_MHEN) ? true : false; 679 680#if 0 681 if (reg & RFCR_APAT) 682 panic("RFCR_APAT not implemented!\n"); 683#endif 684 if (reg & RFCR_UHEN) 685 panic("Unicast hash filtering not used by drivers!\n"); 686 687 if (reg & RFCR_ULM) 688 panic("RFCR_ULM not implemented!\n"); 689 690 break; 691 692 case RFDR: 693 rfaddr = (uint16_t)(regs.rfcr & RFCR_RFADDR); 694 switch (rfaddr) { 695 case 0x000: 696 rom.perfectMatch[0] = (uint8_t)reg; 697 rom.perfectMatch[1] = (uint8_t)(reg >> 8); 698 break; 699 case 0x002: 700 rom.perfectMatch[2] = (uint8_t)reg; 701 rom.perfectMatch[3] = (uint8_t)(reg >> 8); 702 break; 703 case 0x004: 704 rom.perfectMatch[4] = (uint8_t)reg; 705 rom.perfectMatch[5] = (uint8_t)(reg >> 8); 706 break; 707 default: 708 709 if (rfaddr >= FHASH_ADDR && 710 rfaddr < FHASH_ADDR + FHASH_SIZE) { 711 712 // Only word-aligned writes supported 713 if (rfaddr % 2) 714 panic("unaligned write to filter hash table!"); 715 716 rom.filterHash[rfaddr - FHASH_ADDR] = (uint8_t)reg; 717 rom.filterHash[rfaddr - FHASH_ADDR + 1] 718 = (uint8_t)(reg >> 8); 719 break; 720 } 721 panic("writing RFDR for something other than pattern matching\ 722 or hashing! %#x\n", rfaddr); 723 } 724 725 case BRAR: 726 regs.brar = reg; 727 break; 728 729 case BRDR: 730 panic("the driver never uses BRDR, something is wrong!\n"); 731 732 case SRR: 733 panic("SRR is read only register!\n"); 734 735 case MIBC: 736 panic("the driver never uses MIBC, something is wrong!\n"); 737 738 case VRCR: 739 regs.vrcr = reg; 740 break; 741 742 case VTCR: 743 regs.vtcr = reg; 744 break; 745 746 case VDR: 747 panic("the driver never uses VDR, something is wrong!\n"); 748 749 case CCSR: 750 /* not going to implement clockrun stuff */ 751 regs.ccsr = reg; 752 break; 753 754 case TBICR: 755 regs.tbicr = reg; 756 if (reg & TBICR_MR_LOOPBACK) 757 panic("TBICR_MR_LOOPBACK never used, something wrong!\n"); 758 759 if (reg & TBICR_MR_AN_ENABLE) { 760 regs.tanlpar = regs.tanar; 761 regs.tbisr |= (TBISR_MR_AN_COMPLETE | TBISR_MR_LINK_STATUS); 762 } 763 764#if 0 765 if (reg & TBICR_MR_RESTART_AN) ; 766#endif 767 768 break; 769 770 case TBISR: 771 panic("TBISR is read only register!\n"); 772 773 case TANAR: 774 // Only write the writable bits 775 regs.tanar &= TANAR_RF1 | TANAR_RF2 | TANAR_UNUSED; 776 regs.tanar |= reg & ~(TANAR_RF1 | TANAR_RF2 | TANAR_UNUSED); 777 778 // Pause capability unimplemented 779#if 0 780 if (reg & TANAR_PS2) ; 781 if (reg & TANAR_PS1) ; 782#endif 783 784 break; 785 786 case TANLPAR: 787 panic("this should only be written to by the fake phy!\n"); 788 789 case TANER: 790 panic("TANER is read only register!\n"); 791 792 case TESR: 793 regs.tesr = reg; 794 break; 795 796 default: 797 panic("invalid register access daddr=%#x", daddr); 798 } 799 } else { 800 panic("Invalid Request Size"); 801 } 802 pkt->makeAtomicResponse(); 803 return pioDelay; 804} 805 806void 807NSGigE::devIntrPost(uint32_t interrupts) 808{ 809 if (interrupts & ISR_RESERVE) 810 panic("Cannot set a reserved interrupt"); 811 812 if (interrupts & ISR_NOIMPL) 813 warn("interrupt not implemented %#x\n", interrupts); 814 815 interrupts &= ISR_IMPL; 816 regs.isr |= interrupts; 817 818 if (interrupts & regs.imr) { 819 if (interrupts & ISR_SWI) { 820 totalSwi++; 821 } 822 if (interrupts & ISR_RXIDLE) { 823 totalRxIdle++; 824 } 825 if (interrupts & ISR_RXOK) { 826 totalRxOk++; 827 } 828 if (interrupts & ISR_RXDESC) { 829 totalRxDesc++; 830 } 831 if (interrupts & ISR_TXOK) { 832 totalTxOk++; 833 } 834 if (interrupts & ISR_TXIDLE) { 835 totalTxIdle++; 836 } 837 if (interrupts & ISR_TXDESC) { 838 totalTxDesc++; 839 } 840 if (interrupts & ISR_RXORN) { 841 totalRxOrn++; 842 } 843 } 844 845 DPRINTF(EthernetIntr, 846 "interrupt written to ISR: intr=%#x isr=%#x imr=%#x\n", 847 interrupts, regs.isr, regs.imr); 848 849 if ((regs.isr & regs.imr)) { 850 Tick when = curTick; 851 if ((regs.isr & regs.imr & ISR_NODELAY) == 0) 852 when += intrDelay; 853 postedInterrupts++; 854 cpuIntrPost(when); 855 } 856} 857 858/* writing this interrupt counting stats inside this means that this function 859 is now limited to being used to clear all interrupts upon the kernel 860 reading isr and servicing. just telling you in case you were thinking 861 of expanding use. 862*/ 863void 864NSGigE::devIntrClear(uint32_t interrupts) 865{ 866 if (interrupts & ISR_RESERVE) 867 panic("Cannot clear a reserved interrupt"); 868 869 if (regs.isr & regs.imr & ISR_SWI) { 870 postedSwi++; 871 } 872 if (regs.isr & regs.imr & ISR_RXIDLE) { 873 postedRxIdle++; 874 } 875 if (regs.isr & regs.imr & ISR_RXOK) { 876 postedRxOk++; 877 } 878 if (regs.isr & regs.imr & ISR_RXDESC) { 879 postedRxDesc++; 880 } 881 if (regs.isr & regs.imr & ISR_TXOK) { 882 postedTxOk++; 883 } 884 if (regs.isr & regs.imr & ISR_TXIDLE) { 885 postedTxIdle++; 886 } 887 if (regs.isr & regs.imr & ISR_TXDESC) { 888 postedTxDesc++; 889 } 890 if (regs.isr & regs.imr & ISR_RXORN) { 891 postedRxOrn++; 892 } 893 894 interrupts &= ~ISR_NOIMPL; 895 regs.isr &= ~interrupts; 896 897 DPRINTF(EthernetIntr, 898 "interrupt cleared from ISR: intr=%x isr=%x imr=%x\n", 899 interrupts, regs.isr, regs.imr); 900 901 if (!(regs.isr & regs.imr)) 902 cpuIntrClear(); 903} 904 905void 906NSGigE::devIntrChangeMask() 907{ 908 DPRINTF(EthernetIntr, "interrupt mask changed: isr=%x imr=%x masked=%x\n", 909 regs.isr, regs.imr, regs.isr & regs.imr); 910 911 if (regs.isr & regs.imr) 912 cpuIntrPost(curTick); 913 else 914 cpuIntrClear(); 915} 916 917void 918NSGigE::cpuIntrPost(Tick when) 919{ 920 // If the interrupt you want to post is later than an interrupt 921 // already scheduled, just let it post in the coming one and don't 922 // schedule another. 923 // HOWEVER, must be sure that the scheduled intrTick is in the 924 // future (this was formerly the source of a bug) 925 /** 926 * @todo this warning should be removed and the intrTick code should 927 * be fixed. 928 */ 929 assert(when >= curTick); 930 assert(intrTick >= curTick || intrTick == 0); 931 if (when > intrTick && intrTick != 0) { 932 DPRINTF(EthernetIntr, "don't need to schedule event...intrTick=%d\n", 933 intrTick); 934 return; 935 } 936 937 intrTick = when; 938 if (intrTick < curTick) { 939 debug_break(); 940 intrTick = curTick; 941 } 942 943 DPRINTF(EthernetIntr, "going to schedule an interrupt for intrTick=%d\n", 944 intrTick); 945 946 if (intrEvent) 947 intrEvent->squash(); 948 intrEvent = new IntrEvent(this, true); 949 schedule(intrEvent, intrTick); 950} 951 952void 953NSGigE::cpuInterrupt() 954{ 955 assert(intrTick == curTick); 956 957 // Whether or not there's a pending interrupt, we don't care about 958 // it anymore 959 intrEvent = 0; 960 intrTick = 0; 961 962 // Don't send an interrupt if there's already one 963 if (cpuPendingIntr) { 964 DPRINTF(EthernetIntr, 965 "would send an interrupt now, but there's already pending\n"); 966 } else { 967 // Send interrupt 968 cpuPendingIntr = true; 969 970 DPRINTF(EthernetIntr, "posting interrupt\n"); 971 intrPost(); 972 } 973} 974 975void 976NSGigE::cpuIntrClear() 977{ 978 if (!cpuPendingIntr) 979 return; 980 981 if (intrEvent) { 982 intrEvent->squash(); 983 intrEvent = 0; 984 } 985 986 intrTick = 0; 987 988 cpuPendingIntr = false; 989 990 DPRINTF(EthernetIntr, "clearing interrupt\n"); 991 intrClear(); 992} 993 994bool 995NSGigE::cpuIntrPending() const 996{ return cpuPendingIntr; } 997 998void 999NSGigE::txReset() 1000{ 1001 1002 DPRINTF(Ethernet, "transmit reset\n"); 1003 1004 CTDD = false; 1005 txEnable = false;; 1006 txFragPtr = 0; 1007 assert(txDescCnt == 0); 1008 txFifo.clear(); 1009 txState = txIdle; 1010 assert(txDmaState == dmaIdle); 1011} 1012 1013void 1014NSGigE::rxReset() 1015{ 1016 DPRINTF(Ethernet, "receive reset\n"); 1017 1018 CRDD = false; 1019 assert(rxPktBytes == 0); 1020 rxEnable = false; 1021 rxFragPtr = 0; 1022 assert(rxDescCnt == 0); 1023 assert(rxDmaState == dmaIdle); 1024 rxFifo.clear(); 1025 rxState = rxIdle; 1026} 1027 1028void 1029NSGigE::regsReset() 1030{ 1031 memset(®s, 0, sizeof(regs)); 1032 regs.config = (CFGR_LNKSTS | CFGR_TBI_EN | CFGR_MODE_1000); 1033 regs.mear = 0x12; 1034 regs.txcfg = 0x120; // set drain threshold to 1024 bytes and 1035 // fill threshold to 32 bytes 1036 regs.rxcfg = 0x4; // set drain threshold to 16 bytes 1037 regs.srr = 0x0103; // set the silicon revision to rev B or 0x103 1038 regs.mibc = MIBC_FRZ; 1039 regs.vdr = 0x81; // set the vlan tag type to 802.1q 1040 regs.tesr = 0xc000; // TBI capable of both full and half duplex 1041 regs.brar = 0xffffffff; 1042 1043 extstsEnable = false; 1044 acceptBroadcast = false; 1045 acceptMulticast = false; 1046 acceptUnicast = false; 1047 acceptPerfect = false; 1048 acceptArp = false; 1049} 1050 1051bool 1052NSGigE::doRxDmaRead() 1053{ 1054 assert(rxDmaState == dmaIdle || rxDmaState == dmaReadWaiting); 1055 rxDmaState = dmaReading; 1056 1057 if (dmaPending() || getState() != Running) 1058 rxDmaState = dmaReadWaiting; 1059 else 1060 dmaRead(rxDmaAddr, rxDmaLen, &rxDmaReadEvent, (uint8_t*)rxDmaData); 1061 1062 return true; 1063} 1064 1065void 1066NSGigE::rxDmaReadDone() 1067{ 1068 assert(rxDmaState == dmaReading); 1069 rxDmaState = dmaIdle; 1070 1071 DPRINTF(EthernetDMA, "rx dma read paddr=%#x len=%d\n", 1072 rxDmaAddr, rxDmaLen); 1073 DDUMP(EthernetDMA, rxDmaData, rxDmaLen); 1074 1075 // If the transmit state machine has a pending DMA, let it go first 1076 if (txDmaState == dmaReadWaiting || txDmaState == dmaWriteWaiting) 1077 txKick(); 1078 1079 rxKick(); 1080} 1081 1082bool 1083NSGigE::doRxDmaWrite() 1084{ 1085 assert(rxDmaState == dmaIdle || rxDmaState == dmaWriteWaiting); 1086 rxDmaState = dmaWriting; 1087 1088 if (dmaPending() || getState() != Running) 1089 rxDmaState = dmaWriteWaiting; 1090 else 1091 dmaWrite(rxDmaAddr, rxDmaLen, &rxDmaWriteEvent, (uint8_t*)rxDmaData); 1092 return true; 1093} 1094 1095void 1096NSGigE::rxDmaWriteDone() 1097{ 1098 assert(rxDmaState == dmaWriting); 1099 rxDmaState = dmaIdle; 1100 1101 DPRINTF(EthernetDMA, "rx dma write paddr=%#x len=%d\n", 1102 rxDmaAddr, rxDmaLen); 1103 DDUMP(EthernetDMA, rxDmaData, rxDmaLen); 1104 1105 // If the transmit state machine has a pending DMA, let it go first 1106 if (txDmaState == dmaReadWaiting || txDmaState == dmaWriteWaiting) 1107 txKick(); 1108 1109 rxKick(); 1110} 1111 1112void 1113NSGigE::rxKick() 1114{ 1115 bool is64bit = (bool)(regs.config & CFGR_M64ADDR); 1116 1117 DPRINTF(EthernetSM, 1118 "receive kick rxState=%s (rxBuf.size=%d) %d-bit\n", 1119 NsRxStateStrings[rxState], rxFifo.size(), is64bit ? 64 : 32); 1120 1121 Addr link, bufptr; 1122 uint32_t &cmdsts = is64bit ? rxDesc64.cmdsts : rxDesc32.cmdsts; 1123 uint32_t &extsts = is64bit ? rxDesc64.extsts : rxDesc32.extsts; 1124 1125 next: 1126 if (clock) { 1127 if (rxKickTick > curTick) { 1128 DPRINTF(EthernetSM, "receive kick exiting, can't run till %d\n", 1129 rxKickTick); 1130 1131 goto exit; 1132 } 1133 1134 // Go to the next state machine clock tick. 1135 rxKickTick = curTick + ticks(1); 1136 } 1137 1138 switch(rxDmaState) { 1139 case dmaReadWaiting: 1140 if (doRxDmaRead()) 1141 goto exit; 1142 break; 1143 case dmaWriteWaiting: 1144 if (doRxDmaWrite()) 1145 goto exit; 1146 break; 1147 default: 1148 break; 1149 } 1150 1151 link = is64bit ? (Addr)rxDesc64.link : (Addr)rxDesc32.link; 1152 bufptr = is64bit ? (Addr)rxDesc64.bufptr : (Addr)rxDesc32.bufptr; 1153 1154 // see state machine from spec for details 1155 // the way this works is, if you finish work on one state and can 1156 // go directly to another, you do that through jumping to the 1157 // label "next". however, if you have intermediate work, like DMA 1158 // so that you can't go to the next state yet, you go to exit and 1159 // exit the loop. however, when the DMA is done it will trigger 1160 // an event and come back to this loop. 1161 switch (rxState) { 1162 case rxIdle: 1163 if (!rxEnable) { 1164 DPRINTF(EthernetSM, "Receive Disabled! Nothing to do.\n"); 1165 goto exit; 1166 } 1167 1168 if (CRDD) { 1169 rxState = rxDescRefr; 1170 1171 rxDmaAddr = regs.rxdp & 0x3fffffff; 1172 rxDmaData = 1173 is64bit ? (void *)&rxDesc64.link : (void *)&rxDesc32.link; 1174 rxDmaLen = is64bit ? sizeof(rxDesc64.link) : sizeof(rxDesc32.link); 1175 rxDmaFree = dmaDescFree; 1176 1177 descDmaReads++; 1178 descDmaRdBytes += rxDmaLen; 1179 1180 if (doRxDmaRead()) 1181 goto exit; 1182 } else { 1183 rxState = rxDescRead; 1184 1185 rxDmaAddr = regs.rxdp & 0x3fffffff; 1186 rxDmaData = is64bit ? (void *)&rxDesc64 : (void *)&rxDesc32; 1187 rxDmaLen = is64bit ? sizeof(rxDesc64) : sizeof(rxDesc32); 1188 rxDmaFree = dmaDescFree; 1189 1190 descDmaReads++; 1191 descDmaRdBytes += rxDmaLen; 1192 1193 if (doRxDmaRead()) 1194 goto exit; 1195 } 1196 break; 1197 1198 case rxDescRefr: 1199 if (rxDmaState != dmaIdle) 1200 goto exit; 1201 1202 rxState = rxAdvance; 1203 break; 1204 1205 case rxDescRead: 1206 if (rxDmaState != dmaIdle) 1207 goto exit; 1208 1209 DPRINTF(EthernetDesc, "rxDesc: addr=%08x read descriptor\n", 1210 regs.rxdp & 0x3fffffff); 1211 DPRINTF(EthernetDesc, 1212 "rxDesc: link=%#x bufptr=%#x cmdsts=%08x extsts=%08x\n", 1213 link, bufptr, cmdsts, extsts); 1214 1215 if (cmdsts & CMDSTS_OWN) { 1216 devIntrPost(ISR_RXIDLE); 1217 rxState = rxIdle; 1218 goto exit; 1219 } else { 1220 rxState = rxFifoBlock; 1221 rxFragPtr = bufptr; 1222 rxDescCnt = cmdsts & CMDSTS_LEN_MASK; 1223 } 1224 break; 1225 1226 case rxFifoBlock: 1227 if (!rxPacket) { 1228 /** 1229 * @todo in reality, we should be able to start processing 1230 * the packet as it arrives, and not have to wait for the 1231 * full packet ot be in the receive fifo. 1232 */ 1233 if (rxFifo.empty()) 1234 goto exit; 1235 1236 DPRINTF(EthernetSM, "****processing receive of new packet****\n"); 1237 1238 // If we don't have a packet, grab a new one from the fifo. 1239 rxPacket = rxFifo.front(); 1240 rxPktBytes = rxPacket->length; 1241 rxPacketBufPtr = rxPacket->data; 1242 1243#if TRACING_ON 1244 if (DTRACE(Ethernet)) { 1245 IpPtr ip(rxPacket); 1246 if (ip) { 1247 DPRINTF(Ethernet, "ID is %d\n", ip->id()); 1248 TcpPtr tcp(ip); 1249 if (tcp) { 1250 DPRINTF(Ethernet, 1251 "Src Port=%d, Dest Port=%d, Seq=%d, Ack=%d\n", 1252 tcp->sport(), tcp->dport(), tcp->seq(), 1253 tcp->ack()); 1254 } 1255 } 1256 } 1257#endif 1258 1259 // sanity check - i think the driver behaves like this 1260 assert(rxDescCnt >= rxPktBytes); 1261 rxFifo.pop(); 1262 } 1263 1264 1265 // dont' need the && rxDescCnt > 0 if driver sanity check 1266 // above holds 1267 if (rxPktBytes > 0) { 1268 rxState = rxFragWrite; 1269 // don't need min<>(rxPktBytes,rxDescCnt) if above sanity 1270 // check holds 1271 rxXferLen = rxPktBytes; 1272 1273 rxDmaAddr = rxFragPtr & 0x3fffffff; 1274 rxDmaData = rxPacketBufPtr; 1275 rxDmaLen = rxXferLen; 1276 rxDmaFree = dmaDataFree; 1277 1278 if (doRxDmaWrite()) 1279 goto exit; 1280 1281 } else { 1282 rxState = rxDescWrite; 1283 1284 //if (rxPktBytes == 0) { /* packet is done */ 1285 assert(rxPktBytes == 0); 1286 DPRINTF(EthernetSM, "done with receiving packet\n"); 1287 1288 cmdsts |= CMDSTS_OWN; 1289 cmdsts &= ~CMDSTS_MORE; 1290 cmdsts |= CMDSTS_OK; 1291 cmdsts &= 0xffff0000; 1292 cmdsts += rxPacket->length; //i.e. set CMDSTS_SIZE 1293 1294#if 0 1295 /* 1296 * all the driver uses these are for its own stats keeping 1297 * which we don't care about, aren't necessary for 1298 * functionality and doing this would just slow us down. 1299 * if they end up using this in a later version for 1300 * functional purposes, just undef 1301 */ 1302 if (rxFilterEnable) { 1303 cmdsts &= ~CMDSTS_DEST_MASK; 1304 const EthAddr &dst = rxFifoFront()->dst(); 1305 if (dst->unicast()) 1306 cmdsts |= CMDSTS_DEST_SELF; 1307 if (dst->multicast()) 1308 cmdsts |= CMDSTS_DEST_MULTI; 1309 if (dst->broadcast()) 1310 cmdsts |= CMDSTS_DEST_MASK; 1311 } 1312#endif 1313 1314 IpPtr ip(rxPacket); 1315 if (extstsEnable && ip) { 1316 extsts |= EXTSTS_IPPKT; 1317 rxIpChecksums++; 1318 if (cksum(ip) != 0) { 1319 DPRINTF(EthernetCksum, "Rx IP Checksum Error\n"); 1320 extsts |= EXTSTS_IPERR; 1321 } 1322 TcpPtr tcp(ip); 1323 UdpPtr udp(ip); 1324 if (tcp) { 1325 extsts |= EXTSTS_TCPPKT; 1326 rxTcpChecksums++; 1327 if (cksum(tcp) != 0) { 1328 DPRINTF(EthernetCksum, "Rx TCP Checksum Error\n"); 1329 extsts |= EXTSTS_TCPERR; 1330 1331 } 1332 } else if (udp) { 1333 extsts |= EXTSTS_UDPPKT; 1334 rxUdpChecksums++; 1335 if (cksum(udp) != 0) { 1336 DPRINTF(EthernetCksum, "Rx UDP Checksum Error\n"); 1337 extsts |= EXTSTS_UDPERR; 1338 } 1339 } 1340 } 1341 rxPacket = 0; 1342 1343 /* 1344 * the driver seems to always receive into desc buffers 1345 * of size 1514, so you never have a pkt that is split 1346 * into multiple descriptors on the receive side, so 1347 * i don't implement that case, hence the assert above. 1348 */ 1349 1350 DPRINTF(EthernetDesc, 1351 "rxDesc: addr=%08x writeback cmdsts extsts\n", 1352 regs.rxdp & 0x3fffffff); 1353 DPRINTF(EthernetDesc, 1354 "rxDesc: link=%#x bufptr=%#x cmdsts=%08x extsts=%08x\n", 1355 link, bufptr, cmdsts, extsts); 1356 1357 rxDmaAddr = regs.rxdp & 0x3fffffff; 1358 rxDmaData = &cmdsts; 1359 if (is64bit) { 1360 rxDmaAddr += offsetof(ns_desc64, cmdsts); 1361 rxDmaLen = sizeof(rxDesc64.cmdsts) + sizeof(rxDesc64.extsts); 1362 } else { 1363 rxDmaAddr += offsetof(ns_desc32, cmdsts); 1364 rxDmaLen = sizeof(rxDesc32.cmdsts) + sizeof(rxDesc32.extsts); 1365 } 1366 rxDmaFree = dmaDescFree; 1367 1368 descDmaWrites++; 1369 descDmaWrBytes += rxDmaLen; 1370 1371 if (doRxDmaWrite()) 1372 goto exit; 1373 } 1374 break; 1375 1376 case rxFragWrite: 1377 if (rxDmaState != dmaIdle) 1378 goto exit; 1379 1380 rxPacketBufPtr += rxXferLen; 1381 rxFragPtr += rxXferLen; 1382 rxPktBytes -= rxXferLen; 1383 1384 rxState = rxFifoBlock; 1385 break; 1386 1387 case rxDescWrite: 1388 if (rxDmaState != dmaIdle) 1389 goto exit; 1390 1391 assert(cmdsts & CMDSTS_OWN); 1392 1393 assert(rxPacket == 0); 1394 devIntrPost(ISR_RXOK); 1395 1396 if (cmdsts & CMDSTS_INTR) 1397 devIntrPost(ISR_RXDESC); 1398 1399 if (!rxEnable) { 1400 DPRINTF(EthernetSM, "Halting the RX state machine\n"); 1401 rxState = rxIdle; 1402 goto exit; 1403 } else 1404 rxState = rxAdvance; 1405 break; 1406 1407 case rxAdvance: 1408 if (link == 0) { 1409 devIntrPost(ISR_RXIDLE); 1410 rxState = rxIdle; 1411 CRDD = true; 1412 goto exit; 1413 } else { 1414 if (rxDmaState != dmaIdle) 1415 goto exit; 1416 rxState = rxDescRead; 1417 regs.rxdp = link; 1418 CRDD = false; 1419 1420 rxDmaAddr = regs.rxdp & 0x3fffffff; 1421 rxDmaData = is64bit ? (void *)&rxDesc64 : (void *)&rxDesc32; 1422 rxDmaLen = is64bit ? sizeof(rxDesc64) : sizeof(rxDesc32); 1423 rxDmaFree = dmaDescFree; 1424 1425 if (doRxDmaRead()) 1426 goto exit; 1427 } 1428 break; 1429 1430 default: 1431 panic("Invalid rxState!"); 1432 } 1433 1434 DPRINTF(EthernetSM, "entering next rxState=%s\n", 1435 NsRxStateStrings[rxState]); 1436 goto next; 1437 1438 exit: 1439 /** 1440 * @todo do we want to schedule a future kick? 1441 */ 1442 DPRINTF(EthernetSM, "rx state machine exited rxState=%s\n", 1443 NsRxStateStrings[rxState]); 1444 1445 if (clock && !rxKickEvent.scheduled()) 1446 schedule(rxKickEvent, rxKickTick); 1447} 1448 1449void 1450NSGigE::transmit() 1451{ 1452 if (txFifo.empty()) { 1453 DPRINTF(Ethernet, "nothing to transmit\n"); 1454 return; 1455 } 1456 1457 DPRINTF(Ethernet, "Attempt Pkt Transmit: txFifo length=%d\n", 1458 txFifo.size()); 1459 if (interface->sendPacket(txFifo.front())) { 1460#if TRACING_ON 1461 if (DTRACE(Ethernet)) { 1462 IpPtr ip(txFifo.front()); 1463 if (ip) { 1464 DPRINTF(Ethernet, "ID is %d\n", ip->id()); 1465 TcpPtr tcp(ip); 1466 if (tcp) { 1467 DPRINTF(Ethernet, 1468 "Src Port=%d, Dest Port=%d, Seq=%d, Ack=%d\n", 1469 tcp->sport(), tcp->dport(), tcp->seq(), 1470 tcp->ack()); 1471 } 1472 } 1473 } 1474#endif 1475 1476 DDUMP(EthernetData, txFifo.front()->data, txFifo.front()->length); 1477 txBytes += txFifo.front()->length; 1478 txPackets++; 1479 1480 DPRINTF(Ethernet, "Successful Xmit! now txFifoAvail is %d\n", 1481 txFifo.avail()); 1482 txFifo.pop(); 1483 1484 /* 1485 * normally do a writeback of the descriptor here, and ONLY 1486 * after that is done, send this interrupt. but since our 1487 * stuff never actually fails, just do this interrupt here, 1488 * otherwise the code has to stray from this nice format. 1489 * besides, it's functionally the same. 1490 */ 1491 devIntrPost(ISR_TXOK); 1492 } 1493 1494 if (!txFifo.empty() && !txEvent.scheduled()) { 1495 DPRINTF(Ethernet, "reschedule transmit\n"); 1496 schedule(txEvent, curTick + retryTime); 1497 } 1498} 1499 1500bool 1501NSGigE::doTxDmaRead() 1502{ 1503 assert(txDmaState == dmaIdle || txDmaState == dmaReadWaiting); 1504 txDmaState = dmaReading; 1505 1506 if (dmaPending() || getState() != Running) 1507 txDmaState = dmaReadWaiting; 1508 else 1509 dmaRead(txDmaAddr, txDmaLen, &txDmaReadEvent, (uint8_t*)txDmaData); 1510 1511 return true; 1512} 1513 1514void 1515NSGigE::txDmaReadDone() 1516{ 1517 assert(txDmaState == dmaReading); 1518 txDmaState = dmaIdle; 1519 1520 DPRINTF(EthernetDMA, "tx dma read paddr=%#x len=%d\n", 1521 txDmaAddr, txDmaLen); 1522 DDUMP(EthernetDMA, txDmaData, txDmaLen); 1523 1524 // If the receive state machine has a pending DMA, let it go first 1525 if (rxDmaState == dmaReadWaiting || rxDmaState == dmaWriteWaiting) 1526 rxKick(); 1527 1528 txKick(); 1529} 1530 1531bool 1532NSGigE::doTxDmaWrite() 1533{ 1534 assert(txDmaState == dmaIdle || txDmaState == dmaWriteWaiting); 1535 txDmaState = dmaWriting; 1536 1537 if (dmaPending() || getState() != Running) 1538 txDmaState = dmaWriteWaiting; 1539 else 1540 dmaWrite(txDmaAddr, txDmaLen, &txDmaWriteEvent, (uint8_t*)txDmaData); 1541 return true; 1542} 1543 1544void 1545NSGigE::txDmaWriteDone() 1546{ 1547 assert(txDmaState == dmaWriting); 1548 txDmaState = dmaIdle; 1549 1550 DPRINTF(EthernetDMA, "tx dma write paddr=%#x len=%d\n", 1551 txDmaAddr, txDmaLen); 1552 DDUMP(EthernetDMA, txDmaData, txDmaLen); 1553 1554 // If the receive state machine has a pending DMA, let it go first 1555 if (rxDmaState == dmaReadWaiting || rxDmaState == dmaWriteWaiting) 1556 rxKick(); 1557 1558 txKick(); 1559} 1560 1561void 1562NSGigE::txKick() 1563{ 1564 bool is64bit = (bool)(regs.config & CFGR_M64ADDR); 1565 1566 DPRINTF(EthernetSM, "transmit kick txState=%s %d-bit\n", 1567 NsTxStateStrings[txState], is64bit ? 64 : 32); 1568 1569 Addr link, bufptr; 1570 uint32_t &cmdsts = is64bit ? txDesc64.cmdsts : txDesc32.cmdsts; 1571 uint32_t &extsts = is64bit ? txDesc64.extsts : txDesc32.extsts; 1572 1573 next: 1574 if (clock) { 1575 if (txKickTick > curTick) { 1576 DPRINTF(EthernetSM, "transmit kick exiting, can't run till %d\n", 1577 txKickTick); 1578 goto exit; 1579 } 1580 1581 // Go to the next state machine clock tick. 1582 txKickTick = curTick + ticks(1); 1583 } 1584 1585 switch(txDmaState) { 1586 case dmaReadWaiting: 1587 if (doTxDmaRead()) 1588 goto exit; 1589 break; 1590 case dmaWriteWaiting: 1591 if (doTxDmaWrite()) 1592 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