ns_gige.cc revision 10367
16019Shines@cs.fsu.edu/* 26019Shines@cs.fsu.edu * Copyright (c) 2004-2005 The Regents of The University of Michigan 37178Sgblack@eecs.umich.edu * All rights reserved. 47178Sgblack@eecs.umich.edu * 57178Sgblack@eecs.umich.edu * Redistribution and use in source and binary forms, with or without 67178Sgblack@eecs.umich.edu * modification, are permitted provided that the following conditions are 77178Sgblack@eecs.umich.edu * met: redistributions of source code must retain the above copyright 87178Sgblack@eecs.umich.edu * notice, this list of conditions and the following disclaimer; 97178Sgblack@eecs.umich.edu * redistributions in binary form must reproduce the above copyright 107178Sgblack@eecs.umich.edu * notice, this list of conditions and the following disclaimer in the 117178Sgblack@eecs.umich.edu * documentation and/or other materials provided with the distribution; 127178Sgblack@eecs.umich.edu * neither the name of the copyright holders nor the names of its 137178Sgblack@eecs.umich.edu * contributors may be used to endorse or promote products derived from 147178Sgblack@eecs.umich.edu * this software without specific prior written permission. 156019Shines@cs.fsu.edu * 166019Shines@cs.fsu.edu * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 176019Shines@cs.fsu.edu * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 186019Shines@cs.fsu.edu * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR 196019Shines@cs.fsu.edu * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT 206019Shines@cs.fsu.edu * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 216019Shines@cs.fsu.edu * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT 226019Shines@cs.fsu.edu * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 236019Shines@cs.fsu.edu * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 246019Shines@cs.fsu.edu * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 256019Shines@cs.fsu.edu * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 266019Shines@cs.fsu.edu * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 276019Shines@cs.fsu.edu * 286019Shines@cs.fsu.edu * Authors: Nathan Binkert 296019Shines@cs.fsu.edu * Lisa Hsu 306019Shines@cs.fsu.edu */ 316019Shines@cs.fsu.edu 326019Shines@cs.fsu.edu/** @file 336019Shines@cs.fsu.edu * Device module for modelling the National Semiconductor 346019Shines@cs.fsu.edu * DP83820 ethernet controller. Does not support priority queueing 356019Shines@cs.fsu.edu */ 366019Shines@cs.fsu.edu#include <deque> 376019Shines@cs.fsu.edu#include <string> 386019Shines@cs.fsu.edu 396019Shines@cs.fsu.edu#include "base/debug.hh" 406019Shines@cs.fsu.edu#include "base/inet.hh" 416019Shines@cs.fsu.edu#include "base/types.hh" 426019Shines@cs.fsu.edu#include "config/the_isa.hh" 436019Shines@cs.fsu.edu#include "debug/EthernetAll.hh" 446019Shines@cs.fsu.edu#include "dev/etherlink.hh" 456019Shines@cs.fsu.edu#include "dev/ns_gige.hh" 466019Shines@cs.fsu.edu#include "dev/pciconfigall.hh" 476019Shines@cs.fsu.edu#include "mem/packet.hh" 486019Shines@cs.fsu.edu#include "mem/packet_access.hh" 496019Shines@cs.fsu.edu#include "params/NSGigE.hh" 506019Shines@cs.fsu.edu#include "sim/system.hh" 516019Shines@cs.fsu.edu 526019Shines@cs.fsu.edu// clang complains about std::set being overloaded with Packet::set if 536019Shines@cs.fsu.edu// we open up the entire namespace std 546019Shines@cs.fsu.eduusing std::min; 556019Shines@cs.fsu.eduusing std::ostream; 566019Shines@cs.fsu.eduusing std::string; 576019Shines@cs.fsu.edu 586243Sgblack@eecs.umich.educonst char *NsRxStateStrings[] = 596243Sgblack@eecs.umich.edu{ 606243Sgblack@eecs.umich.edu "rxIdle", 616243Sgblack@eecs.umich.edu "rxDescRefr", 626243Sgblack@eecs.umich.edu "rxDescRead", 636019Shines@cs.fsu.edu "rxFifoBlock", 646019Shines@cs.fsu.edu "rxFragWrite", 656019Shines@cs.fsu.edu "rxDescWrite", 666019Shines@cs.fsu.edu "rxAdvance" 676019Shines@cs.fsu.edu}; 686019Shines@cs.fsu.edu 696019Shines@cs.fsu.educonst char *NsTxStateStrings[] = 706019Shines@cs.fsu.edu{ 716019Shines@cs.fsu.edu "txIdle", 726019Shines@cs.fsu.edu "txDescRefr", 736019Shines@cs.fsu.edu "txDescRead", 746019Shines@cs.fsu.edu "txFifoBlock", 756019Shines@cs.fsu.edu "txFragRead", 766019Shines@cs.fsu.edu "txDescWrite", 776019Shines@cs.fsu.edu "txAdvance" 786019Shines@cs.fsu.edu}; 796019Shines@cs.fsu.edu 806019Shines@cs.fsu.educonst char *NsDmaState[] = 816019Shines@cs.fsu.edu{ 826019Shines@cs.fsu.edu "dmaIdle", 836019Shines@cs.fsu.edu "dmaReading", 846019Shines@cs.fsu.edu "dmaWriting", 856019Shines@cs.fsu.edu "dmaReadWaiting", 866019Shines@cs.fsu.edu "dmaWriteWaiting" 876019Shines@cs.fsu.edu}; 886019Shines@cs.fsu.edu 896019Shines@cs.fsu.eduusing namespace Net; 906019Shines@cs.fsu.eduusing namespace TheISA; 916019Shines@cs.fsu.edu 926019Shines@cs.fsu.edu/////////////////////////////////////////////////////////////////////// 936019Shines@cs.fsu.edu// 946252Sgblack@eecs.umich.edu// NSGigE PCI Device 956243Sgblack@eecs.umich.edu// 966243Sgblack@eecs.umich.eduNSGigE::NSGigE(Params *p) 976243Sgblack@eecs.umich.edu : EtherDevBase(p), ioEnable(false), 986019Shines@cs.fsu.edu txFifo(p->tx_fifo_size), rxFifo(p->rx_fifo_size), 996019Shines@cs.fsu.edu txPacket(0), rxPacket(0), txPacketBufPtr(NULL), rxPacketBufPtr(NULL), 1006019Shines@cs.fsu.edu txXferLen(0), rxXferLen(0), rxDmaFree(false), txDmaFree(false), 1016019Shines@cs.fsu.edu txState(txIdle), txEnable(false), CTDD(false), txHalt(false), 1026019Shines@cs.fsu.edu txFragPtr(0), txDescCnt(0), txDmaState(dmaIdle), rxState(rxIdle), 1036252Sgblack@eecs.umich.edu rxEnable(false), CRDD(false), rxPktBytes(0), rxHalt(false), 1046243Sgblack@eecs.umich.edu rxFragPtr(0), rxDescCnt(0), rxDmaState(dmaIdle), extstsEnable(false), 1056243Sgblack@eecs.umich.edu eepromState(eepromStart), eepromClk(false), eepromBitsToRx(0), 1066243Sgblack@eecs.umich.edu eepromOpcode(0), eepromAddress(0), eepromData(0), 1076019Shines@cs.fsu.edu dmaReadDelay(p->dma_read_delay), dmaWriteDelay(p->dma_write_delay), 1086019Shines@cs.fsu.edu dmaReadFactor(p->dma_read_factor), dmaWriteFactor(p->dma_write_factor), 1096019Shines@cs.fsu.edu rxDmaData(NULL), rxDmaAddr(0), rxDmaLen(0), 1106019Shines@cs.fsu.edu txDmaData(NULL), txDmaAddr(0), txDmaLen(0), 1116019Shines@cs.fsu.edu rxDmaReadEvent(this), rxDmaWriteEvent(this), 1126019Shines@cs.fsu.edu txDmaReadEvent(this), txDmaWriteEvent(this), 1136019Shines@cs.fsu.edu dmaDescFree(p->dma_desc_free), dmaDataFree(p->dma_data_free), 1146252Sgblack@eecs.umich.edu txDelay(p->tx_delay), rxDelay(p->rx_delay), 1156243Sgblack@eecs.umich.edu rxKickTick(0), rxKickEvent(this), txKickTick(0), txKickEvent(this), 1166243Sgblack@eecs.umich.edu txEvent(this), rxFilterEnable(p->rx_filter), 1176243Sgblack@eecs.umich.edu acceptBroadcast(false), acceptMulticast(false), acceptUnicast(false), 1186019Shines@cs.fsu.edu acceptPerfect(false), acceptArp(false), multicastHashEnable(false), 1196019Shines@cs.fsu.edu intrDelay(p->intr_delay), intrTick(0), cpuPendingIntr(false), 1206019Shines@cs.fsu.edu intrEvent(0), interface(0) 1216019Shines@cs.fsu.edu{ 1226019Shines@cs.fsu.edu 1236019Shines@cs.fsu.edu 1246019Shines@cs.fsu.edu interface = new NSGigEInt(name() + ".int0", this); 1256019Shines@cs.fsu.edu 1266019Shines@cs.fsu.edu regsReset(); 1276019Shines@cs.fsu.edu memcpy(&rom.perfectMatch, p->hardware_address.bytes(), ETH_ADDR_LEN); 1286019Shines@cs.fsu.edu 1296019Shines@cs.fsu.edu memset(&rxDesc32, 0, sizeof(rxDesc32)); 1306019Shines@cs.fsu.edu memset(&txDesc32, 0, sizeof(txDesc32)); 1316019Shines@cs.fsu.edu memset(&rxDesc64, 0, sizeof(rxDesc64)); 1326019Shines@cs.fsu.edu memset(&txDesc64, 0, sizeof(txDesc64)); 1336019Shines@cs.fsu.edu} 1346724Sgblack@eecs.umich.edu 1356724Sgblack@eecs.umich.eduNSGigE::~NSGigE() 1366019Shines@cs.fsu.edu{ 1376019Shines@cs.fsu.edu delete interface; 1386019Shines@cs.fsu.edu} 1396019Shines@cs.fsu.edu 1406019Shines@cs.fsu.edu/** 1416252Sgblack@eecs.umich.edu * This is to write to the PCI general configuration registers 1426243Sgblack@eecs.umich.edu */ 1436243Sgblack@eecs.umich.eduTick 1446243Sgblack@eecs.umich.eduNSGigE::writeConfig(PacketPtr pkt) 1456019Shines@cs.fsu.edu{ 1466019Shines@cs.fsu.edu int offset = pkt->getAddr() & PCI_CONFIG_SIZE; 1476019Shines@cs.fsu.edu if (offset < PCI_DEVICE_SPECIFIC) 1486019Shines@cs.fsu.edu PciDevice::writeConfig(pkt); 1496019Shines@cs.fsu.edu else 1506019Shines@cs.fsu.edu panic("Device specific PCI config space not implemented!\n"); 1517356Sgblack@eecs.umich.edu 1527356Sgblack@eecs.umich.edu switch (offset) { 1537356Sgblack@eecs.umich.edu // seems to work fine without all these PCI settings, but i 1547356Sgblack@eecs.umich.edu // put in the IO to double check, an assertion will fail if we 1557356Sgblack@eecs.umich.edu // need to properly implement it 1567356Sgblack@eecs.umich.edu case PCI_COMMAND: 1577356Sgblack@eecs.umich.edu if (config.data[offset] & PCI_CMD_IOSE) 1587356Sgblack@eecs.umich.edu ioEnable = true; 1597178Sgblack@eecs.umich.edu else 1607178Sgblack@eecs.umich.edu ioEnable = false; 1617178Sgblack@eecs.umich.edu break; 1627337Sgblack@eecs.umich.edu } 1637178Sgblack@eecs.umich.edu 1647178Sgblack@eecs.umich.edu return configDelay; 1657178Sgblack@eecs.umich.edu} 1667178Sgblack@eecs.umich.edu 1677178Sgblack@eecs.umich.eduEtherInt* 1687178Sgblack@eecs.umich.eduNSGigE::getEthPort(const std::string &if_name, int idx) 1697178Sgblack@eecs.umich.edu{ 1707178Sgblack@eecs.umich.edu if (if_name == "interface") { 1717178Sgblack@eecs.umich.edu if (interface->getPeer()) 1727178Sgblack@eecs.umich.edu panic("interface already connected to\n"); 1737178Sgblack@eecs.umich.edu return interface; 1747335Sgblack@eecs.umich.edu } 1757335Sgblack@eecs.umich.edu return NULL; 1767335Sgblack@eecs.umich.edu} 1777335Sgblack@eecs.umich.edu 1787335Sgblack@eecs.umich.edu/** 1797335Sgblack@eecs.umich.edu * This reads the device registers, which are detailed in the NS83820 1807335Sgblack@eecs.umich.edu * spec sheet 1817335Sgblack@eecs.umich.edu */ 1827335Sgblack@eecs.umich.eduTick 1837335Sgblack@eecs.umich.eduNSGigE::read(PacketPtr pkt) 1847335Sgblack@eecs.umich.edu{ 1857335Sgblack@eecs.umich.edu assert(ioEnable); 1867337Sgblack@eecs.umich.edu 1877335Sgblack@eecs.umich.edu pkt->allocate(); 1887335Sgblack@eecs.umich.edu 1897335Sgblack@eecs.umich.edu //The mask is to give you only the offset into the device register file 1907335Sgblack@eecs.umich.edu Addr daddr = pkt->getAddr() & 0xfff; 1917335Sgblack@eecs.umich.edu DPRINTF(EthernetPIO, "read da=%#x pa=%#x size=%d\n", 1927335Sgblack@eecs.umich.edu daddr, pkt->getAddr(), pkt->getSize()); 1937335Sgblack@eecs.umich.edu 1947335Sgblack@eecs.umich.edu 1957335Sgblack@eecs.umich.edu // there are some reserved registers, you can see ns_gige_reg.h and 1967335Sgblack@eecs.umich.edu // the spec sheet for details 1977335Sgblack@eecs.umich.edu if (daddr > LAST && daddr <= RESERVED) { 1987335Sgblack@eecs.umich.edu panic("Accessing reserved register"); 1997178Sgblack@eecs.umich.edu } else if (daddr > RESERVED && daddr <= 0x3FC) { 2007178Sgblack@eecs.umich.edu return readConfig(pkt); 2017178Sgblack@eecs.umich.edu } else if (daddr >= MIB_START && daddr <= MIB_END) { 2027178Sgblack@eecs.umich.edu // don't implement all the MIB's. hopefully the kernel 2037178Sgblack@eecs.umich.edu // doesn't actually DEPEND upon their values 2047178Sgblack@eecs.umich.edu // MIB are just hardware stats keepers 2057178Sgblack@eecs.umich.edu pkt->set<uint32_t>(0); 2067178Sgblack@eecs.umich.edu pkt->makeAtomicResponse(); 2077178Sgblack@eecs.umich.edu return pioDelay; 2087178Sgblack@eecs.umich.edu } else if (daddr > 0x3FC) 2097178Sgblack@eecs.umich.edu panic("Something is messed up!\n"); 2107178Sgblack@eecs.umich.edu 2117178Sgblack@eecs.umich.edu assert(pkt->getSize() == sizeof(uint32_t)); 2127178Sgblack@eecs.umich.edu uint32_t ® = *pkt->getPtr<uint32_t>(); 2137178Sgblack@eecs.umich.edu uint16_t rfaddr; 2147178Sgblack@eecs.umich.edu 2157178Sgblack@eecs.umich.edu switch (daddr) { 2167178Sgblack@eecs.umich.edu case CR: 2177178Sgblack@eecs.umich.edu reg = regs.command; 2187178Sgblack@eecs.umich.edu //these are supposed to be cleared on a read 2197178Sgblack@eecs.umich.edu reg &= ~(CR_RXD | CR_TXD | CR_TXR | CR_RXR); 2207178Sgblack@eecs.umich.edu break; 2217178Sgblack@eecs.umich.edu 2227178Sgblack@eecs.umich.edu case CFGR: 2237178Sgblack@eecs.umich.edu reg = regs.config; 2247178Sgblack@eecs.umich.edu break; 2257178Sgblack@eecs.umich.edu 2267178Sgblack@eecs.umich.edu case MEAR: 2277178Sgblack@eecs.umich.edu reg = regs.mear; 2287346Sgblack@eecs.umich.edu break; 2297346Sgblack@eecs.umich.edu 2307346Sgblack@eecs.umich.edu case PTSCR: 2317346Sgblack@eecs.umich.edu reg = regs.ptscr; 2327346Sgblack@eecs.umich.edu break; 2337346Sgblack@eecs.umich.edu 2347346Sgblack@eecs.umich.edu case ISR: 2357346Sgblack@eecs.umich.edu reg = regs.isr; 2367346Sgblack@eecs.umich.edu devIntrClear(ISR_ALL); 2377346Sgblack@eecs.umich.edu break; 2387178Sgblack@eecs.umich.edu 2397346Sgblack@eecs.umich.edu case IMR: 2407346Sgblack@eecs.umich.edu reg = regs.imr; 2417346Sgblack@eecs.umich.edu break; 2427346Sgblack@eecs.umich.edu 2437346Sgblack@eecs.umich.edu case IER: 2447346Sgblack@eecs.umich.edu reg = regs.ier; 2457346Sgblack@eecs.umich.edu break; 2467346Sgblack@eecs.umich.edu 2477346Sgblack@eecs.umich.edu case IHR: 2487346Sgblack@eecs.umich.edu reg = regs.ihr; 2497346Sgblack@eecs.umich.edu break; 2507346Sgblack@eecs.umich.edu 2517346Sgblack@eecs.umich.edu case TXDP: 2527346Sgblack@eecs.umich.edu reg = regs.txdp; 2537346Sgblack@eecs.umich.edu break; 2547178Sgblack@eecs.umich.edu 2557337Sgblack@eecs.umich.edu case TXDP_HI: 2567337Sgblack@eecs.umich.edu reg = regs.txdp_hi; 2577337Sgblack@eecs.umich.edu break; 2587337Sgblack@eecs.umich.edu 2597337Sgblack@eecs.umich.edu case TX_CFG: 2607337Sgblack@eecs.umich.edu reg = regs.txcfg; 2617337Sgblack@eecs.umich.edu break; 2627337Sgblack@eecs.umich.edu 2637337Sgblack@eecs.umich.edu case GPIOR: 2647337Sgblack@eecs.umich.edu reg = regs.gpior; 2657337Sgblack@eecs.umich.edu break; 2667337Sgblack@eecs.umich.edu 2677337Sgblack@eecs.umich.edu case RXDP: 2687337Sgblack@eecs.umich.edu reg = regs.rxdp; 2697337Sgblack@eecs.umich.edu break; 2707178Sgblack@eecs.umich.edu 2717178Sgblack@eecs.umich.edu case RXDP_HI: 2727178Sgblack@eecs.umich.edu reg = regs.rxdp_hi; 2737178Sgblack@eecs.umich.edu break; 2747337Sgblack@eecs.umich.edu 2757337Sgblack@eecs.umich.edu case RX_CFG: 2767337Sgblack@eecs.umich.edu reg = regs.rxcfg; 2777337Sgblack@eecs.umich.edu break; 2787346Sgblack@eecs.umich.edu 2797346Sgblack@eecs.umich.edu case PQCR: 2807346Sgblack@eecs.umich.edu reg = regs.pqcr; 2817346Sgblack@eecs.umich.edu break; 2827346Sgblack@eecs.umich.edu 2837337Sgblack@eecs.umich.edu case WCSR: 2847178Sgblack@eecs.umich.edu reg = regs.wcsr; 2857321Sgblack@eecs.umich.edu break; 2867356Sgblack@eecs.umich.edu 2877321Sgblack@eecs.umich.edu case PCR: 2887356Sgblack@eecs.umich.edu reg = regs.pcr; 2897356Sgblack@eecs.umich.edu break; 2907356Sgblack@eecs.umich.edu 2917356Sgblack@eecs.umich.edu // see the spec sheet for how RFCR and RFDR work 2927356Sgblack@eecs.umich.edu // basically, you write to RFCR to tell the machine 2937356Sgblack@eecs.umich.edu // what you want to do next, then you act upon RFDR, 2947356Sgblack@eecs.umich.edu // and the device will be prepared b/c of what you 2957356Sgblack@eecs.umich.edu // wrote to RFCR 2967356Sgblack@eecs.umich.edu case RFCR: 2977356Sgblack@eecs.umich.edu reg = regs.rfcr; 2987356Sgblack@eecs.umich.edu break; 2997356Sgblack@eecs.umich.edu 3007321Sgblack@eecs.umich.edu case RFDR: 3017321Sgblack@eecs.umich.edu rfaddr = (uint16_t)(regs.rfcr & RFCR_RFADDR); 3027321Sgblack@eecs.umich.edu switch (rfaddr) { 3037321Sgblack@eecs.umich.edu // Read from perfect match ROM octets 3047321Sgblack@eecs.umich.edu case 0x000: 3057321Sgblack@eecs.umich.edu reg = rom.perfectMatch[1]; 3067321Sgblack@eecs.umich.edu reg = reg << 8; 3077321Sgblack@eecs.umich.edu reg += rom.perfectMatch[0]; 3087321Sgblack@eecs.umich.edu break; 3097321Sgblack@eecs.umich.edu case 0x002: 3107321Sgblack@eecs.umich.edu reg = rom.perfectMatch[3] << 8; 3117335Sgblack@eecs.umich.edu reg += rom.perfectMatch[2]; 3127335Sgblack@eecs.umich.edu break; 3137335Sgblack@eecs.umich.edu case 0x004: 3147335Sgblack@eecs.umich.edu reg = rom.perfectMatch[5] << 8; 3157335Sgblack@eecs.umich.edu reg += rom.perfectMatch[4]; 3167335Sgblack@eecs.umich.edu break; 3177335Sgblack@eecs.umich.edu default: 3187335Sgblack@eecs.umich.edu // Read filter hash table 3197335Sgblack@eecs.umich.edu if (rfaddr >= FHASH_ADDR && 3207321Sgblack@eecs.umich.edu rfaddr < FHASH_ADDR + FHASH_SIZE) { 3217323Sgblack@eecs.umich.edu 3227323Sgblack@eecs.umich.edu // Only word-aligned reads supported 3237323Sgblack@eecs.umich.edu if (rfaddr % 2) 3247323Sgblack@eecs.umich.edu panic("unaligned read from filter hash table!"); 3257323Sgblack@eecs.umich.edu 3267323Sgblack@eecs.umich.edu reg = rom.filterHash[rfaddr - FHASH_ADDR + 1] << 8; 3277323Sgblack@eecs.umich.edu reg += rom.filterHash[rfaddr - FHASH_ADDR]; 3287323Sgblack@eecs.umich.edu break; 3297323Sgblack@eecs.umich.edu } 3307323Sgblack@eecs.umich.edu 3317323Sgblack@eecs.umich.edu panic("reading RFDR for something other than pattern" 3327323Sgblack@eecs.umich.edu " matching or hashing! %#x\n", rfaddr); 3337323Sgblack@eecs.umich.edu } 3347323Sgblack@eecs.umich.edu break; 3357323Sgblack@eecs.umich.edu 3367323Sgblack@eecs.umich.edu case SRR: 3377323Sgblack@eecs.umich.edu reg = regs.srr; 3387321Sgblack@eecs.umich.edu break; 3397321Sgblack@eecs.umich.edu 3407321Sgblack@eecs.umich.edu case MIBC: 3417335Sgblack@eecs.umich.edu reg = regs.mibc; 3427335Sgblack@eecs.umich.edu reg &= ~(MIBC_MIBS | MIBC_ACLR); 3437335Sgblack@eecs.umich.edu break; 3447335Sgblack@eecs.umich.edu 3457335Sgblack@eecs.umich.edu case VRCR: 3467335Sgblack@eecs.umich.edu reg = regs.vrcr; 3477335Sgblack@eecs.umich.edu break; 3487335Sgblack@eecs.umich.edu 3497335Sgblack@eecs.umich.edu case VTCR: 3507335Sgblack@eecs.umich.edu reg = regs.vtcr; 3517335Sgblack@eecs.umich.edu break; 3527335Sgblack@eecs.umich.edu 3537335Sgblack@eecs.umich.edu case VDR: 3547335Sgblack@eecs.umich.edu reg = regs.vdr; 3557335Sgblack@eecs.umich.edu break; 3567335Sgblack@eecs.umich.edu 3577335Sgblack@eecs.umich.edu case CCSR: 3587335Sgblack@eecs.umich.edu reg = regs.ccsr; 3597335Sgblack@eecs.umich.edu break; 3607335Sgblack@eecs.umich.edu 3617335Sgblack@eecs.umich.edu case TBICR: 3627335Sgblack@eecs.umich.edu reg = regs.tbicr; 3637335Sgblack@eecs.umich.edu break; 3647335Sgblack@eecs.umich.edu 3657335Sgblack@eecs.umich.edu case TBISR: 3667335Sgblack@eecs.umich.edu reg = regs.tbisr; 3677335Sgblack@eecs.umich.edu break; 3687335Sgblack@eecs.umich.edu 3697335Sgblack@eecs.umich.edu case TANAR: 3707335Sgblack@eecs.umich.edu reg = regs.tanar; 3717335Sgblack@eecs.umich.edu break; 3727335Sgblack@eecs.umich.edu 3737335Sgblack@eecs.umich.edu case TANLPAR: 3747321Sgblack@eecs.umich.edu reg = regs.tanlpar; 3757321Sgblack@eecs.umich.edu break; 3767321Sgblack@eecs.umich.edu 3777321Sgblack@eecs.umich.edu case TANER: 3787321Sgblack@eecs.umich.edu reg = regs.taner; 3797321Sgblack@eecs.umich.edu break; 3807335Sgblack@eecs.umich.edu 3817335Sgblack@eecs.umich.edu case TESR: 3827335Sgblack@eecs.umich.edu reg = regs.tesr; 3837335Sgblack@eecs.umich.edu break; 3847335Sgblack@eecs.umich.edu 3857335Sgblack@eecs.umich.edu case M5REG: 3867335Sgblack@eecs.umich.edu reg = 0; 3877335Sgblack@eecs.umich.edu if (params()->rx_thread) 3887335Sgblack@eecs.umich.edu reg |= M5REG_RX_THREAD; 3897321Sgblack@eecs.umich.edu if (params()->tx_thread) 3907326Sgblack@eecs.umich.edu reg |= M5REG_TX_THREAD; 3917326Sgblack@eecs.umich.edu if (params()->rss) 3927326Sgblack@eecs.umich.edu reg |= M5REG_RSS; 3937326Sgblack@eecs.umich.edu break; 3947326Sgblack@eecs.umich.edu 3957326Sgblack@eecs.umich.edu default: 3967326Sgblack@eecs.umich.edu panic("reading unimplemented register: addr=%#x", daddr); 3977326Sgblack@eecs.umich.edu } 3987326Sgblack@eecs.umich.edu 3997326Sgblack@eecs.umich.edu DPRINTF(EthernetPIO, "read from %#x: data=%d data=%#x\n", 4007326Sgblack@eecs.umich.edu daddr, reg, reg); 4017326Sgblack@eecs.umich.edu 4027326Sgblack@eecs.umich.edu pkt->makeAtomicResponse(); 4037326Sgblack@eecs.umich.edu return pioDelay; 4047326Sgblack@eecs.umich.edu} 4057326Sgblack@eecs.umich.edu 4067326Sgblack@eecs.umich.eduTick 4077326Sgblack@eecs.umich.eduNSGigE::write(PacketPtr pkt) 4087326Sgblack@eecs.umich.edu{ 4097326Sgblack@eecs.umich.edu assert(ioEnable); 4107326Sgblack@eecs.umich.edu 4117326Sgblack@eecs.umich.edu Addr daddr = pkt->getAddr() & 0xfff; 4127326Sgblack@eecs.umich.edu DPRINTF(EthernetPIO, "write da=%#x pa=%#x size=%d\n", 4137321Sgblack@eecs.umich.edu daddr, pkt->getAddr(), pkt->getSize()); 4147321Sgblack@eecs.umich.edu 4157335Sgblack@eecs.umich.edu if (daddr > LAST && daddr <= RESERVED) { 4167335Sgblack@eecs.umich.edu panic("Accessing reserved register"); 4177335Sgblack@eecs.umich.edu } else if (daddr > RESERVED && daddr <= 0x3FC) { 4187335Sgblack@eecs.umich.edu return writeConfig(pkt); 4197335Sgblack@eecs.umich.edu } else if (daddr > 0x3FC) 4207335Sgblack@eecs.umich.edu panic("Something is messed up!\n"); 4217335Sgblack@eecs.umich.edu 4227335Sgblack@eecs.umich.edu if (pkt->getSize() == sizeof(uint32_t)) { 4237335Sgblack@eecs.umich.edu uint32_t reg = pkt->get<uint32_t>(); 4247335Sgblack@eecs.umich.edu uint16_t rfaddr; 4257335Sgblack@eecs.umich.edu 4267335Sgblack@eecs.umich.edu DPRINTF(EthernetPIO, "write data=%d data=%#x\n", reg, reg); 4277335Sgblack@eecs.umich.edu 4287335Sgblack@eecs.umich.edu switch (daddr) { 4297335Sgblack@eecs.umich.edu case CR: 4307335Sgblack@eecs.umich.edu regs.command = reg; 4317335Sgblack@eecs.umich.edu if (reg & CR_TXD) { 4327335Sgblack@eecs.umich.edu txEnable = false; 4337335Sgblack@eecs.umich.edu } else if (reg & CR_TXE) { 4347335Sgblack@eecs.umich.edu txEnable = true; 4357335Sgblack@eecs.umich.edu 4367335Sgblack@eecs.umich.edu // the kernel is enabling the transmit machine 4377335Sgblack@eecs.umich.edu if (txState == txIdle) 4387335Sgblack@eecs.umich.edu txKick(); 4397335Sgblack@eecs.umich.edu } 4407335Sgblack@eecs.umich.edu 4417335Sgblack@eecs.umich.edu if (reg & CR_RXD) { 4427335Sgblack@eecs.umich.edu rxEnable = false; 4437335Sgblack@eecs.umich.edu } else if (reg & CR_RXE) { 4447335Sgblack@eecs.umich.edu rxEnable = true; 4457335Sgblack@eecs.umich.edu 4467335Sgblack@eecs.umich.edu if (rxState == rxIdle) 4477335Sgblack@eecs.umich.edu rxKick(); 4487335Sgblack@eecs.umich.edu } 4497335Sgblack@eecs.umich.edu 4507335Sgblack@eecs.umich.edu if (reg & CR_TXR) 4517335Sgblack@eecs.umich.edu txReset(); 4527335Sgblack@eecs.umich.edu 4537335Sgblack@eecs.umich.edu if (reg & CR_RXR) 4547335Sgblack@eecs.umich.edu rxReset(); 4557335Sgblack@eecs.umich.edu 4567335Sgblack@eecs.umich.edu if (reg & CR_SWI) 4577335Sgblack@eecs.umich.edu devIntrPost(ISR_SWI); 4587335Sgblack@eecs.umich.edu 4597321Sgblack@eecs.umich.edu if (reg & CR_RST) { 4607321Sgblack@eecs.umich.edu txReset(); 4617321Sgblack@eecs.umich.edu rxReset(); 4627321Sgblack@eecs.umich.edu 4637321Sgblack@eecs.umich.edu regsReset(); 4647356Sgblack@eecs.umich.edu } 4657356Sgblack@eecs.umich.edu break; 4667356Sgblack@eecs.umich.edu 4677356Sgblack@eecs.umich.edu case CFGR: 4687356Sgblack@eecs.umich.edu if (reg & CFGR_LNKSTS || 4697356Sgblack@eecs.umich.edu reg & CFGR_SPDSTS || 4707363Sgblack@eecs.umich.edu reg & CFGR_DUPSTS || 4717363Sgblack@eecs.umich.edu reg & CFGR_RESERVED || 4727363Sgblack@eecs.umich.edu reg & CFGR_T64ADDR || 4737363Sgblack@eecs.umich.edu reg & CFGR_PCI64_DET) { 4747363Sgblack@eecs.umich.edu // First clear all writable bits 4757363Sgblack@eecs.umich.edu regs.config &= CFGR_LNKSTS | CFGR_SPDSTS | CFGR_DUPSTS | 4767363Sgblack@eecs.umich.edu CFGR_RESERVED | CFGR_T64ADDR | 4777363Sgblack@eecs.umich.edu CFGR_PCI64_DET; 4787363Sgblack@eecs.umich.edu // Now set the appropriate writable bits 4797363Sgblack@eecs.umich.edu regs.config |= reg & ~(CFGR_LNKSTS | CFGR_SPDSTS | CFGR_DUPSTS | 4807363Sgblack@eecs.umich.edu CFGR_RESERVED | CFGR_T64ADDR | 4817363Sgblack@eecs.umich.edu CFGR_PCI64_DET); 4827363Sgblack@eecs.umich.edu } 4837363Sgblack@eecs.umich.edu 4847372Sgblack@eecs.umich.edu// all these #if 0's are because i don't THINK the kernel needs to 4857372Sgblack@eecs.umich.edu// have these implemented. if there is a problem relating to one of 4867372Sgblack@eecs.umich.edu// these, you may need to add functionality in. 4877372Sgblack@eecs.umich.edu 4887372Sgblack@eecs.umich.edu// grouped together and #if 0'ed to avoid empty if body and make clang happy 4897372Sgblack@eecs.umich.edu#if 0 4907372Sgblack@eecs.umich.edu if (reg & CFGR_TBI_EN) ; 4917372Sgblack@eecs.umich.edu if (reg & CFGR_MODE_1000) ; 4927372Sgblack@eecs.umich.edu 4937372Sgblack@eecs.umich.edu if (reg & CFGR_PINT_DUPSTS || 4947372Sgblack@eecs.umich.edu reg & CFGR_PINT_LNKSTS || 4957372Sgblack@eecs.umich.edu reg & CFGR_PINT_SPDSTS) 4967372Sgblack@eecs.umich.edu ; 4977372Sgblack@eecs.umich.edu 4987372Sgblack@eecs.umich.edu if (reg & CFGR_TMRTEST) ; 4997372Sgblack@eecs.umich.edu if (reg & CFGR_MRM_DIS) ; 5007372Sgblack@eecs.umich.edu if (reg & CFGR_MWI_DIS) ; 5017372Sgblack@eecs.umich.edu 5027372Sgblack@eecs.umich.edu if (reg & CFGR_DATA64_EN) ; 5037363Sgblack@eecs.umich.edu if (reg & CFGR_M64ADDR) ; 5047363Sgblack@eecs.umich.edu if (reg & CFGR_PHY_RST) ; 5057370Sgblack@eecs.umich.edu if (reg & CFGR_PHY_DIS) ; 5067372Sgblack@eecs.umich.edu 5077376Sgblack@eecs.umich.edu if (reg & CFGR_REQALG) ; 5087376Sgblack@eecs.umich.edu if (reg & CFGR_SB) ; 5097370Sgblack@eecs.umich.edu if (reg & CFGR_POW) ; 5107376Sgblack@eecs.umich.edu if (reg & CFGR_EXD) ; 5117376Sgblack@eecs.umich.edu if (reg & CFGR_PESEL) ; 5127370Sgblack@eecs.umich.edu if (reg & CFGR_BROM_DIS) ; 5137370Sgblack@eecs.umich.edu if (reg & CFGR_EXT_125) ; 5147372Sgblack@eecs.umich.edu if (reg & CFGR_BEM) ; 5157376Sgblack@eecs.umich.edu 5167376Sgblack@eecs.umich.edu if (reg & CFGR_T64ADDR) ; 5177370Sgblack@eecs.umich.edu // panic("CFGR_T64ADDR is read only register!\n"); 5187376Sgblack@eecs.umich.edu#endif 5197376Sgblack@eecs.umich.edu if (reg & CFGR_AUTO_1000) 5207370Sgblack@eecs.umich.edu panic("CFGR_AUTO_1000 not implemented!\n"); 5217370Sgblack@eecs.umich.edu 5227371Sgblack@eecs.umich.edu if (reg & CFGR_PCI64_DET) 5237371Sgblack@eecs.umich.edu panic("CFGR_PCI64_DET is read only register!\n"); 5247372Sgblack@eecs.umich.edu 5257376Sgblack@eecs.umich.edu if (reg & CFGR_EXTSTS_EN) 5267376Sgblack@eecs.umich.edu extstsEnable = true; 5277371Sgblack@eecs.umich.edu else 5287376Sgblack@eecs.umich.edu extstsEnable = false; 5297376Sgblack@eecs.umich.edu break; 5307371Sgblack@eecs.umich.edu 5317371Sgblack@eecs.umich.edu case MEAR: 5327372Sgblack@eecs.umich.edu // Clear writable bits 5337376Sgblack@eecs.umich.edu regs.mear &= MEAR_EEDO; 5347376Sgblack@eecs.umich.edu // Set appropriate writable bits 5357371Sgblack@eecs.umich.edu regs.mear |= reg & ~MEAR_EEDO; 5367376Sgblack@eecs.umich.edu 5377376Sgblack@eecs.umich.edu // FreeBSD uses the EEPROM to read PMATCH (for the MAC address) 5387371Sgblack@eecs.umich.edu // even though it could get it through RFDR 5397371Sgblack@eecs.umich.edu if (reg & MEAR_EESEL) { 5407363Sgblack@eecs.umich.edu // Rising edge of clock 5417363Sgblack@eecs.umich.edu if (reg & MEAR_EECLK && !eepromClk) 5427372Sgblack@eecs.umich.edu eepromKick(); 5437376Sgblack@eecs.umich.edu } 5447376Sgblack@eecs.umich.edu else { 5457364Sgblack@eecs.umich.edu eepromState = eepromStart; 5467376Sgblack@eecs.umich.edu regs.mear &= ~MEAR_EEDI; 5477376Sgblack@eecs.umich.edu } 5487364Sgblack@eecs.umich.edu 5497371Sgblack@eecs.umich.edu eepromClk = reg & MEAR_EECLK; 5507372Sgblack@eecs.umich.edu 5517376Sgblack@eecs.umich.edu // since phy is completely faked, MEAR_MD* don't matter 5527376Sgblack@eecs.umich.edu 5537371Sgblack@eecs.umich.edu// grouped together and #if 0'ed to avoid empty if body and make clang happy 5547376Sgblack@eecs.umich.edu#if 0 5557376Sgblack@eecs.umich.edu if (reg & MEAR_MDIO) ; 5567371Sgblack@eecs.umich.edu if (reg & MEAR_MDDIR) ; 5577363Sgblack@eecs.umich.edu if (reg & MEAR_MDC) ; 5587363Sgblack@eecs.umich.edu#endif 5597363Sgblack@eecs.umich.edu break; 5607372Sgblack@eecs.umich.edu 5617376Sgblack@eecs.umich.edu case PTSCR: 5627376Sgblack@eecs.umich.edu regs.ptscr = reg & ~(PTSCR_RBIST_RDONLY); 5637367Sgblack@eecs.umich.edu // these control BISTs for various parts of chip - we 5647376Sgblack@eecs.umich.edu // don't care or do just fake that the BIST is done 5657376Sgblack@eecs.umich.edu if (reg & PTSCR_RBIST_EN) 5667367Sgblack@eecs.umich.edu regs.ptscr |= PTSCR_RBIST_DONE; 5677363Sgblack@eecs.umich.edu if (reg & PTSCR_EEBIST_EN) 5687372Sgblack@eecs.umich.edu regs.ptscr &= ~PTSCR_EEBIST_EN; 5697376Sgblack@eecs.umich.edu if (reg & PTSCR_EELOAD_EN) 5707376Sgblack@eecs.umich.edu regs.ptscr &= ~PTSCR_EELOAD_EN; 5717368Sgblack@eecs.umich.edu break; 5727376Sgblack@eecs.umich.edu 5737376Sgblack@eecs.umich.edu case ISR: /* writing to the ISR has no effect */ 5747368Sgblack@eecs.umich.edu panic("ISR is a read only register!\n"); 5757363Sgblack@eecs.umich.edu 5767363Sgblack@eecs.umich.edu case IMR: 5777363Sgblack@eecs.umich.edu regs.imr = reg; 5787372Sgblack@eecs.umich.edu devIntrChangeMask(); 5797376Sgblack@eecs.umich.edu break; 5807376Sgblack@eecs.umich.edu 5817369Sgblack@eecs.umich.edu case IER: 5827376Sgblack@eecs.umich.edu regs.ier = reg; 5837376Sgblack@eecs.umich.edu break; 5847369Sgblack@eecs.umich.edu 5857363Sgblack@eecs.umich.edu case IHR: 5867363Sgblack@eecs.umich.edu regs.ihr = reg; 5877363Sgblack@eecs.umich.edu /* not going to implement real interrupt holdoff */ 5887363Sgblack@eecs.umich.edu break; 5897363Sgblack@eecs.umich.edu 5907363Sgblack@eecs.umich.edu case TXDP: 5917372Sgblack@eecs.umich.edu regs.txdp = (reg & 0xFFFFFFFC); 5927363Sgblack@eecs.umich.edu assert(txState == txIdle); 5937376Sgblack@eecs.umich.edu CTDD = false; 5947376Sgblack@eecs.umich.edu break; 5957363Sgblack@eecs.umich.edu 5967363Sgblack@eecs.umich.edu case TXDP_HI: 5977376Sgblack@eecs.umich.edu regs.txdp_hi = reg; 5987376Sgblack@eecs.umich.edu break; 5997363Sgblack@eecs.umich.edu 6007363Sgblack@eecs.umich.edu case TX_CFG: 6017363Sgblack@eecs.umich.edu regs.txcfg = reg; 6027363Sgblack@eecs.umich.edu#if 0 6037363Sgblack@eecs.umich.edu if (reg & TX_CFG_CSI) ; 6047372Sgblack@eecs.umich.edu if (reg & TX_CFG_HBI) ; 6057376Sgblack@eecs.umich.edu if (reg & TX_CFG_MLB) ; 6067376Sgblack@eecs.umich.edu if (reg & TX_CFG_ATP) ; 6077363Sgblack@eecs.umich.edu if (reg & TX_CFG_ECRETRY) { 6087376Sgblack@eecs.umich.edu /* 6097376Sgblack@eecs.umich.edu * this could easily be implemented, but considering 6107363Sgblack@eecs.umich.edu * the network is just a fake pipe, wouldn't make 6117363Sgblack@eecs.umich.edu * sense to do this 6127372Sgblack@eecs.umich.edu */ 6137376Sgblack@eecs.umich.edu } 6147376Sgblack@eecs.umich.edu 6157366Sgblack@eecs.umich.edu if (reg & TX_CFG_BRST_DIS) ; 6167376Sgblack@eecs.umich.edu#endif 6177376Sgblack@eecs.umich.edu 6187366Sgblack@eecs.umich.edu#if 0 6197363Sgblack@eecs.umich.edu /* we handle our own DMA, ignore the kernel's exhortations */ 6207363Sgblack@eecs.umich.edu if (reg & TX_CFG_MXDMA) ; 6217363Sgblack@eecs.umich.edu#endif 6227372Sgblack@eecs.umich.edu 6237376Sgblack@eecs.umich.edu // also, we currently don't care about fill/drain 6247376Sgblack@eecs.umich.edu // thresholds though this may change in the future with 6257365Sgblack@eecs.umich.edu // more realistic networks or a driver which changes it 6267376Sgblack@eecs.umich.edu // according to feedback 6277376Sgblack@eecs.umich.edu 6287365Sgblack@eecs.umich.edu break; 6297363Sgblack@eecs.umich.edu 6307372Sgblack@eecs.umich.edu case GPIOR: 6317376Sgblack@eecs.umich.edu // Only write writable bits 6327376Sgblack@eecs.umich.edu regs.gpior &= GPIOR_UNUSED | GPIOR_GP5_IN | GPIOR_GP4_IN 6337369Sgblack@eecs.umich.edu | GPIOR_GP3_IN | GPIOR_GP2_IN | GPIOR_GP1_IN; 6347376Sgblack@eecs.umich.edu regs.gpior |= reg & ~(GPIOR_UNUSED | GPIOR_GP5_IN | GPIOR_GP4_IN 6357376Sgblack@eecs.umich.edu | GPIOR_GP3_IN | GPIOR_GP2_IN | GPIOR_GP1_IN); 6367369Sgblack@eecs.umich.edu /* these just control general purpose i/o pins, don't matter */ 6377363Sgblack@eecs.umich.edu break; 6387363Sgblack@eecs.umich.edu 6397363Sgblack@eecs.umich.edu case RXDP: 6407363Sgblack@eecs.umich.edu regs.rxdp = reg; 6417363Sgblack@eecs.umich.edu CRDD = false; 6427363Sgblack@eecs.umich.edu break; 6437377Sgblack@eecs.umich.edu 6447377Sgblack@eecs.umich.edu case RXDP_HI: 6457377Sgblack@eecs.umich.edu regs.rxdp_hi = reg; 6467377Sgblack@eecs.umich.edu break; 6477377Sgblack@eecs.umich.edu 6487363Sgblack@eecs.umich.edu case RX_CFG: 6497377Sgblack@eecs.umich.edu regs.rxcfg = reg; 6507377Sgblack@eecs.umich.edu#if 0 6517377Sgblack@eecs.umich.edu if (reg & RX_CFG_AEP) ; 6527377Sgblack@eecs.umich.edu if (reg & RX_CFG_ARP) ; 6537377Sgblack@eecs.umich.edu if (reg & RX_CFG_STRIPCRC) ; 6547363Sgblack@eecs.umich.edu if (reg & RX_CFG_RX_RD) ; 6557363Sgblack@eecs.umich.edu if (reg & RX_CFG_ALP) ; 6567374Sgblack@eecs.umich.edu if (reg & RX_CFG_AIRL) ; 6577374Sgblack@eecs.umich.edu 6587374Sgblack@eecs.umich.edu /* we handle our own DMA, ignore what kernel says about it */ 6597374Sgblack@eecs.umich.edu if (reg & RX_CFG_MXDMA) ; 6607374Sgblack@eecs.umich.edu 6617374Sgblack@eecs.umich.edu //also, we currently don't care about fill/drain thresholds 6627374Sgblack@eecs.umich.edu //though this may change in the future with more realistic 6637374Sgblack@eecs.umich.edu //networks or a driver which changes it according to feedback 6647374Sgblack@eecs.umich.edu if (reg & (RX_CFG_DRTH | RX_CFG_DRTH0)) ; 6657363Sgblack@eecs.umich.edu#endif 6667363Sgblack@eecs.umich.edu break; 6677363Sgblack@eecs.umich.edu 6687373Sgblack@eecs.umich.edu case PQCR: 6697373Sgblack@eecs.umich.edu /* there is no priority queueing used in the linux 2.6 driver */ 6707373Sgblack@eecs.umich.edu regs.pqcr = reg; 6717373Sgblack@eecs.umich.edu break; 6727373Sgblack@eecs.umich.edu 6737373Sgblack@eecs.umich.edu case WCSR: 6747373Sgblack@eecs.umich.edu /* not going to implement wake on LAN */ 6757373Sgblack@eecs.umich.edu regs.wcsr = reg; 6767373Sgblack@eecs.umich.edu break; 6777373Sgblack@eecs.umich.edu 6787373Sgblack@eecs.umich.edu case PCR: 6797373Sgblack@eecs.umich.edu /* not going to implement pause control */ 6807373Sgblack@eecs.umich.edu regs.pcr = reg; 6817373Sgblack@eecs.umich.edu break; 6827373Sgblack@eecs.umich.edu 6837373Sgblack@eecs.umich.edu case RFCR: 6847373Sgblack@eecs.umich.edu regs.rfcr = reg; 6857363Sgblack@eecs.umich.edu 6867363Sgblack@eecs.umich.edu rxFilterEnable = (reg & RFCR_RFEN) ? true : false; 6877363Sgblack@eecs.umich.edu acceptBroadcast = (reg & RFCR_AAB) ? true : false; 6887363Sgblack@eecs.umich.edu acceptMulticast = (reg & RFCR_AAM) ? true : false; 6897363Sgblack@eecs.umich.edu acceptUnicast = (reg & RFCR_AAU) ? true : false; 6907373Sgblack@eecs.umich.edu acceptPerfect = (reg & RFCR_APM) ? true : false; 6917373Sgblack@eecs.umich.edu acceptArp = (reg & RFCR_AARP) ? true : false; 6927373Sgblack@eecs.umich.edu multicastHashEnable = (reg & RFCR_MHEN) ? true : false; 6937373Sgblack@eecs.umich.edu 6947373Sgblack@eecs.umich.edu#if 0 6957373Sgblack@eecs.umich.edu if (reg & RFCR_APAT) 6967373Sgblack@eecs.umich.edu panic("RFCR_APAT not implemented!\n"); 6977363Sgblack@eecs.umich.edu#endif 6987373Sgblack@eecs.umich.edu if (reg & RFCR_UHEN) 6997373Sgblack@eecs.umich.edu panic("Unicast hash filtering not used by drivers!\n"); 7007373Sgblack@eecs.umich.edu 7017373Sgblack@eecs.umich.edu if (reg & RFCR_ULM) 7027373Sgblack@eecs.umich.edu panic("RFCR_ULM not implemented!\n"); 7037373Sgblack@eecs.umich.edu 7047373Sgblack@eecs.umich.edu break; 7057363Sgblack@eecs.umich.edu 7067363Sgblack@eecs.umich.edu case RFDR: 7077363Sgblack@eecs.umich.edu rfaddr = (uint16_t)(regs.rfcr & RFCR_RFADDR); 7087363Sgblack@eecs.umich.edu switch (rfaddr) { 7097363Sgblack@eecs.umich.edu case 0x000: 7107363Sgblack@eecs.umich.edu rom.perfectMatch[0] = (uint8_t)reg; 7117363Sgblack@eecs.umich.edu rom.perfectMatch[1] = (uint8_t)(reg >> 8); 7127363Sgblack@eecs.umich.edu break; 7137363Sgblack@eecs.umich.edu case 0x002: 7147363Sgblack@eecs.umich.edu rom.perfectMatch[2] = (uint8_t)reg; 7157363Sgblack@eecs.umich.edu rom.perfectMatch[3] = (uint8_t)(reg >> 8); 7167363Sgblack@eecs.umich.edu break; 7177363Sgblack@eecs.umich.edu case 0x004: 7187363Sgblack@eecs.umich.edu rom.perfectMatch[4] = (uint8_t)reg; 7197363Sgblack@eecs.umich.edu rom.perfectMatch[5] = (uint8_t)(reg >> 8); 7207363Sgblack@eecs.umich.edu break; 7217363Sgblack@eecs.umich.edu default: 722 723 if (rfaddr >= FHASH_ADDR && 724 rfaddr < FHASH_ADDR + FHASH_SIZE) { 725 726 // Only word-aligned writes supported 727 if (rfaddr % 2) 728 panic("unaligned write to filter hash table!"); 729 730 rom.filterHash[rfaddr - FHASH_ADDR] = (uint8_t)reg; 731 rom.filterHash[rfaddr - FHASH_ADDR + 1] 732 = (uint8_t)(reg >> 8); 733 break; 734 } 735 panic("writing RFDR for something other than pattern matching " 736 "or hashing! %#x\n", rfaddr); 737 } 738 739 case BRAR: 740 regs.brar = reg; 741 break; 742 743 case BRDR: 744 panic("the driver never uses BRDR, something is wrong!\n"); 745 746 case SRR: 747 panic("SRR is read only register!\n"); 748 749 case MIBC: 750 panic("the driver never uses MIBC, something is wrong!\n"); 751 752 case VRCR: 753 regs.vrcr = reg; 754 break; 755 756 case VTCR: 757 regs.vtcr = reg; 758 break; 759 760 case VDR: 761 panic("the driver never uses VDR, something is wrong!\n"); 762 763 case CCSR: 764 /* not going to implement clockrun stuff */ 765 regs.ccsr = reg; 766 break; 767 768 case TBICR: 769 regs.tbicr = reg; 770 if (reg & TBICR_MR_LOOPBACK) 771 panic("TBICR_MR_LOOPBACK never used, something wrong!\n"); 772 773 if (reg & TBICR_MR_AN_ENABLE) { 774 regs.tanlpar = regs.tanar; 775 regs.tbisr |= (TBISR_MR_AN_COMPLETE | TBISR_MR_LINK_STATUS); 776 } 777 778#if 0 779 if (reg & TBICR_MR_RESTART_AN) ; 780#endif 781 782 break; 783 784 case TBISR: 785 panic("TBISR is read only register!\n"); 786 787 case TANAR: 788 // Only write the writable bits 789 regs.tanar &= TANAR_RF1 | TANAR_RF2 | TANAR_UNUSED; 790 regs.tanar |= reg & ~(TANAR_RF1 | TANAR_RF2 | TANAR_UNUSED); 791 792 // Pause capability unimplemented 793#if 0 794 if (reg & TANAR_PS2) ; 795 if (reg & TANAR_PS1) ; 796#endif 797 798 break; 799 800 case TANLPAR: 801 panic("this should only be written to by the fake phy!\n"); 802 803 case TANER: 804 panic("TANER is read only register!\n"); 805 806 case TESR: 807 regs.tesr = reg; 808 break; 809 810 default: 811 panic("invalid register access daddr=%#x", daddr); 812 } 813 } else { 814 panic("Invalid Request Size"); 815 } 816 pkt->makeAtomicResponse(); 817 return pioDelay; 818} 819 820void 821NSGigE::devIntrPost(uint32_t interrupts) 822{ 823 if (interrupts & ISR_RESERVE) 824 panic("Cannot set a reserved interrupt"); 825 826 if (interrupts & ISR_NOIMPL) 827 warn("interrupt not implemented %#x\n", interrupts); 828 829 interrupts &= ISR_IMPL; 830 regs.isr |= interrupts; 831 832 if (interrupts & regs.imr) { 833 if (interrupts & ISR_SWI) { 834 totalSwi++; 835 } 836 if (interrupts & ISR_RXIDLE) { 837 totalRxIdle++; 838 } 839 if (interrupts & ISR_RXOK) { 840 totalRxOk++; 841 } 842 if (interrupts & ISR_RXDESC) { 843 totalRxDesc++; 844 } 845 if (interrupts & ISR_TXOK) { 846 totalTxOk++; 847 } 848 if (interrupts & ISR_TXIDLE) { 849 totalTxIdle++; 850 } 851 if (interrupts & ISR_TXDESC) { 852 totalTxDesc++; 853 } 854 if (interrupts & ISR_RXORN) { 855 totalRxOrn++; 856 } 857 } 858 859 DPRINTF(EthernetIntr, 860 "interrupt written to ISR: intr=%#x isr=%#x imr=%#x\n", 861 interrupts, regs.isr, regs.imr); 862 863 if ((regs.isr & regs.imr)) { 864 Tick when = curTick(); 865 if ((regs.isr & regs.imr & ISR_NODELAY) == 0) 866 when += intrDelay; 867 postedInterrupts++; 868 cpuIntrPost(when); 869 } 870} 871 872/* writing this interrupt counting stats inside this means that this function 873 is now limited to being used to clear all interrupts upon the kernel 874 reading isr and servicing. just telling you in case you were thinking 875 of expanding use. 876*/ 877void 878NSGigE::devIntrClear(uint32_t interrupts) 879{ 880 if (interrupts & ISR_RESERVE) 881 panic("Cannot clear a reserved interrupt"); 882 883 if (regs.isr & regs.imr & ISR_SWI) { 884 postedSwi++; 885 } 886 if (regs.isr & regs.imr & ISR_RXIDLE) { 887 postedRxIdle++; 888 } 889 if (regs.isr & regs.imr & ISR_RXOK) { 890 postedRxOk++; 891 } 892 if (regs.isr & regs.imr & ISR_RXDESC) { 893 postedRxDesc++; 894 } 895 if (regs.isr & regs.imr & ISR_TXOK) { 896 postedTxOk++; 897 } 898 if (regs.isr & regs.imr & ISR_TXIDLE) { 899 postedTxIdle++; 900 } 901 if (regs.isr & regs.imr & ISR_TXDESC) { 902 postedTxDesc++; 903 } 904 if (regs.isr & regs.imr & ISR_RXORN) { 905 postedRxOrn++; 906 } 907 908 interrupts &= ~ISR_NOIMPL; 909 regs.isr &= ~interrupts; 910 911 DPRINTF(EthernetIntr, 912 "interrupt cleared from ISR: intr=%x isr=%x imr=%x\n", 913 interrupts, regs.isr, regs.imr); 914 915 if (!(regs.isr & regs.imr)) 916 cpuIntrClear(); 917} 918 919void 920NSGigE::devIntrChangeMask() 921{ 922 DPRINTF(EthernetIntr, "interrupt mask changed: isr=%x imr=%x masked=%x\n", 923 regs.isr, regs.imr, regs.isr & regs.imr); 924 925 if (regs.isr & regs.imr) 926 cpuIntrPost(curTick()); 927 else 928 cpuIntrClear(); 929} 930 931void 932NSGigE::cpuIntrPost(Tick when) 933{ 934 // If the interrupt you want to post is later than an interrupt 935 // already scheduled, just let it post in the coming one and don't 936 // schedule another. 937 // HOWEVER, must be sure that the scheduled intrTick is in the 938 // future (this was formerly the source of a bug) 939 /** 940 * @todo this warning should be removed and the intrTick code should 941 * be fixed. 942 */ 943 assert(when >= curTick()); 944 assert(intrTick >= curTick() || intrTick == 0); 945 if (when > intrTick && intrTick != 0) { 946 DPRINTF(EthernetIntr, "don't need to schedule event...intrTick=%d\n", 947 intrTick); 948 return; 949 } 950 951 intrTick = when; 952 if (intrTick < curTick()) { 953 Debug::breakpoint(); 954 intrTick = curTick(); 955 } 956 957 DPRINTF(EthernetIntr, "going to schedule an interrupt for intrTick=%d\n", 958 intrTick); 959 960 if (intrEvent) 961 intrEvent->squash(); 962 intrEvent = new IntrEvent(this, true); 963 schedule(intrEvent, intrTick); 964} 965 966void 967NSGigE::cpuInterrupt() 968{ 969 assert(intrTick == curTick()); 970 971 // Whether or not there's a pending interrupt, we don't care about 972 // it anymore 973 intrEvent = 0; 974 intrTick = 0; 975 976 // Don't send an interrupt if there's already one 977 if (cpuPendingIntr) { 978 DPRINTF(EthernetIntr, 979 "would send an interrupt now, but there's already pending\n"); 980 } else { 981 // Send interrupt 982 cpuPendingIntr = true; 983 984 DPRINTF(EthernetIntr, "posting interrupt\n"); 985 intrPost(); 986 } 987} 988 989void 990NSGigE::cpuIntrClear() 991{ 992 if (!cpuPendingIntr) 993 return; 994 995 if (intrEvent) { 996 intrEvent->squash(); 997 intrEvent = 0; 998 } 999 1000 intrTick = 0; 1001 1002 cpuPendingIntr = false; 1003 1004 DPRINTF(EthernetIntr, "clearing interrupt\n"); 1005 intrClear(); 1006} 1007 1008bool 1009NSGigE::cpuIntrPending() const 1010{ return cpuPendingIntr; } 1011 1012void 1013NSGigE::txReset() 1014{ 1015 1016 DPRINTF(Ethernet, "transmit reset\n"); 1017 1018 CTDD = false; 1019 txEnable = false;; 1020 txFragPtr = 0; 1021 assert(txDescCnt == 0); 1022 txFifo.clear(); 1023 txState = txIdle; 1024 assert(txDmaState == dmaIdle); 1025} 1026 1027void 1028NSGigE::rxReset() 1029{ 1030 DPRINTF(Ethernet, "receive reset\n"); 1031 1032 CRDD = false; 1033 assert(rxPktBytes == 0); 1034 rxEnable = false; 1035 rxFragPtr = 0; 1036 assert(rxDescCnt == 0); 1037 assert(rxDmaState == dmaIdle); 1038 rxFifo.clear(); 1039 rxState = rxIdle; 1040} 1041 1042void 1043NSGigE::regsReset() 1044{ 1045 memset(®s, 0, sizeof(regs)); 1046 regs.config = (CFGR_LNKSTS | CFGR_TBI_EN | CFGR_MODE_1000); 1047 regs.mear = 0x12; 1048 regs.txcfg = 0x120; // set drain threshold to 1024 bytes and 1049 // fill threshold to 32 bytes 1050 regs.rxcfg = 0x4; // set drain threshold to 16 bytes 1051 regs.srr = 0x0103; // set the silicon revision to rev B or 0x103 1052 regs.mibc = MIBC_FRZ; 1053 regs.vdr = 0x81; // set the vlan tag type to 802.1q 1054 regs.tesr = 0xc000; // TBI capable of both full and half duplex 1055 regs.brar = 0xffffffff; 1056 1057 extstsEnable = false; 1058 acceptBroadcast = false; 1059 acceptMulticast = false; 1060 acceptUnicast = false; 1061 acceptPerfect = false; 1062 acceptArp = false; 1063} 1064 1065bool 1066NSGigE::doRxDmaRead() 1067{ 1068 assert(rxDmaState == dmaIdle || rxDmaState == dmaReadWaiting); 1069 rxDmaState = dmaReading; 1070 1071 if (dmaPending() || getDrainState() != Drainable::Running) 1072 rxDmaState = dmaReadWaiting; 1073 else 1074 dmaRead(rxDmaAddr, rxDmaLen, &rxDmaReadEvent, (uint8_t*)rxDmaData); 1075 1076 return true; 1077} 1078 1079void 1080NSGigE::rxDmaReadDone() 1081{ 1082 assert(rxDmaState == dmaReading); 1083 rxDmaState = dmaIdle; 1084 1085 DPRINTF(EthernetDMA, "rx dma read paddr=%#x len=%d\n", 1086 rxDmaAddr, rxDmaLen); 1087 DDUMP(EthernetDMA, rxDmaData, rxDmaLen); 1088 1089 // If the transmit state machine has a pending DMA, let it go first 1090 if (txDmaState == dmaReadWaiting || txDmaState == dmaWriteWaiting) 1091 txKick(); 1092 1093 rxKick(); 1094} 1095 1096bool 1097NSGigE::doRxDmaWrite() 1098{ 1099 assert(rxDmaState == dmaIdle || rxDmaState == dmaWriteWaiting); 1100 rxDmaState = dmaWriting; 1101 1102 if (dmaPending() || getDrainState() != Running) 1103 rxDmaState = dmaWriteWaiting; 1104 else 1105 dmaWrite(rxDmaAddr, rxDmaLen, &rxDmaWriteEvent, (uint8_t*)rxDmaData); 1106 return true; 1107} 1108 1109void 1110NSGigE::rxDmaWriteDone() 1111{ 1112 assert(rxDmaState == dmaWriting); 1113 rxDmaState = dmaIdle; 1114 1115 DPRINTF(EthernetDMA, "rx dma write paddr=%#x len=%d\n", 1116 rxDmaAddr, rxDmaLen); 1117 DDUMP(EthernetDMA, rxDmaData, rxDmaLen); 1118 1119 // If the transmit state machine has a pending DMA, let it go first 1120 if (txDmaState == dmaReadWaiting || txDmaState == dmaWriteWaiting) 1121 txKick(); 1122 1123 rxKick(); 1124} 1125 1126void 1127NSGigE::rxKick() 1128{ 1129 bool is64bit = (bool)(regs.config & CFGR_M64ADDR); 1130 1131 DPRINTF(EthernetSM, 1132 "receive kick rxState=%s (rxBuf.size=%d) %d-bit\n", 1133 NsRxStateStrings[rxState], rxFifo.size(), is64bit ? 64 : 32); 1134 1135 Addr link, bufptr; 1136 uint32_t &cmdsts = is64bit ? rxDesc64.cmdsts : rxDesc32.cmdsts; 1137 uint32_t &extsts = is64bit ? rxDesc64.extsts : rxDesc32.extsts; 1138 1139 next: 1140 if (rxKickTick > curTick()) { 1141 DPRINTF(EthernetSM, "receive kick exiting, can't run till %d\n", 1142 rxKickTick); 1143 1144 goto exit; 1145 } 1146 1147 // Go to the next state machine clock tick. 1148 rxKickTick = clockEdge(Cycles(1)); 1149 1150 switch(rxDmaState) { 1151 case dmaReadWaiting: 1152 if (doRxDmaRead()) 1153 goto exit; 1154 break; 1155 case dmaWriteWaiting: 1156 if (doRxDmaWrite()) 1157 goto exit; 1158 break; 1159 default: 1160 break; 1161 } 1162 1163 link = is64bit ? (Addr)rxDesc64.link : (Addr)rxDesc32.link; 1164 bufptr = is64bit ? (Addr)rxDesc64.bufptr : (Addr)rxDesc32.bufptr; 1165 1166 // see state machine from spec for details 1167 // the way this works is, if you finish work on one state and can 1168 // go directly to another, you do that through jumping to the 1169 // label "next". however, if you have intermediate work, like DMA 1170 // so that you can't go to the next state yet, you go to exit and 1171 // exit the loop. however, when the DMA is done it will trigger 1172 // an event and come back to this loop. 1173 switch (rxState) { 1174 case rxIdle: 1175 if (!rxEnable) { 1176 DPRINTF(EthernetSM, "Receive Disabled! Nothing to do.\n"); 1177 goto exit; 1178 } 1179 1180 if (CRDD) { 1181 rxState = rxDescRefr; 1182 1183 rxDmaAddr = regs.rxdp & 0x3fffffff; 1184 rxDmaData = 1185 is64bit ? (void *)&rxDesc64.link : (void *)&rxDesc32.link; 1186 rxDmaLen = is64bit ? sizeof(rxDesc64.link) : sizeof(rxDesc32.link); 1187 rxDmaFree = dmaDescFree; 1188 1189 descDmaReads++; 1190 descDmaRdBytes += rxDmaLen; 1191 1192 if (doRxDmaRead()) 1193 goto exit; 1194 } else { 1195 rxState = rxDescRead; 1196 1197 rxDmaAddr = regs.rxdp & 0x3fffffff; 1198 rxDmaData = is64bit ? (void *)&rxDesc64 : (void *)&rxDesc32; 1199 rxDmaLen = is64bit ? sizeof(rxDesc64) : sizeof(rxDesc32); 1200 rxDmaFree = dmaDescFree; 1201 1202 descDmaReads++; 1203 descDmaRdBytes += rxDmaLen; 1204 1205 if (doRxDmaRead()) 1206 goto exit; 1207 } 1208 break; 1209 1210 case rxDescRefr: 1211 if (rxDmaState != dmaIdle) 1212 goto exit; 1213 1214 rxState = rxAdvance; 1215 break; 1216 1217 case rxDescRead: 1218 if (rxDmaState != dmaIdle) 1219 goto exit; 1220 1221 DPRINTF(EthernetDesc, "rxDesc: addr=%08x read descriptor\n", 1222 regs.rxdp & 0x3fffffff); 1223 DPRINTF(EthernetDesc, 1224 "rxDesc: link=%#x bufptr=%#x cmdsts=%08x extsts=%08x\n", 1225 link, bufptr, cmdsts, extsts); 1226 1227 if (cmdsts & CMDSTS_OWN) { 1228 devIntrPost(ISR_RXIDLE); 1229 rxState = rxIdle; 1230 goto exit; 1231 } else { 1232 rxState = rxFifoBlock; 1233 rxFragPtr = bufptr; 1234 rxDescCnt = cmdsts & CMDSTS_LEN_MASK; 1235 } 1236 break; 1237 1238 case rxFifoBlock: 1239 if (!rxPacket) { 1240 /** 1241 * @todo in reality, we should be able to start processing 1242 * the packet as it arrives, and not have to wait for the 1243 * full packet ot be in the receive fifo. 1244 */ 1245 if (rxFifo.empty()) 1246 goto exit; 1247 1248 DPRINTF(EthernetSM, "****processing receive of new packet****\n"); 1249 1250 // If we don't have a packet, grab a new one from the fifo. 1251 rxPacket = rxFifo.front(); 1252 rxPktBytes = rxPacket->length; 1253 rxPacketBufPtr = rxPacket->data; 1254 1255#if TRACING_ON 1256 if (DTRACE(Ethernet)) { 1257 IpPtr ip(rxPacket); 1258 if (ip) { 1259 DPRINTF(Ethernet, "ID is %d\n", ip->id()); 1260 TcpPtr tcp(ip); 1261 if (tcp) { 1262 DPRINTF(Ethernet, 1263 "Src Port=%d, Dest Port=%d, Seq=%d, Ack=%d\n", 1264 tcp->sport(), tcp->dport(), tcp->seq(), 1265 tcp->ack()); 1266 } 1267 } 1268 } 1269#endif 1270 1271 // sanity check - i think the driver behaves like this 1272 assert(rxDescCnt >= rxPktBytes); 1273 rxFifo.pop(); 1274 } 1275 1276 1277 // dont' need the && rxDescCnt > 0 if driver sanity check 1278 // above holds 1279 if (rxPktBytes > 0) { 1280 rxState = rxFragWrite; 1281 // don't need min<>(rxPktBytes,rxDescCnt) if above sanity 1282 // check holds 1283 rxXferLen = rxPktBytes; 1284 1285 rxDmaAddr = rxFragPtr & 0x3fffffff; 1286 rxDmaData = rxPacketBufPtr; 1287 rxDmaLen = rxXferLen; 1288 rxDmaFree = dmaDataFree; 1289 1290 if (doRxDmaWrite()) 1291 goto exit; 1292 1293 } else { 1294 rxState = rxDescWrite; 1295 1296 //if (rxPktBytes == 0) { /* packet is done */ 1297 assert(rxPktBytes == 0); 1298 DPRINTF(EthernetSM, "done with receiving packet\n"); 1299 1300 cmdsts |= CMDSTS_OWN; 1301 cmdsts &= ~CMDSTS_MORE; 1302 cmdsts |= CMDSTS_OK; 1303 cmdsts &= 0xffff0000; 1304 cmdsts += rxPacket->length; //i.e. set CMDSTS_SIZE 1305 1306#if 0 1307 /* 1308 * all the driver uses these are for its own stats keeping 1309 * which we don't care about, aren't necessary for 1310 * functionality and doing this would just slow us down. 1311 * if they end up using this in a later version for 1312 * functional purposes, just undef 1313 */ 1314 if (rxFilterEnable) { 1315 cmdsts &= ~CMDSTS_DEST_MASK; 1316 const EthAddr &dst = rxFifoFront()->dst(); 1317 if (dst->unicast()) 1318 cmdsts |= CMDSTS_DEST_SELF; 1319 if (dst->multicast()) 1320 cmdsts |= CMDSTS_DEST_MULTI; 1321 if (dst->broadcast()) 1322 cmdsts |= CMDSTS_DEST_MASK; 1323 } 1324#endif 1325 1326 IpPtr ip(rxPacket); 1327 if (extstsEnable && ip) { 1328 extsts |= EXTSTS_IPPKT; 1329 rxIpChecksums++; 1330 if (cksum(ip) != 0) { 1331 DPRINTF(EthernetCksum, "Rx IP Checksum Error\n"); 1332 extsts |= EXTSTS_IPERR; 1333 } 1334 TcpPtr tcp(ip); 1335 UdpPtr udp(ip); 1336 if (tcp) { 1337 extsts |= EXTSTS_TCPPKT; 1338 rxTcpChecksums++; 1339 if (cksum(tcp) != 0) { 1340 DPRINTF(EthernetCksum, "Rx TCP Checksum Error\n"); 1341 extsts |= EXTSTS_TCPERR; 1342 1343 } 1344 } else if (udp) { 1345 extsts |= EXTSTS_UDPPKT; 1346 rxUdpChecksums++; 1347 if (cksum(udp) != 0) { 1348 DPRINTF(EthernetCksum, "Rx UDP Checksum Error\n"); 1349 extsts |= EXTSTS_UDPERR; 1350 } 1351 } 1352 } 1353 rxPacket = 0; 1354 1355 /* 1356 * the driver seems to always receive into desc buffers 1357 * of size 1514, so you never have a pkt that is split 1358 * into multiple descriptors on the receive side, so 1359 * i don't implement that case, hence the assert above. 1360 */ 1361 1362 DPRINTF(EthernetDesc, 1363 "rxDesc: addr=%08x writeback cmdsts extsts\n", 1364 regs.rxdp & 0x3fffffff); 1365 DPRINTF(EthernetDesc, 1366 "rxDesc: link=%#x bufptr=%#x cmdsts=%08x extsts=%08x\n", 1367 link, bufptr, cmdsts, extsts); 1368 1369 rxDmaAddr = regs.rxdp & 0x3fffffff; 1370 rxDmaData = &cmdsts; 1371 if (is64bit) { 1372 rxDmaAddr += offsetof(ns_desc64, cmdsts); 1373 rxDmaLen = sizeof(rxDesc64.cmdsts) + sizeof(rxDesc64.extsts); 1374 } else { 1375 rxDmaAddr += offsetof(ns_desc32, cmdsts); 1376 rxDmaLen = sizeof(rxDesc32.cmdsts) + sizeof(rxDesc32.extsts); 1377 } 1378 rxDmaFree = dmaDescFree; 1379 1380 descDmaWrites++; 1381 descDmaWrBytes += rxDmaLen; 1382 1383 if (doRxDmaWrite()) 1384 goto exit; 1385 } 1386 break; 1387 1388 case rxFragWrite: 1389 if (rxDmaState != dmaIdle) 1390 goto exit; 1391 1392 rxPacketBufPtr += rxXferLen; 1393 rxFragPtr += rxXferLen; 1394 rxPktBytes -= rxXferLen; 1395 1396 rxState = rxFifoBlock; 1397 break; 1398 1399 case rxDescWrite: 1400 if (rxDmaState != dmaIdle) 1401 goto exit; 1402 1403 assert(cmdsts & CMDSTS_OWN); 1404 1405 assert(rxPacket == 0); 1406 devIntrPost(ISR_RXOK); 1407 1408 if (cmdsts & CMDSTS_INTR) 1409 devIntrPost(ISR_RXDESC); 1410 1411 if (!rxEnable) { 1412 DPRINTF(EthernetSM, "Halting the RX state machine\n"); 1413 rxState = rxIdle; 1414 goto exit; 1415 } else 1416 rxState = rxAdvance; 1417 break; 1418 1419 case rxAdvance: 1420 if (link == 0) { 1421 devIntrPost(ISR_RXIDLE); 1422 rxState = rxIdle; 1423 CRDD = true; 1424 goto exit; 1425 } else { 1426 if (rxDmaState != dmaIdle) 1427 goto exit; 1428 rxState = rxDescRead; 1429 regs.rxdp = link; 1430 CRDD = false; 1431 1432 rxDmaAddr = regs.rxdp & 0x3fffffff; 1433 rxDmaData = is64bit ? (void *)&rxDesc64 : (void *)&rxDesc32; 1434 rxDmaLen = is64bit ? sizeof(rxDesc64) : sizeof(rxDesc32); 1435 rxDmaFree = dmaDescFree; 1436 1437 if (doRxDmaRead()) 1438 goto exit; 1439 } 1440 break; 1441 1442 default: 1443 panic("Invalid rxState!"); 1444 } 1445 1446 DPRINTF(EthernetSM, "entering next rxState=%s\n", 1447 NsRxStateStrings[rxState]); 1448 goto next; 1449 1450 exit: 1451 /** 1452 * @todo do we want to schedule a future kick? 1453 */ 1454 DPRINTF(EthernetSM, "rx state machine exited rxState=%s\n", 1455 NsRxStateStrings[rxState]); 1456 1457 if (!rxKickEvent.scheduled()) 1458 schedule(rxKickEvent, rxKickTick); 1459} 1460 1461void 1462NSGigE::transmit() 1463{ 1464 if (txFifo.empty()) { 1465 DPRINTF(Ethernet, "nothing to transmit\n"); 1466 return; 1467 } 1468 1469 DPRINTF(Ethernet, "Attempt Pkt Transmit: txFifo length=%d\n", 1470 txFifo.size()); 1471 if (interface->sendPacket(txFifo.front())) { 1472#if TRACING_ON 1473 if (DTRACE(Ethernet)) { 1474 IpPtr ip(txFifo.front()); 1475 if (ip) { 1476 DPRINTF(Ethernet, "ID is %d\n", ip->id()); 1477 TcpPtr tcp(ip); 1478 if (tcp) { 1479 DPRINTF(Ethernet, 1480 "Src Port=%d, Dest Port=%d, Seq=%d, Ack=%d\n", 1481 tcp->sport(), tcp->dport(), tcp->seq(), 1482 tcp->ack()); 1483 } 1484 } 1485 } 1486#endif 1487 1488 DDUMP(EthernetData, txFifo.front()->data, txFifo.front()->length); 1489 txBytes += txFifo.front()->length; 1490 txPackets++; 1491 1492 DPRINTF(Ethernet, "Successful Xmit! now txFifoAvail is %d\n", 1493 txFifo.avail()); 1494 txFifo.pop(); 1495 1496 /* 1497 * normally do a writeback of the descriptor here, and ONLY 1498 * after that is done, send this interrupt. but since our 1499 * stuff never actually fails, just do this interrupt here, 1500 * otherwise the code has to stray from this nice format. 1501 * besides, it's functionally the same. 1502 */ 1503 devIntrPost(ISR_TXOK); 1504 } 1505 1506 if (!txFifo.empty() && !txEvent.scheduled()) { 1507 DPRINTF(Ethernet, "reschedule transmit\n"); 1508 schedule(txEvent, curTick() + retryTime); 1509 } 1510} 1511 1512bool 1513NSGigE::doTxDmaRead() 1514{ 1515 assert(txDmaState == dmaIdle || txDmaState == dmaReadWaiting); 1516 txDmaState = dmaReading; 1517 1518 if (dmaPending() || getDrainState() != Running) 1519 txDmaState = dmaReadWaiting; 1520 else 1521 dmaRead(txDmaAddr, txDmaLen, &txDmaReadEvent, (uint8_t*)txDmaData); 1522 1523 return true; 1524} 1525 1526void 1527NSGigE::txDmaReadDone() 1528{ 1529 assert(txDmaState == dmaReading); 1530 txDmaState = dmaIdle; 1531 1532 DPRINTF(EthernetDMA, "tx dma read paddr=%#x len=%d\n", 1533 txDmaAddr, txDmaLen); 1534 DDUMP(EthernetDMA, txDmaData, txDmaLen); 1535 1536 // If the receive state machine has a pending DMA, let it go first 1537 if (rxDmaState == dmaReadWaiting || rxDmaState == dmaWriteWaiting) 1538 rxKick(); 1539 1540 txKick(); 1541} 1542 1543bool 1544NSGigE::doTxDmaWrite() 1545{ 1546 assert(txDmaState == dmaIdle || txDmaState == dmaWriteWaiting); 1547 txDmaState = dmaWriting; 1548 1549 if (dmaPending() || getDrainState() != Running) 1550 txDmaState = dmaWriteWaiting; 1551 else 1552 dmaWrite(txDmaAddr, txDmaLen, &txDmaWriteEvent, (uint8_t*)txDmaData); 1553 return true; 1554} 1555 1556void 1557NSGigE::txDmaWriteDone() 1558{ 1559 assert(txDmaState == dmaWriting); 1560 txDmaState = dmaIdle; 1561 1562 DPRINTF(EthernetDMA, "tx dma write paddr=%#x len=%d\n", 1563 txDmaAddr, txDmaLen); 1564 DDUMP(EthernetDMA, txDmaData, txDmaLen); 1565 1566 // If the receive state machine has a pending DMA, let it go first 1567 if (rxDmaState == dmaReadWaiting || rxDmaState == dmaWriteWaiting) 1568 rxKick(); 1569 1570 txKick(); 1571} 1572 1573void 1574NSGigE::txKick() 1575{ 1576 bool is64bit = (bool)(regs.config & CFGR_M64ADDR); 1577 1578 DPRINTF(EthernetSM, "transmit kick txState=%s %d-bit\n", 1579 NsTxStateStrings[txState], is64bit ? 64 : 32); 1580 1581 Addr link, bufptr; 1582 uint32_t &cmdsts = is64bit ? txDesc64.cmdsts : txDesc32.cmdsts; 1583 uint32_t &extsts = is64bit ? txDesc64.extsts : txDesc32.extsts; 1584 1585 next: 1586 if (txKickTick > curTick()) { 1587 DPRINTF(EthernetSM, "transmit kick exiting, can't run till %d\n", 1588 txKickTick); 1589 goto exit; 1590 } 1591 1592 // Go to the next state machine clock tick. 1593 txKickTick = clockEdge(Cycles(1)); 1594 1595 switch(txDmaState) { 1596 case dmaReadWaiting: 1597 if (doTxDmaRead()) 1598 goto exit; 1599 break; 1600 case dmaWriteWaiting: 1601 if (doTxDmaWrite()) 1602 goto exit; 1603 break; 1604 default: 1605 break; 1606 } 1607 1608 link = is64bit ? (Addr)txDesc64.link : (Addr)txDesc32.link; 1609 bufptr = is64bit ? (Addr)txDesc64.bufptr : (Addr)txDesc32.bufptr; 1610 switch (txState) { 1611 case txIdle: 1612 if (!txEnable) { 1613 DPRINTF(EthernetSM, "Transmit disabled. Nothing to do.\n"); 1614 goto exit; 1615 } 1616 1617 if (CTDD) { 1618 txState = txDescRefr; 1619 1620 txDmaAddr = regs.txdp & 0x3fffffff; 1621 txDmaData = 1622 is64bit ? (void *)&txDesc64.link : (void *)&txDesc32.link; 1623 txDmaLen = is64bit ? sizeof(txDesc64.link) : sizeof(txDesc32.link); 1624 txDmaFree = dmaDescFree; 1625 1626 descDmaReads++; 1627 descDmaRdBytes += txDmaLen; 1628 1629 if (doTxDmaRead()) 1630 goto exit; 1631 1632 } else { 1633 txState = txDescRead; 1634 1635 txDmaAddr = regs.txdp & 0x3fffffff; 1636 txDmaData = is64bit ? (void *)&txDesc64 : (void *)&txDesc32; 1637 txDmaLen = is64bit ? sizeof(txDesc64) : sizeof(txDesc32); 1638 txDmaFree = dmaDescFree; 1639 1640 descDmaReads++; 1641 descDmaRdBytes += txDmaLen; 1642 1643 if (doTxDmaRead()) 1644 goto exit; 1645 } 1646 break; 1647 1648 case txDescRefr: 1649 if (txDmaState != dmaIdle) 1650 goto exit; 1651 1652 txState = txAdvance; 1653 break; 1654 1655 case txDescRead: 1656 if (txDmaState != dmaIdle) 1657 goto exit; 1658 1659 DPRINTF(EthernetDesc, "txDesc: addr=%08x read descriptor\n", 1660 regs.txdp & 0x3fffffff); 1661 DPRINTF(EthernetDesc, 1662 "txDesc: link=%#x bufptr=%#x cmdsts=%#08x extsts=%#08x\n", 1663 link, bufptr, cmdsts, extsts); 1664 1665 if (cmdsts & CMDSTS_OWN) { 1666 txState = txFifoBlock; 1667 txFragPtr = bufptr; 1668 txDescCnt = cmdsts & CMDSTS_LEN_MASK; 1669 } else { 1670 devIntrPost(ISR_TXIDLE); 1671 txState = txIdle; 1672 goto exit; 1673 } 1674 break; 1675 1676 case txFifoBlock: 1677 if (!txPacket) { 1678 DPRINTF(EthernetSM, "****starting the tx of a new packet****\n"); 1679 txPacket = new EthPacketData(16384); 1680 txPacketBufPtr = txPacket->data; 1681 } 1682 1683 if (txDescCnt == 0) { 1684 DPRINTF(EthernetSM, "the txDescCnt == 0, done with descriptor\n"); 1685 if (cmdsts & CMDSTS_MORE) { 1686 DPRINTF(EthernetSM, "there are more descriptors to come\n"); 1687 txState = txDescWrite; 1688 1689 cmdsts &= ~CMDSTS_OWN; 1690 1691 txDmaAddr = regs.txdp & 0x3fffffff; 1692 txDmaData = &cmdsts; 1693 if (is64bit) { 1694 txDmaAddr += offsetof(ns_desc64, cmdsts); 1695 txDmaLen = sizeof(txDesc64.cmdsts); 1696 } else { 1697 txDmaAddr += offsetof(ns_desc32, cmdsts); 1698 txDmaLen = sizeof(txDesc32.cmdsts); 1699 } 1700 txDmaFree = dmaDescFree; 1701 1702 if (doTxDmaWrite()) 1703 goto exit; 1704 1705 } else { /* this packet is totally done */ 1706 DPRINTF(EthernetSM, "This packet is done, let's wrap it up\n"); 1707 /* deal with the the packet that just finished */ 1708 if ((regs.vtcr & VTCR_PPCHK) && extstsEnable) { 1709 IpPtr ip(txPacket); 1710 if (extsts & EXTSTS_UDPPKT) { 1711 UdpPtr udp(ip); 1712 if (udp) { 1713 udp->sum(0); 1714 udp->sum(cksum(udp)); 1715 txUdpChecksums++; 1716 } else { 1717 Debug::breakpoint(); 1718 warn_once("UDPPKT set, but not UDP!\n"); 1719 } 1720 } else if (extsts & EXTSTS_TCPPKT) { 1721 TcpPtr tcp(ip); 1722 if (tcp) { 1723 tcp->sum(0); 1724 tcp->sum(cksum(tcp)); 1725 txTcpChecksums++; 1726 } else { 1727 Debug::breakpoint(); 1728 warn_once("TCPPKT set, but not UDP!\n"); 1729 } 1730 } 1731 if (extsts & EXTSTS_IPPKT) { 1732 if (ip) { 1733 ip->sum(0); 1734 ip->sum(cksum(ip)); 1735 txIpChecksums++; 1736 } else { 1737 Debug::breakpoint(); 1738 warn_once("IPPKT set, but not UDP!\n"); 1739 } 1740 } 1741 } 1742 1743 txPacket->length = txPacketBufPtr - txPacket->data; 1744 // this is just because the receive can't handle a 1745 // packet bigger want to make sure 1746 if (txPacket->length > 1514) 1747 panic("transmit packet too large, %s > 1514\n", 1748 txPacket->length); 1749 1750#ifndef NDEBUG 1751 bool success = 1752#endif 1753 txFifo.push(txPacket); 1754 assert(success); 1755 1756 /* 1757 * this following section is not tqo spec, but 1758 * functionally shouldn't be any different. normally, 1759 * the chip will wait til the transmit has occurred 1760 * before writing back the descriptor because it has 1761 * to wait to see that it was successfully transmitted 1762 * to decide whether to set CMDSTS_OK or not. 1763 * however, in the simulator since it is always 1764 * successfully transmitted, and writing it exactly to 1765 * spec would complicate the code, we just do it here 1766 */ 1767 1768 cmdsts &= ~CMDSTS_OWN; 1769 cmdsts |= CMDSTS_OK; 1770 1771 DPRINTF(EthernetDesc, 1772 "txDesc writeback: cmdsts=%08x extsts=%08x\n", 1773 cmdsts, extsts); 1774 1775 txDmaFree = dmaDescFree; 1776 txDmaAddr = regs.txdp & 0x3fffffff; 1777 txDmaData = &cmdsts; 1778 if (is64bit) { 1779 txDmaAddr += offsetof(ns_desc64, cmdsts); 1780 txDmaLen = 1781 sizeof(txDesc64.cmdsts) + sizeof(txDesc64.extsts); 1782 } else { 1783 txDmaAddr += offsetof(ns_desc32, cmdsts); 1784 txDmaLen = 1785 sizeof(txDesc32.cmdsts) + sizeof(txDesc32.extsts); 1786 } 1787 1788 descDmaWrites++; 1789 descDmaWrBytes += txDmaLen; 1790 1791 transmit(); 1792 txPacket = 0; 1793 1794 if (!txEnable) { 1795 DPRINTF(EthernetSM, "halting TX state machine\n"); 1796 txState = txIdle; 1797 goto exit; 1798 } else 1799 txState = txAdvance; 1800 1801 if (doTxDmaWrite()) 1802 goto exit; 1803 } 1804 } else { 1805 DPRINTF(EthernetSM, "this descriptor isn't done yet\n"); 1806 if (!txFifo.full()) { 1807 txState = txFragRead; 1808 1809 /* 1810 * The number of bytes transferred is either whatever 1811 * is left in the descriptor (txDescCnt), or if there 1812 * is not enough room in the fifo, just whatever room 1813 * is left in the fifo 1814 */ 1815 txXferLen = min<uint32_t>(txDescCnt, txFifo.avail()); 1816 1817 txDmaAddr = txFragPtr & 0x3fffffff; 1818 txDmaData = txPacketBufPtr; 1819 txDmaLen = txXferLen; 1820 txDmaFree = dmaDataFree; 1821 1822 if (doTxDmaRead()) 1823 goto exit; 1824 } else { 1825 txState = txFifoBlock; 1826 transmit(); 1827 1828 goto exit; 1829 } 1830 1831 } 1832 break; 1833 1834 case txFragRead: 1835 if (txDmaState != dmaIdle) 1836 goto exit; 1837 1838 txPacketBufPtr += txXferLen; 1839 txFragPtr += txXferLen; 1840 txDescCnt -= txXferLen; 1841 txFifo.reserve(txXferLen); 1842 1843 txState = txFifoBlock; 1844 break; 1845 1846 case txDescWrite: 1847 if (txDmaState != dmaIdle) 1848 goto exit; 1849 1850 if (cmdsts & CMDSTS_INTR) 1851 devIntrPost(ISR_TXDESC); 1852 1853 if (!txEnable) { 1854 DPRINTF(EthernetSM, "halting TX state machine\n"); 1855 txState = txIdle; 1856 goto exit; 1857 } else 1858 txState = txAdvance; 1859 break; 1860 1861 case txAdvance: 1862 if (link == 0) { 1863 devIntrPost(ISR_TXIDLE); 1864 txState = txIdle; 1865 goto exit; 1866 } else { 1867 if (txDmaState != dmaIdle) 1868 goto exit; 1869 txState = txDescRead; 1870 regs.txdp = link; 1871 CTDD = false; 1872 1873 txDmaAddr = link & 0x3fffffff; 1874 txDmaData = is64bit ? (void *)&txDesc64 : (void *)&txDesc32; 1875 txDmaLen = is64bit ? sizeof(txDesc64) : sizeof(txDesc32); 1876 txDmaFree = dmaDescFree; 1877 1878 if (doTxDmaRead()) 1879 goto exit; 1880 } 1881 break; 1882 1883 default: 1884 panic("invalid state"); 1885 } 1886 1887 DPRINTF(EthernetSM, "entering next txState=%s\n", 1888 NsTxStateStrings[txState]); 1889 goto next; 1890 1891 exit: 1892 /** 1893 * @todo do we want to schedule a future kick? 1894 */ 1895 DPRINTF(EthernetSM, "tx state machine exited txState=%s\n", 1896 NsTxStateStrings[txState]); 1897 1898 if (!txKickEvent.scheduled()) 1899 schedule(txKickEvent, txKickTick); 1900} 1901 1902/** 1903 * Advance the EEPROM state machine 1904 * Called on rising edge of EEPROM clock bit in MEAR 1905 */ 1906void 1907NSGigE::eepromKick() 1908{ 1909 switch (eepromState) { 1910 1911 case eepromStart: 1912 1913 // Wait for start bit 1914 if (regs.mear & MEAR_EEDI) { 1915 // Set up to get 2 opcode bits 1916 eepromState = eepromGetOpcode; 1917 eepromBitsToRx = 2; 1918 eepromOpcode = 0; 1919 } 1920 break; 1921 1922 case eepromGetOpcode: 1923 eepromOpcode <<= 1; 1924 eepromOpcode += (regs.mear & MEAR_EEDI) ? 1 : 0; 1925 --eepromBitsToRx; 1926 1927 // Done getting opcode 1928 if (eepromBitsToRx == 0) { 1929 if (eepromOpcode != EEPROM_READ) 1930 panic("only EEPROM reads are implemented!"); 1931 1932 // Set up to get address 1933 eepromState = eepromGetAddress; 1934 eepromBitsToRx = 6; 1935 eepromAddress = 0; 1936 } 1937 break; 1938 1939 case eepromGetAddress: 1940 eepromAddress <<= 1; 1941 eepromAddress += (regs.mear & MEAR_EEDI) ? 1 : 0; 1942 --eepromBitsToRx; 1943 1944 // Done getting address 1945 if (eepromBitsToRx == 0) { 1946 1947 if (eepromAddress >= EEPROM_SIZE) 1948 panic("EEPROM read access out of range!"); 1949 1950 switch (eepromAddress) { 1951 1952 case EEPROM_PMATCH2_ADDR: 1953 eepromData = rom.perfectMatch[5]; 1954 eepromData <<= 8; 1955 eepromData += rom.perfectMatch[4]; 1956 break; 1957 1958 case EEPROM_PMATCH1_ADDR: 1959 eepromData = rom.perfectMatch[3]; 1960 eepromData <<= 8; 1961 eepromData += rom.perfectMatch[2]; 1962 break; 1963 1964 case EEPROM_PMATCH0_ADDR: 1965 eepromData = rom.perfectMatch[1]; 1966 eepromData <<= 8; 1967 eepromData += rom.perfectMatch[0]; 1968 break; 1969 1970 default: 1971 panic("FreeBSD driver only uses EEPROM to read PMATCH!"); 1972 } 1973 // Set up to read data 1974 eepromState = eepromRead; 1975 eepromBitsToRx = 16; 1976 1977 // Clear data in bit 1978 regs.mear &= ~MEAR_EEDI; 1979 } 1980 break; 1981 1982 case eepromRead: 1983 // Clear Data Out bit 1984 regs.mear &= ~MEAR_EEDO; 1985 // Set bit to value of current EEPROM bit 1986 regs.mear |= (eepromData & 0x8000) ? MEAR_EEDO : 0x0; 1987 1988 eepromData <<= 1; 1989 --eepromBitsToRx; 1990 1991 // All done 1992 if (eepromBitsToRx == 0) { 1993 eepromState = eepromStart; 1994 } 1995 break; 1996 1997 default: 1998 panic("invalid EEPROM state"); 1999 } 2000 2001} 2002 2003void 2004NSGigE::transferDone() 2005{ 2006 if (txFifo.empty()) { 2007 DPRINTF(Ethernet, "transfer complete: txFifo empty...nothing to do\n"); 2008 return; 2009 } 2010 2011 DPRINTF(Ethernet, "transfer complete: data in txFifo...schedule xmit\n"); 2012 2013 reschedule(txEvent, clockEdge(Cycles(1)), true); 2014} 2015 2016bool 2017NSGigE::rxFilter(const EthPacketPtr &packet) 2018{ 2019 EthPtr eth = packet; 2020 bool drop = true; 2021 string type; 2022 2023 const EthAddr &dst = eth->dst(); 2024 if (dst.unicast()) { 2025 // If we're accepting all unicast addresses 2026 if (acceptUnicast) 2027 drop = false; 2028 2029 // If we make a perfect match 2030 if (acceptPerfect && dst == rom.perfectMatch) 2031 drop = false; 2032 2033 if (acceptArp && eth->type() == ETH_TYPE_ARP) 2034 drop = false; 2035 2036 } else if (dst.broadcast()) { 2037 // if we're accepting broadcasts 2038 if (acceptBroadcast) 2039 drop = false; 2040 2041 } else if (dst.multicast()) { 2042 // if we're accepting all multicasts 2043 if (acceptMulticast) 2044 drop = false; 2045 2046 // Multicast hashing faked - all packets accepted 2047 if (multicastHashEnable) 2048 drop = false; 2049 } 2050 2051 if (drop) { 2052 DPRINTF(Ethernet, "rxFilter drop\n"); 2053 DDUMP(EthernetData, packet->data, packet->length); 2054 } 2055 2056 return drop; 2057} 2058 2059bool 2060NSGigE::recvPacket(EthPacketPtr packet) 2061{ 2062 rxBytes += packet->length; 2063 rxPackets++; 2064 2065 DPRINTF(Ethernet, "Receiving packet from wire, rxFifoAvail=%d\n", 2066 rxFifo.avail()); 2067 2068 if (!rxEnable) { 2069 DPRINTF(Ethernet, "receive disabled...packet dropped\n"); 2070 return true; 2071 } 2072 2073 if (!rxFilterEnable) { 2074 DPRINTF(Ethernet, 2075 "receive packet filtering disabled . . . packet dropped\n"); 2076 return true; 2077 } 2078 2079 if (rxFilter(packet)) { 2080 DPRINTF(Ethernet, "packet filtered...dropped\n"); 2081 return true; 2082 } 2083 2084 if (rxFifo.avail() < packet->length) { 2085#if TRACING_ON 2086 IpPtr ip(packet); 2087 TcpPtr tcp(ip); 2088 if (ip) { 2089 DPRINTF(Ethernet, 2090 "packet won't fit in receive buffer...pkt ID %d dropped\n", 2091 ip->id()); 2092 if (tcp) { 2093 DPRINTF(Ethernet, "Seq=%d\n", tcp->seq()); 2094 } 2095 } 2096#endif 2097 droppedPackets++; 2098 devIntrPost(ISR_RXORN); 2099 return false; 2100 } 2101 2102 rxFifo.push(packet); 2103 2104 rxKick(); 2105 return true; 2106} 2107 2108 2109void 2110NSGigE::drainResume() 2111{ 2112 Drainable::drainResume(); 2113 2114 // During drain we could have left the state machines in a waiting state and 2115 // they wouldn't get out until some other event occured to kick them. 2116 // This way they'll get out immediately 2117 txKick(); 2118 rxKick(); 2119} 2120 2121 2122//===================================================================== 2123// 2124// 2125void 2126NSGigE::serialize(ostream &os) 2127{ 2128 // Serialize the PciDevice base class 2129 PciDevice::serialize(os); 2130 2131 /* 2132 * Finalize any DMA events now. 2133 */ 2134 // @todo will mem system save pending dma? 2135 2136 /* 2137 * Serialize the device registers 2138 */ 2139 SERIALIZE_SCALAR(regs.command); 2140 SERIALIZE_SCALAR(regs.config); 2141 SERIALIZE_SCALAR(regs.mear); 2142 SERIALIZE_SCALAR(regs.ptscr); 2143 SERIALIZE_SCALAR(regs.isr); 2144 SERIALIZE_SCALAR(regs.imr); 2145 SERIALIZE_SCALAR(regs.ier); 2146 SERIALIZE_SCALAR(regs.ihr); 2147 SERIALIZE_SCALAR(regs.txdp); 2148 SERIALIZE_SCALAR(regs.txdp_hi); 2149 SERIALIZE_SCALAR(regs.txcfg); 2150 SERIALIZE_SCALAR(regs.gpior); 2151 SERIALIZE_SCALAR(regs.rxdp); 2152 SERIALIZE_SCALAR(regs.rxdp_hi); 2153 SERIALIZE_SCALAR(regs.rxcfg); 2154 SERIALIZE_SCALAR(regs.pqcr); 2155 SERIALIZE_SCALAR(regs.wcsr); 2156 SERIALIZE_SCALAR(regs.pcr); 2157 SERIALIZE_SCALAR(regs.rfcr); 2158 SERIALIZE_SCALAR(regs.rfdr); 2159 SERIALIZE_SCALAR(regs.brar); 2160 SERIALIZE_SCALAR(regs.brdr); 2161 SERIALIZE_SCALAR(regs.srr); 2162 SERIALIZE_SCALAR(regs.mibc); 2163 SERIALIZE_SCALAR(regs.vrcr); 2164 SERIALIZE_SCALAR(regs.vtcr); 2165 SERIALIZE_SCALAR(regs.vdr); 2166 SERIALIZE_SCALAR(regs.ccsr); 2167 SERIALIZE_SCALAR(regs.tbicr); 2168 SERIALIZE_SCALAR(regs.tbisr); 2169 SERIALIZE_SCALAR(regs.tanar); 2170 SERIALIZE_SCALAR(regs.tanlpar); 2171 SERIALIZE_SCALAR(regs.taner); 2172 SERIALIZE_SCALAR(regs.tesr); 2173 2174 SERIALIZE_ARRAY(rom.perfectMatch, ETH_ADDR_LEN); 2175 SERIALIZE_ARRAY(rom.filterHash, FHASH_SIZE); 2176 2177 SERIALIZE_SCALAR(ioEnable); 2178 2179 /* 2180 * Serialize the data Fifos 2181 */ 2182 rxFifo.serialize("rxFifo", os); 2183 txFifo.serialize("txFifo", os); 2184 2185 /* 2186 * Serialize the various helper variables 2187 */ 2188 bool txPacketExists = txPacket; 2189 SERIALIZE_SCALAR(txPacketExists); 2190 if (txPacketExists) { 2191 txPacket->length = txPacketBufPtr - txPacket->data; 2192 txPacket->serialize("txPacket", os); 2193 uint32_t txPktBufPtr = (uint32_t) (txPacketBufPtr - txPacket->data); 2194 SERIALIZE_SCALAR(txPktBufPtr); 2195 } 2196 2197 bool rxPacketExists = rxPacket; 2198 SERIALIZE_SCALAR(rxPacketExists); 2199 if (rxPacketExists) { 2200 rxPacket->serialize("rxPacket", os); 2201 uint32_t rxPktBufPtr = (uint32_t) (rxPacketBufPtr - rxPacket->data); 2202 SERIALIZE_SCALAR(rxPktBufPtr); 2203 } 2204 2205 SERIALIZE_SCALAR(txXferLen); 2206 SERIALIZE_SCALAR(rxXferLen); 2207 2208 /* 2209 * Serialize Cached Descriptors 2210 */ 2211 SERIALIZE_SCALAR(rxDesc64.link); 2212 SERIALIZE_SCALAR(rxDesc64.bufptr); 2213 SERIALIZE_SCALAR(rxDesc64.cmdsts); 2214 SERIALIZE_SCALAR(rxDesc64.extsts); 2215 SERIALIZE_SCALAR(txDesc64.link); 2216 SERIALIZE_SCALAR(txDesc64.bufptr); 2217 SERIALIZE_SCALAR(txDesc64.cmdsts); 2218 SERIALIZE_SCALAR(txDesc64.extsts); 2219 SERIALIZE_SCALAR(rxDesc32.link); 2220 SERIALIZE_SCALAR(rxDesc32.bufptr); 2221 SERIALIZE_SCALAR(rxDesc32.cmdsts); 2222 SERIALIZE_SCALAR(rxDesc32.extsts); 2223 SERIALIZE_SCALAR(txDesc32.link); 2224 SERIALIZE_SCALAR(txDesc32.bufptr); 2225 SERIALIZE_SCALAR(txDesc32.cmdsts); 2226 SERIALIZE_SCALAR(txDesc32.extsts); 2227 SERIALIZE_SCALAR(extstsEnable); 2228 2229 /* 2230 * Serialize tx state machine 2231 */ 2232 int txState = this->txState; 2233 SERIALIZE_SCALAR(txState); 2234 SERIALIZE_SCALAR(txEnable); 2235 SERIALIZE_SCALAR(CTDD); 2236 SERIALIZE_SCALAR(txFragPtr); 2237 SERIALIZE_SCALAR(txDescCnt); 2238 int txDmaState = this->txDmaState; 2239 SERIALIZE_SCALAR(txDmaState); 2240 SERIALIZE_SCALAR(txKickTick); 2241 2242 /* 2243 * Serialize rx state machine 2244 */ 2245 int rxState = this->rxState; 2246 SERIALIZE_SCALAR(rxState); 2247 SERIALIZE_SCALAR(rxEnable); 2248 SERIALIZE_SCALAR(CRDD); 2249 SERIALIZE_SCALAR(rxPktBytes); 2250 SERIALIZE_SCALAR(rxFragPtr); 2251 SERIALIZE_SCALAR(rxDescCnt); 2252 int rxDmaState = this->rxDmaState; 2253 SERIALIZE_SCALAR(rxDmaState); 2254 SERIALIZE_SCALAR(rxKickTick); 2255 2256 /* 2257 * Serialize EEPROM state machine 2258 */ 2259 int eepromState = this->eepromState; 2260 SERIALIZE_SCALAR(eepromState); 2261 SERIALIZE_SCALAR(eepromClk); 2262 SERIALIZE_SCALAR(eepromBitsToRx); 2263 SERIALIZE_SCALAR(eepromOpcode); 2264 SERIALIZE_SCALAR(eepromAddress); 2265 SERIALIZE_SCALAR(eepromData); 2266 2267 /* 2268 * If there's a pending transmit, store the time so we can 2269 * reschedule it later 2270 */ 2271 Tick transmitTick = txEvent.scheduled() ? txEvent.when() - curTick() : 0; 2272 SERIALIZE_SCALAR(transmitTick); 2273 2274 /* 2275 * receive address filter settings 2276 */ 2277 SERIALIZE_SCALAR(rxFilterEnable); 2278 SERIALIZE_SCALAR(acceptBroadcast); 2279 SERIALIZE_SCALAR(acceptMulticast); 2280 SERIALIZE_SCALAR(acceptUnicast); 2281 SERIALIZE_SCALAR(acceptPerfect); 2282 SERIALIZE_SCALAR(acceptArp); 2283 SERIALIZE_SCALAR(multicastHashEnable); 2284 2285 /* 2286 * Keep track of pending interrupt status. 2287 */ 2288 SERIALIZE_SCALAR(intrTick); 2289 SERIALIZE_SCALAR(cpuPendingIntr); 2290 Tick intrEventTick = 0; 2291 if (intrEvent) 2292 intrEventTick = intrEvent->when(); 2293 SERIALIZE_SCALAR(intrEventTick); 2294 2295} 2296 2297void 2298NSGigE::unserialize(Checkpoint *cp, const std::string §ion) 2299{ 2300 // Unserialize the PciDevice base class 2301 PciDevice::unserialize(cp, section); 2302 2303 UNSERIALIZE_SCALAR(regs.command); 2304 UNSERIALIZE_SCALAR(regs.config); 2305 UNSERIALIZE_SCALAR(regs.mear); 2306 UNSERIALIZE_SCALAR(regs.ptscr); 2307 UNSERIALIZE_SCALAR(regs.isr); 2308 UNSERIALIZE_SCALAR(regs.imr); 2309 UNSERIALIZE_SCALAR(regs.ier); 2310 UNSERIALIZE_SCALAR(regs.ihr); 2311 UNSERIALIZE_SCALAR(regs.txdp); 2312 UNSERIALIZE_SCALAR(regs.txdp_hi); 2313 UNSERIALIZE_SCALAR(regs.txcfg); 2314 UNSERIALIZE_SCALAR(regs.gpior); 2315 UNSERIALIZE_SCALAR(regs.rxdp); 2316 UNSERIALIZE_SCALAR(regs.rxdp_hi); 2317 UNSERIALIZE_SCALAR(regs.rxcfg); 2318 UNSERIALIZE_SCALAR(regs.pqcr); 2319 UNSERIALIZE_SCALAR(regs.wcsr); 2320 UNSERIALIZE_SCALAR(regs.pcr); 2321 UNSERIALIZE_SCALAR(regs.rfcr); 2322 UNSERIALIZE_SCALAR(regs.rfdr); 2323 UNSERIALIZE_SCALAR(regs.brar); 2324 UNSERIALIZE_SCALAR(regs.brdr); 2325 UNSERIALIZE_SCALAR(regs.srr); 2326 UNSERIALIZE_SCALAR(regs.mibc); 2327 UNSERIALIZE_SCALAR(regs.vrcr); 2328 UNSERIALIZE_SCALAR(regs.vtcr); 2329 UNSERIALIZE_SCALAR(regs.vdr); 2330 UNSERIALIZE_SCALAR(regs.ccsr); 2331 UNSERIALIZE_SCALAR(regs.tbicr); 2332 UNSERIALIZE_SCALAR(regs.tbisr); 2333 UNSERIALIZE_SCALAR(regs.tanar); 2334 UNSERIALIZE_SCALAR(regs.tanlpar); 2335 UNSERIALIZE_SCALAR(regs.taner); 2336 UNSERIALIZE_SCALAR(regs.tesr); 2337 2338 UNSERIALIZE_ARRAY(rom.perfectMatch, ETH_ADDR_LEN); 2339 UNSERIALIZE_ARRAY(rom.filterHash, FHASH_SIZE); 2340 2341 UNSERIALIZE_SCALAR(ioEnable); 2342 2343 /* 2344 * unserialize the data fifos 2345 */ 2346 rxFifo.unserialize("rxFifo", cp, section); 2347 txFifo.unserialize("txFifo", cp, section); 2348 2349 /* 2350 * unserialize the various helper variables 2351 */ 2352 bool txPacketExists; 2353 UNSERIALIZE_SCALAR(txPacketExists); 2354 if (txPacketExists) { 2355 txPacket = new EthPacketData(16384); 2356 txPacket->unserialize("txPacket", cp, section); 2357 uint32_t txPktBufPtr; 2358 UNSERIALIZE_SCALAR(txPktBufPtr); 2359 txPacketBufPtr = (uint8_t *) txPacket->data + txPktBufPtr; 2360 } else 2361 txPacket = 0; 2362 2363 bool rxPacketExists; 2364 UNSERIALIZE_SCALAR(rxPacketExists); 2365 rxPacket = 0; 2366 if (rxPacketExists) { 2367 rxPacket = new EthPacketData(16384); 2368 rxPacket->unserialize("rxPacket", cp, section); 2369 uint32_t rxPktBufPtr; 2370 UNSERIALIZE_SCALAR(rxPktBufPtr); 2371 rxPacketBufPtr = (uint8_t *) rxPacket->data + rxPktBufPtr; 2372 } else 2373 rxPacket = 0; 2374 2375 UNSERIALIZE_SCALAR(txXferLen); 2376 UNSERIALIZE_SCALAR(rxXferLen); 2377 2378 /* 2379 * Unserialize Cached Descriptors 2380 */ 2381 UNSERIALIZE_SCALAR(rxDesc64.link); 2382 UNSERIALIZE_SCALAR(rxDesc64.bufptr); 2383 UNSERIALIZE_SCALAR(rxDesc64.cmdsts); 2384 UNSERIALIZE_SCALAR(rxDesc64.extsts); 2385 UNSERIALIZE_SCALAR(txDesc64.link); 2386 UNSERIALIZE_SCALAR(txDesc64.bufptr); 2387 UNSERIALIZE_SCALAR(txDesc64.cmdsts); 2388 UNSERIALIZE_SCALAR(txDesc64.extsts); 2389 UNSERIALIZE_SCALAR(rxDesc32.link); 2390 UNSERIALIZE_SCALAR(rxDesc32.bufptr); 2391 UNSERIALIZE_SCALAR(rxDesc32.cmdsts); 2392 UNSERIALIZE_SCALAR(rxDesc32.extsts); 2393 UNSERIALIZE_SCALAR(txDesc32.link); 2394 UNSERIALIZE_SCALAR(txDesc32.bufptr); 2395 UNSERIALIZE_SCALAR(txDesc32.cmdsts); 2396 UNSERIALIZE_SCALAR(txDesc32.extsts); 2397 UNSERIALIZE_SCALAR(extstsEnable); 2398 2399 /* 2400 * unserialize tx state machine 2401 */ 2402 int txState; 2403 UNSERIALIZE_SCALAR(txState); 2404 this->txState = (TxState) txState; 2405 UNSERIALIZE_SCALAR(txEnable); 2406 UNSERIALIZE_SCALAR(CTDD); 2407 UNSERIALIZE_SCALAR(txFragPtr); 2408 UNSERIALIZE_SCALAR(txDescCnt); 2409 int txDmaState; 2410 UNSERIALIZE_SCALAR(txDmaState); 2411 this->txDmaState = (DmaState) txDmaState; 2412 UNSERIALIZE_SCALAR(txKickTick); 2413 if (txKickTick) 2414 schedule(txKickEvent, txKickTick); 2415 2416 /* 2417 * unserialize rx state machine 2418 */ 2419 int rxState; 2420 UNSERIALIZE_SCALAR(rxState); 2421 this->rxState = (RxState) rxState; 2422 UNSERIALIZE_SCALAR(rxEnable); 2423 UNSERIALIZE_SCALAR(CRDD); 2424 UNSERIALIZE_SCALAR(rxPktBytes); 2425 UNSERIALIZE_SCALAR(rxFragPtr); 2426 UNSERIALIZE_SCALAR(rxDescCnt); 2427 int rxDmaState; 2428 UNSERIALIZE_SCALAR(rxDmaState); 2429 this->rxDmaState = (DmaState) rxDmaState; 2430 UNSERIALIZE_SCALAR(rxKickTick); 2431 if (rxKickTick) 2432 schedule(rxKickEvent, rxKickTick); 2433 2434 /* 2435 * Unserialize EEPROM state machine 2436 */ 2437 int eepromState; 2438 UNSERIALIZE_SCALAR(eepromState); 2439 this->eepromState = (EEPROMState) eepromState; 2440 UNSERIALIZE_SCALAR(eepromClk); 2441 UNSERIALIZE_SCALAR(eepromBitsToRx); 2442 UNSERIALIZE_SCALAR(eepromOpcode); 2443 UNSERIALIZE_SCALAR(eepromAddress); 2444 UNSERIALIZE_SCALAR(eepromData); 2445 2446 /* 2447 * If there's a pending transmit, reschedule it now 2448 */ 2449 Tick transmitTick; 2450 UNSERIALIZE_SCALAR(transmitTick); 2451 if (transmitTick) 2452 schedule(txEvent, curTick() + transmitTick); 2453 2454 /* 2455 * unserialize receive address filter settings 2456 */ 2457 UNSERIALIZE_SCALAR(rxFilterEnable); 2458 UNSERIALIZE_SCALAR(acceptBroadcast); 2459 UNSERIALIZE_SCALAR(acceptMulticast); 2460 UNSERIALIZE_SCALAR(acceptUnicast); 2461 UNSERIALIZE_SCALAR(acceptPerfect); 2462 UNSERIALIZE_SCALAR(acceptArp); 2463 UNSERIALIZE_SCALAR(multicastHashEnable); 2464 2465 /* 2466 * Keep track of pending interrupt status. 2467 */ 2468 UNSERIALIZE_SCALAR(intrTick); 2469 UNSERIALIZE_SCALAR(cpuPendingIntr); 2470 Tick intrEventTick; 2471 UNSERIALIZE_SCALAR(intrEventTick); 2472 if (intrEventTick) { 2473 intrEvent = new IntrEvent(this, true); 2474 schedule(intrEvent, intrEventTick); 2475 } 2476} 2477 2478NSGigE * 2479NSGigEParams::create() 2480{ 2481 return new NSGigE(this); 2482} 2483