ns_gige.cc revision 9342
12292SN/A/* 27597Sminkyu.jeong@arm.com * Copyright (c) 2004-2005 The Regents of The University of Michigan 37597Sminkyu.jeong@arm.com * All rights reserved. 47597Sminkyu.jeong@arm.com * 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 142292SN/A * this software without specific prior written permission. 152292SN/A * 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 392689Sktlim@umich.edu#include "base/debug.hh" 402689Sktlim@umich.edu#include "base/inet.hh" 412689Sktlim@umich.edu#include "base/types.hh" 422292SN/A#include "config/the_isa.hh" 432292SN/A#include "cpu/thread_context.hh" 443326Sktlim@umich.edu#include "debug/EthernetAll.hh" 456658Snate@binkert.org#include "dev/etherlink.hh" 462733Sktlim@umich.edu#include "dev/ns_gige.hh" 472907Sktlim@umich.edu#include "dev/pciconfigall.hh" 482292SN/A#include "mem/packet.hh" 492292SN/A#include "mem/packet_access.hh" 502722Sktlim@umich.edu#include "params/NSGigE.hh" 512669Sktlim@umich.edu#include "sim/system.hh" 522292SN/A 532790Sktlim@umich.edu// clang complains about std::set being overloaded with Packet::set if 542790Sktlim@umich.edu// we open up the entire namespace std 552790Sktlim@umich.eduusing std::min; 562790Sktlim@umich.eduusing std::ostream; 572669Sktlim@umich.eduusing std::string; 582678Sktlim@umich.edu 592678Sktlim@umich.educonst char *NsRxStateStrings[] = 605606Snate@binkert.org{ 612292SN/A "rxIdle", 622678Sktlim@umich.edu "rxDescRefr", 632292SN/A "rxDescRead", 642292SN/A "rxFifoBlock", 652669Sktlim@umich.edu "rxFragWrite", 662292SN/A "rxDescWrite", 672678Sktlim@umich.edu "rxAdvance" 682292SN/A}; 692678Sktlim@umich.edu 702678Sktlim@umich.educonst char *NsTxStateStrings[] = 712678Sktlim@umich.edu{ 724319Sktlim@umich.edu "txIdle", 734319Sktlim@umich.edu "txDescRefr", 744319Sktlim@umich.edu "txDescRead", 754319Sktlim@umich.edu "txFifoBlock", 764319Sktlim@umich.edu "txFragRead", 772678Sktlim@umich.edu "txDescWrite", 782678Sktlim@umich.edu "txAdvance" 792292SN/A}; 802678Sktlim@umich.edu 812678Sktlim@umich.educonst char *NsDmaState[] = 825336Shines@cs.fsu.edu{ 832678Sktlim@umich.edu "dmaIdle", 844873Sstever@eecs.umich.edu "dmaReading", 852678Sktlim@umich.edu "dmaWriting", 862292SN/A "dmaReadWaiting", 872678Sktlim@umich.edu "dmaWriteWaiting" 882678Sktlim@umich.edu}; 892678Sktlim@umich.edu 902678Sktlim@umich.eduusing namespace Net; 912678Sktlim@umich.eduusing namespace TheISA; 922678Sktlim@umich.edu 932678Sktlim@umich.edu/////////////////////////////////////////////////////////////////////// 942698Sktlim@umich.edu// 952344SN/A// NSGigE PCI Device 962678Sktlim@umich.edu// 972678Sktlim@umich.eduNSGigE::NSGigE(Params *p) 984986Ssaidi@eecs.umich.edu : EtherDevBase(p), ioEnable(false), 994986Ssaidi@eecs.umich.edu txFifo(p->tx_fifo_size), rxFifo(p->rx_fifo_size), 1006974Stjones1@inf.ed.ac.uk txPacket(0), rxPacket(0), txPacketBufPtr(NULL), rxPacketBufPtr(NULL), 1016974Stjones1@inf.ed.ac.uk txXferLen(0), rxXferLen(0), rxDmaFree(false), txDmaFree(false), 1026974Stjones1@inf.ed.ac.uk txState(txIdle), txEnable(false), CTDD(false), txHalt(false), 1036974Stjones1@inf.ed.ac.uk txFragPtr(0), txDescCnt(0), txDmaState(dmaIdle), rxState(rxIdle), 1046974Stjones1@inf.ed.ac.uk rxEnable(false), CRDD(false), rxPktBytes(0), rxHalt(false), 1056974Stjones1@inf.ed.ac.uk rxFragPtr(0), rxDescCnt(0), rxDmaState(dmaIdle), extstsEnable(false), 1066974Stjones1@inf.ed.ac.uk eepromState(eepromStart), eepromClk(false), eepromBitsToRx(0), 1072678Sktlim@umich.edu eepromOpcode(0), eepromAddress(0), eepromData(0), 1082820Sktlim@umich.edu dmaReadDelay(p->dma_read_delay), dmaWriteDelay(p->dma_write_delay), 1092678Sktlim@umich.edu dmaReadFactor(p->dma_read_factor), dmaWriteFactor(p->dma_write_factor), 1102678Sktlim@umich.edu rxDmaData(NULL), rxDmaAddr(0), rxDmaLen(0), 1116974Stjones1@inf.ed.ac.uk txDmaData(NULL), txDmaAddr(0), txDmaLen(0), 1126974Stjones1@inf.ed.ac.uk rxDmaReadEvent(this), rxDmaWriteEvent(this), 1136974Stjones1@inf.ed.ac.uk txDmaReadEvent(this), txDmaWriteEvent(this), 1146974Stjones1@inf.ed.ac.uk dmaDescFree(p->dma_desc_free), dmaDataFree(p->dma_data_free), 1156974Stjones1@inf.ed.ac.uk txDelay(p->tx_delay), rxDelay(p->rx_delay), 1166974Stjones1@inf.ed.ac.uk rxKickTick(0), rxKickEvent(this), txKickTick(0), txKickEvent(this), 1172678Sktlim@umich.edu txEvent(this), rxFilterEnable(p->rx_filter), 1182678Sktlim@umich.edu acceptBroadcast(false), acceptMulticast(false), acceptUnicast(false), 1192678Sktlim@umich.edu acceptPerfect(false), acceptArp(false), multicastHashEnable(false), 1202678Sktlim@umich.edu intrDelay(p->intr_delay), intrTick(0), cpuPendingIntr(false), 1212678Sktlim@umich.edu intrEvent(0), interface(0) 1222344SN/A{ 1232307SN/A 1246974Stjones1@inf.ed.ac.uk 1256974Stjones1@inf.ed.ac.uk interface = new NSGigEInt(name() + ".int0", this); 1266974Stjones1@inf.ed.ac.uk 1276974Stjones1@inf.ed.ac.uk regsReset(); 1282678Sktlim@umich.edu memcpy(&rom.perfectMatch, p->hardware_address.bytes(), ETH_ADDR_LEN); 1294032Sktlim@umich.edu 1302678Sktlim@umich.edu memset(&rxDesc32, 0, sizeof(rxDesc32)); 1312292SN/A memset(&txDesc32, 0, sizeof(txDesc32)); 1322292SN/A memset(&rxDesc64, 0, sizeof(rxDesc64)); 1332292SN/A memset(&txDesc64, 0, sizeof(txDesc64)); 1342292SN/A} 1352678Sktlim@umich.edu 1362678Sktlim@umich.eduNSGigE::~NSGigE() 1376974Stjones1@inf.ed.ac.uk{ 1382292SN/A delete interface; 1392292SN/A} 1402292SN/A 1412292SN/A/** 1422292SN/A * This is to write to the PCI general configuration registers 1435529Snate@binkert.org */ 1445529Snate@binkert.orgTick 1455529Snate@binkert.orgNSGigE::writeConfig(PacketPtr pkt) 1462292SN/A{ 1474329Sktlim@umich.edu int offset = pkt->getAddr() & PCI_CONFIG_SIZE; 1484329Sktlim@umich.edu if (offset < PCI_DEVICE_SPECIFIC) 1494329Sktlim@umich.edu PciDev::writeConfig(pkt); 1504329Sktlim@umich.edu else 1512292SN/A panic("Device specific PCI config space not implemented!\n"); 1522307SN/A 1532307SN/A switch (offset) { 1542907Sktlim@umich.edu // seems to work fine without all these PCI settings, but i 1552907Sktlim@umich.edu // put in the IO to double check, an assertion will fail if we 1562292SN/A // need to properly implement it 1572292SN/A case PCI_COMMAND: 1582329SN/A if (config.data[offset] & PCI_CMD_IOSE) 1592329SN/A ioEnable = true; 1602329SN/A else 1612292SN/A ioEnable = false; 1622292SN/A break; 1632292SN/A } 1642292SN/A 1652292SN/A return configDelay; 1662292SN/A} 1672292SN/A 1682292SN/AEtherInt* 1692292SN/ANSGigE::getEthPort(const std::string &if_name, int idx) 1702292SN/A{ 1712292SN/A if (if_name == "interface") { 1723492Sktlim@umich.edu if (interface->getPeer()) 1732329SN/A panic("interface already connected to\n"); 1742292SN/A return interface; 1752292SN/A } 1762292SN/A return NULL; 1772292SN/A} 1782292SN/A 1792292SN/A/** 1802292SN/A * This reads the device registers, which are detailed in the NS83820 1812292SN/A * spec sheet 1822292SN/A */ 1832292SN/ATick 1842292SN/ANSGigE::read(PacketPtr pkt) 1852292SN/A{ 1862292SN/A assert(ioEnable); 1872292SN/A 1882292SN/A pkt->allocate(); 1892292SN/A 1902292SN/A //The mask is to give you only the offset into the device register file 1912727Sktlim@umich.edu Addr daddr = pkt->getAddr() & 0xfff; 1922727Sktlim@umich.edu DPRINTF(EthernetPIO, "read da=%#x pa=%#x size=%d\n", 1932727Sktlim@umich.edu daddr, pkt->getAddr(), pkt->getSize()); 1942727Sktlim@umich.edu 1952727Sktlim@umich.edu 1962727Sktlim@umich.edu // there are some reserved registers, you can see ns_gige_reg.h and 1972727Sktlim@umich.edu // the spec sheet for details 1982727Sktlim@umich.edu if (daddr > LAST && daddr <= RESERVED) { 1992727Sktlim@umich.edu panic("Accessing reserved register"); 2002727Sktlim@umich.edu } else if (daddr > RESERVED && daddr <= 0x3FC) { 2012727Sktlim@umich.edu return readConfig(pkt); 2022727Sktlim@umich.edu } else if (daddr >= MIB_START && daddr <= MIB_END) { 2032727Sktlim@umich.edu // don't implement all the MIB's. hopefully the kernel 2042727Sktlim@umich.edu // doesn't actually DEPEND upon their values 2052727Sktlim@umich.edu // MIB are just hardware stats keepers 2062727Sktlim@umich.edu pkt->set<uint32_t>(0); 2072727Sktlim@umich.edu pkt->makeAtomicResponse(); 2082727Sktlim@umich.edu return pioDelay; 2092361SN/A } else if (daddr > 0x3FC) 2102361SN/A panic("Something is messed up!\n"); 2112361SN/A 2122361SN/A 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: 2242727Sktlim@umich.edu reg = regs.config; 2252727Sktlim@umich.edu break; 2262727Sktlim@umich.edu 2272727Sktlim@umich.edu 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: 2364329Sktlim@umich.edu reg = regs.isr; 2374329Sktlim@umich.edu devIntrClear(ISR_ALL); 2384329Sktlim@umich.edu break; 2394329Sktlim@umich.edu 2404329Sktlim@umich.edu case IMR: 2414329Sktlim@umich.edu reg = regs.imr; 2424329Sktlim@umich.edu break; 2434329Sktlim@umich.edu 2444329Sktlim@umich.edu case IER: 2454329Sktlim@umich.edu reg = regs.ier; 2464329Sktlim@umich.edu break; 2474329Sktlim@umich.edu 2484329Sktlim@umich.edu case IHR: 2492292SN/A reg = regs.ihr; 2502292SN/A break; 2512292SN/A 2522292SN/A case TXDP: 2532292SN/A reg = regs.txdp; 2542292SN/A break; 2552292SN/A 2562292SN/A case TXDP_HI: 2572292SN/A reg = regs.txdp_hi; 2582292SN/A break; 2592292SN/A 2602292SN/A case TX_CFG: 2612292SN/A reg = regs.txcfg; 2622292SN/A break; 2632307SN/A 2642307SN/A case GPIOR: 2652307SN/A reg = regs.gpior; 2662367SN/A break; 2672367SN/A 2682307SN/A case RXDP: 2692367SN/A reg = regs.rxdp; 2702307SN/A break; 2712329SN/A 2722307SN/A case RXDP_HI: 2732307SN/A reg = regs.rxdp_hi; 2742307SN/A break; 2752307SN/A 2762307SN/A case RX_CFG: 2772307SN/A reg = regs.rxcfg; 2782307SN/A break; 2792307SN/A 2802307SN/A case PQCR: 2812307SN/A reg = regs.pqcr; 2822307SN/A break; 2832307SN/A 2842307SN/A case WCSR: 2852307SN/A reg = regs.wcsr; 2862307SN/A break; 2872329SN/A 2882307SN/A case PCR: 2892307SN/A reg = regs.pcr; 2902307SN/A break; 2912307SN/A 2922307SN/A // see the spec sheet for how RFCR and RFDR work 2932307SN/A // basically, you write to RFCR to tell the machine 2942307SN/A // what you want to do next, then you act upon RFDR, 2952307SN/A // and the device will be prepared b/c of what you 2962307SN/A // wrote to RFCR 2972307SN/A case RFCR: 2982292SN/A reg = regs.rfcr; 2992292SN/A break; 3002329SN/A 3012329SN/A case RFDR: 3022292SN/A rfaddr = (uint16_t)(regs.rfcr & RFCR_RFADDR); 3032329SN/A switch (rfaddr) { 3042329SN/A // Read from perfect match ROM octets 3052292SN/A case 0x000: 3062292SN/A reg = rom.perfectMatch[1]; 3072292SN/A reg = reg << 8; 3082292SN/A reg += rom.perfectMatch[0]; 3092292SN/A break; 3102329SN/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; 3162292SN/A reg += rom.perfectMatch[4]; 3172292SN/A break; 3182292SN/A default: 3192329SN/A // Read filter hash table 3202329SN/A if (rfaddr >= FHASH_ADDR && 3212329SN/A rfaddr < FHASH_ADDR + FHASH_SIZE) { 3222292SN/A 3232292SN/A // Only word-aligned reads supported 3242292SN/A if (rfaddr % 2) 3252292SN/A panic("unaligned read from filter hash table!"); 3262292SN/A 3272329SN/A reg = rom.filterHash[rfaddr - FHASH_ADDR + 1] << 8; 3282292SN/A reg += rom.filterHash[rfaddr - FHASH_ADDR]; 3292292SN/A break; 3302292SN/A } 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; 3482292SN/A break; 3492292SN/A 3502292SN/A case VTCR: 3512292SN/A reg = regs.vtcr; 3522329SN/A break; 3532329SN/A 3542292SN/A case VDR: 3557720Sgblack@eecs.umich.edu reg = regs.vdr; 3567720Sgblack@eecs.umich.edu break; 3572292SN/A 3582292SN/A case CCSR: 3592292SN/A reg = regs.ccsr; 3602292SN/A break; 3612292SN/A 3622292SN/A case TBICR: 3632292SN/A reg = regs.tbicr; 3642292SN/A break; 3652292SN/A 3662292SN/A case TBISR: 3672292SN/A reg = regs.tbisr; 3682292SN/A break; 3692292SN/A 3702292SN/A case TANAR: 3712292SN/A reg = regs.tanar; 3722292SN/A break; 3732292SN/A 3742292SN/A case TANLPAR: 3752292SN/A reg = regs.tanlpar; 3762292SN/A break; 3772292SN/A 3782292SN/A case TANER: 3792292SN/A reg = regs.taner; 3802292SN/A break; 3817720Sgblack@eecs.umich.edu 3827720Sgblack@eecs.umich.edu case TESR: 3832292SN/A reg = regs.tesr; 3842292SN/A break; 3852292SN/A 3862292SN/A case M5REG: 3872292SN/A reg = 0; 3882292SN/A if (params()->rx_thread) 3892292SN/A reg |= M5REG_RX_THREAD; 3902292SN/A if (params()->tx_thread) 3912292SN/A reg |= M5REG_TX_THREAD; 3922292SN/A if (params()->rss) 3932292SN/A reg |= M5REG_RSS; 3942292SN/A break; 3952292SN/A 3962292SN/A default: 3972292SN/A panic("reading unimplemented register: addr=%#x", daddr); 3982292SN/A } 3992292SN/A 4002292SN/A DPRINTF(EthernetPIO, "read from %#x: data=%d data=%#x\n", 4012292SN/A daddr, reg, reg); 4022292SN/A 4032292SN/A pkt->makeAtomicResponse(); 4042292SN/A return pioDelay; 4052292SN/A} 4062292SN/A 4072292SN/ATick 4082292SN/ANSGigE::write(PacketPtr pkt) 4092292SN/A{ 4102292SN/A assert(ioEnable); 4112292SN/A 4122292SN/A Addr daddr = pkt->getAddr() & 0xfff; 4132292SN/A DPRINTF(EthernetPIO, "write da=%#x pa=%#x size=%d\n", 4142292SN/A daddr, pkt->getAddr(), pkt->getSize()); 4152292SN/A 4162292SN/A if (daddr > LAST && daddr <= RESERVED) { 4172292SN/A panic("Accessing reserved register"); 4182292SN/A } else if (daddr > RESERVED && daddr <= 0x3FC) { 4192292SN/A return writeConfig(pkt); 4202292SN/A } else if (daddr > 0x3FC) 4212292SN/A panic("Something is messed up!\n"); 4222292SN/A 4232292SN/A if (pkt->getSize() == sizeof(uint32_t)) { 4242292SN/A uint32_t reg = pkt->get<uint32_t>(); 4252292SN/A uint16_t rfaddr; 4262292SN/A 4272292SN/A DPRINTF(EthernetPIO, "write data=%d data=%#x\n", reg, reg); 4282292SN/A 4292292SN/A switch (daddr) { 4302292SN/A case CR: 4312292SN/A regs.command = reg; 4322292SN/A if (reg & CR_TXD) { 4332292SN/A txEnable = false; 4342292SN/A } else if (reg & CR_TXE) { 4352292SN/A txEnable = true; 4362292SN/A 4372292SN/A // the kernel is enabling the transmit machine 4382292SN/A if (txState == txIdle) 4392292SN/A txKick(); 4402292SN/A } 4412292SN/A 4422292SN/A if (reg & CR_RXD) { 4434032Sktlim@umich.edu rxEnable = false; 4442292SN/A } else if (reg & CR_RXE) { 4452292SN/A rxEnable = true; 4462292SN/A 4477720Sgblack@eecs.umich.edu if (rxState == rxIdle) 4487720Sgblack@eecs.umich.edu rxKick(); 4492292SN/A } 4504032Sktlim@umich.edu 4514032Sktlim@umich.edu if (reg & CR_TXR) 4522669Sktlim@umich.edu txReset(); 4532292SN/A 4547597Sminkyu.jeong@arm.com if (reg & CR_RXR) 4557597Sminkyu.jeong@arm.com rxReset(); 4567597Sminkyu.jeong@arm.com 4572329SN/A if (reg & CR_SWI) 4582329SN/A devIntrPost(ISR_SWI); 4592367SN/A 4602367SN/A if (reg & CR_RST) { 4617600Sminkyu.jeong@arm.com txReset(); 4627600Sminkyu.jeong@arm.com rxReset(); 4637600Sminkyu.jeong@arm.com 4644032Sktlim@umich.edu regsReset(); 4653731Sktlim@umich.edu } 4662367SN/A break; 4672367SN/A 4682292SN/A case CFGR: 4692292SN/A if (reg & CFGR_LNKSTS || 4704032Sktlim@umich.edu reg & CFGR_SPDSTS || 4714032Sktlim@umich.edu reg & CFGR_DUPSTS || 4724032Sktlim@umich.edu reg & CFGR_RESERVED || 4734032Sktlim@umich.edu reg & CFGR_T64ADDR || 4744032Sktlim@umich.edu reg & CFGR_PCI64_DET) { 4754032Sktlim@umich.edu // First clear all writable bits 4764032Sktlim@umich.edu regs.config &= CFGR_LNKSTS | CFGR_SPDSTS | CFGR_DUPSTS | 4774032Sktlim@umich.edu CFGR_RESERVED | CFGR_T64ADDR | 4784032Sktlim@umich.edu CFGR_PCI64_DET; 4794032Sktlim@umich.edu // Now set the appropriate writable bits 4804032Sktlim@umich.edu regs.config |= reg & ~(CFGR_LNKSTS | CFGR_SPDSTS | CFGR_DUPSTS | 4814032Sktlim@umich.edu CFGR_RESERVED | CFGR_T64ADDR | 4827616Sminkyu.jeong@arm.com CFGR_PCI64_DET); 4837616Sminkyu.jeong@arm.com } 4847616Sminkyu.jeong@arm.com 4857616Sminkyu.jeong@arm.com// all these #if 0's are because i don't THINK the kernel needs to 4864032Sktlim@umich.edu// have these implemented. if there is a problem relating to one of 4877616Sminkyu.jeong@arm.com// these, you may need to add functionality in. 4887616Sminkyu.jeong@arm.com 4897616Sminkyu.jeong@arm.com// grouped together and #if 0'ed to avoid empty if body and make clang happy 4904032Sktlim@umich.edu#if 0 4914032Sktlim@umich.edu if (reg & CFGR_TBI_EN) ; 4924032Sktlim@umich.edu if (reg & CFGR_MODE_1000) ; 4934032Sktlim@umich.edu 4944032Sktlim@umich.edu if (reg & CFGR_PINT_DUPSTS || 4954032Sktlim@umich.edu reg & CFGR_PINT_LNKSTS || 4964032Sktlim@umich.edu reg & CFGR_PINT_SPDSTS) 4974032Sktlim@umich.edu ; 4984032Sktlim@umich.edu 4994032Sktlim@umich.edu if (reg & CFGR_TMRTEST) ; 5004032Sktlim@umich.edu if (reg & CFGR_MRM_DIS) ; 5014032Sktlim@umich.edu if (reg & CFGR_MWI_DIS) ; 5024032Sktlim@umich.edu 5034032Sktlim@umich.edu if (reg & CFGR_DATA64_EN) ; 5044032Sktlim@umich.edu if (reg & CFGR_M64ADDR) ; 5054032Sktlim@umich.edu if (reg & CFGR_PHY_RST) ; 5064032Sktlim@umich.edu if (reg & CFGR_PHY_DIS) ; 5072292SN/A 5082292SN/A if (reg & CFGR_REQALG) ; 5092292SN/A if (reg & CFGR_SB) ; 5102292SN/A if (reg & CFGR_POW) ; 5112292SN/A if (reg & CFGR_EXD) ; 5122292SN/A if (reg & CFGR_PESEL) ; 5132292SN/A if (reg & CFGR_BROM_DIS) ; 5142292SN/A if (reg & CFGR_EXT_125) ; 5152292SN/A if (reg & CFGR_BEM) ; 5162292SN/A 5172292SN/A if (reg & CFGR_T64ADDR) ; 5182292SN/A // panic("CFGR_T64ADDR is read only register!\n"); 5192292SN/A#endif 5202292SN/A if (reg & CFGR_AUTO_1000) 5212292SN/A panic("CFGR_AUTO_1000 not implemented!\n"); 5227720Sgblack@eecs.umich.edu 5237720Sgblack@eecs.umich.edu if (reg & CFGR_PCI64_DET) 5242292SN/A panic("CFGR_PCI64_DET is read only register!\n"); 5254032Sktlim@umich.edu 5264032Sktlim@umich.edu if (reg & CFGR_EXTSTS_EN) 5272292SN/A extstsEnable = true; 5282292SN/A else 5292292SN/A extstsEnable = false; 5302292SN/A break; 5312292SN/A 5322292SN/A case MEAR: 5332329SN/A // Clear writable bits 5347782Sminkyu.jeong@arm.com regs.mear &= MEAR_EEDO; 5357720Sgblack@eecs.umich.edu // Set appropriate writable bits 5362292SN/A regs.mear |= reg & ~MEAR_EEDO; 5372292SN/A 5387782Sminkyu.jeong@arm.com // FreeBSD uses the EEPROM to read PMATCH (for the MAC address) 5397782Sminkyu.jeong@arm.com // even though it could get it through RFDR 5407782Sminkyu.jeong@arm.com if (reg & MEAR_EESEL) { 5417782Sminkyu.jeong@arm.com // Rising edge of clock 5422292SN/A if (reg & MEAR_EECLK && !eepromClk) 5432292SN/A eepromKick(); 5442292SN/A } 5452292SN/A else { 5462336SN/A eepromState = eepromStart; 5472336SN/A regs.mear &= ~MEAR_EEDI; 5482336SN/A } 5492329SN/A 5502292SN/A eepromClk = reg & MEAR_EECLK; 5512329SN/A 5522292SN/A // since phy is completely faked, MEAR_MD* don't matter 5532292SN/A 5544032Sktlim@umich.edu// grouped together and #if 0'ed to avoid empty if body and make clang happy 5554032Sktlim@umich.edu#if 0 5564032Sktlim@umich.edu if (reg & MEAR_MDIO) ; 5574032Sktlim@umich.edu if (reg & MEAR_MDDIR) ; 5584032Sktlim@umich.edu if (reg & MEAR_MDC) ; 5592292SN/A#endif 5604032Sktlim@umich.edu break; 5614032Sktlim@umich.edu 5624032Sktlim@umich.edu case PTSCR: 5632329SN/A regs.ptscr = reg & ~(PTSCR_RBIST_RDONLY); 5644032Sktlim@umich.edu // these control BISTs for various parts of chip - we 5657616Sminkyu.jeong@arm.com // don't care or do just fake that the BIST is done 5667616Sminkyu.jeong@arm.com if (reg & PTSCR_RBIST_EN) 5677616Sminkyu.jeong@arm.com regs.ptscr |= PTSCR_RBIST_DONE; 5687616Sminkyu.jeong@arm.com if (reg & PTSCR_EEBIST_EN) 5694032Sktlim@umich.edu regs.ptscr &= ~PTSCR_EEBIST_EN; 5707616Sminkyu.jeong@arm.com if (reg & PTSCR_EELOAD_EN) 5717616Sminkyu.jeong@arm.com regs.ptscr &= ~PTSCR_EELOAD_EN; 5727616Sminkyu.jeong@arm.com break; 5734032Sktlim@umich.edu 5744032Sktlim@umich.edu case ISR: /* writing to the ISR has no effect */ 5754032Sktlim@umich.edu panic("ISR is a read only register!\n"); 5764032Sktlim@umich.edu 5774032Sktlim@umich.edu case IMR: 5784032Sktlim@umich.edu regs.imr = reg; 5794032Sktlim@umich.edu devIntrChangeMask(); 5804032Sktlim@umich.edu break; 5812292SN/A 5822292SN/A case IER: 5834032Sktlim@umich.edu regs.ier = reg; 5844032Sktlim@umich.edu break; 5854032Sktlim@umich.edu 5862292SN/A case IHR: 5872292SN/A regs.ihr = reg; 5884032Sktlim@umich.edu /* not going to implement real interrupt holdoff */ 5892292SN/A break; 5902292SN/A 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: 5982292SN/A regs.txdp_hi = reg; 5992292SN/A break; 6007720Sgblack@eecs.umich.edu 6017720Sgblack@eecs.umich.edu case TX_CFG: 6022292SN/A regs.txcfg = reg; 6032292SN/A#if 0 6042292SN/A if (reg & TX_CFG_CSI) ; 6052292SN/A 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) { 6092292SN/A /* 6102292SN/A * this could easily be implemented, but considering 6112292SN/A * the network is just a fake pipe, wouldn't make 6122292SN/A * sense to do this 6132292SN/A */ 6142292SN/A } 6152292SN/A 6162292SN/A if (reg & TX_CFG_BRST_DIS) ; 6172292SN/A#endif 6182292SN/A 6192292SN/A#if 0 6202292SN/A /* we handle our own DMA, ignore the kernel's exhortations */ 6212292SN/A if (reg & TX_CFG_MXDMA) ; 6222292SN/A#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 6292292SN/A break; 6302292SN/A 6312329SN/A case GPIOR: 6322329SN/A // Only write writable bits 6332292SN/A regs.gpior &= GPIOR_UNUSED | GPIOR_GP5_IN | GPIOR_GP4_IN 6342292SN/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); 6372292SN/A /* these just control general purpose i/o pins, don't matter */ 6387720Sgblack@eecs.umich.edu break; 6397720Sgblack@eecs.umich.edu 6402292SN/A case RXDP: 6412292SN/A regs.rxdp = reg; 6422292SN/A CRDD = false; 6432292SN/A break; 6442292SN/A 6452292SN/A case RXDP_HI: 6462292SN/A regs.rxdp_hi = reg; 6472292SN/A break; 6482292SN/A 6492292SN/A case RX_CFG: 6502292SN/A regs.rxcfg = reg; 6512292SN/A#if 0 6522292SN/A if (reg & RX_CFG_AEP) ; 6536974Stjones1@inf.ed.ac.uk if (reg & RX_CFG_ARP) ; 6546974Stjones1@inf.ed.ac.uk if (reg & RX_CFG_STRIPCRC) ; 6556974Stjones1@inf.ed.ac.uk if (reg & RX_CFG_RX_RD) ; 6566974Stjones1@inf.ed.ac.uk if (reg & RX_CFG_ALP) ; 6576974Stjones1@inf.ed.ac.uk if (reg & RX_CFG_AIRL) ; 6586974Stjones1@inf.ed.ac.uk 6596974Stjones1@inf.ed.ac.uk /* we handle our own DMA, ignore what kernel says about it */ 6606974Stjones1@inf.ed.ac.uk if (reg & RX_CFG_MXDMA) ; 6616974Stjones1@inf.ed.ac.uk 6626974Stjones1@inf.ed.ac.uk //also, we currently don't care about fill/drain thresholds 6636974Stjones1@inf.ed.ac.uk //though this may change in the future with more realistic 6646974Stjones1@inf.ed.ac.uk //networks or a driver which changes it according to feedback 6656974Stjones1@inf.ed.ac.uk if (reg & (RX_CFG_DRTH | RX_CFG_DRTH0)) ; 6666974Stjones1@inf.ed.ac.uk#endif 6676974Stjones1@inf.ed.ac.uk break; 6686974Stjones1@inf.ed.ac.uk 6692292SN/A case PQCR: 6702292SN/A /* there is no priority queueing used in the linux 2.6 driver */ 6716974Stjones1@inf.ed.ac.uk regs.pqcr = reg; 6726974Stjones1@inf.ed.ac.uk break; 6736974Stjones1@inf.ed.ac.uk 6746974Stjones1@inf.ed.ac.uk case WCSR: 6756974Stjones1@inf.ed.ac.uk /* not going to implement wake on LAN */ 6766974Stjones1@inf.ed.ac.uk regs.wcsr = reg; 6772292SN/A break; 6782292SN/A 6792292SN/A case PCR: 6802292SN/A /* not going to implement pause control */ 6812292SN/A regs.pcr = reg; 6822292SN/A break; 6832907Sktlim@umich.edu 6842678Sktlim@umich.edu case RFCR: 6852678Sktlim@umich.edu regs.rfcr = reg; 6862678Sktlim@umich.edu 6872678Sktlim@umich.edu rxFilterEnable = (reg & RFCR_RFEN) ? true : false; 6882678Sktlim@umich.edu acceptBroadcast = (reg & RFCR_AAB) ? true : false; 6892329SN/A acceptMulticast = (reg & RFCR_AAM) ? true : false; 6902329SN/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) 6972292SN/A panic("RFCR_APAT not implemented!\n"); 6982678Sktlim@umich.edu#endif 6992292SN/A if (reg & RFCR_UHEN) 7002292SN/A panic("Unicast hash filtering not used by drivers!\n"); 7012292SN/A 7022292SN/A if (reg & RFCR_ULM) 7032292SN/A panic("RFCR_ULM not implemented!\n"); 7042292SN/A 7052292SN/A break; 7062292SN/A 7072292SN/A case RFDR: 7082292SN/A rfaddr = (uint16_t)(regs.rfcr & RFCR_RFADDR); 7092292SN/A switch (rfaddr) { 7106974Stjones1@inf.ed.ac.uk case 0x000: 7116974Stjones1@inf.ed.ac.uk rom.perfectMatch[0] = (uint8_t)reg; 7126974Stjones1@inf.ed.ac.uk rom.perfectMatch[1] = (uint8_t)(reg >> 8); 7136974Stjones1@inf.ed.ac.uk break; 7146974Stjones1@inf.ed.ac.uk case 0x002: 7152669Sktlim@umich.edu rom.perfectMatch[2] = (uint8_t)reg; 7162669Sktlim@umich.edu rom.perfectMatch[3] = (uint8_t)(reg >> 8); 7172669Sktlim@umich.edu break; 7182292SN/A case 0x004: 7192292SN/A rom.perfectMatch[4] = (uint8_t)reg; 7202669Sktlim@umich.edu rom.perfectMatch[5] = (uint8_t)(reg >> 8); 7212669Sktlim@umich.edu break; 7223772Sgblack@eecs.umich.edu default: 7234326Sgblack@eecs.umich.edu 7242669Sktlim@umich.edu if (rfaddr >= FHASH_ADDR && 7254878Sstever@eecs.umich.edu rfaddr < FHASH_ADDR + FHASH_SIZE) { 7264878Sstever@eecs.umich.edu 7276102Sgblack@eecs.umich.edu // Only word-aligned writes supported 7286974Stjones1@inf.ed.ac.uk if (rfaddr % 2) 7296974Stjones1@inf.ed.ac.uk panic("unaligned write to filter hash table!"); 7302292SN/A 7312678Sktlim@umich.edu rom.filterHash[rfaddr - FHASH_ADDR] = (uint8_t)reg; 7322678Sktlim@umich.edu rom.filterHash[rfaddr - FHASH_ADDR + 1] 7332678Sktlim@umich.edu = (uint8_t)(reg >> 8); 7342678Sktlim@umich.edu break; 7356974Stjones1@inf.ed.ac.uk } 7366974Stjones1@inf.ed.ac.uk panic("writing RFDR for something other than pattern matching\ 7376974Stjones1@inf.ed.ac.uk or hashing! %#x\n", rfaddr); 7386974Stjones1@inf.ed.ac.uk } 7396974Stjones1@inf.ed.ac.uk 7406974Stjones1@inf.ed.ac.uk case BRAR: 7416974Stjones1@inf.ed.ac.uk regs.brar = reg; 7426974Stjones1@inf.ed.ac.uk break; 7436974Stjones1@inf.ed.ac.uk 7446974Stjones1@inf.ed.ac.uk case BRDR: 7456974Stjones1@inf.ed.ac.uk panic("the driver never uses BRDR, something is wrong!\n"); 7466974Stjones1@inf.ed.ac.uk 7476974Stjones1@inf.ed.ac.uk case SRR: 7486974Stjones1@inf.ed.ac.uk panic("SRR is read only register!\n"); 7496974Stjones1@inf.ed.ac.uk 7506974Stjones1@inf.ed.ac.uk case MIBC: 7516974Stjones1@inf.ed.ac.uk panic("the driver never uses MIBC, something is wrong!\n"); 7526974Stjones1@inf.ed.ac.uk 7536974Stjones1@inf.ed.ac.uk case VRCR: 7546974Stjones1@inf.ed.ac.uk regs.vrcr = reg; 7556974Stjones1@inf.ed.ac.uk break; 7566974Stjones1@inf.ed.ac.uk 7576974Stjones1@inf.ed.ac.uk case VTCR: 7586974Stjones1@inf.ed.ac.uk regs.vtcr = reg; 7596974Stjones1@inf.ed.ac.uk break; 7606974Stjones1@inf.ed.ac.uk 7616974Stjones1@inf.ed.ac.uk case VDR: 7626974Stjones1@inf.ed.ac.uk panic("the driver never uses VDR, something is wrong!\n"); 7632678Sktlim@umich.edu 7647720Sgblack@eecs.umich.edu case CCSR: 7652292SN/A /* not going to implement clockrun stuff */ 7667720Sgblack@eecs.umich.edu regs.ccsr = reg; 7673797Sgblack@eecs.umich.edu break; 7683221Sktlim@umich.edu 7692292SN/A case TBICR: 7702693Sktlim@umich.edu regs.tbicr = reg; 7714350Sgblack@eecs.umich.edu if (reg & TBICR_MR_LOOPBACK) 7726974Stjones1@inf.ed.ac.uk panic("TBICR_MR_LOOPBACK never used, something wrong!\n"); 7733326Sktlim@umich.edu 7743326Sktlim@umich.edu if (reg & TBICR_MR_AN_ENABLE) { 7753326Sktlim@umich.edu regs.tanlpar = regs.tanar; 7763326Sktlim@umich.edu regs.tbisr |= (TBISR_MR_AN_COMPLETE | TBISR_MR_LINK_STATUS); 7773326Sktlim@umich.edu } 7783326Sktlim@umich.edu 7793326Sktlim@umich.edu#if 0 7803326Sktlim@umich.edu if (reg & TBICR_MR_RESTART_AN) ; 7813326Sktlim@umich.edu#endif 7823326Sktlim@umich.edu 7833326Sktlim@umich.edu break; 7843326Sktlim@umich.edu 7853326Sktlim@umich.edu case TBISR: 7865606Snate@binkert.org panic("TBISR is read only register!\n"); 7873326Sktlim@umich.edu 7883326Sktlim@umich.edu case TANAR: 7893326Sktlim@umich.edu // Only write the writable bits 7902693Sktlim@umich.edu regs.tanar &= TANAR_RF1 | TANAR_RF2 | TANAR_UNUSED; 7912693Sktlim@umich.edu regs.tanar |= reg & ~(TANAR_RF1 | TANAR_RF2 | TANAR_UNUSED); 7922693Sktlim@umich.edu 7932693Sktlim@umich.edu // Pause capability unimplemented 7942693Sktlim@umich.edu#if 0 7952693Sktlim@umich.edu if (reg & TANAR_PS2) ; 7966974Stjones1@inf.ed.ac.uk if (reg & TANAR_PS1) ; 7974032Sktlim@umich.edu#endif 7983221Sktlim@umich.edu 7993221Sktlim@umich.edu break; 8006974Stjones1@inf.ed.ac.uk 8016974Stjones1@inf.ed.ac.uk case TANLPAR: 8026974Stjones1@inf.ed.ac.uk panic("this should only be written to by the fake phy!\n"); 8036974Stjones1@inf.ed.ac.uk 8046974Stjones1@inf.ed.ac.uk case TANER: 8056974Stjones1@inf.ed.ac.uk panic("TANER is read only register!\n"); 8062669Sktlim@umich.edu 8076974Stjones1@inf.ed.ac.uk case TESR: 8086974Stjones1@inf.ed.ac.uk regs.tesr = reg; 8096974Stjones1@inf.ed.ac.uk break; 8106974Stjones1@inf.ed.ac.uk 8116974Stjones1@inf.ed.ac.uk default: 8126974Stjones1@inf.ed.ac.uk panic("invalid register access daddr=%#x", daddr); 8136974Stjones1@inf.ed.ac.uk } 8146974Stjones1@inf.ed.ac.uk } else { 8156974Stjones1@inf.ed.ac.uk panic("Invalid Request Size"); 8166974Stjones1@inf.ed.ac.uk } 8176974Stjones1@inf.ed.ac.uk pkt->makeAtomicResponse(); 8186974Stjones1@inf.ed.ac.uk return pioDelay; 8196974Stjones1@inf.ed.ac.uk} 8206974Stjones1@inf.ed.ac.uk 8216974Stjones1@inf.ed.ac.ukvoid 8226974Stjones1@inf.ed.ac.ukNSGigE::devIntrPost(uint32_t interrupts) 8236974Stjones1@inf.ed.ac.uk{ 8246974Stjones1@inf.ed.ac.uk if (interrupts & ISR_RESERVE) 8256974Stjones1@inf.ed.ac.uk panic("Cannot set a reserved interrupt"); 8266974Stjones1@inf.ed.ac.uk 8276974Stjones1@inf.ed.ac.uk if (interrupts & ISR_NOIMPL) 8286974Stjones1@inf.ed.ac.uk warn("interrupt not implemented %#x\n", interrupts); 8296974Stjones1@inf.ed.ac.uk 8306974Stjones1@inf.ed.ac.uk interrupts &= ISR_IMPL; 8316974Stjones1@inf.ed.ac.uk regs.isr |= interrupts; 8326974Stjones1@inf.ed.ac.uk 8336974Stjones1@inf.ed.ac.uk 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) { 8412292SN/A totalRxOk++; 8422292SN/A } 8432292SN/A if (interrupts & ISR_RXDESC) { 8442292SN/A totalRxDesc++; 8452292SN/A } 8462292SN/A if (interrupts & ISR_TXOK) { 8472292SN/A totalTxOk++; 8482292SN/A } 8492292SN/A if (interrupts & ISR_TXIDLE) { 8502292SN/A totalTxIdle++; 8512292SN/A } 8522292SN/A if (interrupts & ISR_TXDESC) { 8532292SN/A totalTxDesc++; 8542292SN/A } 8552292SN/A if (interrupts & ISR_RXORN) { 8562292SN/A totalRxOrn++; 8572292SN/A } 8582292SN/A } 8592292SN/A 8602292SN/A DPRINTF(EthernetIntr, 8612292SN/A "interrupt written to ISR: intr=%#x isr=%#x imr=%#x\n", 8622329SN/A interrupts, regs.isr, regs.imr); 8632292SN/A 8642292SN/A if ((regs.isr & regs.imr)) { 8652292SN/A Tick when = curTick(); 8662292SN/A if ((regs.isr & regs.imr & ISR_NODELAY) == 0) 8672292SN/A when += intrDelay; 8687720Sgblack@eecs.umich.edu postedInterrupts++; 8692292SN/A cpuIntrPost(when); 8707720Sgblack@eecs.umich.edu } 8712292SN/A} 8722292SN/A 8732292SN/A/* 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. 8772292SN/A*/ 8782292SN/Avoid 8792329SN/ANSGigE::devIntrClear(uint32_t interrupts) 8802731Sktlim@umich.edu{ 8812292SN/A if (interrupts & ISR_RESERVE) 8822292SN/A panic("Cannot clear a reserved interrupt"); 8832292SN/A 8842292SN/A if (regs.isr & regs.imr & ISR_SWI) { 8852292SN/A postedSwi++; 8862292SN/A } 8872292SN/A if (regs.isr & regs.imr & ISR_RXIDLE) { 8882727Sktlim@umich.edu postedRxIdle++; 8892292SN/A } 8902292SN/A if (regs.isr & regs.imr & ISR_RXOK) { 8912292SN/A postedRxOk++; 8922292SN/A } 8932292SN/A if (regs.isr & regs.imr & ISR_RXDESC) { 8942292SN/A postedRxDesc++; 8952292SN/A } 8962292SN/A if (regs.isr & regs.imr & ISR_TXOK) { 8972292SN/A postedTxOk++; 8982292SN/A } 8994032Sktlim@umich.edu if (regs.isr & regs.imr & ISR_TXIDLE) { 9004032Sktlim@umich.edu postedTxIdle++; 9014032Sktlim@umich.edu } 9024032Sktlim@umich.edu if (regs.isr & regs.imr & ISR_TXDESC) { 9032292SN/A postedTxDesc++; 9042292SN/A } 9052292SN/A if (regs.isr & regs.imr & ISR_RXORN) { 9062292SN/A postedRxOrn++; 9072292SN/A } 9082329SN/A 9092292SN/A interrupts &= ~ISR_NOIMPL; 9102292SN/A regs.isr &= ~interrupts; 9112292SN/A 9122292SN/A DPRINTF(EthernetIntr, 9137720Sgblack@eecs.umich.edu "interrupt cleared from ISR: intr=%x isr=%x imr=%x\n", 9142292SN/A interrupts, regs.isr, regs.imr); 9157720Sgblack@eecs.umich.edu 9162292SN/A if (!(regs.isr & regs.imr)) 9172292SN/A cpuIntrClear(); 9182329SN/A} 9192329SN/A 9202292SN/Avoid 9212292SN/ANSGigE::devIntrChangeMask() 9222292SN/A{ 9232292SN/A DPRINTF(EthernetIntr, "interrupt mask changed: isr=%x imr=%x masked=%x\n", 9242292SN/A regs.isr, regs.imr, regs.isr & regs.imr); 9252292SN/A 9262292SN/A if (regs.isr & regs.imr) 9272329SN/A cpuIntrPost(curTick()); 9282731Sktlim@umich.edu else 9292292SN/A cpuIntrClear(); 9302292SN/A} 9312292SN/A 9324032Sktlim@umich.eduvoid 9334032Sktlim@umich.eduNSGigE::cpuIntrPost(Tick when) 9344032Sktlim@umich.edu{ 9354032Sktlim@umich.edu // If the interrupt you want to post is later than an interrupt 9366974Stjones1@inf.ed.ac.uk // already scheduled, just let it post in the coming one and don't 9376974Stjones1@inf.ed.ac.uk // schedule another. 9386974Stjones1@inf.ed.ac.uk // HOWEVER, must be sure that the scheduled intrTick is in the 9396974Stjones1@inf.ed.ac.uk // future (this was formerly the source of a bug) 9406974Stjones1@inf.ed.ac.uk /** 9416974Stjones1@inf.ed.ac.uk * @todo this warning should be removed and the intrTick code should 9426974Stjones1@inf.ed.ac.uk * be fixed. 9434032Sktlim@umich.edu */ 9442292SN/A assert(when >= curTick()); 9452292SN/A assert(intrTick >= curTick() || intrTick == 0); 9462292SN/A if (when > intrTick && intrTick != 0) { 9472292SN/A DPRINTF(EthernetIntr, "don't need to schedule event...intrTick=%d\n", 9482292SN/A intrTick); 9492292SN/A return; 9502292SN/A } 9512727Sktlim@umich.edu 9522292SN/A intrTick = when; 9532292SN/A if (intrTick < curTick()) { 9542292SN/A Debug::breakpoint(); 9552292SN/A intrTick = curTick(); 9562292SN/A } 9573349Sbinkertn@umich.edu 9582693Sktlim@umich.edu DPRINTF(EthernetIntr, "going to schedule an interrupt for intrTick=%d\n", 9592693Sktlim@umich.edu intrTick); 9602693Sktlim@umich.edu 9612693Sktlim@umich.edu if (intrEvent) 9622693Sktlim@umich.edu intrEvent->squash(); 9632693Sktlim@umich.edu intrEvent = new IntrEvent(this, true); 9642693Sktlim@umich.edu schedule(intrEvent, intrTick); 9652693Sktlim@umich.edu} 9662693Sktlim@umich.edu 9672693Sktlim@umich.eduvoid 9682693Sktlim@umich.eduNSGigE::cpuInterrupt() 9692693Sktlim@umich.edu{ 9702693Sktlim@umich.edu assert(intrTick == curTick()); 9712693Sktlim@umich.edu 9722693Sktlim@umich.edu // Whether or not there's a pending interrupt, we don't care about 9732693Sktlim@umich.edu // it anymore 9742733Sktlim@umich.edu intrEvent = 0; 9752693Sktlim@umich.edu intrTick = 0; 9762732Sktlim@umich.edu 9772693Sktlim@umich.edu // Don't send an interrupt if there's already one 9782733Sktlim@umich.edu if (cpuPendingIntr) { 9792693Sktlim@umich.edu DPRINTF(EthernetIntr, 9802693Sktlim@umich.edu "would send an interrupt now, but there's already pending\n"); 9812693Sktlim@umich.edu } else { 9822693Sktlim@umich.edu // Send interrupt 9832693Sktlim@umich.edu cpuPendingIntr = true; 9842693Sktlim@umich.edu 9852693Sktlim@umich.edu DPRINTF(EthernetIntr, "posting interrupt\n"); 9862678Sktlim@umich.edu intrPost(); 9872678Sktlim@umich.edu } 9882678Sktlim@umich.edu} 9892678Sktlim@umich.edu 9902678Sktlim@umich.eduvoid 9912678Sktlim@umich.eduNSGigE::cpuIntrClear() 9922927Sktlim@umich.edu{ 9932678Sktlim@umich.edu if (!cpuPendingIntr) 9942727Sktlim@umich.edu return; 9952678Sktlim@umich.edu 9962678Sktlim@umich.edu if (intrEvent) { 9972678Sktlim@umich.edu intrEvent->squash(); 9982678Sktlim@umich.edu intrEvent = 0; 9992678Sktlim@umich.edu } 10002678Sktlim@umich.edu 10012678Sktlim@umich.edu intrTick = 0; 10022678Sktlim@umich.edu 10032678Sktlim@umich.edu cpuPendingIntr = false; 10042678Sktlim@umich.edu 10052678Sktlim@umich.edu DPRINTF(EthernetIntr, "clearing interrupt\n"); 10062678Sktlim@umich.edu intrClear(); 10072678Sktlim@umich.edu} 10082678Sktlim@umich.edu 10097598Sminkyu.jeong@arm.combool 10107598Sminkyu.jeong@arm.comNSGigE::cpuIntrPending() const 10117598Sminkyu.jeong@arm.com{ return cpuPendingIntr; } 10122678Sktlim@umich.edu 10132678Sktlim@umich.eduvoid 10142678Sktlim@umich.eduNSGigE::txReset() 10152678Sktlim@umich.edu{ 10162292SN/A 10172292SN/A DPRINTF(Ethernet, "transmit reset\n"); 10182292SN/A 10192292SN/A CTDD = false; 10202292SN/A txEnable = false;; 10212292SN/A txFragPtr = 0; 10222292SN/A assert(txDescCnt == 0); 10232292SN/A txFifo.clear(); 10243126Sktlim@umich.edu txState = txIdle; 10252292SN/A assert(txDmaState == dmaIdle); 10262292SN/A} 10272292SN/A 10282292SN/Avoid 10292292SN/ANSGigE::rxReset() 10302292SN/A{ 10312292SN/A DPRINTF(Ethernet, "receive reset\n"); 10322292SN/A 10332292SN/A CRDD = false; 10342292SN/A assert(rxPktBytes == 0); 10352292SN/A rxEnable = false; 10362292SN/A rxFragPtr = 0; 10372292SN/A assert(rxDescCnt == 0); 10382329SN/A assert(rxDmaState == dmaIdle); 10392329SN/A rxFifo.clear(); 10402329SN/A rxState = rxIdle; 10412292SN/A} 10422292SN/A 10432292SN/Avoid 10442292SN/ANSGigE::regsReset() 10452292SN/A{ 10462292SN/A memset(®s, 0, sizeof(regs)); 10472292SN/A regs.config = (CFGR_LNKSTS | CFGR_TBI_EN | CFGR_MODE_1000); 10482292SN/A regs.mear = 0x12; 10492292SN/A regs.txcfg = 0x120; // set drain threshold to 1024 bytes and 10502292SN/A // fill threshold to 32 bytes 10512316SN/A regs.rxcfg = 0x4; // set drain threshold to 16 bytes 10522316SN/A regs.srr = 0x0103; // set the silicon revision to rev B or 0x103 10532329SN/A regs.mibc = MIBC_FRZ; 10542329SN/A regs.vdr = 0x81; // set the vlan tag type to 802.1q 10552329SN/A regs.tesr = 0xc000; // TBI capable of both full and half duplex 10562329SN/A regs.brar = 0xffffffff; 10572733Sktlim@umich.edu 10582316SN/A extstsEnable = false; 10592732Sktlim@umich.edu acceptBroadcast = false; 10602316SN/A acceptMulticast = false; 10612733Sktlim@umich.edu acceptUnicast = false; 10622292SN/A acceptPerfect = false; 10632292SN/A acceptArp = false; 10642292SN/A} 10656974Stjones1@inf.ed.ac.uk 10666974Stjones1@inf.ed.ac.ukbool 10676974Stjones1@inf.ed.ac.ukNSGigE::doRxDmaRead() 10686974Stjones1@inf.ed.ac.uk{ 10696974Stjones1@inf.ed.ac.uk assert(rxDmaState == dmaIdle || rxDmaState == dmaReadWaiting); 10706974Stjones1@inf.ed.ac.uk rxDmaState = dmaReading; 10716974Stjones1@inf.ed.ac.uk 10726974Stjones1@inf.ed.ac.uk if (dmaPending() || getDrainState() != Drainable::Running) 10736974Stjones1@inf.ed.ac.uk rxDmaState = dmaReadWaiting; 10746974Stjones1@inf.ed.ac.uk else 10756974Stjones1@inf.ed.ac.uk dmaRead(rxDmaAddr, rxDmaLen, &rxDmaReadEvent, (uint8_t*)rxDmaData); 10766974Stjones1@inf.ed.ac.uk 10776974Stjones1@inf.ed.ac.uk return true; 10786974Stjones1@inf.ed.ac.uk} 10796974Stjones1@inf.ed.ac.uk 10806974Stjones1@inf.ed.ac.ukvoid 10812693Sktlim@umich.eduNSGigE::rxDmaReadDone() 10822693Sktlim@umich.edu{ 10832693Sktlim@umich.edu assert(rxDmaState == dmaReading); 10842698Sktlim@umich.edu rxDmaState = dmaIdle; 10854985Sktlim@umich.edu 10862698Sktlim@umich.edu DPRINTF(EthernetDMA, "rx dma read paddr=%#x len=%d\n", 10872693Sktlim@umich.edu rxDmaAddr, rxDmaLen); 10882698Sktlim@umich.edu DDUMP(EthernetDMA, rxDmaData, rxDmaLen); 10896974Stjones1@inf.ed.ac.uk 10906974Stjones1@inf.ed.ac.uk // If the transmit state machine has a pending DMA, let it go first 10916974Stjones1@inf.ed.ac.uk if (txDmaState == dmaReadWaiting || txDmaState == dmaWriteWaiting) 10926974Stjones1@inf.ed.ac.uk txKick(); 10936974Stjones1@inf.ed.ac.uk 10946974Stjones1@inf.ed.ac.uk rxKick(); 10956974Stjones1@inf.ed.ac.uk} 10962699Sktlim@umich.edu 10972693Sktlim@umich.edubool 10986221Snate@binkert.orgNSGigE::doRxDmaWrite() 10996974Stjones1@inf.ed.ac.uk{ 11006974Stjones1@inf.ed.ac.uk assert(rxDmaState == dmaIdle || rxDmaState == dmaWriteWaiting); 11016974Stjones1@inf.ed.ac.uk rxDmaState = dmaWriting; 11026974Stjones1@inf.ed.ac.uk 11036974Stjones1@inf.ed.ac.uk if (dmaPending() || getDrainState() != Running) 11046974Stjones1@inf.ed.ac.uk rxDmaState = dmaWriteWaiting; 11056974Stjones1@inf.ed.ac.uk else 11066974Stjones1@inf.ed.ac.uk dmaWrite(rxDmaAddr, rxDmaLen, &rxDmaWriteEvent, (uint8_t*)rxDmaData); 11072693Sktlim@umich.edu return true; 11082693Sktlim@umich.edu} 11092727Sktlim@umich.edu 11102907Sktlim@umich.eduvoid 11112693Sktlim@umich.eduNSGigE::rxDmaWriteDone() 11122693Sktlim@umich.edu{ 11132693Sktlim@umich.edu assert(rxDmaState == dmaWriting); 11142693Sktlim@umich.edu rxDmaState = dmaIdle; 11152693Sktlim@umich.edu 11162693Sktlim@umich.edu DPRINTF(EthernetDMA, "rx dma write paddr=%#x len=%d\n", 11172693Sktlim@umich.edu rxDmaAddr, rxDmaLen); 11182693Sktlim@umich.edu DDUMP(EthernetDMA, rxDmaData, rxDmaLen); 11192693Sktlim@umich.edu 11202693Sktlim@umich.edu // If the transmit state machine has a pending DMA, let it go first 11212292SN/A if (txDmaState == dmaReadWaiting || txDmaState == dmaWriteWaiting) 11222292SN/A txKick(); 11232292SN/A 11242292SN/A rxKick(); 11252292SN/A} 11262292SN/A 11272292SN/Avoid 11282292SN/ANSGigE::rxKick() 11292292SN/A{ 11302292SN/A bool is64bit = (bool)(regs.config & CFGR_M64ADDR); 11312292SN/A 11322292SN/A DPRINTF(EthernetSM, 11332292SN/A "receive kick rxState=%s (rxBuf.size=%d) %d-bit\n", 11342292SN/A NsRxStateStrings[rxState], rxFifo.size(), is64bit ? 64 : 32); 11352292SN/A 11362292SN/A Addr link, bufptr; 11372292SN/A uint32_t &cmdsts = is64bit ? rxDesc64.cmdsts : rxDesc32.cmdsts; 11382292SN/A uint32_t &extsts = is64bit ? rxDesc64.extsts : rxDesc32.extsts; 11392292SN/A 11402292SN/A next: 11412292SN/A if (clock) { 11422292SN/A if (rxKickTick > curTick()) { 11432292SN/A DPRINTF(EthernetSM, "receive kick exiting, can't run till %d\n", 11442292SN/A rxKickTick); 11452292SN/A 11462292SN/A goto exit; 11472292SN/A } 11482292SN/A 11492292SN/A // Go to the next state machine clock tick. 11502292SN/A rxKickTick = curTick() + clockPeriod(); 11512329SN/A } 11522329SN/A 11532329SN/A switch(rxDmaState) { 11542329SN/A case dmaReadWaiting: 11552329SN/A if (doRxDmaRead()) 11562329SN/A goto exit; 11572329SN/A break; 11582329SN/A case dmaWriteWaiting: 11592329SN/A if (doRxDmaWrite()) 11602329SN/A goto exit; 11612329SN/A break; 11622329SN/A default: 11637720Sgblack@eecs.umich.edu break; 11642329SN/A } 11652329SN/A 11662329SN/A link = is64bit ? (Addr)rxDesc64.link : (Addr)rxDesc32.link; 11672329SN/A bufptr = is64bit ? (Addr)rxDesc64.bufptr : (Addr)rxDesc32.bufptr; 11682329SN/A 11692329SN/A // see state machine from spec for details 11702329SN/A // the way this works is, if you finish work on one state and can 11712329SN/A // go directly to another, you do that through jumping to the 11722329SN/A // label "next". however, if you have intermediate work, like DMA 11732329SN/A // so that you can't go to the next state yet, you go to exit and 11747720Sgblack@eecs.umich.edu // exit the loop. however, when the DMA is done it will trigger 11752329SN/A // an event and come back to this loop. 11762329SN/A switch (rxState) { 11772329SN/A case rxIdle: 11782329SN/A if (!rxEnable) { 11792329SN/A DPRINTF(EthernetSM, "Receive Disabled! Nothing to do.\n"); 11802329SN/A 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() || getDrainState() != 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() || getDrainState() != 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::drainResume() 2116{ 2117 Drainable::drainResume(); 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