ns_gige.cc revision 9339
19814Sandreas.hansson@arm.com/* 22292SN/A * Copyright (c) 2004-2005 The Regents of The University of Michigan 313590Srekai.gonzalezalberquilla@arm.com * All rights reserved. 410239Sbinhpham@cs.rutgers.edu * 57597Sminkyu.jeong@arm.com * Redistribution and use in source and binary forms, with or without 67597Sminkyu.jeong@arm.com * modification, are permitted provided that the following conditions are 77597Sminkyu.jeong@arm.com * met: redistributions of source code must retain the above copyright 87597Sminkyu.jeong@arm.com * notice, this list of conditions and the following disclaimer; 97597Sminkyu.jeong@arm.com * redistributions in binary form must reproduce the above copyright 107597Sminkyu.jeong@arm.com * notice, this list of conditions and the following disclaimer in the 117597Sminkyu.jeong@arm.com * documentation and/or other materials provided with the distribution; 127597Sminkyu.jeong@arm.com * neither the name of the copyright holders nor the names of its 137597Sminkyu.jeong@arm.com * contributors may be used to endorse or promote products derived from 147597Sminkyu.jeong@arm.com * this software without specific prior written permission. 157597Sminkyu.jeong@arm.com * 162292SN/A * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 172292SN/A * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 182292SN/A * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR 192292SN/A * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT 202292SN/A * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 212292SN/A * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT 222292SN/A * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 232292SN/A * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 242292SN/A * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 252292SN/A * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 262292SN/A * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 272292SN/A * 282292SN/A * Authors: Nathan Binkert 292292SN/A * Lisa Hsu 302292SN/A */ 312292SN/A 322292SN/A/** @file 332292SN/A * Device module for modelling the National Semiconductor 342292SN/A * DP83820 ethernet controller. Does not support priority queueing 352292SN/A */ 362292SN/A#include <deque> 372292SN/A#include <string> 382292SN/A 392292SN/A#include "base/debug.hh" 402292SN/A#include "base/inet.hh" 412689Sktlim@umich.edu#include "base/types.hh" 422689Sktlim@umich.edu#include "config/the_isa.hh" 432689Sktlim@umich.edu#include "cpu/thread_context.hh" 442292SN/A#include "debug/EthernetAll.hh" 452292SN/A#include "dev/etherlink.hh" 469944Smatt.horsnell@ARM.com#include "dev/ns_gige.hh" 479944Smatt.horsnell@ARM.com#include "dev/pciconfigall.hh" 489944Smatt.horsnell@ARM.com#include "mem/packet.hh" 498591Sgblack@eecs.umich.edu#include "mem/packet_access.hh" 503326Sktlim@umich.edu#include "params/NSGigE.hh" 518229Snate@binkert.org#include "sim/system.hh" 526658Snate@binkert.org 538887Sgeoffrey.blake@arm.com// clang complains about std::set being overloaded with Packet::set if 542907Sktlim@umich.edu// we open up the entire namespace std 552292SN/Ausing std::min; 568232Snate@binkert.orgusing std::ostream; 578232Snate@binkert.orgusing std::string; 588232Snate@binkert.org 599527SMatt.Horsnell@arm.comconst char *NsRxStateStrings[] = 602722Sktlim@umich.edu{ 612669Sktlim@umich.edu "rxIdle", 622292SN/A "rxDescRefr", 632669Sktlim@umich.edu "rxDescRead", 6413429Srekai.gonzalezalberquilla@arm.com "rxFifoBlock", 6513429Srekai.gonzalezalberquilla@arm.com "rxFragWrite", 668581Ssteve.reinhardt@amd.com "rxDescWrite", 678581Ssteve.reinhardt@amd.com "rxAdvance" 682292SN/A}; 6913590Srekai.gonzalezalberquilla@arm.com 7013590Srekai.gonzalezalberquilla@arm.comconst char *NsTxStateStrings[] = 712292SN/A{ 722292SN/A "txIdle", 732669Sktlim@umich.edu "txDescRefr", 742292SN/A "txDescRead", 752678Sktlim@umich.edu "txFifoBlock", 762292SN/A "txFragRead", 779444SAndreas.Sandberg@ARM.com "txDescWrite", 789444SAndreas.Sandberg@ARM.com "txAdvance" 799444SAndreas.Sandberg@ARM.com}; 804319Sktlim@umich.edu 8113590Srekai.gonzalezalberquilla@arm.comconst char *NsDmaState[] = 8213590Srekai.gonzalezalberquilla@arm.com{ 832678Sktlim@umich.edu "dmaIdle", 842678Sktlim@umich.edu "dmaReading", 852292SN/A "dmaWriting", 862678Sktlim@umich.edu "dmaReadWaiting", 872678Sktlim@umich.edu "dmaWriteWaiting" 885336Shines@cs.fsu.edu}; 892678Sktlim@umich.edu 904873Sstever@eecs.umich.eduusing namespace Net; 912678Sktlim@umich.eduusing namespace TheISA; 922292SN/A 9313590Srekai.gonzalezalberquilla@arm.com/////////////////////////////////////////////////////////////////////// 9413590Srekai.gonzalezalberquilla@arm.com// 9513590Srekai.gonzalezalberquilla@arm.com// NSGigE PCI Device 9613590Srekai.gonzalezalberquilla@arm.com// 9713590Srekai.gonzalezalberquilla@arm.comNSGigE::NSGigE(Params *p) 9813590Srekai.gonzalezalberquilla@arm.com : EtherDevBase(p), ioEnable(false), 9913590Srekai.gonzalezalberquilla@arm.com txFifo(p->tx_fifo_size), rxFifo(p->rx_fifo_size), 10013590Srekai.gonzalezalberquilla@arm.com txPacket(0), rxPacket(0), txPacketBufPtr(NULL), rxPacketBufPtr(NULL), 10113590Srekai.gonzalezalberquilla@arm.com txXferLen(0), rxXferLen(0), rxDmaFree(false), txDmaFree(false), 10213590Srekai.gonzalezalberquilla@arm.com txState(txIdle), txEnable(false), CTDD(false), txHalt(false), 10313590Srekai.gonzalezalberquilla@arm.com txFragPtr(0), txDescCnt(0), txDmaState(dmaIdle), rxState(rxIdle), 10413590Srekai.gonzalezalberquilla@arm.com rxEnable(false), CRDD(false), rxPktBytes(0), rxHalt(false), 10513590Srekai.gonzalezalberquilla@arm.com rxFragPtr(0), rxDescCnt(0), rxDmaState(dmaIdle), extstsEnable(false), 10613590Srekai.gonzalezalberquilla@arm.com eepromState(eepromStart), eepromClk(false), eepromBitsToRx(0), 10713590Srekai.gonzalezalberquilla@arm.com eepromOpcode(0), eepromAddress(0), eepromData(0), 10813590Srekai.gonzalezalberquilla@arm.com dmaReadDelay(p->dma_read_delay), dmaWriteDelay(p->dma_write_delay), 10913590Srekai.gonzalezalberquilla@arm.com dmaReadFactor(p->dma_read_factor), dmaWriteFactor(p->dma_write_factor), 11013590Srekai.gonzalezalberquilla@arm.com rxDmaData(NULL), rxDmaAddr(0), rxDmaLen(0), 1112678Sktlim@umich.edu txDmaData(NULL), txDmaAddr(0), txDmaLen(0), 1122678Sktlim@umich.edu rxDmaReadEvent(this), rxDmaWriteEvent(this), 1132678Sktlim@umich.edu txDmaReadEvent(this), txDmaWriteEvent(this), 1142678Sktlim@umich.edu dmaDescFree(p->dma_desc_free), dmaDataFree(p->dma_data_free), 1152678Sktlim@umich.edu txDelay(p->tx_delay), rxDelay(p->rx_delay), 1162678Sktlim@umich.edu rxKickTick(0), rxKickEvent(this), txKickTick(0), txKickEvent(this), 1172344SN/A txEvent(this), rxFilterEnable(p->rx_filter), 11813590Srekai.gonzalezalberquilla@arm.com acceptBroadcast(false), acceptMulticast(false), acceptUnicast(false), 1192678Sktlim@umich.edu acceptPerfect(false), acceptArp(false), multicastHashEnable(false), 12013590Srekai.gonzalezalberquilla@arm.com intrDelay(p->intr_delay), intrTick(0), cpuPendingIntr(false), 12113590Srekai.gonzalezalberquilla@arm.com intrEvent(0), interface(0) 12213590Srekai.gonzalezalberquilla@arm.com{ 1236974Stjones1@inf.ed.ac.uk 1249444SAndreas.Sandberg@ARM.com 12510327Smitch.hayenga@arm.com interface = new NSGigEInt(name() + ".int0", this); 12613590Srekai.gonzalezalberquilla@arm.com 12713652Sqtt2@cornell.edu regsReset(); 12812216Snikos.nikoleris@arm.com memcpy(&rom.perfectMatch, p->hardware_address.bytes(), ETH_ADDR_LEN); 12913652Sqtt2@cornell.edu 13013652Sqtt2@cornell.edu memset(&rxDesc32, 0, sizeof(rxDesc32)); 13113590Srekai.gonzalezalberquilla@arm.com memset(&txDesc32, 0, sizeof(txDesc32)); 13213652Sqtt2@cornell.edu memset(&rxDesc64, 0, sizeof(rxDesc64)); 13313590Srekai.gonzalezalberquilla@arm.com memset(&txDesc64, 0, sizeof(txDesc64)); 13413590Srekai.gonzalezalberquilla@arm.com} 13513590Srekai.gonzalezalberquilla@arm.com 1366974Stjones1@inf.ed.ac.ukNSGigE::~NSGigE() 13713590Srekai.gonzalezalberquilla@arm.com{ 13813652Sqtt2@cornell.edu delete interface; 13913652Sqtt2@cornell.edu} 14013590Srekai.gonzalezalberquilla@arm.com 1412678Sktlim@umich.edu/** 1422344SN/A * This is to write to the PCI general configuration registers 1432292SN/A */ 1442292SN/ATick 1452292SN/ANSGigE::writeConfig(PacketPtr pkt) 14613472Srekai.gonzalezalberquilla@arm.com{ 14713472Srekai.gonzalezalberquilla@arm.com int offset = pkt->getAddr() & PCI_CONFIG_SIZE; 14813472Srekai.gonzalezalberquilla@arm.com if (offset < PCI_DEVICE_SPECIFIC) 14913590Srekai.gonzalezalberquilla@arm.com PciDev::writeConfig(pkt); 15013590Srekai.gonzalezalberquilla@arm.com else 1512292SN/A panic("Device specific PCI config space not implemented!\n"); 1522292SN/A 1532292SN/A switch (offset) { 1542292SN/A // seems to work fine without all these PCI settings, but i 1552292SN/A // put in the IO to double check, an assertion will fail if we 1565529Snate@binkert.org // need to properly implement it 15713472Srekai.gonzalezalberquilla@arm.com case PCI_COMMAND: 1582292SN/A if (config.data[offset] & PCI_CMD_IOSE) 15913472Srekai.gonzalezalberquilla@arm.com ioEnable = true; 16013472Srekai.gonzalezalberquilla@arm.com else 1614329Sktlim@umich.edu ioEnable = false; 1624329Sktlim@umich.edu break; 1634329Sktlim@umich.edu } 1642907Sktlim@umich.edu 1652907Sktlim@umich.edu return configDelay; 16613472Srekai.gonzalezalberquilla@arm.com} 1672292SN/A 1688199SAli.Saidi@ARM.comEtherInt* 1698199SAli.Saidi@ARM.comNSGigE::getEthPort(const std::string &if_name, int idx) 1709444SAndreas.Sandberg@ARM.com{ 1719444SAndreas.Sandberg@ARM.com if (if_name == "interface") { 1729444SAndreas.Sandberg@ARM.com if (interface->getPeer()) 1739444SAndreas.Sandberg@ARM.com panic("interface already connected to\n"); 1749444SAndreas.Sandberg@ARM.com return interface; 1759444SAndreas.Sandberg@ARM.com } 1769444SAndreas.Sandberg@ARM.com return NULL; 1779444SAndreas.Sandberg@ARM.com} 1789444SAndreas.Sandberg@ARM.com 1799444SAndreas.Sandberg@ARM.com/** 1809444SAndreas.Sandberg@ARM.com * This reads the device registers, which are detailed in the NS83820 1818199SAli.Saidi@ARM.com * spec sheet 1822292SN/A */ 18313590Srekai.gonzalezalberquilla@arm.comTick 1842292SN/ANSGigE::read(PacketPtr pkt) 1853492Sktlim@umich.edu{ 1862329SN/A assert(ioEnable); 1872292SN/A 1889444SAndreas.Sandberg@ARM.com pkt->allocate(); 1899444SAndreas.Sandberg@ARM.com 1909814Sandreas.hansson@arm.com //The mask is to give you only the offset into the device register file 1912292SN/A Addr daddr = pkt->getAddr() & 0xfff; 1922292SN/A DPRINTF(EthernetPIO, "read da=%#x pa=%#x size=%d\n", 1932292SN/A daddr, pkt->getAddr(), pkt->getSize()); 1942292SN/A 1952292SN/A 1962292SN/A // there are some reserved registers, you can see ns_gige_reg.h and 1972292SN/A // the spec sheet for details 1982292SN/A if (daddr > LAST && daddr <= RESERVED) { 1992292SN/A panic("Accessing reserved register"); 20010386Sandreas.hansson@arm.com } else if (daddr > RESERVED && daddr <= 0x3FC) { 2012292SN/A return readConfig(pkt); 2022292SN/A } else if (daddr >= MIB_START && daddr <= MIB_END) { 2032292SN/A // don't implement all the MIB's. hopefully the kernel 2042292SN/A // doesn't actually DEPEND upon their values 2052292SN/A // MIB are just hardware stats keepers 2062727Sktlim@umich.edu pkt->set<uint32_t>(0); 2072727Sktlim@umich.edu pkt->makeAtomicResponse(); 2082727Sktlim@umich.edu return pioDelay; 2092727Sktlim@umich.edu } else if (daddr > 0x3FC) 2102727Sktlim@umich.edu panic("Something is messed up!\n"); 2112727Sktlim@umich.edu 2122727Sktlim@umich.edu assert(pkt->getSize() == sizeof(uint32_t)); 2132727Sktlim@umich.edu uint32_t ® = *pkt->getPtr<uint32_t>(); 2142727Sktlim@umich.edu uint16_t rfaddr; 2152727Sktlim@umich.edu 2162727Sktlim@umich.edu switch (daddr) { 2172727Sktlim@umich.edu case CR: 2182727Sktlim@umich.edu reg = regs.command; 2192727Sktlim@umich.edu //these are supposed to be cleared on a read 2202727Sktlim@umich.edu reg &= ~(CR_RXD | CR_TXD | CR_TXR | CR_RXR); 2212727Sktlim@umich.edu break; 2222727Sktlim@umich.edu 2232727Sktlim@umich.edu case CFGR: 2242361SN/A reg = regs.config; 2252361SN/A break; 2262361SN/A 2272361SN/A case MEAR: 2282727Sktlim@umich.edu reg = regs.mear; 2292727Sktlim@umich.edu break; 2302727Sktlim@umich.edu 2312727Sktlim@umich.edu case PTSCR: 2322727Sktlim@umich.edu reg = regs.ptscr; 2332727Sktlim@umich.edu break; 2342727Sktlim@umich.edu 2352727Sktlim@umich.edu case ISR: 2362727Sktlim@umich.edu reg = regs.isr; 2372727Sktlim@umich.edu devIntrClear(ISR_ALL); 2382727Sktlim@umich.edu break; 2392727Sktlim@umich.edu 2402727Sktlim@umich.edu case IMR: 2412727Sktlim@umich.edu reg = regs.imr; 2422727Sktlim@umich.edu break; 2432727Sktlim@umich.edu 2442727Sktlim@umich.edu case IER: 2452727Sktlim@umich.edu reg = regs.ier; 2462727Sktlim@umich.edu break; 2472727Sktlim@umich.edu 2482727Sktlim@umich.edu case IHR: 2492727Sktlim@umich.edu reg = regs.ihr; 2502727Sktlim@umich.edu break; 2518922Swilliam.wang@arm.com 2524329Sktlim@umich.edu case TXDP: 2534329Sktlim@umich.edu reg = regs.txdp; 2544329Sktlim@umich.edu break; 2554329Sktlim@umich.edu 2564329Sktlim@umich.edu case TXDP_HI: 2574329Sktlim@umich.edu reg = regs.txdp_hi; 2589444SAndreas.Sandberg@ARM.com break; 2592307SN/A 26013590Srekai.gonzalezalberquilla@arm.com case TX_CFG: 26113590Srekai.gonzalezalberquilla@arm.com reg = regs.txcfg; 2622307SN/A break; 2632329SN/A 2649444SAndreas.Sandberg@ARM.com case GPIOR: 2652307SN/A reg = regs.gpior; 2662307SN/A break; 2672307SN/A 2682307SN/A case RXDP: 2692307SN/A reg = regs.rxdp; 2702307SN/A break; 2719444SAndreas.Sandberg@ARM.com 2722307SN/A case RXDP_HI: 2732307SN/A reg = regs.rxdp_hi; 2742292SN/A break; 2752292SN/A 27613429Srekai.gonzalezalberquilla@arm.com case RX_CFG: 2772292SN/A reg = regs.rxcfg; 2782292SN/A break; 2792292SN/A 28013652Sqtt2@cornell.edu case PQCR: 2812292SN/A reg = regs.pqcr; 2822292SN/A break; 2832292SN/A 2842292SN/A case WCSR: 2852292SN/A reg = regs.wcsr; 2862292SN/A break; 2872292SN/A 2882292SN/A case PCR: 2892292SN/A reg = regs.pcr; 2902292SN/A break; 2912292SN/A 2922292SN/A // see the spec sheet for how RFCR and RFDR work 29313429Srekai.gonzalezalberquilla@arm.com // basically, you write to RFCR to tell the machine 2942292SN/A // what you want to do next, then you act upon RFDR, 29513590Srekai.gonzalezalberquilla@arm.com // and the device will be prepared b/c of what you 29613590Srekai.gonzalezalberquilla@arm.com // wrote to RFCR 2972292SN/A case RFCR: 2987720Sgblack@eecs.umich.edu reg = regs.rfcr; 29913590Srekai.gonzalezalberquilla@arm.com break; 3002292SN/A 30113590Srekai.gonzalezalberquilla@arm.com case RFDR: 30213590Srekai.gonzalezalberquilla@arm.com rfaddr = (uint16_t)(regs.rfcr & RFCR_RFADDR); 3032292SN/A switch (rfaddr) { 30413590Srekai.gonzalezalberquilla@arm.com // Read from perfect match ROM octets 3052292SN/A case 0x000: 30613590Srekai.gonzalezalberquilla@arm.com reg = rom.perfectMatch[1]; 30713590Srekai.gonzalezalberquilla@arm.com reg = reg << 8; 30813590Srekai.gonzalezalberquilla@arm.com reg += rom.perfectMatch[0]; 30913590Srekai.gonzalezalberquilla@arm.com break; 3102292SN/A case 0x002: 3112292SN/A reg = rom.perfectMatch[3] << 8; 3122292SN/A reg += rom.perfectMatch[2]; 3132292SN/A break; 3142292SN/A case 0x004: 3152292SN/A reg = rom.perfectMatch[5] << 8; 31613590Srekai.gonzalezalberquilla@arm.com reg += rom.perfectMatch[4]; 3172292SN/A break; 3182292SN/A default: 31913590Srekai.gonzalezalberquilla@arm.com // Read filter hash table 32013590Srekai.gonzalezalberquilla@arm.com if (rfaddr >= FHASH_ADDR && 3212292SN/A rfaddr < FHASH_ADDR + FHASH_SIZE) { 3227720Sgblack@eecs.umich.edu 32313590Srekai.gonzalezalberquilla@arm.com // Only word-aligned reads supported 32413590Srekai.gonzalezalberquilla@arm.com if (rfaddr % 2) 3252292SN/A panic("unaligned read from filter hash table!"); 32613590Srekai.gonzalezalberquilla@arm.com 32713590Srekai.gonzalezalberquilla@arm.com reg = rom.filterHash[rfaddr - FHASH_ADDR + 1] << 8; 32813590Srekai.gonzalezalberquilla@arm.com reg += rom.filterHash[rfaddr - FHASH_ADDR]; 3292292SN/A break; 33013590Srekai.gonzalezalberquilla@arm.com } 3312292SN/A 3322292SN/A panic("reading RFDR for something other than pattern" 3332292SN/A " matching or hashing! %#x\n", rfaddr); 3342292SN/A } 3352292SN/A break; 3362292SN/A 3372292SN/A case SRR: 3382292SN/A reg = regs.srr; 3392292SN/A break; 3402292SN/A 3412292SN/A case MIBC: 3422292SN/A reg = regs.mibc; 3432292SN/A reg &= ~(MIBC_MIBS | MIBC_ACLR); 3442292SN/A break; 3452292SN/A 3462292SN/A case VRCR: 3472292SN/A reg = regs.vrcr; 34810239Sbinhpham@cs.rutgers.edu break; 3492292SN/A 35010239Sbinhpham@cs.rutgers.edu case VTCR: 35110239Sbinhpham@cs.rutgers.edu reg = regs.vtcr; 35213590Srekai.gonzalezalberquilla@arm.com break; 35313590Srekai.gonzalezalberquilla@arm.com 35413590Srekai.gonzalezalberquilla@arm.com case VDR: 35510239Sbinhpham@cs.rutgers.edu reg = regs.vdr; 3562292SN/A break; 35710239Sbinhpham@cs.rutgers.edu 35810239Sbinhpham@cs.rutgers.edu case CCSR: 35910239Sbinhpham@cs.rutgers.edu reg = regs.ccsr; 36010239Sbinhpham@cs.rutgers.edu break; 36110239Sbinhpham@cs.rutgers.edu 36210239Sbinhpham@cs.rutgers.edu case TBICR: 36313590Srekai.gonzalezalberquilla@arm.com reg = regs.tbicr; 36413590Srekai.gonzalezalberquilla@arm.com break; 36513590Srekai.gonzalezalberquilla@arm.com 36610239Sbinhpham@cs.rutgers.edu case TBISR: 36710239Sbinhpham@cs.rutgers.edu reg = regs.tbisr; 3682292SN/A break; 3692292SN/A 3708545Ssaidi@eecs.umich.edu case TANAR: 3718545Ssaidi@eecs.umich.edu reg = regs.tanar; 3728545Ssaidi@eecs.umich.edu break; 37311357Sstephan.diestelhorst@arm.com 37411357Sstephan.diestelhorst@arm.com case TANLPAR: 37511357Sstephan.diestelhorst@arm.com reg = regs.tanlpar; 37610030SAli.Saidi@ARM.com break; 3778545Ssaidi@eecs.umich.edu 37810030SAli.Saidi@ARM.com case TANER: 3799383SAli.Saidi@ARM.com reg = regs.taner; 3809383SAli.Saidi@ARM.com break; 3819383SAli.Saidi@ARM.com 3829383SAli.Saidi@ARM.com case TESR: 3839383SAli.Saidi@ARM.com reg = regs.tesr; 3849383SAli.Saidi@ARM.com break; 3859383SAli.Saidi@ARM.com 38613590Srekai.gonzalezalberquilla@arm.com case M5REG: 38713590Srekai.gonzalezalberquilla@arm.com reg = 0; 38813590Srekai.gonzalezalberquilla@arm.com if (params()->rx_thread) 38913590Srekai.gonzalezalberquilla@arm.com reg |= M5REG_RX_THREAD; 39013590Srekai.gonzalezalberquilla@arm.com if (params()->tx_thread) 39110030SAli.Saidi@ARM.com reg |= M5REG_TX_THREAD; 39210030SAli.Saidi@ARM.com if (params()->rss) 39313590Srekai.gonzalezalberquilla@arm.com reg |= M5REG_RSS; 39413590Srekai.gonzalezalberquilla@arm.com break; 39513590Srekai.gonzalezalberquilla@arm.com 39611097Songal@cs.wisc.edu default: 39713590Srekai.gonzalezalberquilla@arm.com panic("reading unimplemented register: addr=%#x", daddr); 39813590Srekai.gonzalezalberquilla@arm.com } 39913590Srekai.gonzalezalberquilla@arm.com 40013590Srekai.gonzalezalberquilla@arm.com DPRINTF(EthernetPIO, "read from %#x: data=%d data=%#x\n", 40113590Srekai.gonzalezalberquilla@arm.com daddr, reg, reg); 4028545Ssaidi@eecs.umich.edu 40310149Smarco.elver@ed.ac.uk pkt->makeAtomicResponse(); 40410149Smarco.elver@ed.ac.uk return pioDelay; 40513590Srekai.gonzalezalberquilla@arm.com} 40613590Srekai.gonzalezalberquilla@arm.com 40713590Srekai.gonzalezalberquilla@arm.comTick 40813590Srekai.gonzalezalberquilla@arm.comNSGigE::write(PacketPtr pkt) 40913590Srekai.gonzalezalberquilla@arm.com{ 41013590Srekai.gonzalezalberquilla@arm.com assert(ioEnable); 4118545Ssaidi@eecs.umich.edu 41213590Srekai.gonzalezalberquilla@arm.com Addr daddr = pkt->getAddr() & 0xfff; 41313590Srekai.gonzalezalberquilla@arm.com DPRINTF(EthernetPIO, "write da=%#x pa=%#x size=%d\n", 4148545Ssaidi@eecs.umich.edu daddr, pkt->getAddr(), pkt->getSize()); 41513590Srekai.gonzalezalberquilla@arm.com 41613590Srekai.gonzalezalberquilla@arm.com if (daddr > LAST && daddr <= RESERVED) { 41710149Smarco.elver@ed.ac.uk panic("Accessing reserved register"); 41810149Smarco.elver@ed.ac.uk } else if (daddr > RESERVED && daddr <= 0x3FC) { 41910149Smarco.elver@ed.ac.uk return writeConfig(pkt); 42010149Smarco.elver@ed.ac.uk } else if (daddr > 0x3FC) 42110149Smarco.elver@ed.ac.uk panic("Something is messed up!\n"); 42210149Smarco.elver@ed.ac.uk 42310149Smarco.elver@ed.ac.uk if (pkt->getSize() == sizeof(uint32_t)) { 4248545Ssaidi@eecs.umich.edu uint32_t reg = pkt->get<uint32_t>(); 42510030SAli.Saidi@ARM.com uint16_t rfaddr; 4268545Ssaidi@eecs.umich.edu 4278545Ssaidi@eecs.umich.edu DPRINTF(EthernetPIO, "write data=%d data=%#x\n", reg, reg); 42810474Sandreas.hansson@arm.com 4298545Ssaidi@eecs.umich.edu switch (daddr) { 43010030SAli.Saidi@ARM.com case CR: 43110030SAli.Saidi@ARM.com regs.command = reg; 43210030SAli.Saidi@ARM.com if (reg & CR_TXD) { 43310030SAli.Saidi@ARM.com txEnable = false; 43410030SAli.Saidi@ARM.com } else if (reg & CR_TXE) { 43510030SAli.Saidi@ARM.com txEnable = true; 43610030SAli.Saidi@ARM.com 43710030SAli.Saidi@ARM.com // the kernel is enabling the transmit machine 43810030SAli.Saidi@ARM.com if (txState == txIdle) 4398545Ssaidi@eecs.umich.edu txKick(); 4408545Ssaidi@eecs.umich.edu } 4418545Ssaidi@eecs.umich.edu 4429046SAli.Saidi@ARM.com if (reg & CR_RXD) { 4438545Ssaidi@eecs.umich.edu rxEnable = false; 4448545Ssaidi@eecs.umich.edu } else if (reg & CR_RXE) { 4458545Ssaidi@eecs.umich.edu rxEnable = true; 4468545Ssaidi@eecs.umich.edu 4478545Ssaidi@eecs.umich.edu if (rxState == rxIdle) 4488545Ssaidi@eecs.umich.edu rxKick(); 4498545Ssaidi@eecs.umich.edu } 4502292SN/A 45113590Srekai.gonzalezalberquilla@arm.com if (reg & CR_TXR) 45213590Srekai.gonzalezalberquilla@arm.com txReset(); 4538199SAli.Saidi@ARM.com 4548199SAli.Saidi@ARM.com if (reg & CR_RXR) 4558199SAli.Saidi@ARM.com rxReset(); 4568199SAli.Saidi@ARM.com 4578199SAli.Saidi@ARM.com if (reg & CR_SWI) 4588199SAli.Saidi@ARM.com devIntrPost(ISR_SWI); 4598199SAli.Saidi@ARM.com 4608199SAli.Saidi@ARM.com if (reg & CR_RST) { 4618199SAli.Saidi@ARM.com txReset(); 46213590Srekai.gonzalezalberquilla@arm.com rxReset(); 46313590Srekai.gonzalezalberquilla@arm.com 46410824SAndreas.Sandberg@ARM.com regsReset(); 46513590Srekai.gonzalezalberquilla@arm.com } 4668199SAli.Saidi@ARM.com break; 4678199SAli.Saidi@ARM.com 4688199SAli.Saidi@ARM.com case CFGR: 4698199SAli.Saidi@ARM.com if (reg & CFGR_LNKSTS || 4708199SAli.Saidi@ARM.com reg & CFGR_SPDSTS || 4718199SAli.Saidi@ARM.com reg & CFGR_DUPSTS || 4728199SAli.Saidi@ARM.com reg & CFGR_RESERVED || 4738272SAli.Saidi@ARM.com reg & CFGR_T64ADDR || 4748545Ssaidi@eecs.umich.edu reg & CFGR_PCI64_DET) { 4758545Ssaidi@eecs.umich.edu // First clear all writable bits 4768545Ssaidi@eecs.umich.edu regs.config &= CFGR_LNKSTS | CFGR_SPDSTS | CFGR_DUPSTS | 4778545Ssaidi@eecs.umich.edu CFGR_RESERVED | CFGR_T64ADDR | 4789046SAli.Saidi@ARM.com CFGR_PCI64_DET; 4798545Ssaidi@eecs.umich.edu // Now set the appropriate writable bits 4808545Ssaidi@eecs.umich.edu regs.config |= reg & ~(CFGR_LNKSTS | CFGR_SPDSTS | CFGR_DUPSTS | 4818545Ssaidi@eecs.umich.edu CFGR_RESERVED | CFGR_T64ADDR | 4828592Sgblack@eecs.umich.edu CFGR_PCI64_DET); 4838592Sgblack@eecs.umich.edu } 4848545Ssaidi@eecs.umich.edu 4858199SAli.Saidi@ARM.com// all these #if 0's are because i don't THINK the kernel needs to 4868545Ssaidi@eecs.umich.edu// have these implemented. if there is a problem relating to one of 4878199SAli.Saidi@ARM.com// these, you may need to add functionality in. 48810474Sandreas.hansson@arm.com 48910474Sandreas.hansson@arm.com// grouped together and #if 0'ed to avoid empty if body and make clang happy 49010474Sandreas.hansson@arm.com#if 0 49110474Sandreas.hansson@arm.com if (reg & CFGR_TBI_EN) ; 4928545Ssaidi@eecs.umich.edu if (reg & CFGR_MODE_1000) ; 4938545Ssaidi@eecs.umich.edu 4948199SAli.Saidi@ARM.com if (reg & CFGR_PINT_DUPSTS || 4958545Ssaidi@eecs.umich.edu reg & CFGR_PINT_LNKSTS || 4968545Ssaidi@eecs.umich.edu reg & CFGR_PINT_SPDSTS) 4979046SAli.Saidi@ARM.com ; 49810575SMarco.Elver@ARM.com 4998545Ssaidi@eecs.umich.edu if (reg & CFGR_TMRTEST) ; 5008545Ssaidi@eecs.umich.edu if (reg & CFGR_MRM_DIS) ; 5018545Ssaidi@eecs.umich.edu if (reg & CFGR_MWI_DIS) ; 5028545Ssaidi@eecs.umich.edu 5038545Ssaidi@eecs.umich.edu if (reg & CFGR_DATA64_EN) ; 5048545Ssaidi@eecs.umich.edu if (reg & CFGR_M64ADDR) ; 5058545Ssaidi@eecs.umich.edu if (reg & CFGR_PHY_RST) ; 5068545Ssaidi@eecs.umich.edu if (reg & CFGR_PHY_DIS) ; 5078545Ssaidi@eecs.umich.edu 5088592Sgblack@eecs.umich.edu if (reg & CFGR_REQALG) ; 5098592Sgblack@eecs.umich.edu if (reg & CFGR_SB) ; 5108592Sgblack@eecs.umich.edu if (reg & CFGR_POW) ; 5118545Ssaidi@eecs.umich.edu if (reg & CFGR_EXD) ; 5128545Ssaidi@eecs.umich.edu if (reg & CFGR_PESEL) ; 5138545Ssaidi@eecs.umich.edu if (reg & CFGR_BROM_DIS) ; 5148545Ssaidi@eecs.umich.edu if (reg & CFGR_EXT_125) ; 51510474Sandreas.hansson@arm.com if (reg & CFGR_BEM) ; 51610474Sandreas.hansson@arm.com 51710474Sandreas.hansson@arm.com if (reg & CFGR_T64ADDR) ; 51810474Sandreas.hansson@arm.com // panic("CFGR_T64ADDR is read only register!\n"); 5198545Ssaidi@eecs.umich.edu#endif 5208199SAli.Saidi@ARM.com if (reg & CFGR_AUTO_1000) 5218199SAli.Saidi@ARM.com panic("CFGR_AUTO_1000 not implemented!\n"); 52213590Srekai.gonzalezalberquilla@arm.com 5238199SAli.Saidi@ARM.com if (reg & CFGR_PCI64_DET) 5248199SAli.Saidi@ARM.com panic("CFGR_PCI64_DET is read only register!\n"); 5258199SAli.Saidi@ARM.com 5268199SAli.Saidi@ARM.com if (reg & CFGR_EXTSTS_EN) 5278199SAli.Saidi@ARM.com extstsEnable = true; 5288199SAli.Saidi@ARM.com else 5298199SAli.Saidi@ARM.com extstsEnable = false; 5308199SAli.Saidi@ARM.com break; 5318199SAli.Saidi@ARM.com 53213429Srekai.gonzalezalberquilla@arm.com case MEAR: 5332292SN/A // Clear writable bits 5344032Sktlim@umich.edu regs.mear &= MEAR_EEDO; 5352292SN/A // Set appropriate writable bits 5362292SN/A regs.mear |= reg & ~MEAR_EEDO; 5372292SN/A 5387720Sgblack@eecs.umich.edu // FreeBSD uses the EEPROM to read PMATCH (for the MAC address) 5397944SGiacomo.Gabrielli@arm.com // even though it could get it through RFDR 5402292SN/A if (reg & MEAR_EESEL) { 5414032Sktlim@umich.edu // Rising edge of clock 5424032Sktlim@umich.edu if (reg & MEAR_EECLK && !eepromClk) 5432669Sktlim@umich.edu eepromKick(); 5442292SN/A } 54513954Sgiacomo.gabrielli@arm.com else { 54613953Sgiacomo.gabrielli@arm.com eepromState = eepromStart; 54713953Sgiacomo.gabrielli@arm.com regs.mear &= ~MEAR_EEDI; 54813953Sgiacomo.gabrielli@arm.com } 54913953Sgiacomo.gabrielli@arm.com 55013953Sgiacomo.gabrielli@arm.com eepromClk = reg & MEAR_EECLK; 55113953Sgiacomo.gabrielli@arm.com 55213953Sgiacomo.gabrielli@arm.com // since phy is completely faked, MEAR_MD* don't matter 55313953Sgiacomo.gabrielli@arm.com 55413590Srekai.gonzalezalberquilla@arm.com// grouped together and #if 0'ed to avoid empty if body and make clang happy 5557944SGiacomo.Gabrielli@arm.com#if 0 5567944SGiacomo.Gabrielli@arm.com if (reg & MEAR_MDIO) ; 5577597Sminkyu.jeong@arm.com if (reg & MEAR_MDDIR) ; 5587597Sminkyu.jeong@arm.com if (reg & MEAR_MDC) ; 55910231Ssteve.reinhardt@amd.com#endif 5602329SN/A break; 56110824SAndreas.Sandberg@ARM.com 56210824SAndreas.Sandberg@ARM.com case PTSCR: 56310824SAndreas.Sandberg@ARM.com regs.ptscr = reg & ~(PTSCR_RBIST_RDONLY); 56410231Ssteve.reinhardt@amd.com // these control BISTs for various parts of chip - we 5657848SAli.Saidi@ARM.com // don't care or do just fake that the BIST is done 5667600Sminkyu.jeong@arm.com if (reg & PTSCR_RBIST_EN) 5677600Sminkyu.jeong@arm.com regs.ptscr |= PTSCR_RBIST_DONE; 5687600Sminkyu.jeong@arm.com if (reg & PTSCR_EEBIST_EN) 56910824SAndreas.Sandberg@ARM.com regs.ptscr &= ~PTSCR_EEBIST_EN; 5703731Sktlim@umich.edu if (reg & PTSCR_EELOAD_EN) 5712367SN/A regs.ptscr &= ~PTSCR_EELOAD_EN; 5722367SN/A break; 5732292SN/A 5742292SN/A case ISR: /* writing to the ISR has no effect */ 57510333Smitch.hayenga@arm.com panic("ISR is a read only register!\n"); 57613590Srekai.gonzalezalberquilla@arm.com 57713590Srekai.gonzalezalberquilla@arm.com case IMR: 57813590Srekai.gonzalezalberquilla@arm.com regs.imr = reg; 5794032Sktlim@umich.edu devIntrChangeMask(); 58013590Srekai.gonzalezalberquilla@arm.com break; 58113590Srekai.gonzalezalberquilla@arm.com 58213590Srekai.gonzalezalberquilla@arm.com case IER: 5832292SN/A regs.ier = reg; 5842292SN/A break; 5852292SN/A 5862292SN/A case IHR: 5872292SN/A regs.ihr = reg; 5882292SN/A /* not going to implement real interrupt holdoff */ 5892292SN/A break; 59013429Srekai.gonzalezalberquilla@arm.com 5912292SN/A case TXDP: 5922292SN/A regs.txdp = (reg & 0xFFFFFFFC); 5932292SN/A assert(txState == txIdle); 5942292SN/A CTDD = false; 5952292SN/A break; 5962292SN/A 5972292SN/A case TXDP_HI: 5987720Sgblack@eecs.umich.edu regs.txdp_hi = reg; 5997720Sgblack@eecs.umich.edu break; 6002292SN/A 6014032Sktlim@umich.edu case TX_CFG: 6024032Sktlim@umich.edu regs.txcfg = reg; 6032292SN/A#if 0 6042292SN/A if (reg & TX_CFG_CSI) ; 60513590Srekai.gonzalezalberquilla@arm.com if (reg & TX_CFG_HBI) ; 6062292SN/A if (reg & TX_CFG_MLB) ; 6072292SN/A if (reg & TX_CFG_ATP) ; 6082292SN/A if (reg & TX_CFG_ECRETRY) { 6097944SGiacomo.Gabrielli@arm.com /* 6107944SGiacomo.Gabrielli@arm.com * this could easily be implemented, but considering 6117944SGiacomo.Gabrielli@arm.com * the network is just a fake pipe, wouldn't make 6127944SGiacomo.Gabrielli@arm.com * sense to do this 61312217Snikos.nikoleris@arm.com */ 61412217Snikos.nikoleris@arm.com } 61512217Snikos.nikoleris@arm.com 6167848SAli.Saidi@ARM.com if (reg & TX_CFG_BRST_DIS) ; 61712217Snikos.nikoleris@arm.com#endif 61812217Snikos.nikoleris@arm.com 6197848SAli.Saidi@ARM.com#if 0 62013590Srekai.gonzalezalberquilla@arm.com /* we handle our own DMA, ignore the kernel's exhortations */ 6217782Sminkyu.jeong@arm.com if (reg & TX_CFG_MXDMA) ; 6227720Sgblack@eecs.umich.edu#endif 6232292SN/A 6242292SN/A // also, we currently don't care about fill/drain 6252292SN/A // thresholds though this may change in the future with 6262292SN/A // more realistic networks or a driver which changes it 6272292SN/A // according to feedback 6282292SN/A 62913652Sqtt2@cornell.edu break; 63013652Sqtt2@cornell.edu 6312336SN/A case GPIOR: 63213590Srekai.gonzalezalberquilla@arm.com // Only write writable bits 6332292SN/A regs.gpior &= GPIOR_UNUSED | GPIOR_GP5_IN | GPIOR_GP4_IN 6342329SN/A | GPIOR_GP3_IN | GPIOR_GP2_IN | GPIOR_GP1_IN; 6352292SN/A regs.gpior |= reg & ~(GPIOR_UNUSED | GPIOR_GP5_IN | GPIOR_GP4_IN 6362292SN/A | GPIOR_GP3_IN | GPIOR_GP2_IN | GPIOR_GP1_IN); 63713590Srekai.gonzalezalberquilla@arm.com /* these just control general purpose i/o pins, don't matter */ 6382292SN/A break; 6392292SN/A 6402292SN/A case RXDP: 6412292SN/A regs.rxdp = reg; 6422292SN/A CRDD = false; 6432292SN/A break; 6442292SN/A 64513590Srekai.gonzalezalberquilla@arm.com case RXDP_HI: 6462292SN/A regs.rxdp_hi = reg; 6477720Sgblack@eecs.umich.edu break; 64813590Srekai.gonzalezalberquilla@arm.com 6492292SN/A case RX_CFG: 65013590Srekai.gonzalezalberquilla@arm.com regs.rxcfg = reg; 65113590Srekai.gonzalezalberquilla@arm.com#if 0 6522292SN/A if (reg & RX_CFG_AEP) ; 6532292SN/A if (reg & RX_CFG_ARP) ; 6542292SN/A if (reg & RX_CFG_STRIPCRC) ; 6552292SN/A if (reg & RX_CFG_RX_RD) ; 6562292SN/A if (reg & RX_CFG_ALP) ; 6572292SN/A if (reg & RX_CFG_AIRL) ; 6582292SN/A 6592292SN/A /* we handle our own DMA, ignore what kernel says about it */ 66013590Srekai.gonzalezalberquilla@arm.com if (reg & RX_CFG_MXDMA) ; 6612292SN/A 66213590Srekai.gonzalezalberquilla@arm.com //also, we currently don't care about fill/drain thresholds 66313590Srekai.gonzalezalberquilla@arm.com //though this may change in the future with more realistic 6642292SN/A //networks or a driver which changes it according to feedback 6652292SN/A if (reg & (RX_CFG_DRTH | RX_CFG_DRTH0)) ; 6662292SN/A#endif 6672292SN/A break; 6682292SN/A 6692292SN/A case PQCR: 6702292SN/A /* there is no priority queueing used in the linux 2.6 driver */ 6712292SN/A regs.pqcr = reg; 67213590Srekai.gonzalezalberquilla@arm.com break; 6732292SN/A 67413590Srekai.gonzalezalberquilla@arm.com case WCSR: 67513590Srekai.gonzalezalberquilla@arm.com /* not going to implement wake on LAN */ 67613590Srekai.gonzalezalberquilla@arm.com regs.wcsr = reg; 6772329SN/A break; 6782329SN/A 67913590Srekai.gonzalezalberquilla@arm.com case PCR: 68013590Srekai.gonzalezalberquilla@arm.com /* not going to implement pause control */ 6812292SN/A regs.pcr = reg; 6822292SN/A break; 6832292SN/A 6847720Sgblack@eecs.umich.edu case RFCR: 68513590Srekai.gonzalezalberquilla@arm.com regs.rfcr = reg; 68613590Srekai.gonzalezalberquilla@arm.com 6872292SN/A rxFilterEnable = (reg & RFCR_RFEN) ? true : false; 68813590Srekai.gonzalezalberquilla@arm.com acceptBroadcast = (reg & RFCR_AAB) ? true : false; 6892292SN/A acceptMulticast = (reg & RFCR_AAM) ? true : false; 6902292SN/A acceptUnicast = (reg & RFCR_AAU) ? true : false; 6912292SN/A acceptPerfect = (reg & RFCR_APM) ? true : false; 6922292SN/A acceptArp = (reg & RFCR_AARP) ? true : false; 6932292SN/A multicastHashEnable = (reg & RFCR_MHEN) ? true : false; 6942292SN/A 6952292SN/A#if 0 6962292SN/A if (reg & RFCR_APAT) 69713590Srekai.gonzalezalberquilla@arm.com panic("RFCR_APAT not implemented!\n"); 6986974Stjones1@inf.ed.ac.uk#endif 69913590Srekai.gonzalezalberquilla@arm.com if (reg & RFCR_UHEN) 70013590Srekai.gonzalezalberquilla@arm.com panic("Unicast hash filtering not used by drivers!\n"); 70113590Srekai.gonzalezalberquilla@arm.com 70213590Srekai.gonzalezalberquilla@arm.com if (reg & RFCR_ULM) 7036974Stjones1@inf.ed.ac.uk panic("RFCR_ULM not implemented!\n"); 7046974Stjones1@inf.ed.ac.uk 7056974Stjones1@inf.ed.ac.uk break; 7066974Stjones1@inf.ed.ac.uk 7076974Stjones1@inf.ed.ac.uk case RFDR: 7082292SN/A rfaddr = (uint16_t)(regs.rfcr & RFCR_RFADDR); 7092292SN/A switch (rfaddr) { 71013590Srekai.gonzalezalberquilla@arm.com case 0x000: 71113590Srekai.gonzalezalberquilla@arm.com rom.perfectMatch[0] = (uint8_t)reg; 71213590Srekai.gonzalezalberquilla@arm.com rom.perfectMatch[1] = (uint8_t)(reg >> 8); 7136974Stjones1@inf.ed.ac.uk break; 7146974Stjones1@inf.ed.ac.uk case 0x002: 7152292SN/A rom.perfectMatch[2] = (uint8_t)reg; 71613590Srekai.gonzalezalberquilla@arm.com rom.perfectMatch[3] = (uint8_t)(reg >> 8); 71713590Srekai.gonzalezalberquilla@arm.com break; 71813590Srekai.gonzalezalberquilla@arm.com case 0x004: 7198727Snilay@cs.wisc.edu rom.perfectMatch[4] = (uint8_t)reg; 72013710Sgabor.dozsa@arm.com rom.perfectMatch[5] = (uint8_t)(reg >> 8); 7212292SN/A break; 72210333Smitch.hayenga@arm.com default: 7232678Sktlim@umich.edu 7242678Sktlim@umich.edu if (rfaddr >= FHASH_ADDR && 7252678Sktlim@umich.edu rfaddr < FHASH_ADDR + FHASH_SIZE) { 7262678Sktlim@umich.edu 7272678Sktlim@umich.edu // Only word-aligned writes supported 7282329SN/A if (rfaddr % 2) 7292329SN/A panic("unaligned write to filter hash table!"); 73013590Srekai.gonzalezalberquilla@arm.com 73113590Srekai.gonzalezalberquilla@arm.com rom.filterHash[rfaddr - FHASH_ADDR] = (uint8_t)reg; 73213590Srekai.gonzalezalberquilla@arm.com rom.filterHash[rfaddr - FHASH_ADDR + 1] 73313590Srekai.gonzalezalberquilla@arm.com = (uint8_t)(reg >> 8); 73413590Srekai.gonzalezalberquilla@arm.com break; 7352292SN/A } 7362292SN/A panic("writing RFDR for something other than pattern matching\ 7372678Sktlim@umich.edu or hashing! %#x\n", rfaddr); 73813590Srekai.gonzalezalberquilla@arm.com } 73913590Srekai.gonzalezalberquilla@arm.com 7402292SN/A case BRAR: 7412292SN/A regs.brar = reg; 7422292SN/A break; 74313590Srekai.gonzalezalberquilla@arm.com 74413590Srekai.gonzalezalberquilla@arm.com case BRDR: 7452292SN/A panic("the driver never uses BRDR, something is wrong!\n"); 74613590Srekai.gonzalezalberquilla@arm.com 74713590Srekai.gonzalezalberquilla@arm.com case SRR: 74813590Srekai.gonzalezalberquilla@arm.com panic("SRR is read only register!\n"); 7492292SN/A 7502669Sktlim@umich.edu case MIBC: 75113590Srekai.gonzalezalberquilla@arm.com panic("the driver never uses MIBC, something is wrong!\n"); 7523772Sgblack@eecs.umich.edu 75313590Srekai.gonzalezalberquilla@arm.com case VRCR: 75413590Srekai.gonzalezalberquilla@arm.com regs.vrcr = reg; 75510031SAli.Saidi@ARM.com break; 75613590Srekai.gonzalezalberquilla@arm.com 7572669Sktlim@umich.edu case VTCR: 7582292SN/A regs.vtcr = reg; 75913590Srekai.gonzalezalberquilla@arm.com break; 76013590Srekai.gonzalezalberquilla@arm.com 76113590Srekai.gonzalezalberquilla@arm.com case VDR: 76213590Srekai.gonzalezalberquilla@arm.com panic("the driver never uses VDR, something is wrong!\n"); 76313590Srekai.gonzalezalberquilla@arm.com 7646974Stjones1@inf.ed.ac.uk case CCSR: 76513590Srekai.gonzalezalberquilla@arm.com /* not going to implement clockrun stuff */ 76613652Sqtt2@cornell.edu regs.ccsr = reg; 76713652Sqtt2@cornell.edu break; 76813590Srekai.gonzalezalberquilla@arm.com 76913590Srekai.gonzalezalberquilla@arm.com case TBICR: 7706974Stjones1@inf.ed.ac.uk regs.tbicr = reg; 77113590Srekai.gonzalezalberquilla@arm.com if (reg & TBICR_MR_LOOPBACK) 7722678Sktlim@umich.edu panic("TBICR_MR_LOOPBACK never used, something wrong!\n"); 7737720Sgblack@eecs.umich.edu 7742292SN/A if (reg & TBICR_MR_AN_ENABLE) { 77513590Srekai.gonzalezalberquilla@arm.com regs.tanlpar = regs.tanar; 77613590Srekai.gonzalezalberquilla@arm.com regs.tbisr |= (TBISR_MR_AN_COMPLETE | TBISR_MR_LINK_STATUS); 7773221Sktlim@umich.edu } 7782292SN/A 7792693Sktlim@umich.edu#if 0 7804350Sgblack@eecs.umich.edu if (reg & TBICR_MR_RESTART_AN) ; 7813326Sktlim@umich.edu#endif 7823326Sktlim@umich.edu 7833326Sktlim@umich.edu break; 7849046SAli.Saidi@ARM.com 78513590Srekai.gonzalezalberquilla@arm.com case TBISR: 78613590Srekai.gonzalezalberquilla@arm.com panic("TBISR is read only register!\n"); 7879046SAli.Saidi@ARM.com 78813590Srekai.gonzalezalberquilla@arm.com case TANAR: 7893326Sktlim@umich.edu // Only write the writable bits 7903326Sktlim@umich.edu regs.tanar &= TANAR_RF1 | TANAR_RF2 | TANAR_UNUSED; 79113590Srekai.gonzalezalberquilla@arm.com regs.tanar |= reg & ~(TANAR_RF1 | TANAR_RF2 | TANAR_UNUSED); 7923326Sktlim@umich.edu 7933326Sktlim@umich.edu // Pause capability unimplemented 7943326Sktlim@umich.edu#if 0 7953326Sktlim@umich.edu if (reg & TANAR_PS2) ; 79613590Srekai.gonzalezalberquilla@arm.com if (reg & TANAR_PS1) ; 79713590Srekai.gonzalezalberquilla@arm.com#endif 79813590Srekai.gonzalezalberquilla@arm.com 7997823Ssteve.reinhardt@amd.com break; 80013590Srekai.gonzalezalberquilla@arm.com 80113590Srekai.gonzalezalberquilla@arm.com case TANLPAR: 80213590Srekai.gonzalezalberquilla@arm.com panic("this should only be written to by the fake phy!\n"); 80313590Srekai.gonzalezalberquilla@arm.com 80413590Srekai.gonzalezalberquilla@arm.com case TANER: 8053326Sktlim@umich.edu panic("TANER is read only register!\n"); 8062693Sktlim@umich.edu 8072693Sktlim@umich.edu case TESR: 8082693Sktlim@umich.edu regs.tesr = reg; 80913590Srekai.gonzalezalberquilla@arm.com break; 81013590Srekai.gonzalezalberquilla@arm.com 81113590Srekai.gonzalezalberquilla@arm.com default: 81213590Srekai.gonzalezalberquilla@arm.com panic("invalid register access daddr=%#x", daddr); 81313590Srekai.gonzalezalberquilla@arm.com } 81413590Srekai.gonzalezalberquilla@arm.com } else { 81513590Srekai.gonzalezalberquilla@arm.com panic("Invalid Request Size"); 81613590Srekai.gonzalezalberquilla@arm.com } 81713590Srekai.gonzalezalberquilla@arm.com pkt->makeAtomicResponse(); 81813590Srekai.gonzalezalberquilla@arm.com return pioDelay; 81913590Srekai.gonzalezalberquilla@arm.com} 82013590Srekai.gonzalezalberquilla@arm.com 82113590Srekai.gonzalezalberquilla@arm.comvoid 82213590Srekai.gonzalezalberquilla@arm.comNSGigE::devIntrPost(uint32_t interrupts) 8238481Sgblack@eecs.umich.edu{ 82413590Srekai.gonzalezalberquilla@arm.com if (interrupts & ISR_RESERVE) 82513590Srekai.gonzalezalberquilla@arm.com panic("Cannot set a reserved interrupt"); 82613590Srekai.gonzalezalberquilla@arm.com 82713590Srekai.gonzalezalberquilla@arm.com if (interrupts & ISR_NOIMPL) 82813590Srekai.gonzalezalberquilla@arm.com warn("interrupt not implemented %#x\n", interrupts); 82913590Srekai.gonzalezalberquilla@arm.com 8303221Sktlim@umich.edu interrupts &= ISR_IMPL; 8312292SN/A regs.isr |= interrupts; 8322292SN/A 8332292SN/A if (interrupts & regs.imr) { 8342292SN/A if (interrupts & ISR_SWI) { 8352292SN/A totalSwi++; 8362292SN/A } 8372292SN/A if (interrupts & ISR_RXIDLE) { 8382292SN/A totalRxIdle++; 8392292SN/A } 8402292SN/A if (interrupts & ISR_RXOK) { 8412329SN/A totalRxOk++; 8422292SN/A } 84313590Srekai.gonzalezalberquilla@arm.com if (interrupts & ISR_RXDESC) { 84413590Srekai.gonzalezalberquilla@arm.com totalRxDesc++; 8457720Sgblack@eecs.umich.edu } 8462292SN/A if (interrupts & ISR_TXOK) { 84713590Srekai.gonzalezalberquilla@arm.com totalTxOk++; 84813590Srekai.gonzalezalberquilla@arm.com } 8492292SN/A if (interrupts & ISR_TXIDLE) { 85013590Srekai.gonzalezalberquilla@arm.com totalTxIdle++; 8512292SN/A } 8522292SN/A if (interrupts & ISR_TXDESC) { 8532292SN/A totalTxDesc++; 8542292SN/A } 8552292SN/A if (interrupts & ISR_RXORN) { 8562329SN/A totalRxOrn++; 85713590Srekai.gonzalezalberquilla@arm.com } 85813590Srekai.gonzalezalberquilla@arm.com } 85913590Srekai.gonzalezalberquilla@arm.com 8602292SN/A DPRINTF(EthernetIntr, 8612292SN/A "interrupt written to ISR: intr=%#x isr=%#x imr=%#x\n", 86213590Srekai.gonzalezalberquilla@arm.com interrupts, regs.isr, regs.imr); 8632727Sktlim@umich.edu 8642292SN/A if ((regs.isr & regs.imr)) { 8652292SN/A Tick when = curTick(); 8664032Sktlim@umich.edu if ((regs.isr & regs.imr & ISR_NODELAY) == 0) 8674032Sktlim@umich.edu when += intrDelay; 8684032Sktlim@umich.edu postedInterrupts++; 8694032Sktlim@umich.edu cpuIntrPost(when); 8702292SN/A } 87113590Srekai.gonzalezalberquilla@arm.com} 8722329SN/A 87313590Srekai.gonzalezalberquilla@arm.com/* writing this interrupt counting stats inside this means that this function 8742292SN/A is now limited to being used to clear all interrupts upon the kernel 8752292SN/A reading isr and servicing. just telling you in case you were thinking 8762292SN/A of expanding use. 8777720Sgblack@eecs.umich.edu*/ 8782292SN/Avoid 87913590Srekai.gonzalezalberquilla@arm.comNSGigE::devIntrClear(uint32_t interrupts) 88013590Srekai.gonzalezalberquilla@arm.com{ 8812292SN/A if (interrupts & ISR_RESERVE) 8822329SN/A panic("Cannot clear a reserved interrupt"); 8832329SN/A 8842292SN/A if (regs.isr & regs.imr & ISR_SWI) { 88513590Srekai.gonzalezalberquilla@arm.com postedSwi++; 8862292SN/A } 8872292SN/A if (regs.isr & regs.imr & ISR_RXIDLE) { 8882292SN/A postedRxIdle++; 8892292SN/A } 8902292SN/A if (regs.isr & regs.imr & ISR_RXOK) { 8912329SN/A postedRxOk++; 89213590Srekai.gonzalezalberquilla@arm.com } 8932292SN/A if (regs.isr & regs.imr & ISR_RXDESC) { 8944032Sktlim@umich.edu postedRxDesc++; 8954032Sktlim@umich.edu } 8964032Sktlim@umich.edu if (regs.isr & regs.imr & ISR_TXOK) { 89713590Srekai.gonzalezalberquilla@arm.com postedTxOk++; 8982292SN/A } 8992292SN/A if (regs.isr & regs.imr & ISR_TXIDLE) { 90013590Srekai.gonzalezalberquilla@arm.com postedTxIdle++; 9012727Sktlim@umich.edu } 9022292SN/A if (regs.isr & regs.imr & ISR_TXDESC) { 9032292SN/A postedTxDesc++; 9042292SN/A } 9052292SN/A if (regs.isr & regs.imr & ISR_RXORN) { 9062292SN/A postedRxOrn++; 90713590Srekai.gonzalezalberquilla@arm.com } 9082693Sktlim@umich.edu 9092693Sktlim@umich.edu interrupts &= ~ISR_NOIMPL; 91013590Srekai.gonzalezalberquilla@arm.com regs.isr &= ~interrupts; 9112693Sktlim@umich.edu 9122693Sktlim@umich.edu DPRINTF(EthernetIntr, 9132693Sktlim@umich.edu "interrupt cleared from ISR: intr=%x isr=%x imr=%x\n", 9142693Sktlim@umich.edu interrupts, regs.isr, regs.imr); 9152693Sktlim@umich.edu 91613590Srekai.gonzalezalberquilla@arm.com if (!(regs.isr & regs.imr)) 9172693Sktlim@umich.edu cpuIntrClear(); 9182693Sktlim@umich.edu} 91913590Srekai.gonzalezalberquilla@arm.com 9202693Sktlim@umich.eduvoid 9212693Sktlim@umich.eduNSGigE::devIntrChangeMask() 9222693Sktlim@umich.edu{ 92313590Srekai.gonzalezalberquilla@arm.com DPRINTF(EthernetIntr, "interrupt mask changed: isr=%x imr=%x masked=%x\n", 9248887Sgeoffrey.blake@arm.com regs.isr, regs.imr, regs.isr & regs.imr); 9252693Sktlim@umich.edu 92613590Srekai.gonzalezalberquilla@arm.com if (regs.isr & regs.imr) 9272693Sktlim@umich.edu cpuIntrPost(curTick()); 9282693Sktlim@umich.edu else 9292693Sktlim@umich.edu cpuIntrClear(); 9308727Snilay@cs.wisc.edu} 9318727Snilay@cs.wisc.edu 9328727Snilay@cs.wisc.eduvoid 9338727Snilay@cs.wisc.eduNSGigE::cpuIntrPost(Tick when) 93413590Srekai.gonzalezalberquilla@arm.com{ 9352693Sktlim@umich.edu // If the interrupt you want to post is later than an interrupt 9362693Sktlim@umich.edu // already scheduled, just let it post in the coming one and don't 9372693Sktlim@umich.edu // schedule another. 9382693Sktlim@umich.edu // HOWEVER, must be sure that the scheduled intrTick is in the 93913429Srekai.gonzalezalberquilla@arm.com // future (this was formerly the source of a bug) 9402678Sktlim@umich.edu /** 9412678Sktlim@umich.edu * @todo this warning should be removed and the intrTick code should 9422678Sktlim@umich.edu * be fixed. 9432678Sktlim@umich.edu */ 9442678Sktlim@umich.edu assert(when >= curTick()); 9452678Sktlim@umich.edu assert(intrTick >= curTick() || intrTick == 0); 9462727Sktlim@umich.edu if (when > intrTick && intrTick != 0) { 9472678Sktlim@umich.edu DPRINTF(EthernetIntr, "don't need to schedule event...intrTick=%d\n", 9482678Sktlim@umich.edu intrTick); 9492678Sktlim@umich.edu return; 9502678Sktlim@umich.edu } 9512678Sktlim@umich.edu 9522678Sktlim@umich.edu intrTick = when; 95310575SMarco.Elver@ARM.com if (intrTick < curTick()) { 95410575SMarco.Elver@ARM.com Debug::breakpoint(); 95510575SMarco.Elver@ARM.com intrTick = curTick(); 95610575SMarco.Elver@ARM.com } 95710575SMarco.Elver@ARM.com 95810575SMarco.Elver@ARM.com DPRINTF(EthernetIntr, "going to schedule an interrupt for intrTick=%d\n", 95910575SMarco.Elver@ARM.com intrTick); 96010575SMarco.Elver@ARM.com 96110575SMarco.Elver@ARM.com if (intrEvent) 96210575SMarco.Elver@ARM.com intrEvent->squash(); 96310575SMarco.Elver@ARM.com intrEvent = new IntrEvent(this, true); 96410575SMarco.Elver@ARM.com schedule(intrEvent, intrTick); 96510575SMarco.Elver@ARM.com} 96610575SMarco.Elver@ARM.com 9672678Sktlim@umich.eduvoid 9682678Sktlim@umich.eduNSGigE::cpuInterrupt() 9692678Sktlim@umich.edu{ 9702678Sktlim@umich.edu assert(intrTick == curTick()); 9712678Sktlim@umich.edu 9722678Sktlim@umich.edu // Whether or not there's a pending interrupt, we don't care about 9737598Sminkyu.jeong@arm.com // it anymore 9747598Sminkyu.jeong@arm.com intrEvent = 0; 9757598Sminkyu.jeong@arm.com intrTick = 0; 9762678Sktlim@umich.edu 9772678Sktlim@umich.edu // Don't send an interrupt if there's already one 9782678Sktlim@umich.edu if (cpuPendingIntr) { 9792678Sktlim@umich.edu DPRINTF(EthernetIntr, 98013590Srekai.gonzalezalberquilla@arm.com "would send an interrupt now, but there's already pending\n"); 9812292SN/A } else { 98213590Srekai.gonzalezalberquilla@arm.com // Send interrupt 98313590Srekai.gonzalezalberquilla@arm.com cpuPendingIntr = true; 9842292SN/A 9852292SN/A DPRINTF(EthernetIntr, "posting interrupt\n"); 9862292SN/A intrPost(); 9872292SN/A } 9883126Sktlim@umich.edu} 9892292SN/A 9902292SN/Avoid 99113590Srekai.gonzalezalberquilla@arm.comNSGigE::cpuIntrClear() 99213590Srekai.gonzalezalberquilla@arm.com{ 99313590Srekai.gonzalezalberquilla@arm.com if (!cpuPendingIntr) 99413590Srekai.gonzalezalberquilla@arm.com return; 9952292SN/A 99613590Srekai.gonzalezalberquilla@arm.com if (intrEvent) { 99713590Srekai.gonzalezalberquilla@arm.com intrEvent->squash(); 9982292SN/A intrEvent = 0; 99913590Srekai.gonzalezalberquilla@arm.com } 100013590Srekai.gonzalezalberquilla@arm.com 10012292SN/A intrTick = 0; 10022292SN/A 10032292SN/A cpuPendingIntr = false; 10042292SN/A 10052329SN/A DPRINTF(EthernetIntr, "clearing interrupt\n"); 10062329SN/A intrClear(); 100713590Srekai.gonzalezalberquilla@arm.com} 10082292SN/A 10099527SMatt.Horsnell@arm.combool 10109527SMatt.Horsnell@arm.comNSGigE::cpuIntrPending() const 101113734SAndrea.Mondelli@ucf.edu{ return cpuPendingIntr; } 101213734SAndrea.Mondelli@ucf.edu 10139527SMatt.Horsnell@arm.comvoid 10149527SMatt.Horsnell@arm.comNSGigE::txReset() 10159527SMatt.Horsnell@arm.com{ 10162292SN/A 101713590Srekai.gonzalezalberquilla@arm.com DPRINTF(Ethernet, "transmit reset\n"); 10182292SN/A 10192292SN/A CTDD = false; 10202292SN/A txEnable = false;; 10212292SN/A txFragPtr = 0; 10222292SN/A assert(txDescCnt == 0); 102313590Srekai.gonzalezalberquilla@arm.com txFifo.clear(); 10242292SN/A txState = txIdle; 10252316SN/A assert(txDmaState == dmaIdle); 102613590Srekai.gonzalezalberquilla@arm.com} 10272329SN/A 10288727Snilay@cs.wisc.eduvoid 10298727Snilay@cs.wisc.eduNSGigE::rxReset() 10308727Snilay@cs.wisc.edu{ 10318727Snilay@cs.wisc.edu DPRINTF(Ethernet, "receive reset\n"); 10322329SN/A 10332329SN/A CRDD = false; 10342329SN/A assert(rxPktBytes == 0); 103512216Snikos.nikoleris@arm.com rxEnable = false; 103612216Snikos.nikoleris@arm.com rxFragPtr = 0; 103712216Snikos.nikoleris@arm.com assert(rxDescCnt == 0); 103813590Srekai.gonzalezalberquilla@arm.com assert(rxDmaState == dmaIdle); 103913590Srekai.gonzalezalberquilla@arm.com rxFifo.clear(); 10402316SN/A rxState = rxIdle; 10412292SN/A} 10422292SN/A 10432292SN/Avoid 10446974Stjones1@inf.ed.ac.ukNSGigE::regsReset() 104513590Srekai.gonzalezalberquilla@arm.com{ 10466974Stjones1@inf.ed.ac.uk memset(®s, 0, sizeof(regs)); 104713590Srekai.gonzalezalberquilla@arm.com regs.config = (CFGR_LNKSTS | CFGR_TBI_EN | CFGR_MODE_1000); 104813590Srekai.gonzalezalberquilla@arm.com regs.mear = 0x12; 104913590Srekai.gonzalezalberquilla@arm.com regs.txcfg = 0x120; // set drain threshold to 1024 bytes and 105013590Srekai.gonzalezalberquilla@arm.com // fill threshold to 32 bytes 105113590Srekai.gonzalezalberquilla@arm.com regs.rxcfg = 0x4; // set drain threshold to 16 bytes 105213710Sgabor.dozsa@arm.com regs.srr = 0x0103; // set the silicon revision to rev B or 0x103 105313710Sgabor.dozsa@arm.com regs.mibc = MIBC_FRZ; 105413590Srekai.gonzalezalberquilla@arm.com regs.vdr = 0x81; // set the vlan tag type to 802.1q 105513590Srekai.gonzalezalberquilla@arm.com regs.tesr = 0xc000; // TBI capable of both full and half duplex 105613590Srekai.gonzalezalberquilla@arm.com regs.brar = 0xffffffff; 105713590Srekai.gonzalezalberquilla@arm.com 105813590Srekai.gonzalezalberquilla@arm.com extstsEnable = false; 105913590Srekai.gonzalezalberquilla@arm.com acceptBroadcast = false; 10606974Stjones1@inf.ed.ac.uk acceptMulticast = false; 106113590Srekai.gonzalezalberquilla@arm.com acceptUnicast = false; 106213590Srekai.gonzalezalberquilla@arm.com acceptPerfect = false; 106313590Srekai.gonzalezalberquilla@arm.com acceptArp = false; 106413590Srekai.gonzalezalberquilla@arm.com} 106513590Srekai.gonzalezalberquilla@arm.com 106613710Sgabor.dozsa@arm.combool 106713590Srekai.gonzalezalberquilla@arm.comNSGigE::doRxDmaRead() 106813590Srekai.gonzalezalberquilla@arm.com{ 106913590Srekai.gonzalezalberquilla@arm.com assert(rxDmaState == dmaIdle || rxDmaState == dmaReadWaiting); 107013590Srekai.gonzalezalberquilla@arm.com rxDmaState = dmaReading; 107113590Srekai.gonzalezalberquilla@arm.com 107213590Srekai.gonzalezalberquilla@arm.com if (dmaPending() || getState() != Running) 107313590Srekai.gonzalezalberquilla@arm.com rxDmaState = dmaReadWaiting; 107413590Srekai.gonzalezalberquilla@arm.com else 107513590Srekai.gonzalezalberquilla@arm.com dmaRead(rxDmaAddr, rxDmaLen, &rxDmaReadEvent, (uint8_t*)rxDmaData); 107613590Srekai.gonzalezalberquilla@arm.com 107713590Srekai.gonzalezalberquilla@arm.com return true; 107813590Srekai.gonzalezalberquilla@arm.com} 107913590Srekai.gonzalezalberquilla@arm.com 108013590Srekai.gonzalezalberquilla@arm.comvoid 10816974Stjones1@inf.ed.ac.ukNSGigE::rxDmaReadDone() 10826974Stjones1@inf.ed.ac.uk{ 10836974Stjones1@inf.ed.ac.uk assert(rxDmaState == dmaReading); 10842693Sktlim@umich.edu rxDmaState = dmaIdle; 10852693Sktlim@umich.edu 10862693Sktlim@umich.edu DPRINTF(EthernetDMA, "rx dma read paddr=%#x len=%d\n", 10872698Sktlim@umich.edu rxDmaAddr, rxDmaLen); 108813590Srekai.gonzalezalberquilla@arm.com DDUMP(EthernetDMA, rxDmaData, rxDmaLen); 108913590Srekai.gonzalezalberquilla@arm.com 10902693Sktlim@umich.edu // If the transmit state machine has a pending DMA, let it go first 10912693Sktlim@umich.edu if (txDmaState == dmaReadWaiting || txDmaState == dmaWriteWaiting) 10922693Sktlim@umich.edu txKick(); 10932693Sktlim@umich.edu 10942329SN/A rxKick(); 10959440SAndreas.Sandberg@ARM.com} 10962329SN/A 10972329SN/Abool 10982329SN/ANSGigE::doRxDmaWrite() 10992329SN/A{ 11002329SN/A assert(rxDmaState == dmaIdle || rxDmaState == dmaWriteWaiting); 110113590Srekai.gonzalezalberquilla@arm.com rxDmaState = dmaWriting; 110213590Srekai.gonzalezalberquilla@arm.com 110313831SAndrea.Mondelli@ucf.edu if (dmaPending() || getState() != Running) 11042329SN/A rxDmaState = dmaWriteWaiting; 11059440SAndreas.Sandberg@ARM.com else 11062329SN/A dmaWrite(rxDmaAddr, rxDmaLen, &rxDmaWriteEvent, (uint8_t*)rxDmaData); 11072329SN/A return true; 11082329SN/A} 11092329SN/A 111013590Srekai.gonzalezalberquilla@arm.comvoid 111113590Srekai.gonzalezalberquilla@arm.comNSGigE::rxDmaWriteDone() 111213831SAndrea.Mondelli@ucf.edu{ 11132329SN/A assert(rxDmaState == dmaWriting); 11142329SN/A rxDmaState = dmaIdle; 11152329SN/A 11162329SN/A DPRINTF(EthernetDMA, "rx dma write paddr=%#x len=%d\n", 11179944Smatt.horsnell@ARM.com rxDmaAddr, rxDmaLen); 111813590Srekai.gonzalezalberquilla@arm.com DDUMP(EthernetDMA, rxDmaData, rxDmaLen); 111913590Srekai.gonzalezalberquilla@arm.com 112013590Srekai.gonzalezalberquilla@arm.com // If the transmit state machine has a pending DMA, let it go first 112113590Srekai.gonzalezalberquilla@arm.com if (txDmaState == dmaReadWaiting || txDmaState == dmaWriteWaiting) 112213590Srekai.gonzalezalberquilla@arm.com txKick(); 112313590Srekai.gonzalezalberquilla@arm.com 112413590Srekai.gonzalezalberquilla@arm.com rxKick(); 11259944Smatt.horsnell@ARM.com} 1126 1127void 1128NSGigE::rxKick() 1129{ 1130 bool is64bit = (bool)(regs.config & CFGR_M64ADDR); 1131 1132 DPRINTF(EthernetSM, 1133 "receive kick rxState=%s (rxBuf.size=%d) %d-bit\n", 1134 NsRxStateStrings[rxState], rxFifo.size(), is64bit ? 64 : 32); 1135 1136 Addr link, bufptr; 1137 uint32_t &cmdsts = is64bit ? rxDesc64.cmdsts : rxDesc32.cmdsts; 1138 uint32_t &extsts = is64bit ? rxDesc64.extsts : rxDesc32.extsts; 1139 1140 next: 1141 if (clock) { 1142 if (rxKickTick > curTick()) { 1143 DPRINTF(EthernetSM, "receive kick exiting, can't run till %d\n", 1144 rxKickTick); 1145 1146 goto exit; 1147 } 1148 1149 // Go to the next state machine clock tick. 1150 rxKickTick = curTick() + clockPeriod(); 1151 } 1152 1153 switch(rxDmaState) { 1154 case dmaReadWaiting: 1155 if (doRxDmaRead()) 1156 goto exit; 1157 break; 1158 case dmaWriteWaiting: 1159 if (doRxDmaWrite()) 1160 goto exit; 1161 break; 1162 default: 1163 break; 1164 } 1165 1166 link = is64bit ? (Addr)rxDesc64.link : (Addr)rxDesc32.link; 1167 bufptr = is64bit ? (Addr)rxDesc64.bufptr : (Addr)rxDesc32.bufptr; 1168 1169 // see state machine from spec for details 1170 // the way this works is, if you finish work on one state and can 1171 // go directly to another, you do that through jumping to the 1172 // label "next". however, if you have intermediate work, like DMA 1173 // so that you can't go to the next state yet, you go to exit and 1174 // exit the loop. however, when the DMA is done it will trigger 1175 // an event and come back to this loop. 1176 switch (rxState) { 1177 case rxIdle: 1178 if (!rxEnable) { 1179 DPRINTF(EthernetSM, "Receive Disabled! Nothing to do.\n"); 1180 goto exit; 1181 } 1182 1183 if (CRDD) { 1184 rxState = rxDescRefr; 1185 1186 rxDmaAddr = regs.rxdp & 0x3fffffff; 1187 rxDmaData = 1188 is64bit ? (void *)&rxDesc64.link : (void *)&rxDesc32.link; 1189 rxDmaLen = is64bit ? sizeof(rxDesc64.link) : sizeof(rxDesc32.link); 1190 rxDmaFree = dmaDescFree; 1191 1192 descDmaReads++; 1193 descDmaRdBytes += rxDmaLen; 1194 1195 if (doRxDmaRead()) 1196 goto exit; 1197 } else { 1198 rxState = rxDescRead; 1199 1200 rxDmaAddr = regs.rxdp & 0x3fffffff; 1201 rxDmaData = is64bit ? (void *)&rxDesc64 : (void *)&rxDesc32; 1202 rxDmaLen = is64bit ? sizeof(rxDesc64) : sizeof(rxDesc32); 1203 rxDmaFree = dmaDescFree; 1204 1205 descDmaReads++; 1206 descDmaRdBytes += rxDmaLen; 1207 1208 if (doRxDmaRead()) 1209 goto exit; 1210 } 1211 break; 1212 1213 case rxDescRefr: 1214 if (rxDmaState != dmaIdle) 1215 goto exit; 1216 1217 rxState = rxAdvance; 1218 break; 1219 1220 case rxDescRead: 1221 if (rxDmaState != dmaIdle) 1222 goto exit; 1223 1224 DPRINTF(EthernetDesc, "rxDesc: addr=%08x read descriptor\n", 1225 regs.rxdp & 0x3fffffff); 1226 DPRINTF(EthernetDesc, 1227 "rxDesc: link=%#x bufptr=%#x cmdsts=%08x extsts=%08x\n", 1228 link, bufptr, cmdsts, extsts); 1229 1230 if (cmdsts & CMDSTS_OWN) { 1231 devIntrPost(ISR_RXIDLE); 1232 rxState = rxIdle; 1233 goto exit; 1234 } else { 1235 rxState = rxFifoBlock; 1236 rxFragPtr = bufptr; 1237 rxDescCnt = cmdsts & CMDSTS_LEN_MASK; 1238 } 1239 break; 1240 1241 case rxFifoBlock: 1242 if (!rxPacket) { 1243 /** 1244 * @todo in reality, we should be able to start processing 1245 * the packet as it arrives, and not have to wait for the 1246 * full packet ot be in the receive fifo. 1247 */ 1248 if (rxFifo.empty()) 1249 goto exit; 1250 1251 DPRINTF(EthernetSM, "****processing receive of new packet****\n"); 1252 1253 // If we don't have a packet, grab a new one from the fifo. 1254 rxPacket = rxFifo.front(); 1255 rxPktBytes = rxPacket->length; 1256 rxPacketBufPtr = rxPacket->data; 1257 1258#if TRACING_ON 1259 if (DTRACE(Ethernet)) { 1260 IpPtr ip(rxPacket); 1261 if (ip) { 1262 DPRINTF(Ethernet, "ID is %d\n", ip->id()); 1263 TcpPtr tcp(ip); 1264 if (tcp) { 1265 DPRINTF(Ethernet, 1266 "Src Port=%d, Dest Port=%d, Seq=%d, Ack=%d\n", 1267 tcp->sport(), tcp->dport(), tcp->seq(), 1268 tcp->ack()); 1269 } 1270 } 1271 } 1272#endif 1273 1274 // sanity check - i think the driver behaves like this 1275 assert(rxDescCnt >= rxPktBytes); 1276 rxFifo.pop(); 1277 } 1278 1279 1280 // dont' need the && rxDescCnt > 0 if driver sanity check 1281 // above holds 1282 if (rxPktBytes > 0) { 1283 rxState = rxFragWrite; 1284 // don't need min<>(rxPktBytes,rxDescCnt) if above sanity 1285 // check holds 1286 rxXferLen = rxPktBytes; 1287 1288 rxDmaAddr = rxFragPtr & 0x3fffffff; 1289 rxDmaData = rxPacketBufPtr; 1290 rxDmaLen = rxXferLen; 1291 rxDmaFree = dmaDataFree; 1292 1293 if (doRxDmaWrite()) 1294 goto exit; 1295 1296 } else { 1297 rxState = rxDescWrite; 1298 1299 //if (rxPktBytes == 0) { /* packet is done */ 1300 assert(rxPktBytes == 0); 1301 DPRINTF(EthernetSM, "done with receiving packet\n"); 1302 1303 cmdsts |= CMDSTS_OWN; 1304 cmdsts &= ~CMDSTS_MORE; 1305 cmdsts |= CMDSTS_OK; 1306 cmdsts &= 0xffff0000; 1307 cmdsts += rxPacket->length; //i.e. set CMDSTS_SIZE 1308 1309#if 0 1310 /* 1311 * all the driver uses these are for its own stats keeping 1312 * which we don't care about, aren't necessary for 1313 * functionality and doing this would just slow us down. 1314 * if they end up using this in a later version for 1315 * functional purposes, just undef 1316 */ 1317 if (rxFilterEnable) { 1318 cmdsts &= ~CMDSTS_DEST_MASK; 1319 const EthAddr &dst = rxFifoFront()->dst(); 1320 if (dst->unicast()) 1321 cmdsts |= CMDSTS_DEST_SELF; 1322 if (dst->multicast()) 1323 cmdsts |= CMDSTS_DEST_MULTI; 1324 if (dst->broadcast()) 1325 cmdsts |= CMDSTS_DEST_MASK; 1326 } 1327#endif 1328 1329 IpPtr ip(rxPacket); 1330 if (extstsEnable && ip) { 1331 extsts |= EXTSTS_IPPKT; 1332 rxIpChecksums++; 1333 if (cksum(ip) != 0) { 1334 DPRINTF(EthernetCksum, "Rx IP Checksum Error\n"); 1335 extsts |= EXTSTS_IPERR; 1336 } 1337 TcpPtr tcp(ip); 1338 UdpPtr udp(ip); 1339 if (tcp) { 1340 extsts |= EXTSTS_TCPPKT; 1341 rxTcpChecksums++; 1342 if (cksum(tcp) != 0) { 1343 DPRINTF(EthernetCksum, "Rx TCP Checksum Error\n"); 1344 extsts |= EXTSTS_TCPERR; 1345 1346 } 1347 } else if (udp) { 1348 extsts |= EXTSTS_UDPPKT; 1349 rxUdpChecksums++; 1350 if (cksum(udp) != 0) { 1351 DPRINTF(EthernetCksum, "Rx UDP Checksum Error\n"); 1352 extsts |= EXTSTS_UDPERR; 1353 } 1354 } 1355 } 1356 rxPacket = 0; 1357 1358 /* 1359 * the driver seems to always receive into desc buffers 1360 * of size 1514, so you never have a pkt that is split 1361 * into multiple descriptors on the receive side, so 1362 * i don't implement that case, hence the assert above. 1363 */ 1364 1365 DPRINTF(EthernetDesc, 1366 "rxDesc: addr=%08x writeback cmdsts extsts\n", 1367 regs.rxdp & 0x3fffffff); 1368 DPRINTF(EthernetDesc, 1369 "rxDesc: link=%#x bufptr=%#x cmdsts=%08x extsts=%08x\n", 1370 link, bufptr, cmdsts, extsts); 1371 1372 rxDmaAddr = regs.rxdp & 0x3fffffff; 1373 rxDmaData = &cmdsts; 1374 if (is64bit) { 1375 rxDmaAddr += offsetof(ns_desc64, cmdsts); 1376 rxDmaLen = sizeof(rxDesc64.cmdsts) + sizeof(rxDesc64.extsts); 1377 } else { 1378 rxDmaAddr += offsetof(ns_desc32, cmdsts); 1379 rxDmaLen = sizeof(rxDesc32.cmdsts) + sizeof(rxDesc32.extsts); 1380 } 1381 rxDmaFree = dmaDescFree; 1382 1383 descDmaWrites++; 1384 descDmaWrBytes += rxDmaLen; 1385 1386 if (doRxDmaWrite()) 1387 goto exit; 1388 } 1389 break; 1390 1391 case rxFragWrite: 1392 if (rxDmaState != dmaIdle) 1393 goto exit; 1394 1395 rxPacketBufPtr += rxXferLen; 1396 rxFragPtr += rxXferLen; 1397 rxPktBytes -= rxXferLen; 1398 1399 rxState = rxFifoBlock; 1400 break; 1401 1402 case rxDescWrite: 1403 if (rxDmaState != dmaIdle) 1404 goto exit; 1405 1406 assert(cmdsts & CMDSTS_OWN); 1407 1408 assert(rxPacket == 0); 1409 devIntrPost(ISR_RXOK); 1410 1411 if (cmdsts & CMDSTS_INTR) 1412 devIntrPost(ISR_RXDESC); 1413 1414 if (!rxEnable) { 1415 DPRINTF(EthernetSM, "Halting the RX state machine\n"); 1416 rxState = rxIdle; 1417 goto exit; 1418 } else 1419 rxState = rxAdvance; 1420 break; 1421 1422 case rxAdvance: 1423 if (link == 0) { 1424 devIntrPost(ISR_RXIDLE); 1425 rxState = rxIdle; 1426 CRDD = true; 1427 goto exit; 1428 } else { 1429 if (rxDmaState != dmaIdle) 1430 goto exit; 1431 rxState = rxDescRead; 1432 regs.rxdp = link; 1433 CRDD = false; 1434 1435 rxDmaAddr = regs.rxdp & 0x3fffffff; 1436 rxDmaData = is64bit ? (void *)&rxDesc64 : (void *)&rxDesc32; 1437 rxDmaLen = is64bit ? sizeof(rxDesc64) : sizeof(rxDesc32); 1438 rxDmaFree = dmaDescFree; 1439 1440 if (doRxDmaRead()) 1441 goto exit; 1442 } 1443 break; 1444 1445 default: 1446 panic("Invalid rxState!"); 1447 } 1448 1449 DPRINTF(EthernetSM, "entering next rxState=%s\n", 1450 NsRxStateStrings[rxState]); 1451 goto next; 1452 1453 exit: 1454 /** 1455 * @todo do we want to schedule a future kick? 1456 */ 1457 DPRINTF(EthernetSM, "rx state machine exited rxState=%s\n", 1458 NsRxStateStrings[rxState]); 1459 1460 if (clock && !rxKickEvent.scheduled()) 1461 schedule(rxKickEvent, rxKickTick); 1462} 1463 1464void 1465NSGigE::transmit() 1466{ 1467 if (txFifo.empty()) { 1468 DPRINTF(Ethernet, "nothing to transmit\n"); 1469 return; 1470 } 1471 1472 DPRINTF(Ethernet, "Attempt Pkt Transmit: txFifo length=%d\n", 1473 txFifo.size()); 1474 if (interface->sendPacket(txFifo.front())) { 1475#if TRACING_ON 1476 if (DTRACE(Ethernet)) { 1477 IpPtr ip(txFifo.front()); 1478 if (ip) { 1479 DPRINTF(Ethernet, "ID is %d\n", ip->id()); 1480 TcpPtr tcp(ip); 1481 if (tcp) { 1482 DPRINTF(Ethernet, 1483 "Src Port=%d, Dest Port=%d, Seq=%d, Ack=%d\n", 1484 tcp->sport(), tcp->dport(), tcp->seq(), 1485 tcp->ack()); 1486 } 1487 } 1488 } 1489#endif 1490 1491 DDUMP(EthernetData, txFifo.front()->data, txFifo.front()->length); 1492 txBytes += txFifo.front()->length; 1493 txPackets++; 1494 1495 DPRINTF(Ethernet, "Successful Xmit! now txFifoAvail is %d\n", 1496 txFifo.avail()); 1497 txFifo.pop(); 1498 1499 /* 1500 * normally do a writeback of the descriptor here, and ONLY 1501 * after that is done, send this interrupt. but since our 1502 * stuff never actually fails, just do this interrupt here, 1503 * otherwise the code has to stray from this nice format. 1504 * besides, it's functionally the same. 1505 */ 1506 devIntrPost(ISR_TXOK); 1507 } 1508 1509 if (!txFifo.empty() && !txEvent.scheduled()) { 1510 DPRINTF(Ethernet, "reschedule transmit\n"); 1511 schedule(txEvent, curTick() + retryTime); 1512 } 1513} 1514 1515bool 1516NSGigE::doTxDmaRead() 1517{ 1518 assert(txDmaState == dmaIdle || txDmaState == dmaReadWaiting); 1519 txDmaState = dmaReading; 1520 1521 if (dmaPending() || getState() != Running) 1522 txDmaState = dmaReadWaiting; 1523 else 1524 dmaRead(txDmaAddr, txDmaLen, &txDmaReadEvent, (uint8_t*)txDmaData); 1525 1526 return true; 1527} 1528 1529void 1530NSGigE::txDmaReadDone() 1531{ 1532 assert(txDmaState == dmaReading); 1533 txDmaState = dmaIdle; 1534 1535 DPRINTF(EthernetDMA, "tx dma read paddr=%#x len=%d\n", 1536 txDmaAddr, txDmaLen); 1537 DDUMP(EthernetDMA, txDmaData, txDmaLen); 1538 1539 // If the receive state machine has a pending DMA, let it go first 1540 if (rxDmaState == dmaReadWaiting || rxDmaState == dmaWriteWaiting) 1541 rxKick(); 1542 1543 txKick(); 1544} 1545 1546bool 1547NSGigE::doTxDmaWrite() 1548{ 1549 assert(txDmaState == dmaIdle || txDmaState == dmaWriteWaiting); 1550 txDmaState = dmaWriting; 1551 1552 if (dmaPending() || getState() != Running) 1553 txDmaState = dmaWriteWaiting; 1554 else 1555 dmaWrite(txDmaAddr, txDmaLen, &txDmaWriteEvent, (uint8_t*)txDmaData); 1556 return true; 1557} 1558 1559void 1560NSGigE::txDmaWriteDone() 1561{ 1562 assert(txDmaState == dmaWriting); 1563 txDmaState = dmaIdle; 1564 1565 DPRINTF(EthernetDMA, "tx dma write paddr=%#x len=%d\n", 1566 txDmaAddr, txDmaLen); 1567 DDUMP(EthernetDMA, txDmaData, txDmaLen); 1568 1569 // If the receive state machine has a pending DMA, let it go first 1570 if (rxDmaState == dmaReadWaiting || rxDmaState == dmaWriteWaiting) 1571 rxKick(); 1572 1573 txKick(); 1574} 1575 1576void 1577NSGigE::txKick() 1578{ 1579 bool is64bit = (bool)(regs.config & CFGR_M64ADDR); 1580 1581 DPRINTF(EthernetSM, "transmit kick txState=%s %d-bit\n", 1582 NsTxStateStrings[txState], is64bit ? 64 : 32); 1583 1584 Addr link, bufptr; 1585 uint32_t &cmdsts = is64bit ? txDesc64.cmdsts : txDesc32.cmdsts; 1586 uint32_t &extsts = is64bit ? txDesc64.extsts : txDesc32.extsts; 1587 1588 next: 1589 if (clock) { 1590 if (txKickTick > curTick()) { 1591 DPRINTF(EthernetSM, "transmit kick exiting, can't run till %d\n", 1592 txKickTick); 1593 goto exit; 1594 } 1595 1596 // Go to the next state machine clock tick. 1597 txKickTick = curTick() + clockPeriod(); 1598 } 1599 1600 switch(txDmaState) { 1601 case dmaReadWaiting: 1602 if (doTxDmaRead()) 1603 goto exit; 1604 break; 1605 case dmaWriteWaiting: 1606 if (doTxDmaWrite()) 1607 goto exit; 1608 break; 1609 default: 1610 break; 1611 } 1612 1613 link = is64bit ? (Addr)txDesc64.link : (Addr)txDesc32.link; 1614 bufptr = is64bit ? (Addr)txDesc64.bufptr : (Addr)txDesc32.bufptr; 1615 switch (txState) { 1616 case txIdle: 1617 if (!txEnable) { 1618 DPRINTF(EthernetSM, "Transmit disabled. Nothing to do.\n"); 1619 goto exit; 1620 } 1621 1622 if (CTDD) { 1623 txState = txDescRefr; 1624 1625 txDmaAddr = regs.txdp & 0x3fffffff; 1626 txDmaData = 1627 is64bit ? (void *)&txDesc64.link : (void *)&txDesc32.link; 1628 txDmaLen = is64bit ? sizeof(txDesc64.link) : sizeof(txDesc32.link); 1629 txDmaFree = dmaDescFree; 1630 1631 descDmaReads++; 1632 descDmaRdBytes += txDmaLen; 1633 1634 if (doTxDmaRead()) 1635 goto exit; 1636 1637 } else { 1638 txState = txDescRead; 1639 1640 txDmaAddr = regs.txdp & 0x3fffffff; 1641 txDmaData = is64bit ? (void *)&txDesc64 : (void *)&txDesc32; 1642 txDmaLen = is64bit ? sizeof(txDesc64) : sizeof(txDesc32); 1643 txDmaFree = dmaDescFree; 1644 1645 descDmaReads++; 1646 descDmaRdBytes += txDmaLen; 1647 1648 if (doTxDmaRead()) 1649 goto exit; 1650 } 1651 break; 1652 1653 case txDescRefr: 1654 if (txDmaState != dmaIdle) 1655 goto exit; 1656 1657 txState = txAdvance; 1658 break; 1659 1660 case txDescRead: 1661 if (txDmaState != dmaIdle) 1662 goto exit; 1663 1664 DPRINTF(EthernetDesc, "txDesc: addr=%08x read descriptor\n", 1665 regs.txdp & 0x3fffffff); 1666 DPRINTF(EthernetDesc, 1667 "txDesc: link=%#x bufptr=%#x cmdsts=%#08x extsts=%#08x\n", 1668 link, bufptr, cmdsts, extsts); 1669 1670 if (cmdsts & CMDSTS_OWN) { 1671 txState = txFifoBlock; 1672 txFragPtr = bufptr; 1673 txDescCnt = cmdsts & CMDSTS_LEN_MASK; 1674 } else { 1675 devIntrPost(ISR_TXIDLE); 1676 txState = txIdle; 1677 goto exit; 1678 } 1679 break; 1680 1681 case txFifoBlock: 1682 if (!txPacket) { 1683 DPRINTF(EthernetSM, "****starting the tx of a new packet****\n"); 1684 txPacket = new EthPacketData(16384); 1685 txPacketBufPtr = txPacket->data; 1686 } 1687 1688 if (txDescCnt == 0) { 1689 DPRINTF(EthernetSM, "the txDescCnt == 0, done with descriptor\n"); 1690 if (cmdsts & CMDSTS_MORE) { 1691 DPRINTF(EthernetSM, "there are more descriptors to come\n"); 1692 txState = txDescWrite; 1693 1694 cmdsts &= ~CMDSTS_OWN; 1695 1696 txDmaAddr = regs.txdp & 0x3fffffff; 1697 txDmaData = &cmdsts; 1698 if (is64bit) { 1699 txDmaAddr += offsetof(ns_desc64, cmdsts); 1700 txDmaLen = sizeof(txDesc64.cmdsts); 1701 } else { 1702 txDmaAddr += offsetof(ns_desc32, cmdsts); 1703 txDmaLen = sizeof(txDesc32.cmdsts); 1704 } 1705 txDmaFree = dmaDescFree; 1706 1707 if (doTxDmaWrite()) 1708 goto exit; 1709 1710 } else { /* this packet is totally done */ 1711 DPRINTF(EthernetSM, "This packet is done, let's wrap it up\n"); 1712 /* deal with the the packet that just finished */ 1713 if ((regs.vtcr & VTCR_PPCHK) && extstsEnable) { 1714 IpPtr ip(txPacket); 1715 if (extsts & EXTSTS_UDPPKT) { 1716 UdpPtr udp(ip); 1717 if (udp) { 1718 udp->sum(0); 1719 udp->sum(cksum(udp)); 1720 txUdpChecksums++; 1721 } else { 1722 Debug::breakpoint(); 1723 warn_once("UDPPKT set, but not UDP!\n"); 1724 } 1725 } else if (extsts & EXTSTS_TCPPKT) { 1726 TcpPtr tcp(ip); 1727 if (tcp) { 1728 tcp->sum(0); 1729 tcp->sum(cksum(tcp)); 1730 txTcpChecksums++; 1731 } else { 1732 Debug::breakpoint(); 1733 warn_once("TCPPKT set, but not UDP!\n"); 1734 } 1735 } 1736 if (extsts & EXTSTS_IPPKT) { 1737 if (ip) { 1738 ip->sum(0); 1739 ip->sum(cksum(ip)); 1740 txIpChecksums++; 1741 } else { 1742 Debug::breakpoint(); 1743 warn_once("IPPKT set, but not UDP!\n"); 1744 } 1745 } 1746 } 1747 1748 txPacket->length = txPacketBufPtr - txPacket->data; 1749 // this is just because the receive can't handle a 1750 // packet bigger want to make sure 1751 if (txPacket->length > 1514) 1752 panic("transmit packet too large, %s > 1514\n", 1753 txPacket->length); 1754 1755#ifndef NDEBUG 1756 bool success = 1757#endif 1758 txFifo.push(txPacket); 1759 assert(success); 1760 1761 /* 1762 * this following section is not tqo spec, but 1763 * functionally shouldn't be any different. normally, 1764 * the chip will wait til the transmit has occurred 1765 * before writing back the descriptor because it has 1766 * to wait to see that it was successfully transmitted 1767 * to decide whether to set CMDSTS_OK or not. 1768 * however, in the simulator since it is always 1769 * successfully transmitted, and writing it exactly to 1770 * spec would complicate the code, we just do it here 1771 */ 1772 1773 cmdsts &= ~CMDSTS_OWN; 1774 cmdsts |= CMDSTS_OK; 1775 1776 DPRINTF(EthernetDesc, 1777 "txDesc writeback: cmdsts=%08x extsts=%08x\n", 1778 cmdsts, extsts); 1779 1780 txDmaFree = dmaDescFree; 1781 txDmaAddr = regs.txdp & 0x3fffffff; 1782 txDmaData = &cmdsts; 1783 if (is64bit) { 1784 txDmaAddr += offsetof(ns_desc64, cmdsts); 1785 txDmaLen = 1786 sizeof(txDesc64.cmdsts) + sizeof(txDesc64.extsts); 1787 } else { 1788 txDmaAddr += offsetof(ns_desc32, cmdsts); 1789 txDmaLen = 1790 sizeof(txDesc32.cmdsts) + sizeof(txDesc32.extsts); 1791 } 1792 1793 descDmaWrites++; 1794 descDmaWrBytes += txDmaLen; 1795 1796 transmit(); 1797 txPacket = 0; 1798 1799 if (!txEnable) { 1800 DPRINTF(EthernetSM, "halting TX state machine\n"); 1801 txState = txIdle; 1802 goto exit; 1803 } else 1804 txState = txAdvance; 1805 1806 if (doTxDmaWrite()) 1807 goto exit; 1808 } 1809 } else { 1810 DPRINTF(EthernetSM, "this descriptor isn't done yet\n"); 1811 if (!txFifo.full()) { 1812 txState = txFragRead; 1813 1814 /* 1815 * The number of bytes transferred is either whatever 1816 * is left in the descriptor (txDescCnt), or if there 1817 * is not enough room in the fifo, just whatever room 1818 * is left in the fifo 1819 */ 1820 txXferLen = min<uint32_t>(txDescCnt, txFifo.avail()); 1821 1822 txDmaAddr = txFragPtr & 0x3fffffff; 1823 txDmaData = txPacketBufPtr; 1824 txDmaLen = txXferLen; 1825 txDmaFree = dmaDataFree; 1826 1827 if (doTxDmaRead()) 1828 goto exit; 1829 } else { 1830 txState = txFifoBlock; 1831 transmit(); 1832 1833 goto exit; 1834 } 1835 1836 } 1837 break; 1838 1839 case txFragRead: 1840 if (txDmaState != dmaIdle) 1841 goto exit; 1842 1843 txPacketBufPtr += txXferLen; 1844 txFragPtr += txXferLen; 1845 txDescCnt -= txXferLen; 1846 txFifo.reserve(txXferLen); 1847 1848 txState = txFifoBlock; 1849 break; 1850 1851 case txDescWrite: 1852 if (txDmaState != dmaIdle) 1853 goto exit; 1854 1855 if (cmdsts & CMDSTS_INTR) 1856 devIntrPost(ISR_TXDESC); 1857 1858 if (!txEnable) { 1859 DPRINTF(EthernetSM, "halting TX state machine\n"); 1860 txState = txIdle; 1861 goto exit; 1862 } else 1863 txState = txAdvance; 1864 break; 1865 1866 case txAdvance: 1867 if (link == 0) { 1868 devIntrPost(ISR_TXIDLE); 1869 txState = txIdle; 1870 goto exit; 1871 } else { 1872 if (txDmaState != dmaIdle) 1873 goto exit; 1874 txState = txDescRead; 1875 regs.txdp = link; 1876 CTDD = false; 1877 1878 txDmaAddr = link & 0x3fffffff; 1879 txDmaData = is64bit ? (void *)&txDesc64 : (void *)&txDesc32; 1880 txDmaLen = is64bit ? sizeof(txDesc64) : sizeof(txDesc32); 1881 txDmaFree = dmaDescFree; 1882 1883 if (doTxDmaRead()) 1884 goto exit; 1885 } 1886 break; 1887 1888 default: 1889 panic("invalid state"); 1890 } 1891 1892 DPRINTF(EthernetSM, "entering next txState=%s\n", 1893 NsTxStateStrings[txState]); 1894 goto next; 1895 1896 exit: 1897 /** 1898 * @todo do we want to schedule a future kick? 1899 */ 1900 DPRINTF(EthernetSM, "tx state machine exited txState=%s\n", 1901 NsTxStateStrings[txState]); 1902 1903 if (clock && !txKickEvent.scheduled()) 1904 schedule(txKickEvent, txKickTick); 1905} 1906 1907/** 1908 * Advance the EEPROM state machine 1909 * Called on rising edge of EEPROM clock bit in MEAR 1910 */ 1911void 1912NSGigE::eepromKick() 1913{ 1914 switch (eepromState) { 1915 1916 case eepromStart: 1917 1918 // Wait for start bit 1919 if (regs.mear & MEAR_EEDI) { 1920 // Set up to get 2 opcode bits 1921 eepromState = eepromGetOpcode; 1922 eepromBitsToRx = 2; 1923 eepromOpcode = 0; 1924 } 1925 break; 1926 1927 case eepromGetOpcode: 1928 eepromOpcode <<= 1; 1929 eepromOpcode += (regs.mear & MEAR_EEDI) ? 1 : 0; 1930 --eepromBitsToRx; 1931 1932 // Done getting opcode 1933 if (eepromBitsToRx == 0) { 1934 if (eepromOpcode != EEPROM_READ) 1935 panic("only EEPROM reads are implemented!"); 1936 1937 // Set up to get address 1938 eepromState = eepromGetAddress; 1939 eepromBitsToRx = 6; 1940 eepromAddress = 0; 1941 } 1942 break; 1943 1944 case eepromGetAddress: 1945 eepromAddress <<= 1; 1946 eepromAddress += (regs.mear & MEAR_EEDI) ? 1 : 0; 1947 --eepromBitsToRx; 1948 1949 // Done getting address 1950 if (eepromBitsToRx == 0) { 1951 1952 if (eepromAddress >= EEPROM_SIZE) 1953 panic("EEPROM read access out of range!"); 1954 1955 switch (eepromAddress) { 1956 1957 case EEPROM_PMATCH2_ADDR: 1958 eepromData = rom.perfectMatch[5]; 1959 eepromData <<= 8; 1960 eepromData += rom.perfectMatch[4]; 1961 break; 1962 1963 case EEPROM_PMATCH1_ADDR: 1964 eepromData = rom.perfectMatch[3]; 1965 eepromData <<= 8; 1966 eepromData += rom.perfectMatch[2]; 1967 break; 1968 1969 case EEPROM_PMATCH0_ADDR: 1970 eepromData = rom.perfectMatch[1]; 1971 eepromData <<= 8; 1972 eepromData += rom.perfectMatch[0]; 1973 break; 1974 1975 default: 1976 panic("FreeBSD driver only uses EEPROM to read PMATCH!"); 1977 } 1978 // Set up to read data 1979 eepromState = eepromRead; 1980 eepromBitsToRx = 16; 1981 1982 // Clear data in bit 1983 regs.mear &= ~MEAR_EEDI; 1984 } 1985 break; 1986 1987 case eepromRead: 1988 // Clear Data Out bit 1989 regs.mear &= ~MEAR_EEDO; 1990 // Set bit to value of current EEPROM bit 1991 regs.mear |= (eepromData & 0x8000) ? MEAR_EEDO : 0x0; 1992 1993 eepromData <<= 1; 1994 --eepromBitsToRx; 1995 1996 // All done 1997 if (eepromBitsToRx == 0) { 1998 eepromState = eepromStart; 1999 } 2000 break; 2001 2002 default: 2003 panic("invalid EEPROM state"); 2004 } 2005 2006} 2007 2008void 2009NSGigE::transferDone() 2010{ 2011 if (txFifo.empty()) { 2012 DPRINTF(Ethernet, "transfer complete: txFifo empty...nothing to do\n"); 2013 return; 2014 } 2015 2016 DPRINTF(Ethernet, "transfer complete: data in txFifo...schedule xmit\n"); 2017 2018 reschedule(txEvent, curTick() + clockPeriod(), true); 2019} 2020 2021bool 2022NSGigE::rxFilter(const EthPacketPtr &packet) 2023{ 2024 EthPtr eth = packet; 2025 bool drop = true; 2026 string type; 2027 2028 const EthAddr &dst = eth->dst(); 2029 if (dst.unicast()) { 2030 // If we're accepting all unicast addresses 2031 if (acceptUnicast) 2032 drop = false; 2033 2034 // If we make a perfect match 2035 if (acceptPerfect && dst == rom.perfectMatch) 2036 drop = false; 2037 2038 if (acceptArp && eth->type() == ETH_TYPE_ARP) 2039 drop = false; 2040 2041 } else if (dst.broadcast()) { 2042 // if we're accepting broadcasts 2043 if (acceptBroadcast) 2044 drop = false; 2045 2046 } else if (dst.multicast()) { 2047 // if we're accepting all multicasts 2048 if (acceptMulticast) 2049 drop = false; 2050 2051 // Multicast hashing faked - all packets accepted 2052 if (multicastHashEnable) 2053 drop = false; 2054 } 2055 2056 if (drop) { 2057 DPRINTF(Ethernet, "rxFilter drop\n"); 2058 DDUMP(EthernetData, packet->data, packet->length); 2059 } 2060 2061 return drop; 2062} 2063 2064bool 2065NSGigE::recvPacket(EthPacketPtr packet) 2066{ 2067 rxBytes += packet->length; 2068 rxPackets++; 2069 2070 DPRINTF(Ethernet, "Receiving packet from wire, rxFifoAvail=%d\n", 2071 rxFifo.avail()); 2072 2073 if (!rxEnable) { 2074 DPRINTF(Ethernet, "receive disabled...packet dropped\n"); 2075 return true; 2076 } 2077 2078 if (!rxFilterEnable) { 2079 DPRINTF(Ethernet, 2080 "receive packet filtering disabled . . . packet dropped\n"); 2081 return true; 2082 } 2083 2084 if (rxFilter(packet)) { 2085 DPRINTF(Ethernet, "packet filtered...dropped\n"); 2086 return true; 2087 } 2088 2089 if (rxFifo.avail() < packet->length) { 2090#if TRACING_ON 2091 IpPtr ip(packet); 2092 TcpPtr tcp(ip); 2093 if (ip) { 2094 DPRINTF(Ethernet, 2095 "packet won't fit in receive buffer...pkt ID %d dropped\n", 2096 ip->id()); 2097 if (tcp) { 2098 DPRINTF(Ethernet, "Seq=%d\n", tcp->seq()); 2099 } 2100 } 2101#endif 2102 droppedPackets++; 2103 devIntrPost(ISR_RXORN); 2104 return false; 2105 } 2106 2107 rxFifo.push(packet); 2108 2109 rxKick(); 2110 return true; 2111} 2112 2113 2114void 2115NSGigE::resume() 2116{ 2117 SimObject::resume(); 2118 2119 // During drain we could have left the state machines in a waiting state and 2120 // they wouldn't get out until some other event occured to kick them. 2121 // This way they'll get out immediately 2122 txKick(); 2123 rxKick(); 2124} 2125 2126 2127//===================================================================== 2128// 2129// 2130void 2131NSGigE::serialize(ostream &os) 2132{ 2133 // Serialize the PciDev base class 2134 PciDev::serialize(os); 2135 2136 /* 2137 * Finalize any DMA events now. 2138 */ 2139 // @todo will mem system save pending dma? 2140 2141 /* 2142 * Serialize the device registers 2143 */ 2144 SERIALIZE_SCALAR(regs.command); 2145 SERIALIZE_SCALAR(regs.config); 2146 SERIALIZE_SCALAR(regs.mear); 2147 SERIALIZE_SCALAR(regs.ptscr); 2148 SERIALIZE_SCALAR(regs.isr); 2149 SERIALIZE_SCALAR(regs.imr); 2150 SERIALIZE_SCALAR(regs.ier); 2151 SERIALIZE_SCALAR(regs.ihr); 2152 SERIALIZE_SCALAR(regs.txdp); 2153 SERIALIZE_SCALAR(regs.txdp_hi); 2154 SERIALIZE_SCALAR(regs.txcfg); 2155 SERIALIZE_SCALAR(regs.gpior); 2156 SERIALIZE_SCALAR(regs.rxdp); 2157 SERIALIZE_SCALAR(regs.rxdp_hi); 2158 SERIALIZE_SCALAR(regs.rxcfg); 2159 SERIALIZE_SCALAR(regs.pqcr); 2160 SERIALIZE_SCALAR(regs.wcsr); 2161 SERIALIZE_SCALAR(regs.pcr); 2162 SERIALIZE_SCALAR(regs.rfcr); 2163 SERIALIZE_SCALAR(regs.rfdr); 2164 SERIALIZE_SCALAR(regs.brar); 2165 SERIALIZE_SCALAR(regs.brdr); 2166 SERIALIZE_SCALAR(regs.srr); 2167 SERIALIZE_SCALAR(regs.mibc); 2168 SERIALIZE_SCALAR(regs.vrcr); 2169 SERIALIZE_SCALAR(regs.vtcr); 2170 SERIALIZE_SCALAR(regs.vdr); 2171 SERIALIZE_SCALAR(regs.ccsr); 2172 SERIALIZE_SCALAR(regs.tbicr); 2173 SERIALIZE_SCALAR(regs.tbisr); 2174 SERIALIZE_SCALAR(regs.tanar); 2175 SERIALIZE_SCALAR(regs.tanlpar); 2176 SERIALIZE_SCALAR(regs.taner); 2177 SERIALIZE_SCALAR(regs.tesr); 2178 2179 SERIALIZE_ARRAY(rom.perfectMatch, ETH_ADDR_LEN); 2180 SERIALIZE_ARRAY(rom.filterHash, FHASH_SIZE); 2181 2182 SERIALIZE_SCALAR(ioEnable); 2183 2184 /* 2185 * Serialize the data Fifos 2186 */ 2187 rxFifo.serialize("rxFifo", os); 2188 txFifo.serialize("txFifo", os); 2189 2190 /* 2191 * Serialize the various helper variables 2192 */ 2193 bool txPacketExists = txPacket; 2194 SERIALIZE_SCALAR(txPacketExists); 2195 if (txPacketExists) { 2196 txPacket->length = txPacketBufPtr - txPacket->data; 2197 txPacket->serialize("txPacket", os); 2198 uint32_t txPktBufPtr = (uint32_t) (txPacketBufPtr - txPacket->data); 2199 SERIALIZE_SCALAR(txPktBufPtr); 2200 } 2201 2202 bool rxPacketExists = rxPacket; 2203 SERIALIZE_SCALAR(rxPacketExists); 2204 if (rxPacketExists) { 2205 rxPacket->serialize("rxPacket", os); 2206 uint32_t rxPktBufPtr = (uint32_t) (rxPacketBufPtr - rxPacket->data); 2207 SERIALIZE_SCALAR(rxPktBufPtr); 2208 } 2209 2210 SERIALIZE_SCALAR(txXferLen); 2211 SERIALIZE_SCALAR(rxXferLen); 2212 2213 /* 2214 * Serialize Cached Descriptors 2215 */ 2216 SERIALIZE_SCALAR(rxDesc64.link); 2217 SERIALIZE_SCALAR(rxDesc64.bufptr); 2218 SERIALIZE_SCALAR(rxDesc64.cmdsts); 2219 SERIALIZE_SCALAR(rxDesc64.extsts); 2220 SERIALIZE_SCALAR(txDesc64.link); 2221 SERIALIZE_SCALAR(txDesc64.bufptr); 2222 SERIALIZE_SCALAR(txDesc64.cmdsts); 2223 SERIALIZE_SCALAR(txDesc64.extsts); 2224 SERIALIZE_SCALAR(rxDesc32.link); 2225 SERIALIZE_SCALAR(rxDesc32.bufptr); 2226 SERIALIZE_SCALAR(rxDesc32.cmdsts); 2227 SERIALIZE_SCALAR(rxDesc32.extsts); 2228 SERIALIZE_SCALAR(txDesc32.link); 2229 SERIALIZE_SCALAR(txDesc32.bufptr); 2230 SERIALIZE_SCALAR(txDesc32.cmdsts); 2231 SERIALIZE_SCALAR(txDesc32.extsts); 2232 SERIALIZE_SCALAR(extstsEnable); 2233 2234 /* 2235 * Serialize tx state machine 2236 */ 2237 int txState = this->txState; 2238 SERIALIZE_SCALAR(txState); 2239 SERIALIZE_SCALAR(txEnable); 2240 SERIALIZE_SCALAR(CTDD); 2241 SERIALIZE_SCALAR(txFragPtr); 2242 SERIALIZE_SCALAR(txDescCnt); 2243 int txDmaState = this->txDmaState; 2244 SERIALIZE_SCALAR(txDmaState); 2245 SERIALIZE_SCALAR(txKickTick); 2246 2247 /* 2248 * Serialize rx state machine 2249 */ 2250 int rxState = this->rxState; 2251 SERIALIZE_SCALAR(rxState); 2252 SERIALIZE_SCALAR(rxEnable); 2253 SERIALIZE_SCALAR(CRDD); 2254 SERIALIZE_SCALAR(rxPktBytes); 2255 SERIALIZE_SCALAR(rxFragPtr); 2256 SERIALIZE_SCALAR(rxDescCnt); 2257 int rxDmaState = this->rxDmaState; 2258 SERIALIZE_SCALAR(rxDmaState); 2259 SERIALIZE_SCALAR(rxKickTick); 2260 2261 /* 2262 * Serialize EEPROM state machine 2263 */ 2264 int eepromState = this->eepromState; 2265 SERIALIZE_SCALAR(eepromState); 2266 SERIALIZE_SCALAR(eepromClk); 2267 SERIALIZE_SCALAR(eepromBitsToRx); 2268 SERIALIZE_SCALAR(eepromOpcode); 2269 SERIALIZE_SCALAR(eepromAddress); 2270 SERIALIZE_SCALAR(eepromData); 2271 2272 /* 2273 * If there's a pending transmit, store the time so we can 2274 * reschedule it later 2275 */ 2276 Tick transmitTick = txEvent.scheduled() ? txEvent.when() - curTick() : 0; 2277 SERIALIZE_SCALAR(transmitTick); 2278 2279 /* 2280 * receive address filter settings 2281 */ 2282 SERIALIZE_SCALAR(rxFilterEnable); 2283 SERIALIZE_SCALAR(acceptBroadcast); 2284 SERIALIZE_SCALAR(acceptMulticast); 2285 SERIALIZE_SCALAR(acceptUnicast); 2286 SERIALIZE_SCALAR(acceptPerfect); 2287 SERIALIZE_SCALAR(acceptArp); 2288 SERIALIZE_SCALAR(multicastHashEnable); 2289 2290 /* 2291 * Keep track of pending interrupt status. 2292 */ 2293 SERIALIZE_SCALAR(intrTick); 2294 SERIALIZE_SCALAR(cpuPendingIntr); 2295 Tick intrEventTick = 0; 2296 if (intrEvent) 2297 intrEventTick = intrEvent->when(); 2298 SERIALIZE_SCALAR(intrEventTick); 2299 2300} 2301 2302void 2303NSGigE::unserialize(Checkpoint *cp, const std::string §ion) 2304{ 2305 // Unserialize the PciDev base class 2306 PciDev::unserialize(cp, section); 2307 2308 UNSERIALIZE_SCALAR(regs.command); 2309 UNSERIALIZE_SCALAR(regs.config); 2310 UNSERIALIZE_SCALAR(regs.mear); 2311 UNSERIALIZE_SCALAR(regs.ptscr); 2312 UNSERIALIZE_SCALAR(regs.isr); 2313 UNSERIALIZE_SCALAR(regs.imr); 2314 UNSERIALIZE_SCALAR(regs.ier); 2315 UNSERIALIZE_SCALAR(regs.ihr); 2316 UNSERIALIZE_SCALAR(regs.txdp); 2317 UNSERIALIZE_SCALAR(regs.txdp_hi); 2318 UNSERIALIZE_SCALAR(regs.txcfg); 2319 UNSERIALIZE_SCALAR(regs.gpior); 2320 UNSERIALIZE_SCALAR(regs.rxdp); 2321 UNSERIALIZE_SCALAR(regs.rxdp_hi); 2322 UNSERIALIZE_SCALAR(regs.rxcfg); 2323 UNSERIALIZE_SCALAR(regs.pqcr); 2324 UNSERIALIZE_SCALAR(regs.wcsr); 2325 UNSERIALIZE_SCALAR(regs.pcr); 2326 UNSERIALIZE_SCALAR(regs.rfcr); 2327 UNSERIALIZE_SCALAR(regs.rfdr); 2328 UNSERIALIZE_SCALAR(regs.brar); 2329 UNSERIALIZE_SCALAR(regs.brdr); 2330 UNSERIALIZE_SCALAR(regs.srr); 2331 UNSERIALIZE_SCALAR(regs.mibc); 2332 UNSERIALIZE_SCALAR(regs.vrcr); 2333 UNSERIALIZE_SCALAR(regs.vtcr); 2334 UNSERIALIZE_SCALAR(regs.vdr); 2335 UNSERIALIZE_SCALAR(regs.ccsr); 2336 UNSERIALIZE_SCALAR(regs.tbicr); 2337 UNSERIALIZE_SCALAR(regs.tbisr); 2338 UNSERIALIZE_SCALAR(regs.tanar); 2339 UNSERIALIZE_SCALAR(regs.tanlpar); 2340 UNSERIALIZE_SCALAR(regs.taner); 2341 UNSERIALIZE_SCALAR(regs.tesr); 2342 2343 UNSERIALIZE_ARRAY(rom.perfectMatch, ETH_ADDR_LEN); 2344 UNSERIALIZE_ARRAY(rom.filterHash, FHASH_SIZE); 2345 2346 UNSERIALIZE_SCALAR(ioEnable); 2347 2348 /* 2349 * unserialize the data fifos 2350 */ 2351 rxFifo.unserialize("rxFifo", cp, section); 2352 txFifo.unserialize("txFifo", cp, section); 2353 2354 /* 2355 * unserialize the various helper variables 2356 */ 2357 bool txPacketExists; 2358 UNSERIALIZE_SCALAR(txPacketExists); 2359 if (txPacketExists) { 2360 txPacket = new EthPacketData(16384); 2361 txPacket->unserialize("txPacket", cp, section); 2362 uint32_t txPktBufPtr; 2363 UNSERIALIZE_SCALAR(txPktBufPtr); 2364 txPacketBufPtr = (uint8_t *) txPacket->data + txPktBufPtr; 2365 } else 2366 txPacket = 0; 2367 2368 bool rxPacketExists; 2369 UNSERIALIZE_SCALAR(rxPacketExists); 2370 rxPacket = 0; 2371 if (rxPacketExists) { 2372 rxPacket = new EthPacketData(16384); 2373 rxPacket->unserialize("rxPacket", cp, section); 2374 uint32_t rxPktBufPtr; 2375 UNSERIALIZE_SCALAR(rxPktBufPtr); 2376 rxPacketBufPtr = (uint8_t *) rxPacket->data + rxPktBufPtr; 2377 } else 2378 rxPacket = 0; 2379 2380 UNSERIALIZE_SCALAR(txXferLen); 2381 UNSERIALIZE_SCALAR(rxXferLen); 2382 2383 /* 2384 * Unserialize Cached Descriptors 2385 */ 2386 UNSERIALIZE_SCALAR(rxDesc64.link); 2387 UNSERIALIZE_SCALAR(rxDesc64.bufptr); 2388 UNSERIALIZE_SCALAR(rxDesc64.cmdsts); 2389 UNSERIALIZE_SCALAR(rxDesc64.extsts); 2390 UNSERIALIZE_SCALAR(txDesc64.link); 2391 UNSERIALIZE_SCALAR(txDesc64.bufptr); 2392 UNSERIALIZE_SCALAR(txDesc64.cmdsts); 2393 UNSERIALIZE_SCALAR(txDesc64.extsts); 2394 UNSERIALIZE_SCALAR(rxDesc32.link); 2395 UNSERIALIZE_SCALAR(rxDesc32.bufptr); 2396 UNSERIALIZE_SCALAR(rxDesc32.cmdsts); 2397 UNSERIALIZE_SCALAR(rxDesc32.extsts); 2398 UNSERIALIZE_SCALAR(txDesc32.link); 2399 UNSERIALIZE_SCALAR(txDesc32.bufptr); 2400 UNSERIALIZE_SCALAR(txDesc32.cmdsts); 2401 UNSERIALIZE_SCALAR(txDesc32.extsts); 2402 UNSERIALIZE_SCALAR(extstsEnable); 2403 2404 /* 2405 * unserialize tx state machine 2406 */ 2407 int txState; 2408 UNSERIALIZE_SCALAR(txState); 2409 this->txState = (TxState) txState; 2410 UNSERIALIZE_SCALAR(txEnable); 2411 UNSERIALIZE_SCALAR(CTDD); 2412 UNSERIALIZE_SCALAR(txFragPtr); 2413 UNSERIALIZE_SCALAR(txDescCnt); 2414 int txDmaState; 2415 UNSERIALIZE_SCALAR(txDmaState); 2416 this->txDmaState = (DmaState) txDmaState; 2417 UNSERIALIZE_SCALAR(txKickTick); 2418 if (txKickTick) 2419 schedule(txKickEvent, txKickTick); 2420 2421 /* 2422 * unserialize rx state machine 2423 */ 2424 int rxState; 2425 UNSERIALIZE_SCALAR(rxState); 2426 this->rxState = (RxState) rxState; 2427 UNSERIALIZE_SCALAR(rxEnable); 2428 UNSERIALIZE_SCALAR(CRDD); 2429 UNSERIALIZE_SCALAR(rxPktBytes); 2430 UNSERIALIZE_SCALAR(rxFragPtr); 2431 UNSERIALIZE_SCALAR(rxDescCnt); 2432 int rxDmaState; 2433 UNSERIALIZE_SCALAR(rxDmaState); 2434 this->rxDmaState = (DmaState) rxDmaState; 2435 UNSERIALIZE_SCALAR(rxKickTick); 2436 if (rxKickTick) 2437 schedule(rxKickEvent, rxKickTick); 2438 2439 /* 2440 * Unserialize EEPROM state machine 2441 */ 2442 int eepromState; 2443 UNSERIALIZE_SCALAR(eepromState); 2444 this->eepromState = (EEPROMState) eepromState; 2445 UNSERIALIZE_SCALAR(eepromClk); 2446 UNSERIALIZE_SCALAR(eepromBitsToRx); 2447 UNSERIALIZE_SCALAR(eepromOpcode); 2448 UNSERIALIZE_SCALAR(eepromAddress); 2449 UNSERIALIZE_SCALAR(eepromData); 2450 2451 /* 2452 * If there's a pending transmit, reschedule it now 2453 */ 2454 Tick transmitTick; 2455 UNSERIALIZE_SCALAR(transmitTick); 2456 if (transmitTick) 2457 schedule(txEvent, curTick() + transmitTick); 2458 2459 /* 2460 * unserialize receive address filter settings 2461 */ 2462 UNSERIALIZE_SCALAR(rxFilterEnable); 2463 UNSERIALIZE_SCALAR(acceptBroadcast); 2464 UNSERIALIZE_SCALAR(acceptMulticast); 2465 UNSERIALIZE_SCALAR(acceptUnicast); 2466 UNSERIALIZE_SCALAR(acceptPerfect); 2467 UNSERIALIZE_SCALAR(acceptArp); 2468 UNSERIALIZE_SCALAR(multicastHashEnable); 2469 2470 /* 2471 * Keep track of pending interrupt status. 2472 */ 2473 UNSERIALIZE_SCALAR(intrTick); 2474 UNSERIALIZE_SCALAR(cpuPendingIntr); 2475 Tick intrEventTick; 2476 UNSERIALIZE_SCALAR(intrEventTick); 2477 if (intrEventTick) { 2478 intrEvent = new IntrEvent(this, true); 2479 schedule(intrEvent, intrEventTick); 2480 } 2481} 2482 2483NSGigE * 2484NSGigEParams::create() 2485{ 2486 return new NSGigE(this); 2487} 2488