ns_gige.cc revision 9086
16657Snate@binkert.org/* 26657Snate@binkert.org * Copyright (c) 2004-2005 The Regents of The University of Michigan 36657Snate@binkert.org * All rights reserved. 46657Snate@binkert.org * 56657Snate@binkert.org * Redistribution and use in source and binary forms, with or without 66657Snate@binkert.org * modification, are permitted provided that the following conditions are 76657Snate@binkert.org * met: redistributions of source code must retain the above copyright 86657Snate@binkert.org * notice, this list of conditions and the following disclaimer; 96657Snate@binkert.org * redistributions in binary form must reproduce the above copyright 106657Snate@binkert.org * notice, this list of conditions and the following disclaimer in the 116657Snate@binkert.org * documentation and/or other materials provided with the distribution; 126657Snate@binkert.org * neither the name of the copyright holders nor the names of its 136657Snate@binkert.org * contributors may be used to endorse or promote products derived from 146657Snate@binkert.org * this software without specific prior written permission. 156657Snate@binkert.org * 166657Snate@binkert.org * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 176657Snate@binkert.org * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 186657Snate@binkert.org * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR 196657Snate@binkert.org * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT 206657Snate@binkert.org * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 216657Snate@binkert.org * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT 226657Snate@binkert.org * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 236657Snate@binkert.org * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 246657Snate@binkert.org * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 256657Snate@binkert.org * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 266657Snate@binkert.org * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 276657Snate@binkert.org * 286999Snate@binkert.org * Authors: Nathan Binkert 296657Snate@binkert.org * Lisa Hsu 306657Snate@binkert.org */ 316657Snate@binkert.org 329302Snilay@cs.wisc.edu/** @file 336657Snate@binkert.org * Device module for modelling the National Semiconductor 346657Snate@binkert.org * DP83820 ethernet controller. Does not support priority queueing 356657Snate@binkert.org */ 366657Snate@binkert.org#include <deque> 376657Snate@binkert.org#include <string> 386657Snate@binkert.org 396657Snate@binkert.org#include "base/debug.hh" 406657Snate@binkert.org#include "base/inet.hh" 416657Snate@binkert.org#include "base/types.hh" 426657Snate@binkert.org#include "config/the_isa.hh" 436657Snate@binkert.org#include "cpu/thread_context.hh" 446657Snate@binkert.org#include "debug/EthernetAll.hh" 456657Snate@binkert.org#include "dev/etherlink.hh" 466657Snate@binkert.org#include "dev/ns_gige.hh" 476657Snate@binkert.org#include "dev/pciconfigall.hh" 486657Snate@binkert.org#include "mem/packet.hh" 496657Snate@binkert.org#include "mem/packet_access.hh" 506657Snate@binkert.org#include "params/NSGigE.hh" 516657Snate@binkert.org#include "sim/system.hh" 526657Snate@binkert.org 536657Snate@binkert.org// clang complains about std::set being overloaded with Packet::set if 546657Snate@binkert.org// we open up the entire namespace std 556882SBrad.Beckmann@amd.comusing std::min; 566657Snate@binkert.orgusing std::ostream; 576657Snate@binkert.orgusing std::string; 586657Snate@binkert.org 596657Snate@binkert.orgconst char *NsRxStateStrings[] = 606657Snate@binkert.org{ 616657Snate@binkert.org "rxIdle", 626657Snate@binkert.org "rxDescRefr", 636657Snate@binkert.org "rxDescRead", 646657Snate@binkert.org "rxFifoBlock", 656657Snate@binkert.org "rxFragWrite", 666657Snate@binkert.org "rxDescWrite", 676657Snate@binkert.org "rxAdvance" 686657Snate@binkert.org}; 696657Snate@binkert.org 706657Snate@binkert.orgconst char *NsTxStateStrings[] = 716657Snate@binkert.org{ 726657Snate@binkert.org "txIdle", 736657Snate@binkert.org "txDescRefr", 746657Snate@binkert.org "txDescRead", 7510228Snilay@cs.wisc.edu "txFifoBlock", 766657Snate@binkert.org "txFragRead", 776657Snate@binkert.org "txDescWrite", 7810228Snilay@cs.wisc.edu "txAdvance" 796657Snate@binkert.org}; 806657Snate@binkert.org 816657Snate@binkert.orgconst char *NsDmaState[] = 826657Snate@binkert.org{ 836657Snate@binkert.org "dmaIdle", 846657Snate@binkert.org "dmaReading", 856657Snate@binkert.org "dmaWriting", 866657Snate@binkert.org "dmaReadWaiting", 876657Snate@binkert.org "dmaWriteWaiting" 886657Snate@binkert.org}; 896657Snate@binkert.org 906657Snate@binkert.orgusing namespace Net; 916657Snate@binkert.orgusing namespace TheISA; 926657Snate@binkert.org 936657Snate@binkert.org/////////////////////////////////////////////////////////////////////// 946657Snate@binkert.org// 958086SBrad.Beckmann@amd.com// NSGigE PCI Device 968086SBrad.Beckmann@amd.com// 978086SBrad.Beckmann@amd.comNSGigE::NSGigE(Params *p) 986657Snate@binkert.org : EtherDevice(p), ioEnable(false), 996657Snate@binkert.org txFifo(p->tx_fifo_size), rxFifo(p->rx_fifo_size), 1006657Snate@binkert.org txPacket(0), rxPacket(0), txPacketBufPtr(NULL), rxPacketBufPtr(NULL), 1016657Snate@binkert.org txXferLen(0), rxXferLen(0), rxDmaFree(false), txDmaFree(false), 1029298Snilay@cs.wisc.edu clock(p->clock), 1036657Snate@binkert.org txState(txIdle), txEnable(false), CTDD(false), txHalt(false), 1046657Snate@binkert.org txFragPtr(0), txDescCnt(0), txDmaState(dmaIdle), rxState(rxIdle), 1056657Snate@binkert.org rxEnable(false), CRDD(false), rxPktBytes(0), rxHalt(false), 1066657Snate@binkert.org rxFragPtr(0), rxDescCnt(0), rxDmaState(dmaIdle), extstsEnable(false), 1076657Snate@binkert.org eepromState(eepromStart), eepromClk(false), eepromBitsToRx(0), 1086657Snate@binkert.org eepromOpcode(0), eepromAddress(0), eepromData(0), 1096657Snate@binkert.org dmaReadDelay(p->dma_read_delay), dmaWriteDelay(p->dma_write_delay), 1106657Snate@binkert.org dmaReadFactor(p->dma_read_factor), dmaWriteFactor(p->dma_write_factor), 1116657Snate@binkert.org rxDmaData(NULL), rxDmaAddr(0), rxDmaLen(0), 1126657Snate@binkert.org txDmaData(NULL), txDmaAddr(0), txDmaLen(0), 1136657Snate@binkert.org rxDmaReadEvent(this), rxDmaWriteEvent(this), 1146657Snate@binkert.org txDmaReadEvent(this), txDmaWriteEvent(this), 1156657Snate@binkert.org dmaDescFree(p->dma_desc_free), dmaDataFree(p->dma_data_free), 1166657Snate@binkert.org txDelay(p->tx_delay), rxDelay(p->rx_delay), 1176657Snate@binkert.org rxKickTick(0), rxKickEvent(this), txKickTick(0), txKickEvent(this), 1186657Snate@binkert.org txEvent(this), rxFilterEnable(p->rx_filter), 1196657Snate@binkert.org acceptBroadcast(false), acceptMulticast(false), acceptUnicast(false), 1206657Snate@binkert.org acceptPerfect(false), acceptArp(false), multicastHashEnable(false), 1216657Snate@binkert.org intrDelay(p->intr_delay), intrTick(0), cpuPendingIntr(false), 1226657Snate@binkert.org intrEvent(0), interface(0) 1236657Snate@binkert.org{ 1246657Snate@binkert.org 1256657Snate@binkert.org 1266657Snate@binkert.org interface = new NSGigEInt(name() + ".int0", this); 1276657Snate@binkert.org 1286657Snate@binkert.org regsReset(); 1296657Snate@binkert.org memcpy(&rom.perfectMatch, p->hardware_address.bytes(), ETH_ADDR_LEN); 1306657Snate@binkert.org 1316657Snate@binkert.org memset(&rxDesc32, 0, sizeof(rxDesc32)); 1326657Snate@binkert.org memset(&txDesc32, 0, sizeof(txDesc32)); 1336657Snate@binkert.org memset(&rxDesc64, 0, sizeof(rxDesc64)); 1346657Snate@binkert.org memset(&txDesc64, 0, sizeof(txDesc64)); 1356657Snate@binkert.org} 1366657Snate@binkert.org 1376657Snate@binkert.orgNSGigE::~NSGigE() 1386657Snate@binkert.org{ 1399298Snilay@cs.wisc.edu delete interface; 1406657Snate@binkert.org} 1416657Snate@binkert.org 1426657Snate@binkert.org/** 1436657Snate@binkert.org * This is to write to the PCI general configuration registers 1446657Snate@binkert.org */ 1456657Snate@binkert.orgTick 1469302Snilay@cs.wisc.eduNSGigE::writeConfig(PacketPtr pkt) 1479302Snilay@cs.wisc.edu{ 1489302Snilay@cs.wisc.edu int offset = pkt->getAddr() & PCI_CONFIG_SIZE; 1496657Snate@binkert.org if (offset < PCI_DEVICE_SPECIFIC) 1506657Snate@binkert.org PciDev::writeConfig(pkt); 1516657Snate@binkert.org else 1526657Snate@binkert.org panic("Device specific PCI config space not implemented!\n"); 1536657Snate@binkert.org 1546657Snate@binkert.org switch (offset) { 1556657Snate@binkert.org // seems to work fine without all these PCI settings, but i 1566657Snate@binkert.org // put in the IO to double check, an assertion will fail if we 1576882SBrad.Beckmann@amd.com // need to properly implement it 1586882SBrad.Beckmann@amd.com case PCI_COMMAND: 1596882SBrad.Beckmann@amd.com if (config.data[offset] & PCI_CMD_IOSE) 1608086SBrad.Beckmann@amd.com ioEnable = true; 1618086SBrad.Beckmann@amd.com else 1628086SBrad.Beckmann@amd.com ioEnable = false; 1639298Snilay@cs.wisc.edu break; 1646657Snate@binkert.org } 1656657Snate@binkert.org 1666657Snate@binkert.org return configDelay; 1676657Snate@binkert.org} 1686657Snate@binkert.org 1696657Snate@binkert.orgEtherInt* 1706657Snate@binkert.orgNSGigE::getEthPort(const std::string &if_name, int idx) 1719298Snilay@cs.wisc.edu{ 1729298Snilay@cs.wisc.edu if (if_name == "interface") { 1739298Snilay@cs.wisc.edu if (interface->getPeer()) 1749298Snilay@cs.wisc.edu panic("interface already connected to\n"); 1759298Snilay@cs.wisc.edu return interface; 1769298Snilay@cs.wisc.edu } 1779298Snilay@cs.wisc.edu return NULL; 1789298Snilay@cs.wisc.edu} 1799298Snilay@cs.wisc.edu 1809298Snilay@cs.wisc.edu/** 1819298Snilay@cs.wisc.edu * This reads the device registers, which are detailed in the NS83820 1829298Snilay@cs.wisc.edu * spec sheet 1836657Snate@binkert.org */ 1846657Snate@binkert.orgTick 1856657Snate@binkert.orgNSGigE::read(PacketPtr pkt) 1866657Snate@binkert.org{ 1876657Snate@binkert.org assert(ioEnable); 1886657Snate@binkert.org 1896657Snate@binkert.org pkt->allocate(); 1906657Snate@binkert.org 1916657Snate@binkert.org //The mask is to give you only the offset into the device register file 1926657Snate@binkert.org Addr daddr = pkt->getAddr() & 0xfff; 1936657Snate@binkert.org DPRINTF(EthernetPIO, "read da=%#x pa=%#x size=%d\n", 1949219Spower.jg@gmail.com daddr, pkt->getAddr(), pkt->getSize()); 1956657Snate@binkert.org 1966657Snate@binkert.org 1976657Snate@binkert.org // there are some reserved registers, you can see ns_gige_reg.h and 1986657Snate@binkert.org // the spec sheet for details 1996657Snate@binkert.org if (daddr > LAST && daddr <= RESERVED) { 2006657Snate@binkert.org panic("Accessing reserved register"); 2016657Snate@binkert.org } else if (daddr > RESERVED && daddr <= 0x3FC) { 2026657Snate@binkert.org return readConfig(pkt); 2036657Snate@binkert.org } else if (daddr >= MIB_START && daddr <= MIB_END) { 2046657Snate@binkert.org // don't implement all the MIB's. hopefully the kernel 2056657Snate@binkert.org // doesn't actually DEPEND upon their values 2066657Snate@binkert.org // MIB are just hardware stats keepers 2076999Snate@binkert.org pkt->set<uint32_t>(0); 2086657Snate@binkert.org pkt->makeAtomicResponse(); 2096657Snate@binkert.org return pioDelay; 2106657Snate@binkert.org } else if (daddr > 0x3FC) 2116657Snate@binkert.org panic("Something is messed up!\n"); 2126657Snate@binkert.org 2136657Snate@binkert.org assert(pkt->getSize() == sizeof(uint32_t)); 2146657Snate@binkert.org uint32_t ® = *pkt->getPtr<uint32_t>(); 2157007Snate@binkert.org uint16_t rfaddr; 2167007Snate@binkert.org 2176657Snate@binkert.org switch (daddr) { 2187002Snate@binkert.org case CR: 2197002Snate@binkert.org reg = regs.command; 2209466Snilay@cs.wisc.edu //these are supposed to be cleared on a read 2216657Snate@binkert.org reg &= ~(CR_RXD | CR_TXD | CR_TXR | CR_RXR); 2226657Snate@binkert.org break; 2236657Snate@binkert.org 2246657Snate@binkert.org case CFGR: 2256657Snate@binkert.org reg = regs.config; 2266657Snate@binkert.org break; 2276657Snate@binkert.org 2286657Snate@binkert.org case MEAR: 2296657Snate@binkert.org reg = regs.mear; 2306657Snate@binkert.org break; 2316657Snate@binkert.org 2326657Snate@binkert.org case PTSCR: 2337007Snate@binkert.org reg = regs.ptscr; 2347007Snate@binkert.org break; 2356657Snate@binkert.org 2369466Snilay@cs.wisc.edu case ISR: 2376657Snate@binkert.org reg = regs.isr; 2386657Snate@binkert.org devIntrClear(ISR_ALL); 2399466Snilay@cs.wisc.edu break; 2409508Snilay@cs.wisc.edu 2419466Snilay@cs.wisc.edu case IMR: 2429466Snilay@cs.wisc.edu reg = regs.imr; 2439466Snilay@cs.wisc.edu break; 2446657Snate@binkert.org 2456657Snate@binkert.org case IER: 2466657Snate@binkert.org reg = regs.ier; 2476657Snate@binkert.org break; 2486657Snate@binkert.org 2496657Snate@binkert.org case IHR: 2506657Snate@binkert.org reg = regs.ihr; 2516657Snate@binkert.org break; 2526657Snate@binkert.org 2536657Snate@binkert.org case TXDP: 2546657Snate@binkert.org reg = regs.txdp; 2556657Snate@binkert.org break; 2566657Snate@binkert.org 2576657Snate@binkert.org case TXDP_HI: 2586657Snate@binkert.org reg = regs.txdp_hi; 2596657Snate@binkert.org break; 2606657Snate@binkert.org 2617453Snate@binkert.org case TX_CFG: 2627453Snate@binkert.org reg = regs.txcfg; 2637453Snate@binkert.org break; 2647453Snate@binkert.org 2657453Snate@binkert.org case GPIOR: 2667453Snate@binkert.org reg = regs.gpior; 2677453Snate@binkert.org break; 2687453Snate@binkert.org 2697453Snate@binkert.org case RXDP: 2707453Snate@binkert.org reg = regs.rxdp; 2717453Snate@binkert.org break; 2727453Snate@binkert.org 2737453Snate@binkert.org case RXDP_HI: 2747453Snate@binkert.org reg = regs.rxdp_hi; 2757453Snate@binkert.org break; 2767453Snate@binkert.org 2777453Snate@binkert.org case RX_CFG: 2786657Snate@binkert.org reg = regs.rxcfg; 2796657Snate@binkert.org break; 2806657Snate@binkert.org 2816657Snate@binkert.org case PQCR: 2829466Snilay@cs.wisc.edu reg = regs.pqcr; 2836657Snate@binkert.org break; 2849466Snilay@cs.wisc.edu 2859508Snilay@cs.wisc.edu case WCSR: 2869466Snilay@cs.wisc.edu reg = regs.wcsr; 2876657Snate@binkert.org break; 2886657Snate@binkert.org 2896657Snate@binkert.org case PCR: 2906657Snate@binkert.org reg = regs.pcr; 2919466Snilay@cs.wisc.edu break; 2929466Snilay@cs.wisc.edu 2939466Snilay@cs.wisc.edu // see the spec sheet for how RFCR and RFDR work 2949466Snilay@cs.wisc.edu // basically, you write to RFCR to tell the machine 2956657Snate@binkert.org // what you want to do next, then you act upon RFDR, 2966657Snate@binkert.org // and the device will be prepared b/c of what you 2976657Snate@binkert.org // wrote to RFCR 2986657Snate@binkert.org case RFCR: 2996657Snate@binkert.org reg = regs.rfcr; 3006657Snate@binkert.org break; 3016657Snate@binkert.org 3026657Snate@binkert.org case RFDR: 3036657Snate@binkert.org rfaddr = (uint16_t)(regs.rfcr & RFCR_RFADDR); 3046657Snate@binkert.org switch (rfaddr) { 3056657Snate@binkert.org // Read from perfect match ROM octets 3069466Snilay@cs.wisc.edu case 0x000: 3077453Snate@binkert.org reg = rom.perfectMatch[1]; 3087453Snate@binkert.org reg = reg << 8; 3097007Snate@binkert.org reg += rom.perfectMatch[0]; 3107007Snate@binkert.org break; 3117453Snate@binkert.org case 0x002: 3127007Snate@binkert.org reg = rom.perfectMatch[3] << 8; 3136657Snate@binkert.org reg += rom.perfectMatch[2]; 3146657Snate@binkert.org break; 3156657Snate@binkert.org case 0x004: 3166657Snate@binkert.org reg = rom.perfectMatch[5] << 8; 3176657Snate@binkert.org reg += rom.perfectMatch[4]; 3186657Snate@binkert.org break; 3196657Snate@binkert.org default: 3206657Snate@binkert.org // Read filter hash table 3216657Snate@binkert.org if (rfaddr >= FHASH_ADDR && 3226657Snate@binkert.org rfaddr < FHASH_ADDR + FHASH_SIZE) { 3237007Snate@binkert.org 3247007Snate@binkert.org // Only word-aligned reads supported 3257007Snate@binkert.org if (rfaddr % 2) 3267007Snate@binkert.org panic("unaligned read from filter hash table!"); 3277007Snate@binkert.org 3286657Snate@binkert.org reg = rom.filterHash[rfaddr - FHASH_ADDR + 1] << 8; 3296657Snate@binkert.org reg += rom.filterHash[rfaddr - FHASH_ADDR]; 3306657Snate@binkert.org break; 3316657Snate@binkert.org } 3326657Snate@binkert.org 3336657Snate@binkert.org panic("reading RFDR for something other than pattern" 3346657Snate@binkert.org " matching or hashing! %#x\n", rfaddr); 3356657Snate@binkert.org } 3366657Snate@binkert.org break; 3377007Snate@binkert.org 3387007Snate@binkert.org case SRR: 3397007Snate@binkert.org reg = regs.srr; 3407007Snate@binkert.org break; 3417007Snate@binkert.org 3426657Snate@binkert.org case MIBC: 3436657Snate@binkert.org reg = regs.mibc; 3446657Snate@binkert.org reg &= ~(MIBC_MIBS | MIBC_ACLR); 3456657Snate@binkert.org break; 3466657Snate@binkert.org 3476657Snate@binkert.org case VRCR: 3486657Snate@binkert.org reg = regs.vrcr; 3497007Snate@binkert.org break; 3507007Snate@binkert.org 3517007Snate@binkert.org case VTCR: 3527007Snate@binkert.org reg = regs.vtcr; 3537007Snate@binkert.org break; 3546657Snate@binkert.org 3556657Snate@binkert.org case VDR: 3567002Snate@binkert.org reg = regs.vdr; 3576657Snate@binkert.org break; 3586657Snate@binkert.org 3596657Snate@binkert.org case CCSR: 3606657Snate@binkert.org reg = regs.ccsr; 3616657Snate@binkert.org break; 3626657Snate@binkert.org 3636657Snate@binkert.org case TBICR: 3646657Snate@binkert.org reg = regs.tbicr; 3656657Snate@binkert.org break; 3666657Snate@binkert.org 3676657Snate@binkert.org case TBISR: 3686657Snate@binkert.org reg = regs.tbisr; 3696657Snate@binkert.org break; 3706657Snate@binkert.org 3716657Snate@binkert.org case TANAR: 3726657Snate@binkert.org reg = regs.tanar; 3736657Snate@binkert.org break; 3746657Snate@binkert.org 3756657Snate@binkert.org case TANLPAR: 3766657Snate@binkert.org reg = regs.tanlpar; 3776657Snate@binkert.org break; 3787007Snate@binkert.org 3796657Snate@binkert.org case TANER: 3807007Snate@binkert.org reg = regs.taner; 3816657Snate@binkert.org break; 3829298Snilay@cs.wisc.edu 3839298Snilay@cs.wisc.edu case TESR: 3849298Snilay@cs.wisc.edu reg = regs.tesr; 3859298Snilay@cs.wisc.edu break; 3869298Snilay@cs.wisc.edu 3879298Snilay@cs.wisc.edu case M5REG: 3886657Snate@binkert.org reg = 0; 3896657Snate@binkert.org if (params()->rx_thread) 3906657Snate@binkert.org reg |= M5REG_RX_THREAD; 3916657Snate@binkert.org if (params()->tx_thread) 3927055Snate@binkert.org reg |= M5REG_TX_THREAD; 3937007Snate@binkert.org if (params()->rss) 3946657Snate@binkert.org reg |= M5REG_RSS; 3956657Snate@binkert.org break; 3967002Snate@binkert.org 3976657Snate@binkert.org default: 3986657Snate@binkert.org panic("reading unimplemented register: addr=%#x", daddr); 3996657Snate@binkert.org } 4007007Snate@binkert.org 4016657Snate@binkert.org DPRINTF(EthernetPIO, "read from %#x: data=%d data=%#x\n", 4026657Snate@binkert.org daddr, reg, reg); 4036657Snate@binkert.org 4046657Snate@binkert.org pkt->makeAtomicResponse(); 4056657Snate@binkert.org return pioDelay; 4066999Snate@binkert.org} 4076657Snate@binkert.org 4086657Snate@binkert.orgTick 4096657Snate@binkert.orgNSGigE::write(PacketPtr pkt) 4106657Snate@binkert.org{ 4116657Snate@binkert.org assert(ioEnable); 4126657Snate@binkert.org 4136657Snate@binkert.org Addr daddr = pkt->getAddr() & 0xfff; 4147002Snate@binkert.org DPRINTF(EthernetPIO, "write da=%#x pa=%#x size=%d\n", 4157002Snate@binkert.org daddr, pkt->getAddr(), pkt->getSize()); 4166657Snate@binkert.org 4179499Snilay@cs.wisc.edu if (daddr > LAST && daddr <= RESERVED) { 4189499Snilay@cs.wisc.edu panic("Accessing reserved register"); 4197002Snate@binkert.org } else if (daddr > RESERVED && daddr <= 0x3FC) { 4207002Snate@binkert.org return writeConfig(pkt); 4216657Snate@binkert.org } else if (daddr > 0x3FC) 4226657Snate@binkert.org panic("Something is messed up!\n"); 4236657Snate@binkert.org 4246657Snate@binkert.org if (pkt->getSize() == sizeof(uint32_t)) { 4257007Snate@binkert.org uint32_t reg = pkt->get<uint32_t>(); 4267007Snate@binkert.org uint16_t rfaddr; 4276657Snate@binkert.org 4286657Snate@binkert.org DPRINTF(EthernetPIO, "write data=%d data=%#x\n", reg, reg); 4296657Snate@binkert.org 4306657Snate@binkert.org switch (daddr) { 4316657Snate@binkert.org case CR: 4326657Snate@binkert.org regs.command = reg; 4336657Snate@binkert.org if (reg & CR_TXD) { 4346657Snate@binkert.org txEnable = false; 4356657Snate@binkert.org } else if (reg & CR_TXE) { 4366657Snate@binkert.org txEnable = true; 4379206Snilay@cs.wisc.edu 4386657Snate@binkert.org // the kernel is enabling the transmit machine 4396657Snate@binkert.org if (txState == txIdle) 4406657Snate@binkert.org txKick(); 4416657Snate@binkert.org } 4426657Snate@binkert.org 4436657Snate@binkert.org if (reg & CR_RXD) { 4446657Snate@binkert.org rxEnable = false; 4459298Snilay@cs.wisc.edu } else if (reg & CR_RXE) { 4469298Snilay@cs.wisc.edu rxEnable = true; 4479298Snilay@cs.wisc.edu 4489298Snilay@cs.wisc.edu if (rxState == rxIdle) 4496657Snate@binkert.org rxKick(); 4506657Snate@binkert.org } 4516657Snate@binkert.org 4526999Snate@binkert.org if (reg & CR_TXR) 4536657Snate@binkert.org txReset(); 4546657Snate@binkert.org 4556657Snate@binkert.org if (reg & CR_RXR) 4566657Snate@binkert.org rxReset(); 4576657Snate@binkert.org 4587007Snate@binkert.org if (reg & CR_SWI) 4597007Snate@binkert.org devIntrPost(ISR_SWI); 4607007Snate@binkert.org 4616657Snate@binkert.org if (reg & CR_RST) { 4627002Snate@binkert.org txReset(); 4637002Snate@binkert.org rxReset(); 4647002Snate@binkert.org 4658086SBrad.Beckmann@amd.com regsReset(); 4668086SBrad.Beckmann@amd.com } 4678086SBrad.Beckmann@amd.com break; 4688086SBrad.Beckmann@amd.com 4698602Snilay@cs.wisc.edu case CFGR: 4708602Snilay@cs.wisc.edu if (reg & CFGR_LNKSTS || 4718602Snilay@cs.wisc.edu reg & CFGR_SPDSTS || 4728602Snilay@cs.wisc.edu reg & CFGR_DUPSTS || 4738602Snilay@cs.wisc.edu reg & CFGR_RESERVED || 4748086SBrad.Beckmann@amd.com reg & CFGR_T64ADDR || 4756657Snate@binkert.org reg & CFGR_PCI64_DET) { 4767007Snate@binkert.org // First clear all writable bits 4776657Snate@binkert.org regs.config &= CFGR_LNKSTS | CFGR_SPDSTS | CFGR_DUPSTS | 4786657Snate@binkert.org CFGR_RESERVED | CFGR_T64ADDR | 4796657Snate@binkert.org CFGR_PCI64_DET; 4806657Snate@binkert.org // Now set the appropriate writable bits 4816657Snate@binkert.org regs.config |= reg & ~(CFGR_LNKSTS | CFGR_SPDSTS | CFGR_DUPSTS | 4826657Snate@binkert.org CFGR_RESERVED | CFGR_T64ADDR | 4836657Snate@binkert.org CFGR_PCI64_DET); 4846657Snate@binkert.org } 4856657Snate@binkert.org 4866657Snate@binkert.org// all these #if 0's are because i don't THINK the kernel needs to 4876657Snate@binkert.org// have these implemented. if there is a problem relating to one of 4886862Sdrh5@cs.wisc.edu// these, you may need to add functionality in. 4896862Sdrh5@cs.wisc.edu 4906862Sdrh5@cs.wisc.edu// grouped together and #if 0'ed to avoid empty if body and make clang happy 4916862Sdrh5@cs.wisc.edu#if 0 4926657Snate@binkert.org if (reg & CFGR_TBI_EN) ; 4936657Snate@binkert.org if (reg & CFGR_MODE_1000) ; 4946657Snate@binkert.org 4956657Snate@binkert.org if (reg & CFGR_PINT_DUPSTS || 4966657Snate@binkert.org reg & CFGR_PINT_LNKSTS || 4977007Snate@binkert.org reg & CFGR_PINT_SPDSTS) 4987007Snate@binkert.org ; 4997002Snate@binkert.org 5007007Snate@binkert.org if (reg & CFGR_TMRTEST) ; 5017007Snate@binkert.org if (reg & CFGR_MRM_DIS) ; 5027002Snate@binkert.org if (reg & CFGR_MWI_DIS) ; 5037007Snate@binkert.org 5047007Snate@binkert.org if (reg & CFGR_DATA64_EN) ; 5056657Snate@binkert.org if (reg & CFGR_M64ADDR) ; 5066657Snate@binkert.org if (reg & CFGR_PHY_RST) ; 5076657Snate@binkert.org if (reg & CFGR_PHY_DIS) ; 5086657Snate@binkert.org 5096657Snate@binkert.org if (reg & CFGR_REQALG) ; 5106657Snate@binkert.org if (reg & CFGR_SB) ; 5116657Snate@binkert.org if (reg & CFGR_POW) ; 5126657Snate@binkert.org if (reg & CFGR_EXD) ; 5136657Snate@binkert.org if (reg & CFGR_PESEL) ; 5146657Snate@binkert.org if (reg & CFGR_BROM_DIS) ; 5156657Snate@binkert.org if (reg & CFGR_EXT_125) ; 5166657Snate@binkert.org if (reg & CFGR_BEM) ; 5176657Snate@binkert.org 5188602Snilay@cs.wisc.edu if (reg & CFGR_T64ADDR) ; 5198602Snilay@cs.wisc.edu // panic("CFGR_T64ADDR is read only register!\n"); 5208602Snilay@cs.wisc.edu#endif 5218602Snilay@cs.wisc.edu if (reg & CFGR_AUTO_1000) 5228602Snilay@cs.wisc.edu panic("CFGR_AUTO_1000 not implemented!\n"); 5238602Snilay@cs.wisc.edu 5248602Snilay@cs.wisc.edu if (reg & CFGR_PCI64_DET) 5258602Snilay@cs.wisc.edu panic("CFGR_PCI64_DET is read only register!\n"); 5268602Snilay@cs.wisc.edu 5278086SBrad.Beckmann@amd.com if (reg & CFGR_EXTSTS_EN) 5288086SBrad.Beckmann@amd.com extstsEnable = true; 5298086SBrad.Beckmann@amd.com else 5308086SBrad.Beckmann@amd.com extstsEnable = false; 5318086SBrad.Beckmann@amd.com break; 5328086SBrad.Beckmann@amd.com 5338086SBrad.Beckmann@amd.com case MEAR: 5348086SBrad.Beckmann@amd.com // Clear writable bits 5356657Snate@binkert.org regs.mear &= MEAR_EEDO; 5366657Snate@binkert.org // Set appropriate writable bits 5377002Snate@binkert.org regs.mear |= reg & ~MEAR_EEDO; 5386657Snate@binkert.org 5397007Snate@binkert.org // FreeBSD uses the EEPROM to read PMATCH (for the MAC address) 5406657Snate@binkert.org // even though it could get it through RFDR 5416657Snate@binkert.org if (reg & MEAR_EESEL) { 5426657Snate@binkert.org // Rising edge of clock 5436657Snate@binkert.org if (reg & MEAR_EECLK && !eepromClk) 5446657Snate@binkert.org eepromKick(); 5456999Snate@binkert.org } 5466657Snate@binkert.org else { 5476657Snate@binkert.org eepromState = eepromStart; 5486657Snate@binkert.org regs.mear &= ~MEAR_EEDI; 5496657Snate@binkert.org } 5506657Snate@binkert.org 5516657Snate@binkert.org eepromClk = reg & MEAR_EECLK; 5527832Snate@binkert.org 5537002Snate@binkert.org // since phy is completely faked, MEAR_MD* don't matter 5547002Snate@binkert.org 5557002Snate@binkert.org// grouped together and #if 0'ed to avoid empty if body and make clang happy 5567805Snilay@cs.wisc.edu#if 0 5576657Snate@binkert.org if (reg & MEAR_MDIO) ; 5586657Snate@binkert.org if (reg & MEAR_MDDIR) ; 5597002Snate@binkert.org if (reg & MEAR_MDC) ; 5607002Snate@binkert.org#endif 5616657Snate@binkert.org break; 5626657Snate@binkert.org 5638086SBrad.Beckmann@amd.com case PTSCR: 5648086SBrad.Beckmann@amd.com regs.ptscr = reg & ~(PTSCR_RBIST_RDONLY); 5658086SBrad.Beckmann@amd.com // these control BISTs for various parts of chip - we 5668086SBrad.Beckmann@amd.com // don't care or do just fake that the BIST is done 5678086SBrad.Beckmann@amd.com if (reg & PTSCR_RBIST_EN) 5688086SBrad.Beckmann@amd.com regs.ptscr |= PTSCR_RBIST_DONE; 5698086SBrad.Beckmann@amd.com if (reg & PTSCR_EEBIST_EN) 5708086SBrad.Beckmann@amd.com regs.ptscr &= ~PTSCR_EEBIST_EN; 5718086SBrad.Beckmann@amd.com if (reg & PTSCR_EELOAD_EN) 5728086SBrad.Beckmann@amd.com regs.ptscr &= ~PTSCR_EELOAD_EN; 5738086SBrad.Beckmann@amd.com break; 5748086SBrad.Beckmann@amd.com 5758086SBrad.Beckmann@amd.com case ISR: /* writing to the ISR has no effect */ 5768086SBrad.Beckmann@amd.com panic("ISR is a read only register!\n"); 5778086SBrad.Beckmann@amd.com 5788086SBrad.Beckmann@amd.com case IMR: 5798086SBrad.Beckmann@amd.com regs.imr = reg; 5808086SBrad.Beckmann@amd.com devIntrChangeMask(); 5818086SBrad.Beckmann@amd.com break; 5828086SBrad.Beckmann@amd.com 5838086SBrad.Beckmann@amd.com case IER: 5846657Snate@binkert.org regs.ier = reg; 5856657Snate@binkert.org break; 5869773Snilay@cs.wisc.edu 5879773Snilay@cs.wisc.edu case IHR: 5888602Snilay@cs.wisc.edu regs.ihr = reg; 5896657Snate@binkert.org /* not going to implement real interrupt holdoff */ 5906657Snate@binkert.org break; 5917007Snate@binkert.org 5927007Snate@binkert.org case TXDP: 5937007Snate@binkert.org regs.txdp = (reg & 0xFFFFFFFC); 5946657Snate@binkert.org assert(txState == txIdle); 5956657Snate@binkert.org CTDD = false; 5966657Snate@binkert.org break; 5976657Snate@binkert.org 5986657Snate@binkert.org case TXDP_HI: 5996657Snate@binkert.org regs.txdp_hi = reg; 6007007Snate@binkert.org break; 6017007Snate@binkert.org 6027007Snate@binkert.org case TX_CFG: 6036657Snate@binkert.org regs.txcfg = reg; 6046657Snate@binkert.org#if 0 6056657Snate@binkert.org if (reg & TX_CFG_CSI) ; 6066657Snate@binkert.org if (reg & TX_CFG_HBI) ; 6076657Snate@binkert.org if (reg & TX_CFG_MLB) ; 6086657Snate@binkert.org if (reg & TX_CFG_ATP) ; 6096657Snate@binkert.org if (reg & TX_CFG_ECRETRY) { 6106657Snate@binkert.org /* 6116657Snate@binkert.org * this could easily be implemented, but considering 6126657Snate@binkert.org * the network is just a fake pipe, wouldn't make 6136657Snate@binkert.org * sense to do this 6146657Snate@binkert.org */ 6156657Snate@binkert.org } 6166657Snate@binkert.org 6177805Snilay@cs.wisc.edu if (reg & TX_CFG_BRST_DIS) ; 6186657Snate@binkert.org#endif 6196657Snate@binkert.org 6206657Snate@binkert.org#if 0 6217007Snate@binkert.org /* we handle our own DMA, ignore the kernel's exhortations */ 6227007Snate@binkert.org if (reg & TX_CFG_MXDMA) ; 6237007Snate@binkert.org#endif 6246657Snate@binkert.org 6256657Snate@binkert.org // also, we currently don't care about fill/drain 6266657Snate@binkert.org // thresholds though this may change in the future with 6276657Snate@binkert.org // more realistic networks or a driver which changes it 6287007Snate@binkert.org // according to feedback 6296657Snate@binkert.org 6306657Snate@binkert.org break; 6316657Snate@binkert.org 6326657Snate@binkert.org case GPIOR: 6337007Snate@binkert.org // Only write writable bits 6346657Snate@binkert.org regs.gpior &= GPIOR_UNUSED | GPIOR_GP5_IN | GPIOR_GP4_IN 6356657Snate@binkert.org | GPIOR_GP3_IN | GPIOR_GP2_IN | GPIOR_GP1_IN; 6366657Snate@binkert.org regs.gpior |= reg & ~(GPIOR_UNUSED | GPIOR_GP5_IN | GPIOR_GP4_IN 6376657Snate@binkert.org | GPIOR_GP3_IN | GPIOR_GP2_IN | GPIOR_GP1_IN); 6387805Snilay@cs.wisc.edu /* these just control general purpose i/o pins, don't matter */ 6396657Snate@binkert.org break; 6406657Snate@binkert.org 6416657Snate@binkert.org case RXDP: 6427007Snate@binkert.org regs.rxdp = reg; 6437007Snate@binkert.org CRDD = false; 6447007Snate@binkert.org break; 6457007Snate@binkert.org 6466657Snate@binkert.org case RXDP_HI: 6476657Snate@binkert.org regs.rxdp_hi = reg; 6486657Snate@binkert.org break; 6496657Snate@binkert.org 6506657Snate@binkert.org case RX_CFG: 6516657Snate@binkert.org regs.rxcfg = reg; 6526657Snate@binkert.org#if 0 6536657Snate@binkert.org if (reg & RX_CFG_AEP) ; 6546657Snate@binkert.org if (reg & RX_CFG_ARP) ; 6557007Snate@binkert.org if (reg & RX_CFG_STRIPCRC) ; 6567007Snate@binkert.org if (reg & RX_CFG_RX_RD) ; 6576657Snate@binkert.org if (reg & RX_CFG_ALP) ; 6586657Snate@binkert.org if (reg & RX_CFG_AIRL) ; 6596657Snate@binkert.org 6606657Snate@binkert.org /* we handle our own DMA, ignore what kernel says about it */ 6617007Snate@binkert.org if (reg & RX_CFG_MXDMA) ; 6627007Snate@binkert.org 6636657Snate@binkert.org //also, we currently don't care about fill/drain thresholds 6646657Snate@binkert.org //though this may change in the future with more realistic 6656657Snate@binkert.org //networks or a driver which changes it according to feedback 6666657Snate@binkert.org if (reg & (RX_CFG_DRTH | RX_CFG_DRTH0)) ; 6676657Snate@binkert.org#endif 6686657Snate@binkert.org break; 6696657Snate@binkert.org 6706657Snate@binkert.org case PQCR: 6716657Snate@binkert.org /* there is no priority queueing used in the linux 2.6 driver */ 6726657Snate@binkert.org regs.pqcr = reg; 6736657Snate@binkert.org break; 6746657Snate@binkert.org 6756657Snate@binkert.org case WCSR: 6766657Snate@binkert.org /* not going to implement wake on LAN */ 6776657Snate@binkert.org regs.wcsr = reg; 6786657Snate@binkert.org break; 6796657Snate@binkert.org 6807805Snilay@cs.wisc.edu case PCR: 6816657Snate@binkert.org /* not going to implement pause control */ 6826657Snate@binkert.org regs.pcr = reg; 6836657Snate@binkert.org break; 6846657Snate@binkert.org 6856657Snate@binkert.org case RFCR: 6867007Snate@binkert.org regs.rfcr = reg; 6876657Snate@binkert.org 6887007Snate@binkert.org rxFilterEnable = (reg & RFCR_RFEN) ? true : false; 6897007Snate@binkert.org acceptBroadcast = (reg & RFCR_AAB) ? true : false; 6906657Snate@binkert.org acceptMulticast = (reg & RFCR_AAM) ? true : false; 6916657Snate@binkert.org acceptUnicast = (reg & RFCR_AAU) ? true : false; 6926657Snate@binkert.org acceptPerfect = (reg & RFCR_APM) ? true : false; 6936657Snate@binkert.org acceptArp = (reg & RFCR_AARP) ? true : false; 6946657Snate@binkert.org multicastHashEnable = (reg & RFCR_MHEN) ? true : false; 6956657Snate@binkert.org 6966657Snate@binkert.org#if 0 6976657Snate@binkert.org if (reg & RFCR_APAT) 6986657Snate@binkert.org panic("RFCR_APAT not implemented!\n"); 6996657Snate@binkert.org#endif 7006657Snate@binkert.org if (reg & RFCR_UHEN) 7016657Snate@binkert.org panic("Unicast hash filtering not used by drivers!\n"); 7026657Snate@binkert.org 7036657Snate@binkert.org if (reg & RFCR_ULM) 7047805Snilay@cs.wisc.edu panic("RFCR_ULM not implemented!\n"); 7056657Snate@binkert.org 7066657Snate@binkert.org break; 7076657Snate@binkert.org 7086657Snate@binkert.org case RFDR: 7096657Snate@binkert.org rfaddr = (uint16_t)(regs.rfcr & RFCR_RFADDR); 7106657Snate@binkert.org switch (rfaddr) { 7116657Snate@binkert.org case 0x000: 7126657Snate@binkert.org rom.perfectMatch[0] = (uint8_t)reg; 7137007Snate@binkert.org rom.perfectMatch[1] = (uint8_t)(reg >> 8); 7147007Snate@binkert.org break; 7156657Snate@binkert.org case 0x002: 7166657Snate@binkert.org rom.perfectMatch[2] = (uint8_t)reg; 7176657Snate@binkert.org rom.perfectMatch[3] = (uint8_t)(reg >> 8); 7186657Snate@binkert.org break; 7196657Snate@binkert.org case 0x004: 7206657Snate@binkert.org rom.perfectMatch[4] = (uint8_t)reg; 7216657Snate@binkert.org rom.perfectMatch[5] = (uint8_t)(reg >> 8); 7226657Snate@binkert.org break; 7236657Snate@binkert.org default: 7249773Snilay@cs.wisc.edu 7259773Snilay@cs.wisc.edu if (rfaddr >= FHASH_ADDR && 7269773Snilay@cs.wisc.edu rfaddr < FHASH_ADDR + FHASH_SIZE) { 7279773Snilay@cs.wisc.edu 7289773Snilay@cs.wisc.edu // Only word-aligned writes supported 7296657Snate@binkert.org if (rfaddr % 2) 7306657Snate@binkert.org panic("unaligned write to filter hash table!"); 7316657Snate@binkert.org 7326657Snate@binkert.org rom.filterHash[rfaddr - FHASH_ADDR] = (uint8_t)reg; 7336657Snate@binkert.org rom.filterHash[rfaddr - FHASH_ADDR + 1] 7346657Snate@binkert.org = (uint8_t)(reg >> 8); 7357805Snilay@cs.wisc.edu break; 7366657Snate@binkert.org } 7376657Snate@binkert.org panic("writing RFDR for something other than pattern matching\ 7386657Snate@binkert.org or hashing! %#x\n", rfaddr); 7396657Snate@binkert.org } 7406657Snate@binkert.org 7416657Snate@binkert.org case BRAR: 7426657Snate@binkert.org regs.brar = reg; 7436657Snate@binkert.org break; 7447007Snate@binkert.org 7457007Snate@binkert.org case BRDR: 7466657Snate@binkert.org panic("the driver never uses BRDR, something is wrong!\n"); 7476657Snate@binkert.org 7486657Snate@binkert.org case SRR: 7496657Snate@binkert.org panic("SRR is read only register!\n"); 7506657Snate@binkert.org 7516657Snate@binkert.org case MIBC: 7529773Snilay@cs.wisc.edu panic("the driver never uses MIBC, something is wrong!\n"); 7539773Snilay@cs.wisc.edu 7549773Snilay@cs.wisc.edu case VRCR: 7559773Snilay@cs.wisc.edu regs.vrcr = reg; 7569773Snilay@cs.wisc.edu break; 7576657Snate@binkert.org 7586657Snate@binkert.org case VTCR: 7596657Snate@binkert.org regs.vtcr = reg; 7606657Snate@binkert.org break; 7616657Snate@binkert.org 7627805Snilay@cs.wisc.edu case VDR: 7636657Snate@binkert.org panic("the driver never uses VDR, something is wrong!\n"); 7646657Snate@binkert.org 7656657Snate@binkert.org case CCSR: 7666657Snate@binkert.org /* not going to implement clockrun stuff */ 7678602Snilay@cs.wisc.edu regs.ccsr = reg; 7688602Snilay@cs.wisc.edu break; 7698602Snilay@cs.wisc.edu 7708602Snilay@cs.wisc.edu case TBICR: 7718602Snilay@cs.wisc.edu regs.tbicr = reg; 7728602Snilay@cs.wisc.edu if (reg & TBICR_MR_LOOPBACK) 7738602Snilay@cs.wisc.edu panic("TBICR_MR_LOOPBACK never used, something wrong!\n"); 7748602Snilay@cs.wisc.edu 7758602Snilay@cs.wisc.edu if (reg & TBICR_MR_AN_ENABLE) { 7768602Snilay@cs.wisc.edu regs.tanlpar = regs.tanar; 7778602Snilay@cs.wisc.edu regs.tbisr |= (TBISR_MR_AN_COMPLETE | TBISR_MR_LINK_STATUS); 7788602Snilay@cs.wisc.edu } 7798602Snilay@cs.wisc.edu 7808602Snilay@cs.wisc.edu#if 0 7818602Snilay@cs.wisc.edu if (reg & TBICR_MR_RESTART_AN) ; 7828602Snilay@cs.wisc.edu#endif 7838602Snilay@cs.wisc.edu 7848602Snilay@cs.wisc.edu break; 7858602Snilay@cs.wisc.edu 7868602Snilay@cs.wisc.edu case TBISR: 7878602Snilay@cs.wisc.edu panic("TBISR is read only register!\n"); 7886657Snate@binkert.org 7896657Snate@binkert.org case TANAR: 7906657Snate@binkert.org // Only write the writable bits 7916657Snate@binkert.org regs.tanar &= TANAR_RF1 | TANAR_RF2 | TANAR_UNUSED; 792 regs.tanar |= reg & ~(TANAR_RF1 | TANAR_RF2 | TANAR_UNUSED); 793 794 // Pause capability unimplemented 795#if 0 796 if (reg & TANAR_PS2) ; 797 if (reg & TANAR_PS1) ; 798#endif 799 800 break; 801 802 case TANLPAR: 803 panic("this should only be written to by the fake phy!\n"); 804 805 case TANER: 806 panic("TANER is read only register!\n"); 807 808 case TESR: 809 regs.tesr = reg; 810 break; 811 812 default: 813 panic("invalid register access daddr=%#x", daddr); 814 } 815 } else { 816 panic("Invalid Request Size"); 817 } 818 pkt->makeAtomicResponse(); 819 return pioDelay; 820} 821 822void 823NSGigE::devIntrPost(uint32_t interrupts) 824{ 825 if (interrupts & ISR_RESERVE) 826 panic("Cannot set a reserved interrupt"); 827 828 if (interrupts & ISR_NOIMPL) 829 warn("interrupt not implemented %#x\n", interrupts); 830 831 interrupts &= ISR_IMPL; 832 regs.isr |= interrupts; 833 834 if (interrupts & regs.imr) { 835 if (interrupts & ISR_SWI) { 836 totalSwi++; 837 } 838 if (interrupts & ISR_RXIDLE) { 839 totalRxIdle++; 840 } 841 if (interrupts & ISR_RXOK) { 842 totalRxOk++; 843 } 844 if (interrupts & ISR_RXDESC) { 845 totalRxDesc++; 846 } 847 if (interrupts & ISR_TXOK) { 848 totalTxOk++; 849 } 850 if (interrupts & ISR_TXIDLE) { 851 totalTxIdle++; 852 } 853 if (interrupts & ISR_TXDESC) { 854 totalTxDesc++; 855 } 856 if (interrupts & ISR_RXORN) { 857 totalRxOrn++; 858 } 859 } 860 861 DPRINTF(EthernetIntr, 862 "interrupt written to ISR: intr=%#x isr=%#x imr=%#x\n", 863 interrupts, regs.isr, regs.imr); 864 865 if ((regs.isr & regs.imr)) { 866 Tick when = curTick(); 867 if ((regs.isr & regs.imr & ISR_NODELAY) == 0) 868 when += intrDelay; 869 postedInterrupts++; 870 cpuIntrPost(when); 871 } 872} 873 874/* writing this interrupt counting stats inside this means that this function 875 is now limited to being used to clear all interrupts upon the kernel 876 reading isr and servicing. just telling you in case you were thinking 877 of expanding use. 878*/ 879void 880NSGigE::devIntrClear(uint32_t interrupts) 881{ 882 if (interrupts & ISR_RESERVE) 883 panic("Cannot clear a reserved interrupt"); 884 885 if (regs.isr & regs.imr & ISR_SWI) { 886 postedSwi++; 887 } 888 if (regs.isr & regs.imr & ISR_RXIDLE) { 889 postedRxIdle++; 890 } 891 if (regs.isr & regs.imr & ISR_RXOK) { 892 postedRxOk++; 893 } 894 if (regs.isr & regs.imr & ISR_RXDESC) { 895 postedRxDesc++; 896 } 897 if (regs.isr & regs.imr & ISR_TXOK) { 898 postedTxOk++; 899 } 900 if (regs.isr & regs.imr & ISR_TXIDLE) { 901 postedTxIdle++; 902 } 903 if (regs.isr & regs.imr & ISR_TXDESC) { 904 postedTxDesc++; 905 } 906 if (regs.isr & regs.imr & ISR_RXORN) { 907 postedRxOrn++; 908 } 909 910 interrupts &= ~ISR_NOIMPL; 911 regs.isr &= ~interrupts; 912 913 DPRINTF(EthernetIntr, 914 "interrupt cleared from ISR: intr=%x isr=%x imr=%x\n", 915 interrupts, regs.isr, regs.imr); 916 917 if (!(regs.isr & regs.imr)) 918 cpuIntrClear(); 919} 920 921void 922NSGigE::devIntrChangeMask() 923{ 924 DPRINTF(EthernetIntr, "interrupt mask changed: isr=%x imr=%x masked=%x\n", 925 regs.isr, regs.imr, regs.isr & regs.imr); 926 927 if (regs.isr & regs.imr) 928 cpuIntrPost(curTick()); 929 else 930 cpuIntrClear(); 931} 932 933void 934NSGigE::cpuIntrPost(Tick when) 935{ 936 // If the interrupt you want to post is later than an interrupt 937 // already scheduled, just let it post in the coming one and don't 938 // schedule another. 939 // HOWEVER, must be sure that the scheduled intrTick is in the 940 // future (this was formerly the source of a bug) 941 /** 942 * @todo this warning should be removed and the intrTick code should 943 * be fixed. 944 */ 945 assert(when >= curTick()); 946 assert(intrTick >= curTick() || intrTick == 0); 947 if (when > intrTick && intrTick != 0) { 948 DPRINTF(EthernetIntr, "don't need to schedule event...intrTick=%d\n", 949 intrTick); 950 return; 951 } 952 953 intrTick = when; 954 if (intrTick < curTick()) { 955 Debug::breakpoint(); 956 intrTick = curTick(); 957 } 958 959 DPRINTF(EthernetIntr, "going to schedule an interrupt for intrTick=%d\n", 960 intrTick); 961 962 if (intrEvent) 963 intrEvent->squash(); 964 intrEvent = new IntrEvent(this, true); 965 schedule(intrEvent, intrTick); 966} 967 968void 969NSGigE::cpuInterrupt() 970{ 971 assert(intrTick == curTick()); 972 973 // Whether or not there's a pending interrupt, we don't care about 974 // it anymore 975 intrEvent = 0; 976 intrTick = 0; 977 978 // Don't send an interrupt if there's already one 979 if (cpuPendingIntr) { 980 DPRINTF(EthernetIntr, 981 "would send an interrupt now, but there's already pending\n"); 982 } else { 983 // Send interrupt 984 cpuPendingIntr = true; 985 986 DPRINTF(EthernetIntr, "posting interrupt\n"); 987 intrPost(); 988 } 989} 990 991void 992NSGigE::cpuIntrClear() 993{ 994 if (!cpuPendingIntr) 995 return; 996 997 if (intrEvent) { 998 intrEvent->squash(); 999 intrEvent = 0; 1000 } 1001 1002 intrTick = 0; 1003 1004 cpuPendingIntr = false; 1005 1006 DPRINTF(EthernetIntr, "clearing interrupt\n"); 1007 intrClear(); 1008} 1009 1010bool 1011NSGigE::cpuIntrPending() const 1012{ return cpuPendingIntr; } 1013 1014void 1015NSGigE::txReset() 1016{ 1017 1018 DPRINTF(Ethernet, "transmit reset\n"); 1019 1020 CTDD = false; 1021 txEnable = false;; 1022 txFragPtr = 0; 1023 assert(txDescCnt == 0); 1024 txFifo.clear(); 1025 txState = txIdle; 1026 assert(txDmaState == dmaIdle); 1027} 1028 1029void 1030NSGigE::rxReset() 1031{ 1032 DPRINTF(Ethernet, "receive reset\n"); 1033 1034 CRDD = false; 1035 assert(rxPktBytes == 0); 1036 rxEnable = false; 1037 rxFragPtr = 0; 1038 assert(rxDescCnt == 0); 1039 assert(rxDmaState == dmaIdle); 1040 rxFifo.clear(); 1041 rxState = rxIdle; 1042} 1043 1044void 1045NSGigE::regsReset() 1046{ 1047 memset(®s, 0, sizeof(regs)); 1048 regs.config = (CFGR_LNKSTS | CFGR_TBI_EN | CFGR_MODE_1000); 1049 regs.mear = 0x12; 1050 regs.txcfg = 0x120; // set drain threshold to 1024 bytes and 1051 // fill threshold to 32 bytes 1052 regs.rxcfg = 0x4; // set drain threshold to 16 bytes 1053 regs.srr = 0x0103; // set the silicon revision to rev B or 0x103 1054 regs.mibc = MIBC_FRZ; 1055 regs.vdr = 0x81; // set the vlan tag type to 802.1q 1056 regs.tesr = 0xc000; // TBI capable of both full and half duplex 1057 regs.brar = 0xffffffff; 1058 1059 extstsEnable = false; 1060 acceptBroadcast = false; 1061 acceptMulticast = false; 1062 acceptUnicast = false; 1063 acceptPerfect = false; 1064 acceptArp = false; 1065} 1066 1067bool 1068NSGigE::doRxDmaRead() 1069{ 1070 assert(rxDmaState == dmaIdle || rxDmaState == dmaReadWaiting); 1071 rxDmaState = dmaReading; 1072 1073 if (dmaPending() || getState() != Running) 1074 rxDmaState = dmaReadWaiting; 1075 else 1076 dmaRead(rxDmaAddr, rxDmaLen, &rxDmaReadEvent, (uint8_t*)rxDmaData); 1077 1078 return true; 1079} 1080 1081void 1082NSGigE::rxDmaReadDone() 1083{ 1084 assert(rxDmaState == dmaReading); 1085 rxDmaState = dmaIdle; 1086 1087 DPRINTF(EthernetDMA, "rx dma read paddr=%#x len=%d\n", 1088 rxDmaAddr, rxDmaLen); 1089 DDUMP(EthernetDMA, rxDmaData, rxDmaLen); 1090 1091 // If the transmit state machine has a pending DMA, let it go first 1092 if (txDmaState == dmaReadWaiting || txDmaState == dmaWriteWaiting) 1093 txKick(); 1094 1095 rxKick(); 1096} 1097 1098bool 1099NSGigE::doRxDmaWrite() 1100{ 1101 assert(rxDmaState == dmaIdle || rxDmaState == dmaWriteWaiting); 1102 rxDmaState = dmaWriting; 1103 1104 if (dmaPending() || getState() != Running) 1105 rxDmaState = dmaWriteWaiting; 1106 else 1107 dmaWrite(rxDmaAddr, rxDmaLen, &rxDmaWriteEvent, (uint8_t*)rxDmaData); 1108 return true; 1109} 1110 1111void 1112NSGigE::rxDmaWriteDone() 1113{ 1114 assert(rxDmaState == dmaWriting); 1115 rxDmaState = dmaIdle; 1116 1117 DPRINTF(EthernetDMA, "rx dma write paddr=%#x len=%d\n", 1118 rxDmaAddr, rxDmaLen); 1119 DDUMP(EthernetDMA, rxDmaData, rxDmaLen); 1120 1121 // If the transmit state machine has a pending DMA, let it go first 1122 if (txDmaState == dmaReadWaiting || txDmaState == dmaWriteWaiting) 1123 txKick(); 1124 1125 rxKick(); 1126} 1127 1128void 1129NSGigE::rxKick() 1130{ 1131 bool is64bit = (bool)(regs.config & CFGR_M64ADDR); 1132 1133 DPRINTF(EthernetSM, 1134 "receive kick rxState=%s (rxBuf.size=%d) %d-bit\n", 1135 NsRxStateStrings[rxState], rxFifo.size(), is64bit ? 64 : 32); 1136 1137 Addr link, bufptr; 1138 uint32_t &cmdsts = is64bit ? rxDesc64.cmdsts : rxDesc32.cmdsts; 1139 uint32_t &extsts = is64bit ? rxDesc64.extsts : rxDesc32.extsts; 1140 1141 next: 1142 if (clock) { 1143 if (rxKickTick > curTick()) { 1144 DPRINTF(EthernetSM, "receive kick exiting, can't run till %d\n", 1145 rxKickTick); 1146 1147 goto exit; 1148 } 1149 1150 // Go to the next state machine clock tick. 1151 rxKickTick = curTick() + ticks(1); 1152 } 1153 1154 switch(rxDmaState) { 1155 case dmaReadWaiting: 1156 if (doRxDmaRead()) 1157 goto exit; 1158 break; 1159 case dmaWriteWaiting: 1160 if (doRxDmaWrite()) 1161 goto exit; 1162 break; 1163 default: 1164 break; 1165 } 1166 1167 link = is64bit ? (Addr)rxDesc64.link : (Addr)rxDesc32.link; 1168 bufptr = is64bit ? (Addr)rxDesc64.bufptr : (Addr)rxDesc32.bufptr; 1169 1170 // see state machine from spec for details 1171 // the way this works is, if you finish work on one state and can 1172 // go directly to another, you do that through jumping to the 1173 // label "next". however, if you have intermediate work, like DMA 1174 // so that you can't go to the next state yet, you go to exit and 1175 // exit the loop. however, when the DMA is done it will trigger 1176 // an event and come back to this loop. 1177 switch (rxState) { 1178 case rxIdle: 1179 if (!rxEnable) { 1180 DPRINTF(EthernetSM, "Receive Disabled! Nothing to do.\n"); 1181 goto exit; 1182 } 1183 1184 if (CRDD) { 1185 rxState = rxDescRefr; 1186 1187 rxDmaAddr = regs.rxdp & 0x3fffffff; 1188 rxDmaData = 1189 is64bit ? (void *)&rxDesc64.link : (void *)&rxDesc32.link; 1190 rxDmaLen = is64bit ? sizeof(rxDesc64.link) : sizeof(rxDesc32.link); 1191 rxDmaFree = dmaDescFree; 1192 1193 descDmaReads++; 1194 descDmaRdBytes += rxDmaLen; 1195 1196 if (doRxDmaRead()) 1197 goto exit; 1198 } else { 1199 rxState = rxDescRead; 1200 1201 rxDmaAddr = regs.rxdp & 0x3fffffff; 1202 rxDmaData = is64bit ? (void *)&rxDesc64 : (void *)&rxDesc32; 1203 rxDmaLen = is64bit ? sizeof(rxDesc64) : sizeof(rxDesc32); 1204 rxDmaFree = dmaDescFree; 1205 1206 descDmaReads++; 1207 descDmaRdBytes += rxDmaLen; 1208 1209 if (doRxDmaRead()) 1210 goto exit; 1211 } 1212 break; 1213 1214 case rxDescRefr: 1215 if (rxDmaState != dmaIdle) 1216 goto exit; 1217 1218 rxState = rxAdvance; 1219 break; 1220 1221 case rxDescRead: 1222 if (rxDmaState != dmaIdle) 1223 goto exit; 1224 1225 DPRINTF(EthernetDesc, "rxDesc: addr=%08x read descriptor\n", 1226 regs.rxdp & 0x3fffffff); 1227 DPRINTF(EthernetDesc, 1228 "rxDesc: link=%#x bufptr=%#x cmdsts=%08x extsts=%08x\n", 1229 link, bufptr, cmdsts, extsts); 1230 1231 if (cmdsts & CMDSTS_OWN) { 1232 devIntrPost(ISR_RXIDLE); 1233 rxState = rxIdle; 1234 goto exit; 1235 } else { 1236 rxState = rxFifoBlock; 1237 rxFragPtr = bufptr; 1238 rxDescCnt = cmdsts & CMDSTS_LEN_MASK; 1239 } 1240 break; 1241 1242 case rxFifoBlock: 1243 if (!rxPacket) { 1244 /** 1245 * @todo in reality, we should be able to start processing 1246 * the packet as it arrives, and not have to wait for the 1247 * full packet ot be in the receive fifo. 1248 */ 1249 if (rxFifo.empty()) 1250 goto exit; 1251 1252 DPRINTF(EthernetSM, "****processing receive of new packet****\n"); 1253 1254 // If we don't have a packet, grab a new one from the fifo. 1255 rxPacket = rxFifo.front(); 1256 rxPktBytes = rxPacket->length; 1257 rxPacketBufPtr = rxPacket->data; 1258 1259#if TRACING_ON 1260 if (DTRACE(Ethernet)) { 1261 IpPtr ip(rxPacket); 1262 if (ip) { 1263 DPRINTF(Ethernet, "ID is %d\n", ip->id()); 1264 TcpPtr tcp(ip); 1265 if (tcp) { 1266 DPRINTF(Ethernet, 1267 "Src Port=%d, Dest Port=%d, Seq=%d, Ack=%d\n", 1268 tcp->sport(), tcp->dport(), tcp->seq(), 1269 tcp->ack()); 1270 } 1271 } 1272 } 1273#endif 1274 1275 // sanity check - i think the driver behaves like this 1276 assert(rxDescCnt >= rxPktBytes); 1277 rxFifo.pop(); 1278 } 1279 1280 1281 // dont' need the && rxDescCnt > 0 if driver sanity check 1282 // above holds 1283 if (rxPktBytes > 0) { 1284 rxState = rxFragWrite; 1285 // don't need min<>(rxPktBytes,rxDescCnt) if above sanity 1286 // check holds 1287 rxXferLen = rxPktBytes; 1288 1289 rxDmaAddr = rxFragPtr & 0x3fffffff; 1290 rxDmaData = rxPacketBufPtr; 1291 rxDmaLen = rxXferLen; 1292 rxDmaFree = dmaDataFree; 1293 1294 if (doRxDmaWrite()) 1295 goto exit; 1296 1297 } else { 1298 rxState = rxDescWrite; 1299 1300 //if (rxPktBytes == 0) { /* packet is done */ 1301 assert(rxPktBytes == 0); 1302 DPRINTF(EthernetSM, "done with receiving packet\n"); 1303 1304 cmdsts |= CMDSTS_OWN; 1305 cmdsts &= ~CMDSTS_MORE; 1306 cmdsts |= CMDSTS_OK; 1307 cmdsts &= 0xffff0000; 1308 cmdsts += rxPacket->length; //i.e. set CMDSTS_SIZE 1309 1310#if 0 1311 /* 1312 * all the driver uses these are for its own stats keeping 1313 * which we don't care about, aren't necessary for 1314 * functionality and doing this would just slow us down. 1315 * if they end up using this in a later version for 1316 * functional purposes, just undef 1317 */ 1318 if (rxFilterEnable) { 1319 cmdsts &= ~CMDSTS_DEST_MASK; 1320 const EthAddr &dst = rxFifoFront()->dst(); 1321 if (dst->unicast()) 1322 cmdsts |= CMDSTS_DEST_SELF; 1323 if (dst->multicast()) 1324 cmdsts |= CMDSTS_DEST_MULTI; 1325 if (dst->broadcast()) 1326 cmdsts |= CMDSTS_DEST_MASK; 1327 } 1328#endif 1329 1330 IpPtr ip(rxPacket); 1331 if (extstsEnable && ip) { 1332 extsts |= EXTSTS_IPPKT; 1333 rxIpChecksums++; 1334 if (cksum(ip) != 0) { 1335 DPRINTF(EthernetCksum, "Rx IP Checksum Error\n"); 1336 extsts |= EXTSTS_IPERR; 1337 } 1338 TcpPtr tcp(ip); 1339 UdpPtr udp(ip); 1340 if (tcp) { 1341 extsts |= EXTSTS_TCPPKT; 1342 rxTcpChecksums++; 1343 if (cksum(tcp) != 0) { 1344 DPRINTF(EthernetCksum, "Rx TCP Checksum Error\n"); 1345 extsts |= EXTSTS_TCPERR; 1346 1347 } 1348 } else if (udp) { 1349 extsts |= EXTSTS_UDPPKT; 1350 rxUdpChecksums++; 1351 if (cksum(udp) != 0) { 1352 DPRINTF(EthernetCksum, "Rx UDP Checksum Error\n"); 1353 extsts |= EXTSTS_UDPERR; 1354 } 1355 } 1356 } 1357 rxPacket = 0; 1358 1359 /* 1360 * the driver seems to always receive into desc buffers 1361 * of size 1514, so you never have a pkt that is split 1362 * into multiple descriptors on the receive side, so 1363 * i don't implement that case, hence the assert above. 1364 */ 1365 1366 DPRINTF(EthernetDesc, 1367 "rxDesc: addr=%08x writeback cmdsts extsts\n", 1368 regs.rxdp & 0x3fffffff); 1369 DPRINTF(EthernetDesc, 1370 "rxDesc: link=%#x bufptr=%#x cmdsts=%08x extsts=%08x\n", 1371 link, bufptr, cmdsts, extsts); 1372 1373 rxDmaAddr = regs.rxdp & 0x3fffffff; 1374 rxDmaData = &cmdsts; 1375 if (is64bit) { 1376 rxDmaAddr += offsetof(ns_desc64, cmdsts); 1377 rxDmaLen = sizeof(rxDesc64.cmdsts) + sizeof(rxDesc64.extsts); 1378 } else { 1379 rxDmaAddr += offsetof(ns_desc32, cmdsts); 1380 rxDmaLen = sizeof(rxDesc32.cmdsts) + sizeof(rxDesc32.extsts); 1381 } 1382 rxDmaFree = dmaDescFree; 1383 1384 descDmaWrites++; 1385 descDmaWrBytes += rxDmaLen; 1386 1387 if (doRxDmaWrite()) 1388 goto exit; 1389 } 1390 break; 1391 1392 case rxFragWrite: 1393 if (rxDmaState != dmaIdle) 1394 goto exit; 1395 1396 rxPacketBufPtr += rxXferLen; 1397 rxFragPtr += rxXferLen; 1398 rxPktBytes -= rxXferLen; 1399 1400 rxState = rxFifoBlock; 1401 break; 1402 1403 case rxDescWrite: 1404 if (rxDmaState != dmaIdle) 1405 goto exit; 1406 1407 assert(cmdsts & CMDSTS_OWN); 1408 1409 assert(rxPacket == 0); 1410 devIntrPost(ISR_RXOK); 1411 1412 if (cmdsts & CMDSTS_INTR) 1413 devIntrPost(ISR_RXDESC); 1414 1415 if (!rxEnable) { 1416 DPRINTF(EthernetSM, "Halting the RX state machine\n"); 1417 rxState = rxIdle; 1418 goto exit; 1419 } else 1420 rxState = rxAdvance; 1421 break; 1422 1423 case rxAdvance: 1424 if (link == 0) { 1425 devIntrPost(ISR_RXIDLE); 1426 rxState = rxIdle; 1427 CRDD = true; 1428 goto exit; 1429 } else { 1430 if (rxDmaState != dmaIdle) 1431 goto exit; 1432 rxState = rxDescRead; 1433 regs.rxdp = link; 1434 CRDD = false; 1435 1436 rxDmaAddr = regs.rxdp & 0x3fffffff; 1437 rxDmaData = is64bit ? (void *)&rxDesc64 : (void *)&rxDesc32; 1438 rxDmaLen = is64bit ? sizeof(rxDesc64) : sizeof(rxDesc32); 1439 rxDmaFree = dmaDescFree; 1440 1441 if (doRxDmaRead()) 1442 goto exit; 1443 } 1444 break; 1445 1446 default: 1447 panic("Invalid rxState!"); 1448 } 1449 1450 DPRINTF(EthernetSM, "entering next rxState=%s\n", 1451 NsRxStateStrings[rxState]); 1452 goto next; 1453 1454 exit: 1455 /** 1456 * @todo do we want to schedule a future kick? 1457 */ 1458 DPRINTF(EthernetSM, "rx state machine exited rxState=%s\n", 1459 NsRxStateStrings[rxState]); 1460 1461 if (clock && !rxKickEvent.scheduled()) 1462 schedule(rxKickEvent, rxKickTick); 1463} 1464 1465void 1466NSGigE::transmit() 1467{ 1468 if (txFifo.empty()) { 1469 DPRINTF(Ethernet, "nothing to transmit\n"); 1470 return; 1471 } 1472 1473 DPRINTF(Ethernet, "Attempt Pkt Transmit: txFifo length=%d\n", 1474 txFifo.size()); 1475 if (interface->sendPacket(txFifo.front())) { 1476#if TRACING_ON 1477 if (DTRACE(Ethernet)) { 1478 IpPtr ip(txFifo.front()); 1479 if (ip) { 1480 DPRINTF(Ethernet, "ID is %d\n", ip->id()); 1481 TcpPtr tcp(ip); 1482 if (tcp) { 1483 DPRINTF(Ethernet, 1484 "Src Port=%d, Dest Port=%d, Seq=%d, Ack=%d\n", 1485 tcp->sport(), tcp->dport(), tcp->seq(), 1486 tcp->ack()); 1487 } 1488 } 1489 } 1490#endif 1491 1492 DDUMP(EthernetData, txFifo.front()->data, txFifo.front()->length); 1493 txBytes += txFifo.front()->length; 1494 txPackets++; 1495 1496 DPRINTF(Ethernet, "Successful Xmit! now txFifoAvail is %d\n", 1497 txFifo.avail()); 1498 txFifo.pop(); 1499 1500 /* 1501 * normally do a writeback of the descriptor here, and ONLY 1502 * after that is done, send this interrupt. but since our 1503 * stuff never actually fails, just do this interrupt here, 1504 * otherwise the code has to stray from this nice format. 1505 * besides, it's functionally the same. 1506 */ 1507 devIntrPost(ISR_TXOK); 1508 } 1509 1510 if (!txFifo.empty() && !txEvent.scheduled()) { 1511 DPRINTF(Ethernet, "reschedule transmit\n"); 1512 schedule(txEvent, curTick() + retryTime); 1513 } 1514} 1515 1516bool 1517NSGigE::doTxDmaRead() 1518{ 1519 assert(txDmaState == dmaIdle || txDmaState == dmaReadWaiting); 1520 txDmaState = dmaReading; 1521 1522 if (dmaPending() || getState() != Running) 1523 txDmaState = dmaReadWaiting; 1524 else 1525 dmaRead(txDmaAddr, txDmaLen, &txDmaReadEvent, (uint8_t*)txDmaData); 1526 1527 return true; 1528} 1529 1530void 1531NSGigE::txDmaReadDone() 1532{ 1533 assert(txDmaState == dmaReading); 1534 txDmaState = dmaIdle; 1535 1536 DPRINTF(EthernetDMA, "tx dma read paddr=%#x len=%d\n", 1537 txDmaAddr, txDmaLen); 1538 DDUMP(EthernetDMA, txDmaData, txDmaLen); 1539 1540 // If the receive state machine has a pending DMA, let it go first 1541 if (rxDmaState == dmaReadWaiting || rxDmaState == dmaWriteWaiting) 1542 rxKick(); 1543 1544 txKick(); 1545} 1546 1547bool 1548NSGigE::doTxDmaWrite() 1549{ 1550 assert(txDmaState == dmaIdle || txDmaState == dmaWriteWaiting); 1551 txDmaState = dmaWriting; 1552 1553 if (dmaPending() || getState() != Running) 1554 txDmaState = dmaWriteWaiting; 1555 else 1556 dmaWrite(txDmaAddr, txDmaLen, &txDmaWriteEvent, (uint8_t*)txDmaData); 1557 return true; 1558} 1559 1560void 1561NSGigE::txDmaWriteDone() 1562{ 1563 assert(txDmaState == dmaWriting); 1564 txDmaState = dmaIdle; 1565 1566 DPRINTF(EthernetDMA, "tx dma write paddr=%#x len=%d\n", 1567 txDmaAddr, txDmaLen); 1568 DDUMP(EthernetDMA, txDmaData, txDmaLen); 1569 1570 // If the receive state machine has a pending DMA, let it go first 1571 if (rxDmaState == dmaReadWaiting || rxDmaState == dmaWriteWaiting) 1572 rxKick(); 1573 1574 txKick(); 1575} 1576 1577void 1578NSGigE::txKick() 1579{ 1580 bool is64bit = (bool)(regs.config & CFGR_M64ADDR); 1581 1582 DPRINTF(EthernetSM, "transmit kick txState=%s %d-bit\n", 1583 NsTxStateStrings[txState], is64bit ? 64 : 32); 1584 1585 Addr link, bufptr; 1586 uint32_t &cmdsts = is64bit ? txDesc64.cmdsts : txDesc32.cmdsts; 1587 uint32_t &extsts = is64bit ? txDesc64.extsts : txDesc32.extsts; 1588 1589 next: 1590 if (clock) { 1591 if (txKickTick > curTick()) { 1592 DPRINTF(EthernetSM, "transmit kick exiting, can't run till %d\n", 1593 txKickTick); 1594 goto exit; 1595 } 1596 1597 // Go to the next state machine clock tick. 1598 txKickTick = curTick() + ticks(1); 1599 } 1600 1601 switch(txDmaState) { 1602 case dmaReadWaiting: 1603 if (doTxDmaRead()) 1604 goto exit; 1605 break; 1606 case dmaWriteWaiting: 1607 if (doTxDmaWrite()) 1608 goto exit; 1609 break; 1610 default: 1611 break; 1612 } 1613 1614 link = is64bit ? (Addr)txDesc64.link : (Addr)txDesc32.link; 1615 bufptr = is64bit ? (Addr)txDesc64.bufptr : (Addr)txDesc32.bufptr; 1616 switch (txState) { 1617 case txIdle: 1618 if (!txEnable) { 1619 DPRINTF(EthernetSM, "Transmit disabled. Nothing to do.\n"); 1620 goto exit; 1621 } 1622 1623 if (CTDD) { 1624 txState = txDescRefr; 1625 1626 txDmaAddr = regs.txdp & 0x3fffffff; 1627 txDmaData = 1628 is64bit ? (void *)&txDesc64.link : (void *)&txDesc32.link; 1629 txDmaLen = is64bit ? sizeof(txDesc64.link) : sizeof(txDesc32.link); 1630 txDmaFree = dmaDescFree; 1631 1632 descDmaReads++; 1633 descDmaRdBytes += txDmaLen; 1634 1635 if (doTxDmaRead()) 1636 goto exit; 1637 1638 } else { 1639 txState = txDescRead; 1640 1641 txDmaAddr = regs.txdp & 0x3fffffff; 1642 txDmaData = is64bit ? (void *)&txDesc64 : (void *)&txDesc32; 1643 txDmaLen = is64bit ? sizeof(txDesc64) : sizeof(txDesc32); 1644 txDmaFree = dmaDescFree; 1645 1646 descDmaReads++; 1647 descDmaRdBytes += txDmaLen; 1648 1649 if (doTxDmaRead()) 1650 goto exit; 1651 } 1652 break; 1653 1654 case txDescRefr: 1655 if (txDmaState != dmaIdle) 1656 goto exit; 1657 1658 txState = txAdvance; 1659 break; 1660 1661 case txDescRead: 1662 if (txDmaState != dmaIdle) 1663 goto exit; 1664 1665 DPRINTF(EthernetDesc, "txDesc: addr=%08x read descriptor\n", 1666 regs.txdp & 0x3fffffff); 1667 DPRINTF(EthernetDesc, 1668 "txDesc: link=%#x bufptr=%#x cmdsts=%#08x extsts=%#08x\n", 1669 link, bufptr, cmdsts, extsts); 1670 1671 if (cmdsts & CMDSTS_OWN) { 1672 txState = txFifoBlock; 1673 txFragPtr = bufptr; 1674 txDescCnt = cmdsts & CMDSTS_LEN_MASK; 1675 } else { 1676 devIntrPost(ISR_TXIDLE); 1677 txState = txIdle; 1678 goto exit; 1679 } 1680 break; 1681 1682 case txFifoBlock: 1683 if (!txPacket) { 1684 DPRINTF(EthernetSM, "****starting the tx of a new packet****\n"); 1685 txPacket = new EthPacketData(16384); 1686 txPacketBufPtr = txPacket->data; 1687 } 1688 1689 if (txDescCnt == 0) { 1690 DPRINTF(EthernetSM, "the txDescCnt == 0, done with descriptor\n"); 1691 if (cmdsts & CMDSTS_MORE) { 1692 DPRINTF(EthernetSM, "there are more descriptors to come\n"); 1693 txState = txDescWrite; 1694 1695 cmdsts &= ~CMDSTS_OWN; 1696 1697 txDmaAddr = regs.txdp & 0x3fffffff; 1698 txDmaData = &cmdsts; 1699 if (is64bit) { 1700 txDmaAddr += offsetof(ns_desc64, cmdsts); 1701 txDmaLen = sizeof(txDesc64.cmdsts); 1702 } else { 1703 txDmaAddr += offsetof(ns_desc32, cmdsts); 1704 txDmaLen = sizeof(txDesc32.cmdsts); 1705 } 1706 txDmaFree = dmaDescFree; 1707 1708 if (doTxDmaWrite()) 1709 goto exit; 1710 1711 } else { /* this packet is totally done */ 1712 DPRINTF(EthernetSM, "This packet is done, let's wrap it up\n"); 1713 /* deal with the the packet that just finished */ 1714 if ((regs.vtcr & VTCR_PPCHK) && extstsEnable) { 1715 IpPtr ip(txPacket); 1716 if (extsts & EXTSTS_UDPPKT) { 1717 UdpPtr udp(ip); 1718 if (udp) { 1719 udp->sum(0); 1720 udp->sum(cksum(udp)); 1721 txUdpChecksums++; 1722 } else { 1723 Debug::breakpoint(); 1724 warn_once("UDPPKT set, but not UDP!\n"); 1725 } 1726 } else if (extsts & EXTSTS_TCPPKT) { 1727 TcpPtr tcp(ip); 1728 if (tcp) { 1729 tcp->sum(0); 1730 tcp->sum(cksum(tcp)); 1731 txTcpChecksums++; 1732 } else { 1733 Debug::breakpoint(); 1734 warn_once("TCPPKT set, but not UDP!\n"); 1735 } 1736 } 1737 if (extsts & EXTSTS_IPPKT) { 1738 if (ip) { 1739 ip->sum(0); 1740 ip->sum(cksum(ip)); 1741 txIpChecksums++; 1742 } else { 1743 Debug::breakpoint(); 1744 warn_once("IPPKT set, but not UDP!\n"); 1745 } 1746 } 1747 } 1748 1749 txPacket->length = txPacketBufPtr - txPacket->data; 1750 // this is just because the receive can't handle a 1751 // packet bigger want to make sure 1752 if (txPacket->length > 1514) 1753 panic("transmit packet too large, %s > 1514\n", 1754 txPacket->length); 1755 1756#ifndef NDEBUG 1757 bool success = 1758#endif 1759 txFifo.push(txPacket); 1760 assert(success); 1761 1762 /* 1763 * this following section is not tqo spec, but 1764 * functionally shouldn't be any different. normally, 1765 * the chip will wait til the transmit has occurred 1766 * before writing back the descriptor because it has 1767 * to wait to see that it was successfully transmitted 1768 * to decide whether to set CMDSTS_OK or not. 1769 * however, in the simulator since it is always 1770 * successfully transmitted, and writing it exactly to 1771 * spec would complicate the code, we just do it here 1772 */ 1773 1774 cmdsts &= ~CMDSTS_OWN; 1775 cmdsts |= CMDSTS_OK; 1776 1777 DPRINTF(EthernetDesc, 1778 "txDesc writeback: cmdsts=%08x extsts=%08x\n", 1779 cmdsts, extsts); 1780 1781 txDmaFree = dmaDescFree; 1782 txDmaAddr = regs.txdp & 0x3fffffff; 1783 txDmaData = &cmdsts; 1784 if (is64bit) { 1785 txDmaAddr += offsetof(ns_desc64, cmdsts); 1786 txDmaLen = 1787 sizeof(txDesc64.cmdsts) + sizeof(txDesc64.extsts); 1788 } else { 1789 txDmaAddr += offsetof(ns_desc32, cmdsts); 1790 txDmaLen = 1791 sizeof(txDesc32.cmdsts) + sizeof(txDesc32.extsts); 1792 } 1793 1794 descDmaWrites++; 1795 descDmaWrBytes += txDmaLen; 1796 1797 transmit(); 1798 txPacket = 0; 1799 1800 if (!txEnable) { 1801 DPRINTF(EthernetSM, "halting TX state machine\n"); 1802 txState = txIdle; 1803 goto exit; 1804 } else 1805 txState = txAdvance; 1806 1807 if (doTxDmaWrite()) 1808 goto exit; 1809 } 1810 } else { 1811 DPRINTF(EthernetSM, "this descriptor isn't done yet\n"); 1812 if (!txFifo.full()) { 1813 txState = txFragRead; 1814 1815 /* 1816 * The number of bytes transferred is either whatever 1817 * is left in the descriptor (txDescCnt), or if there 1818 * is not enough room in the fifo, just whatever room 1819 * is left in the fifo 1820 */ 1821 txXferLen = min<uint32_t>(txDescCnt, txFifo.avail()); 1822 1823 txDmaAddr = txFragPtr & 0x3fffffff; 1824 txDmaData = txPacketBufPtr; 1825 txDmaLen = txXferLen; 1826 txDmaFree = dmaDataFree; 1827 1828 if (doTxDmaRead()) 1829 goto exit; 1830 } else { 1831 txState = txFifoBlock; 1832 transmit(); 1833 1834 goto exit; 1835 } 1836 1837 } 1838 break; 1839 1840 case txFragRead: 1841 if (txDmaState != dmaIdle) 1842 goto exit; 1843 1844 txPacketBufPtr += txXferLen; 1845 txFragPtr += txXferLen; 1846 txDescCnt -= txXferLen; 1847 txFifo.reserve(txXferLen); 1848 1849 txState = txFifoBlock; 1850 break; 1851 1852 case txDescWrite: 1853 if (txDmaState != dmaIdle) 1854 goto exit; 1855 1856 if (cmdsts & CMDSTS_INTR) 1857 devIntrPost(ISR_TXDESC); 1858 1859 if (!txEnable) { 1860 DPRINTF(EthernetSM, "halting TX state machine\n"); 1861 txState = txIdle; 1862 goto exit; 1863 } else 1864 txState = txAdvance; 1865 break; 1866 1867 case txAdvance: 1868 if (link == 0) { 1869 devIntrPost(ISR_TXIDLE); 1870 txState = txIdle; 1871 goto exit; 1872 } else { 1873 if (txDmaState != dmaIdle) 1874 goto exit; 1875 txState = txDescRead; 1876 regs.txdp = link; 1877 CTDD = false; 1878 1879 txDmaAddr = link & 0x3fffffff; 1880 txDmaData = is64bit ? (void *)&txDesc64 : (void *)&txDesc32; 1881 txDmaLen = is64bit ? sizeof(txDesc64) : sizeof(txDesc32); 1882 txDmaFree = dmaDescFree; 1883 1884 if (doTxDmaRead()) 1885 goto exit; 1886 } 1887 break; 1888 1889 default: 1890 panic("invalid state"); 1891 } 1892 1893 DPRINTF(EthernetSM, "entering next txState=%s\n", 1894 NsTxStateStrings[txState]); 1895 goto next; 1896 1897 exit: 1898 /** 1899 * @todo do we want to schedule a future kick? 1900 */ 1901 DPRINTF(EthernetSM, "tx state machine exited txState=%s\n", 1902 NsTxStateStrings[txState]); 1903 1904 if (clock && !txKickEvent.scheduled()) 1905 schedule(txKickEvent, txKickTick); 1906} 1907 1908/** 1909 * Advance the EEPROM state machine 1910 * Called on rising edge of EEPROM clock bit in MEAR 1911 */ 1912void 1913NSGigE::eepromKick() 1914{ 1915 switch (eepromState) { 1916 1917 case eepromStart: 1918 1919 // Wait for start bit 1920 if (regs.mear & MEAR_EEDI) { 1921 // Set up to get 2 opcode bits 1922 eepromState = eepromGetOpcode; 1923 eepromBitsToRx = 2; 1924 eepromOpcode = 0; 1925 } 1926 break; 1927 1928 case eepromGetOpcode: 1929 eepromOpcode <<= 1; 1930 eepromOpcode += (regs.mear & MEAR_EEDI) ? 1 : 0; 1931 --eepromBitsToRx; 1932 1933 // Done getting opcode 1934 if (eepromBitsToRx == 0) { 1935 if (eepromOpcode != EEPROM_READ) 1936 panic("only EEPROM reads are implemented!"); 1937 1938 // Set up to get address 1939 eepromState = eepromGetAddress; 1940 eepromBitsToRx = 6; 1941 eepromAddress = 0; 1942 } 1943 break; 1944 1945 case eepromGetAddress: 1946 eepromAddress <<= 1; 1947 eepromAddress += (regs.mear & MEAR_EEDI) ? 1 : 0; 1948 --eepromBitsToRx; 1949 1950 // Done getting address 1951 if (eepromBitsToRx == 0) { 1952 1953 if (eepromAddress >= EEPROM_SIZE) 1954 panic("EEPROM read access out of range!"); 1955 1956 switch (eepromAddress) { 1957 1958 case EEPROM_PMATCH2_ADDR: 1959 eepromData = rom.perfectMatch[5]; 1960 eepromData <<= 8; 1961 eepromData += rom.perfectMatch[4]; 1962 break; 1963 1964 case EEPROM_PMATCH1_ADDR: 1965 eepromData = rom.perfectMatch[3]; 1966 eepromData <<= 8; 1967 eepromData += rom.perfectMatch[2]; 1968 break; 1969 1970 case EEPROM_PMATCH0_ADDR: 1971 eepromData = rom.perfectMatch[1]; 1972 eepromData <<= 8; 1973 eepromData += rom.perfectMatch[0]; 1974 break; 1975 1976 default: 1977 panic("FreeBSD driver only uses EEPROM to read PMATCH!"); 1978 } 1979 // Set up to read data 1980 eepromState = eepromRead; 1981 eepromBitsToRx = 16; 1982 1983 // Clear data in bit 1984 regs.mear &= ~MEAR_EEDI; 1985 } 1986 break; 1987 1988 case eepromRead: 1989 // Clear Data Out bit 1990 regs.mear &= ~MEAR_EEDO; 1991 // Set bit to value of current EEPROM bit 1992 regs.mear |= (eepromData & 0x8000) ? MEAR_EEDO : 0x0; 1993 1994 eepromData <<= 1; 1995 --eepromBitsToRx; 1996 1997 // All done 1998 if (eepromBitsToRx == 0) { 1999 eepromState = eepromStart; 2000 } 2001 break; 2002 2003 default: 2004 panic("invalid EEPROM state"); 2005 } 2006 2007} 2008 2009void 2010NSGigE::transferDone() 2011{ 2012 if (txFifo.empty()) { 2013 DPRINTF(Ethernet, "transfer complete: txFifo empty...nothing to do\n"); 2014 return; 2015 } 2016 2017 DPRINTF(Ethernet, "transfer complete: data in txFifo...schedule xmit\n"); 2018 2019 reschedule(txEvent, curTick() + ticks(1), true); 2020} 2021 2022bool 2023NSGigE::rxFilter(const EthPacketPtr &packet) 2024{ 2025 EthPtr eth = packet; 2026 bool drop = true; 2027 string type; 2028 2029 const EthAddr &dst = eth->dst(); 2030 if (dst.unicast()) { 2031 // If we're accepting all unicast addresses 2032 if (acceptUnicast) 2033 drop = false; 2034 2035 // If we make a perfect match 2036 if (acceptPerfect && dst == rom.perfectMatch) 2037 drop = false; 2038 2039 if (acceptArp && eth->type() == ETH_TYPE_ARP) 2040 drop = false; 2041 2042 } else if (dst.broadcast()) { 2043 // if we're accepting broadcasts 2044 if (acceptBroadcast) 2045 drop = false; 2046 2047 } else if (dst.multicast()) { 2048 // if we're accepting all multicasts 2049 if (acceptMulticast) 2050 drop = false; 2051 2052 // Multicast hashing faked - all packets accepted 2053 if (multicastHashEnable) 2054 drop = false; 2055 } 2056 2057 if (drop) { 2058 DPRINTF(Ethernet, "rxFilter drop\n"); 2059 DDUMP(EthernetData, packet->data, packet->length); 2060 } 2061 2062 return drop; 2063} 2064 2065bool 2066NSGigE::recvPacket(EthPacketPtr packet) 2067{ 2068 rxBytes += packet->length; 2069 rxPackets++; 2070 2071 DPRINTF(Ethernet, "Receiving packet from wire, rxFifoAvail=%d\n", 2072 rxFifo.avail()); 2073 2074 if (!rxEnable) { 2075 DPRINTF(Ethernet, "receive disabled...packet dropped\n"); 2076 return true; 2077 } 2078 2079 if (!rxFilterEnable) { 2080 DPRINTF(Ethernet, 2081 "receive packet filtering disabled . . . packet dropped\n"); 2082 return true; 2083 } 2084 2085 if (rxFilter(packet)) { 2086 DPRINTF(Ethernet, "packet filtered...dropped\n"); 2087 return true; 2088 } 2089 2090 if (rxFifo.avail() < packet->length) { 2091#if TRACING_ON 2092 IpPtr ip(packet); 2093 TcpPtr tcp(ip); 2094 if (ip) { 2095 DPRINTF(Ethernet, 2096 "packet won't fit in receive buffer...pkt ID %d dropped\n", 2097 ip->id()); 2098 if (tcp) { 2099 DPRINTF(Ethernet, "Seq=%d\n", tcp->seq()); 2100 } 2101 } 2102#endif 2103 droppedPackets++; 2104 devIntrPost(ISR_RXORN); 2105 return false; 2106 } 2107 2108 rxFifo.push(packet); 2109 2110 rxKick(); 2111 return true; 2112} 2113 2114 2115void 2116NSGigE::resume() 2117{ 2118 SimObject::resume(); 2119 2120 // During drain we could have left the state machines in a waiting state and 2121 // they wouldn't get out until some other event occured to kick them. 2122 // This way they'll get out immediately 2123 txKick(); 2124 rxKick(); 2125} 2126 2127 2128//===================================================================== 2129// 2130// 2131void 2132NSGigE::serialize(ostream &os) 2133{ 2134 // Serialize the PciDev base class 2135 PciDev::serialize(os); 2136 2137 /* 2138 * Finalize any DMA events now. 2139 */ 2140 // @todo will mem system save pending dma? 2141 2142 /* 2143 * Serialize the device registers 2144 */ 2145 SERIALIZE_SCALAR(regs.command); 2146 SERIALIZE_SCALAR(regs.config); 2147 SERIALIZE_SCALAR(regs.mear); 2148 SERIALIZE_SCALAR(regs.ptscr); 2149 SERIALIZE_SCALAR(regs.isr); 2150 SERIALIZE_SCALAR(regs.imr); 2151 SERIALIZE_SCALAR(regs.ier); 2152 SERIALIZE_SCALAR(regs.ihr); 2153 SERIALIZE_SCALAR(regs.txdp); 2154 SERIALIZE_SCALAR(regs.txdp_hi); 2155 SERIALIZE_SCALAR(regs.txcfg); 2156 SERIALIZE_SCALAR(regs.gpior); 2157 SERIALIZE_SCALAR(regs.rxdp); 2158 SERIALIZE_SCALAR(regs.rxdp_hi); 2159 SERIALIZE_SCALAR(regs.rxcfg); 2160 SERIALIZE_SCALAR(regs.pqcr); 2161 SERIALIZE_SCALAR(regs.wcsr); 2162 SERIALIZE_SCALAR(regs.pcr); 2163 SERIALIZE_SCALAR(regs.rfcr); 2164 SERIALIZE_SCALAR(regs.rfdr); 2165 SERIALIZE_SCALAR(regs.brar); 2166 SERIALIZE_SCALAR(regs.brdr); 2167 SERIALIZE_SCALAR(regs.srr); 2168 SERIALIZE_SCALAR(regs.mibc); 2169 SERIALIZE_SCALAR(regs.vrcr); 2170 SERIALIZE_SCALAR(regs.vtcr); 2171 SERIALIZE_SCALAR(regs.vdr); 2172 SERIALIZE_SCALAR(regs.ccsr); 2173 SERIALIZE_SCALAR(regs.tbicr); 2174 SERIALIZE_SCALAR(regs.tbisr); 2175 SERIALIZE_SCALAR(regs.tanar); 2176 SERIALIZE_SCALAR(regs.tanlpar); 2177 SERIALIZE_SCALAR(regs.taner); 2178 SERIALIZE_SCALAR(regs.tesr); 2179 2180 SERIALIZE_ARRAY(rom.perfectMatch, ETH_ADDR_LEN); 2181 SERIALIZE_ARRAY(rom.filterHash, FHASH_SIZE); 2182 2183 SERIALIZE_SCALAR(ioEnable); 2184 2185 /* 2186 * Serialize the data Fifos 2187 */ 2188 rxFifo.serialize("rxFifo", os); 2189 txFifo.serialize("txFifo", os); 2190 2191 /* 2192 * Serialize the various helper variables 2193 */ 2194 bool txPacketExists = txPacket; 2195 SERIALIZE_SCALAR(txPacketExists); 2196 if (txPacketExists) { 2197 txPacket->length = txPacketBufPtr - txPacket->data; 2198 txPacket->serialize("txPacket", os); 2199 uint32_t txPktBufPtr = (uint32_t) (txPacketBufPtr - txPacket->data); 2200 SERIALIZE_SCALAR(txPktBufPtr); 2201 } 2202 2203 bool rxPacketExists = rxPacket; 2204 SERIALIZE_SCALAR(rxPacketExists); 2205 if (rxPacketExists) { 2206 rxPacket->serialize("rxPacket", os); 2207 uint32_t rxPktBufPtr = (uint32_t) (rxPacketBufPtr - rxPacket->data); 2208 SERIALIZE_SCALAR(rxPktBufPtr); 2209 } 2210 2211 SERIALIZE_SCALAR(txXferLen); 2212 SERIALIZE_SCALAR(rxXferLen); 2213 2214 /* 2215 * Serialize Cached Descriptors 2216 */ 2217 SERIALIZE_SCALAR(rxDesc64.link); 2218 SERIALIZE_SCALAR(rxDesc64.bufptr); 2219 SERIALIZE_SCALAR(rxDesc64.cmdsts); 2220 SERIALIZE_SCALAR(rxDesc64.extsts); 2221 SERIALIZE_SCALAR(txDesc64.link); 2222 SERIALIZE_SCALAR(txDesc64.bufptr); 2223 SERIALIZE_SCALAR(txDesc64.cmdsts); 2224 SERIALIZE_SCALAR(txDesc64.extsts); 2225 SERIALIZE_SCALAR(rxDesc32.link); 2226 SERIALIZE_SCALAR(rxDesc32.bufptr); 2227 SERIALIZE_SCALAR(rxDesc32.cmdsts); 2228 SERIALIZE_SCALAR(rxDesc32.extsts); 2229 SERIALIZE_SCALAR(txDesc32.link); 2230 SERIALIZE_SCALAR(txDesc32.bufptr); 2231 SERIALIZE_SCALAR(txDesc32.cmdsts); 2232 SERIALIZE_SCALAR(txDesc32.extsts); 2233 SERIALIZE_SCALAR(extstsEnable); 2234 2235 /* 2236 * Serialize tx state machine 2237 */ 2238 int txState = this->txState; 2239 SERIALIZE_SCALAR(txState); 2240 SERIALIZE_SCALAR(txEnable); 2241 SERIALIZE_SCALAR(CTDD); 2242 SERIALIZE_SCALAR(txFragPtr); 2243 SERIALIZE_SCALAR(txDescCnt); 2244 int txDmaState = this->txDmaState; 2245 SERIALIZE_SCALAR(txDmaState); 2246 SERIALIZE_SCALAR(txKickTick); 2247 2248 /* 2249 * Serialize rx state machine 2250 */ 2251 int rxState = this->rxState; 2252 SERIALIZE_SCALAR(rxState); 2253 SERIALIZE_SCALAR(rxEnable); 2254 SERIALIZE_SCALAR(CRDD); 2255 SERIALIZE_SCALAR(rxPktBytes); 2256 SERIALIZE_SCALAR(rxFragPtr); 2257 SERIALIZE_SCALAR(rxDescCnt); 2258 int rxDmaState = this->rxDmaState; 2259 SERIALIZE_SCALAR(rxDmaState); 2260 SERIALIZE_SCALAR(rxKickTick); 2261 2262 /* 2263 * Serialize EEPROM state machine 2264 */ 2265 int eepromState = this->eepromState; 2266 SERIALIZE_SCALAR(eepromState); 2267 SERIALIZE_SCALAR(eepromClk); 2268 SERIALIZE_SCALAR(eepromBitsToRx); 2269 SERIALIZE_SCALAR(eepromOpcode); 2270 SERIALIZE_SCALAR(eepromAddress); 2271 SERIALIZE_SCALAR(eepromData); 2272 2273 /* 2274 * If there's a pending transmit, store the time so we can 2275 * reschedule it later 2276 */ 2277 Tick transmitTick = txEvent.scheduled() ? txEvent.when() - curTick() : 0; 2278 SERIALIZE_SCALAR(transmitTick); 2279 2280 /* 2281 * receive address filter settings 2282 */ 2283 SERIALIZE_SCALAR(rxFilterEnable); 2284 SERIALIZE_SCALAR(acceptBroadcast); 2285 SERIALIZE_SCALAR(acceptMulticast); 2286 SERIALIZE_SCALAR(acceptUnicast); 2287 SERIALIZE_SCALAR(acceptPerfect); 2288 SERIALIZE_SCALAR(acceptArp); 2289 SERIALIZE_SCALAR(multicastHashEnable); 2290 2291 /* 2292 * Keep track of pending interrupt status. 2293 */ 2294 SERIALIZE_SCALAR(intrTick); 2295 SERIALIZE_SCALAR(cpuPendingIntr); 2296 Tick intrEventTick = 0; 2297 if (intrEvent) 2298 intrEventTick = intrEvent->when(); 2299 SERIALIZE_SCALAR(intrEventTick); 2300 2301} 2302 2303void 2304NSGigE::unserialize(Checkpoint *cp, const std::string §ion) 2305{ 2306 // Unserialize the PciDev base class 2307 PciDev::unserialize(cp, section); 2308 2309 UNSERIALIZE_SCALAR(regs.command); 2310 UNSERIALIZE_SCALAR(regs.config); 2311 UNSERIALIZE_SCALAR(regs.mear); 2312 UNSERIALIZE_SCALAR(regs.ptscr); 2313 UNSERIALIZE_SCALAR(regs.isr); 2314 UNSERIALIZE_SCALAR(regs.imr); 2315 UNSERIALIZE_SCALAR(regs.ier); 2316 UNSERIALIZE_SCALAR(regs.ihr); 2317 UNSERIALIZE_SCALAR(regs.txdp); 2318 UNSERIALIZE_SCALAR(regs.txdp_hi); 2319 UNSERIALIZE_SCALAR(regs.txcfg); 2320 UNSERIALIZE_SCALAR(regs.gpior); 2321 UNSERIALIZE_SCALAR(regs.rxdp); 2322 UNSERIALIZE_SCALAR(regs.rxdp_hi); 2323 UNSERIALIZE_SCALAR(regs.rxcfg); 2324 UNSERIALIZE_SCALAR(regs.pqcr); 2325 UNSERIALIZE_SCALAR(regs.wcsr); 2326 UNSERIALIZE_SCALAR(regs.pcr); 2327 UNSERIALIZE_SCALAR(regs.rfcr); 2328 UNSERIALIZE_SCALAR(regs.rfdr); 2329 UNSERIALIZE_SCALAR(regs.brar); 2330 UNSERIALIZE_SCALAR(regs.brdr); 2331 UNSERIALIZE_SCALAR(regs.srr); 2332 UNSERIALIZE_SCALAR(regs.mibc); 2333 UNSERIALIZE_SCALAR(regs.vrcr); 2334 UNSERIALIZE_SCALAR(regs.vtcr); 2335 UNSERIALIZE_SCALAR(regs.vdr); 2336 UNSERIALIZE_SCALAR(regs.ccsr); 2337 UNSERIALIZE_SCALAR(regs.tbicr); 2338 UNSERIALIZE_SCALAR(regs.tbisr); 2339 UNSERIALIZE_SCALAR(regs.tanar); 2340 UNSERIALIZE_SCALAR(regs.tanlpar); 2341 UNSERIALIZE_SCALAR(regs.taner); 2342 UNSERIALIZE_SCALAR(regs.tesr); 2343 2344 UNSERIALIZE_ARRAY(rom.perfectMatch, ETH_ADDR_LEN); 2345 UNSERIALIZE_ARRAY(rom.filterHash, FHASH_SIZE); 2346 2347 UNSERIALIZE_SCALAR(ioEnable); 2348 2349 /* 2350 * unserialize the data fifos 2351 */ 2352 rxFifo.unserialize("rxFifo", cp, section); 2353 txFifo.unserialize("txFifo", cp, section); 2354 2355 /* 2356 * unserialize the various helper variables 2357 */ 2358 bool txPacketExists; 2359 UNSERIALIZE_SCALAR(txPacketExists); 2360 if (txPacketExists) { 2361 txPacket = new EthPacketData(16384); 2362 txPacket->unserialize("txPacket", cp, section); 2363 uint32_t txPktBufPtr; 2364 UNSERIALIZE_SCALAR(txPktBufPtr); 2365 txPacketBufPtr = (uint8_t *) txPacket->data + txPktBufPtr; 2366 } else 2367 txPacket = 0; 2368 2369 bool rxPacketExists; 2370 UNSERIALIZE_SCALAR(rxPacketExists); 2371 rxPacket = 0; 2372 if (rxPacketExists) { 2373 rxPacket = new EthPacketData(16384); 2374 rxPacket->unserialize("rxPacket", cp, section); 2375 uint32_t rxPktBufPtr; 2376 UNSERIALIZE_SCALAR(rxPktBufPtr); 2377 rxPacketBufPtr = (uint8_t *) rxPacket->data + rxPktBufPtr; 2378 } else 2379 rxPacket = 0; 2380 2381 UNSERIALIZE_SCALAR(txXferLen); 2382 UNSERIALIZE_SCALAR(rxXferLen); 2383 2384 /* 2385 * Unserialize Cached Descriptors 2386 */ 2387 UNSERIALIZE_SCALAR(rxDesc64.link); 2388 UNSERIALIZE_SCALAR(rxDesc64.bufptr); 2389 UNSERIALIZE_SCALAR(rxDesc64.cmdsts); 2390 UNSERIALIZE_SCALAR(rxDesc64.extsts); 2391 UNSERIALIZE_SCALAR(txDesc64.link); 2392 UNSERIALIZE_SCALAR(txDesc64.bufptr); 2393 UNSERIALIZE_SCALAR(txDesc64.cmdsts); 2394 UNSERIALIZE_SCALAR(txDesc64.extsts); 2395 UNSERIALIZE_SCALAR(rxDesc32.link); 2396 UNSERIALIZE_SCALAR(rxDesc32.bufptr); 2397 UNSERIALIZE_SCALAR(rxDesc32.cmdsts); 2398 UNSERIALIZE_SCALAR(rxDesc32.extsts); 2399 UNSERIALIZE_SCALAR(txDesc32.link); 2400 UNSERIALIZE_SCALAR(txDesc32.bufptr); 2401 UNSERIALIZE_SCALAR(txDesc32.cmdsts); 2402 UNSERIALIZE_SCALAR(txDesc32.extsts); 2403 UNSERIALIZE_SCALAR(extstsEnable); 2404 2405 /* 2406 * unserialize tx state machine 2407 */ 2408 int txState; 2409 UNSERIALIZE_SCALAR(txState); 2410 this->txState = (TxState) txState; 2411 UNSERIALIZE_SCALAR(txEnable); 2412 UNSERIALIZE_SCALAR(CTDD); 2413 UNSERIALIZE_SCALAR(txFragPtr); 2414 UNSERIALIZE_SCALAR(txDescCnt); 2415 int txDmaState; 2416 UNSERIALIZE_SCALAR(txDmaState); 2417 this->txDmaState = (DmaState) txDmaState; 2418 UNSERIALIZE_SCALAR(txKickTick); 2419 if (txKickTick) 2420 schedule(txKickEvent, txKickTick); 2421 2422 /* 2423 * unserialize rx state machine 2424 */ 2425 int rxState; 2426 UNSERIALIZE_SCALAR(rxState); 2427 this->rxState = (RxState) rxState; 2428 UNSERIALIZE_SCALAR(rxEnable); 2429 UNSERIALIZE_SCALAR(CRDD); 2430 UNSERIALIZE_SCALAR(rxPktBytes); 2431 UNSERIALIZE_SCALAR(rxFragPtr); 2432 UNSERIALIZE_SCALAR(rxDescCnt); 2433 int rxDmaState; 2434 UNSERIALIZE_SCALAR(rxDmaState); 2435 this->rxDmaState = (DmaState) rxDmaState; 2436 UNSERIALIZE_SCALAR(rxKickTick); 2437 if (rxKickTick) 2438 schedule(rxKickEvent, rxKickTick); 2439 2440 /* 2441 * Unserialize EEPROM state machine 2442 */ 2443 int eepromState; 2444 UNSERIALIZE_SCALAR(eepromState); 2445 this->eepromState = (EEPROMState) eepromState; 2446 UNSERIALIZE_SCALAR(eepromClk); 2447 UNSERIALIZE_SCALAR(eepromBitsToRx); 2448 UNSERIALIZE_SCALAR(eepromOpcode); 2449 UNSERIALIZE_SCALAR(eepromAddress); 2450 UNSERIALIZE_SCALAR(eepromData); 2451 2452 /* 2453 * If there's a pending transmit, reschedule it now 2454 */ 2455 Tick transmitTick; 2456 UNSERIALIZE_SCALAR(transmitTick); 2457 if (transmitTick) 2458 schedule(txEvent, curTick() + transmitTick); 2459 2460 /* 2461 * unserialize receive address filter settings 2462 */ 2463 UNSERIALIZE_SCALAR(rxFilterEnable); 2464 UNSERIALIZE_SCALAR(acceptBroadcast); 2465 UNSERIALIZE_SCALAR(acceptMulticast); 2466 UNSERIALIZE_SCALAR(acceptUnicast); 2467 UNSERIALIZE_SCALAR(acceptPerfect); 2468 UNSERIALIZE_SCALAR(acceptArp); 2469 UNSERIALIZE_SCALAR(multicastHashEnable); 2470 2471 /* 2472 * Keep track of pending interrupt status. 2473 */ 2474 UNSERIALIZE_SCALAR(intrTick); 2475 UNSERIALIZE_SCALAR(cpuPendingIntr); 2476 Tick intrEventTick; 2477 UNSERIALIZE_SCALAR(intrEventTick); 2478 if (intrEventTick) { 2479 intrEvent = new IntrEvent(this, true); 2480 schedule(intrEvent, intrEventTick); 2481 } 2482} 2483 2484NSGigE * 2485NSGigEParams::create() 2486{ 2487 return new NSGigE(this); 2488} 2489