ns_gige.cc revision 6216
15331Sgblack@eecs.umich.edu/* 25331Sgblack@eecs.umich.edu * Copyright (c) 2004-2005 The Regents of The University of Michigan 35331Sgblack@eecs.umich.edu * All rights reserved. 45331Sgblack@eecs.umich.edu * 55331Sgblack@eecs.umich.edu * Redistribution and use in source and binary forms, with or without 65331Sgblack@eecs.umich.edu * modification, are permitted provided that the following conditions are 75331Sgblack@eecs.umich.edu * met: redistributions of source code must retain the above copyright 85331Sgblack@eecs.umich.edu * notice, this list of conditions and the following disclaimer; 95331Sgblack@eecs.umich.edu * redistributions in binary form must reproduce the above copyright 105331Sgblack@eecs.umich.edu * notice, this list of conditions and the following disclaimer in the 115331Sgblack@eecs.umich.edu * documentation and/or other materials provided with the distribution; 125331Sgblack@eecs.umich.edu * neither the name of the copyright holders nor the names of its 135331Sgblack@eecs.umich.edu * contributors may be used to endorse or promote products derived from 145331Sgblack@eecs.umich.edu * this software without specific prior written permission. 155331Sgblack@eecs.umich.edu * 165331Sgblack@eecs.umich.edu * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 175331Sgblack@eecs.umich.edu * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 185331Sgblack@eecs.umich.edu * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR 195331Sgblack@eecs.umich.edu * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT 205331Sgblack@eecs.umich.edu * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 215331Sgblack@eecs.umich.edu * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT 225331Sgblack@eecs.umich.edu * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 235331Sgblack@eecs.umich.edu * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 245331Sgblack@eecs.umich.edu * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 255331Sgblack@eecs.umich.edu * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 265331Sgblack@eecs.umich.edu * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 275331Sgblack@eecs.umich.edu * 285331Sgblack@eecs.umich.edu * Authors: Nathan Binkert 295331Sgblack@eecs.umich.edu * Lisa Hsu 304276Sgblack@eecs.umich.edu */ 314276Sgblack@eecs.umich.edu 324276Sgblack@eecs.umich.edu/** @file 334276Sgblack@eecs.umich.edu * Device module for modelling the National Semiconductor 344276Sgblack@eecs.umich.edu * DP83820 ethernet controller. Does not support priority queueing 354276Sgblack@eecs.umich.edu */ 364276Sgblack@eecs.umich.edu#include <deque> 374276Sgblack@eecs.umich.edu#include <string> 384276Sgblack@eecs.umich.edu 394276Sgblack@eecs.umich.edu#include "base/debug.hh" 404276Sgblack@eecs.umich.edu#include "base/inet.hh" 414276Sgblack@eecs.umich.edu#include "base/types.hh" 424276Sgblack@eecs.umich.edu#include "cpu/thread_context.hh" 434276Sgblack@eecs.umich.edu#include "dev/etherlink.hh" 444276Sgblack@eecs.umich.edu#include "dev/ns_gige.hh" 454276Sgblack@eecs.umich.edu#include "dev/pciconfigall.hh" 464276Sgblack@eecs.umich.edu#include "mem/packet.hh" 474276Sgblack@eecs.umich.edu#include "mem/packet_access.hh" 484276Sgblack@eecs.umich.edu#include "params/NSGigE.hh" 494276Sgblack@eecs.umich.edu#include "sim/system.hh" 504276Sgblack@eecs.umich.edu 514276Sgblack@eecs.umich.educonst char *NsRxStateStrings[] = 524276Sgblack@eecs.umich.edu{ 534276Sgblack@eecs.umich.edu "rxIdle", 544276Sgblack@eecs.umich.edu "rxDescRefr", 554276Sgblack@eecs.umich.edu "rxDescRead", 564276Sgblack@eecs.umich.edu "rxFifoBlock", 574276Sgblack@eecs.umich.edu "rxFragWrite", 584276Sgblack@eecs.umich.edu "rxDescWrite", 594276Sgblack@eecs.umich.edu "rxAdvance" 604276Sgblack@eecs.umich.edu}; 614276Sgblack@eecs.umich.edu 624276Sgblack@eecs.umich.educonst char *NsTxStateStrings[] = 634276Sgblack@eecs.umich.edu{ 644276Sgblack@eecs.umich.edu "txIdle", 654276Sgblack@eecs.umich.edu "txDescRefr", 664276Sgblack@eecs.umich.edu "txDescRead", 674276Sgblack@eecs.umich.edu "txFifoBlock", 684276Sgblack@eecs.umich.edu "txFragRead", 694276Sgblack@eecs.umich.edu "txDescWrite", 704276Sgblack@eecs.umich.edu "txAdvance" 714276Sgblack@eecs.umich.edu}; 724276Sgblack@eecs.umich.edu 734276Sgblack@eecs.umich.educonst char *NsDmaState[] = 744276Sgblack@eecs.umich.edu{ 754276Sgblack@eecs.umich.edu "dmaIdle", 764276Sgblack@eecs.umich.edu "dmaReading", 774276Sgblack@eecs.umich.edu "dmaWriting", 784276Sgblack@eecs.umich.edu "dmaReadWaiting", 794276Sgblack@eecs.umich.edu "dmaWriteWaiting" 804276Sgblack@eecs.umich.edu}; 814276Sgblack@eecs.umich.edu 824276Sgblack@eecs.umich.eduusing namespace std; 834276Sgblack@eecs.umich.eduusing namespace Net; 844276Sgblack@eecs.umich.eduusing namespace TheISA; 854276Sgblack@eecs.umich.edu 864276Sgblack@eecs.umich.edu/////////////////////////////////////////////////////////////////////// 874276Sgblack@eecs.umich.edu// 884276Sgblack@eecs.umich.edu// NSGigE PCI Device 894711Sgblack@eecs.umich.edu// 904276Sgblack@eecs.umich.eduNSGigE::NSGigE(Params *p) 914276Sgblack@eecs.umich.edu : EtherDevice(p), ioEnable(false), 925238Sgblack@eecs.umich.edu txFifo(p->tx_fifo_size), rxFifo(p->rx_fifo_size), 935238Sgblack@eecs.umich.edu txPacket(0), rxPacket(0), txPacketBufPtr(NULL), rxPacketBufPtr(NULL), 945238Sgblack@eecs.umich.edu txXferLen(0), rxXferLen(0), rxDmaFree(false), txDmaFree(false), 955238Sgblack@eecs.umich.edu clock(p->clock), 965937Sgblack@eecs.umich.edu txState(txIdle), txEnable(false), CTDD(false), txHalt(false), 975902Sgblack@eecs.umich.edu txFragPtr(0), txDescCnt(0), txDmaState(dmaIdle), rxState(rxIdle), 985238Sgblack@eecs.umich.edu rxEnable(false), CRDD(false), rxPktBytes(0), rxHalt(false), 995238Sgblack@eecs.umich.edu rxFragPtr(0), rxDescCnt(0), rxDmaState(dmaIdle), extstsEnable(false), 1005238Sgblack@eecs.umich.edu eepromState(eepromStart), eepromClk(false), eepromBitsToRx(0), 1015238Sgblack@eecs.umich.edu eepromOpcode(0), eepromAddress(0), eepromData(0), 1025238Sgblack@eecs.umich.edu dmaReadDelay(p->dma_read_delay), dmaWriteDelay(p->dma_write_delay), 1035238Sgblack@eecs.umich.edu dmaReadFactor(p->dma_read_factor), dmaWriteFactor(p->dma_write_factor), 1045238Sgblack@eecs.umich.edu rxDmaData(NULL), rxDmaAddr(0), rxDmaLen(0), 1055238Sgblack@eecs.umich.edu txDmaData(NULL), txDmaAddr(0), txDmaLen(0), 1065238Sgblack@eecs.umich.edu rxDmaReadEvent(this), rxDmaWriteEvent(this), 1075238Sgblack@eecs.umich.edu txDmaReadEvent(this), txDmaWriteEvent(this), 1085238Sgblack@eecs.umich.edu dmaDescFree(p->dma_desc_free), dmaDataFree(p->dma_data_free), 1095238Sgblack@eecs.umich.edu txDelay(p->tx_delay), rxDelay(p->rx_delay), 1105238Sgblack@eecs.umich.edu rxKickTick(0), rxKickEvent(this), txKickTick(0), txKickEvent(this), 1115238Sgblack@eecs.umich.edu txEvent(this), rxFilterEnable(p->rx_filter), 1125238Sgblack@eecs.umich.edu acceptBroadcast(false), acceptMulticast(false), acceptUnicast(false), 1135238Sgblack@eecs.umich.edu acceptPerfect(false), acceptArp(false), multicastHashEnable(false), 1145238Sgblack@eecs.umich.edu intrDelay(p->intr_delay), intrTick(0), cpuPendingIntr(false), 1155238Sgblack@eecs.umich.edu intrEvent(0), interface(0) 1165238Sgblack@eecs.umich.edu{ 1175238Sgblack@eecs.umich.edu 1185238Sgblack@eecs.umich.edu 1195238Sgblack@eecs.umich.edu interface = new NSGigEInt(name() + ".int0", this); 1205238Sgblack@eecs.umich.edu 1215238Sgblack@eecs.umich.edu regsReset(); 1225238Sgblack@eecs.umich.edu memcpy(&rom.perfectMatch, p->hardware_address.bytes(), ETH_ADDR_LEN); 1235238Sgblack@eecs.umich.edu 1245238Sgblack@eecs.umich.edu memset(&rxDesc32, 0, sizeof(rxDesc32)); 1255238Sgblack@eecs.umich.edu memset(&txDesc32, 0, sizeof(txDesc32)); 1265238Sgblack@eecs.umich.edu memset(&rxDesc64, 0, sizeof(rxDesc64)); 1275238Sgblack@eecs.umich.edu memset(&txDesc64, 0, sizeof(txDesc64)); 1286055Sgblack@eecs.umich.edu} 1296054Sgblack@eecs.umich.edu 1305238Sgblack@eecs.umich.eduNSGigE::~NSGigE() 1315683Sgblack@eecs.umich.edu{} 1325238Sgblack@eecs.umich.edu 1335238Sgblack@eecs.umich.edu/** 1345238Sgblack@eecs.umich.edu * This is to write to the PCI general configuration registers 1355238Sgblack@eecs.umich.edu */ 1365238Sgblack@eecs.umich.eduTick 1375238Sgblack@eecs.umich.eduNSGigE::writeConfig(PacketPtr pkt) 1385238Sgblack@eecs.umich.edu{ 1395238Sgblack@eecs.umich.edu int offset = pkt->getAddr() & PCI_CONFIG_SIZE; 1405291Sgblack@eecs.umich.edu if (offset < PCI_DEVICE_SPECIFIC) 1415291Sgblack@eecs.umich.edu PciDev::writeConfig(pkt); 1425291Sgblack@eecs.umich.edu else 1435291Sgblack@eecs.umich.edu panic("Device specific PCI config space not implemented!\n"); 1445291Sgblack@eecs.umich.edu 1455291Sgblack@eecs.umich.edu switch (offset) { 1465291Sgblack@eecs.umich.edu // seems to work fine without all these PCI settings, but i 1475291Sgblack@eecs.umich.edu // put in the IO to double check, an assertion will fail if we 1485291Sgblack@eecs.umich.edu // need to properly implement it 1495292Sgblack@eecs.umich.edu case PCI_COMMAND: 1505292Sgblack@eecs.umich.edu if (config.data[offset] & PCI_CMD_IOSE) 1515292Sgblack@eecs.umich.edu ioEnable = true; 1525292Sgblack@eecs.umich.edu else 1535292Sgblack@eecs.umich.edu ioEnable = false; 1545292Sgblack@eecs.umich.edu break; 1555292Sgblack@eecs.umich.edu } 1565292Sgblack@eecs.umich.edu 1575292Sgblack@eecs.umich.edu return configDelay; 1586055Sgblack@eecs.umich.edu} 1596054Sgblack@eecs.umich.edu 1605359Sgblack@eecs.umich.eduEtherInt* 1615238Sgblack@eecs.umich.eduNSGigE::getEthPort(const std::string &if_name, int idx) 1625238Sgblack@eecs.umich.edu{ 1635238Sgblack@eecs.umich.edu if (if_name == "interface") { 1644276Sgblack@eecs.umich.edu if (interface->getPeer()) 1654276Sgblack@eecs.umich.edu panic("interface already connected to\n"); 1665789Sgblack@eecs.umich.edu return interface; 1675789Sgblack@eecs.umich.edu } 1685789Sgblack@eecs.umich.edu return NULL; 1695789Sgblack@eecs.umich.edu} 1705789Sgblack@eecs.umich.edu 1715789Sgblack@eecs.umich.edu/** 1725789Sgblack@eecs.umich.edu * This reads the device registers, which are detailed in the NS83820 1735789Sgblack@eecs.umich.edu * spec sheet 1745789Sgblack@eecs.umich.edu */ 1755789Sgblack@eecs.umich.eduTick 1765789Sgblack@eecs.umich.eduNSGigE::read(PacketPtr pkt) 1775789Sgblack@eecs.umich.edu{ 1785789Sgblack@eecs.umich.edu assert(ioEnable); 1795789Sgblack@eecs.umich.edu 1805789Sgblack@eecs.umich.edu pkt->allocate(); 1815789Sgblack@eecs.umich.edu 1825789Sgblack@eecs.umich.edu //The mask is to give you only the offset into the device register file 1835789Sgblack@eecs.umich.edu Addr daddr = pkt->getAddr() & 0xfff; 1845789Sgblack@eecs.umich.edu DPRINTF(EthernetPIO, "read da=%#x pa=%#x size=%d\n", 1855789Sgblack@eecs.umich.edu daddr, pkt->getAddr(), pkt->getSize()); 1865789Sgblack@eecs.umich.edu 1875789Sgblack@eecs.umich.edu 1885789Sgblack@eecs.umich.edu // there are some reserved registers, you can see ns_gige_reg.h and 1895789Sgblack@eecs.umich.edu // the spec sheet for details 1905789Sgblack@eecs.umich.edu if (daddr > LAST && daddr <= RESERVED) { 1915789Sgblack@eecs.umich.edu panic("Accessing reserved register"); 1925789Sgblack@eecs.umich.edu } else if (daddr > RESERVED && daddr <= 0x3FC) { 1935789Sgblack@eecs.umich.edu return readConfig(pkt); 1945789Sgblack@eecs.umich.edu } else if (daddr >= MIB_START && daddr <= MIB_END) { 1955789Sgblack@eecs.umich.edu // don't implement all the MIB's. hopefully the kernel 1965789Sgblack@eecs.umich.edu // doesn't actually DEPEND upon their values 1975789Sgblack@eecs.umich.edu // MIB are just hardware stats keepers 1985789Sgblack@eecs.umich.edu pkt->set<uint32_t>(0); 1995789Sgblack@eecs.umich.edu pkt->makeAtomicResponse(); 2005789Sgblack@eecs.umich.edu return pioDelay; 2015789Sgblack@eecs.umich.edu } else if (daddr > 0x3FC) 2025789Sgblack@eecs.umich.edu panic("Something is messed up!\n"); 2035789Sgblack@eecs.umich.edu 2045789Sgblack@eecs.umich.edu assert(pkt->getSize() == sizeof(uint32_t)); 2055789Sgblack@eecs.umich.edu uint32_t ® = *pkt->getPtr<uint32_t>(); 2065789Sgblack@eecs.umich.edu uint16_t rfaddr; 2075789Sgblack@eecs.umich.edu 2085789Sgblack@eecs.umich.edu switch (daddr) { 2095789Sgblack@eecs.umich.edu case CR: 2105789Sgblack@eecs.umich.edu reg = regs.command; 2115789Sgblack@eecs.umich.edu //these are supposed to be cleared on a read 2125789Sgblack@eecs.umich.edu reg &= ~(CR_RXD | CR_TXD | CR_TXR | CR_RXR); 2135789Sgblack@eecs.umich.edu break; 2145789Sgblack@eecs.umich.edu 2155789Sgblack@eecs.umich.edu case CFGR: 2165789Sgblack@eecs.umich.edu reg = regs.config; 2175789Sgblack@eecs.umich.edu break; 2185789Sgblack@eecs.umich.edu 2195789Sgblack@eecs.umich.edu case MEAR: 2205789Sgblack@eecs.umich.edu reg = regs.mear; 2215789Sgblack@eecs.umich.edu break; 2225789Sgblack@eecs.umich.edu 2235789Sgblack@eecs.umich.edu case PTSCR: 2245789Sgblack@eecs.umich.edu reg = regs.ptscr; 2255789Sgblack@eecs.umich.edu break; 2265789Sgblack@eecs.umich.edu 2275789Sgblack@eecs.umich.edu case ISR: 2285789Sgblack@eecs.umich.edu reg = regs.isr; 2295789Sgblack@eecs.umich.edu devIntrClear(ISR_ALL); 2305789Sgblack@eecs.umich.edu break; 2315789Sgblack@eecs.umich.edu 2325789Sgblack@eecs.umich.edu case IMR: 2335789Sgblack@eecs.umich.edu reg = regs.imr; 2345789Sgblack@eecs.umich.edu break; 2355789Sgblack@eecs.umich.edu 2365789Sgblack@eecs.umich.edu case IER: 2375789Sgblack@eecs.umich.edu reg = regs.ier; 2385789Sgblack@eecs.umich.edu break; 2395789Sgblack@eecs.umich.edu 2405789Sgblack@eecs.umich.edu case IHR: 2415789Sgblack@eecs.umich.edu reg = regs.ihr; 2425789Sgblack@eecs.umich.edu break; 2435789Sgblack@eecs.umich.edu 2445789Sgblack@eecs.umich.edu case TXDP: 2455789Sgblack@eecs.umich.edu reg = regs.txdp; 2465789Sgblack@eecs.umich.edu break; 2475789Sgblack@eecs.umich.edu 2485789Sgblack@eecs.umich.edu case TXDP_HI: 2495789Sgblack@eecs.umich.edu reg = regs.txdp_hi; 2505789Sgblack@eecs.umich.edu break; 2515789Sgblack@eecs.umich.edu 2525789Sgblack@eecs.umich.edu case TX_CFG: 2535789Sgblack@eecs.umich.edu reg = regs.txcfg; 2545789Sgblack@eecs.umich.edu break; 2555789Sgblack@eecs.umich.edu 2564712Sgblack@eecs.umich.edu case GPIOR: 2575907Sgblack@eecs.umich.edu reg = regs.gpior; 2585907Sgblack@eecs.umich.edu break; 2595907Sgblack@eecs.umich.edu 2605907Sgblack@eecs.umich.edu case RXDP: 2615907Sgblack@eecs.umich.edu reg = regs.rxdp; 2625907Sgblack@eecs.umich.edu break; 2635907Sgblack@eecs.umich.edu 2644712Sgblack@eecs.umich.edu case RXDP_HI: 2655659Sgblack@eecs.umich.edu reg = regs.rxdp_hi; 2664712Sgblack@eecs.umich.edu break; 2675933Sgblack@eecs.umich.edu 2685908Sgblack@eecs.umich.edu case RX_CFG: 2695908Sgblack@eecs.umich.edu reg = regs.rxcfg; 2705908Sgblack@eecs.umich.edu break; 2715908Sgblack@eecs.umich.edu 2725908Sgblack@eecs.umich.edu case PQCR: 2735908Sgblack@eecs.umich.edu reg = regs.pqcr; 2745908Sgblack@eecs.umich.edu break; 2755908Sgblack@eecs.umich.edu 2765908Sgblack@eecs.umich.edu case WCSR: 2774276Sgblack@eecs.umich.edu reg = regs.wcsr; 2784276Sgblack@eecs.umich.edu break; 2794712Sgblack@eecs.umich.edu 2804712Sgblack@eecs.umich.edu case PCR: 2814730Sgblack@eecs.umich.edu reg = regs.pcr; 2824760Sgblack@eecs.umich.edu break; 2834730Sgblack@eecs.umich.edu 2845920Sgblack@eecs.umich.edu // see the spec sheet for how RFCR and RFDR work 2855422Sgblack@eecs.umich.edu // basically, you write to RFCR to tell the machine 2865422Sgblack@eecs.umich.edu // what you want to do next, then you act upon RFDR, 2874276Sgblack@eecs.umich.edu // and the device will be prepared b/c of what you 2886576Sgblack@eecs.umich.edu // wrote to RFCR 2896576Sgblack@eecs.umich.edu case RFCR: 2906576Sgblack@eecs.umich.edu reg = regs.rfcr; 2916576Sgblack@eecs.umich.edu break; 2926576Sgblack@eecs.umich.edu 2936576Sgblack@eecs.umich.edu case RFDR: 2946576Sgblack@eecs.umich.edu rfaddr = (uint16_t)(regs.rfcr & RFCR_RFADDR); 2956576Sgblack@eecs.umich.edu switch (rfaddr) { 2966576Sgblack@eecs.umich.edu // Read from perfect match ROM octets 2976576Sgblack@eecs.umich.edu case 0x000: 2986576Sgblack@eecs.umich.edu reg = rom.perfectMatch[1]; 2996576Sgblack@eecs.umich.edu reg = reg << 8; 3006576Sgblack@eecs.umich.edu reg += rom.perfectMatch[0]; 3016576Sgblack@eecs.umich.edu break; 3026576Sgblack@eecs.umich.edu case 0x002: 3036576Sgblack@eecs.umich.edu reg = rom.perfectMatch[3] << 8; 3046576Sgblack@eecs.umich.edu reg += rom.perfectMatch[2]; 3056576Sgblack@eecs.umich.edu break; 3065020Sgblack@eecs.umich.edu case 0x004: 3076576Sgblack@eecs.umich.edu reg = rom.perfectMatch[5] << 8; 3086576Sgblack@eecs.umich.edu reg += rom.perfectMatch[4]; 3096600Sgblack@eecs.umich.edu break; 3106600Sgblack@eecs.umich.edu default: 3116576Sgblack@eecs.umich.edu // Read filter hash table 3126576Sgblack@eecs.umich.edu if (rfaddr >= FHASH_ADDR && 3136576Sgblack@eecs.umich.edu rfaddr < FHASH_ADDR + FHASH_SIZE) { 3145020Sgblack@eecs.umich.edu 3156576Sgblack@eecs.umich.edu // Only word-aligned reads supported 3166576Sgblack@eecs.umich.edu if (rfaddr % 2) 3176576Sgblack@eecs.umich.edu panic("unaligned read from filter hash table!"); 3186576Sgblack@eecs.umich.edu 3196576Sgblack@eecs.umich.edu reg = rom.filterHash[rfaddr - FHASH_ADDR + 1] << 8; 3206576Sgblack@eecs.umich.edu reg += rom.filterHash[rfaddr - FHASH_ADDR]; 3216576Sgblack@eecs.umich.edu break; 3226576Sgblack@eecs.umich.edu } 3236576Sgblack@eecs.umich.edu 3246576Sgblack@eecs.umich.edu panic("reading RFDR for something other than pattern" 3256576Sgblack@eecs.umich.edu " matching or hashing! %#x\n", rfaddr); 3266576Sgblack@eecs.umich.edu } 3276576Sgblack@eecs.umich.edu break; 3286576Sgblack@eecs.umich.edu 3296576Sgblack@eecs.umich.edu case SRR: 3306576Sgblack@eecs.umich.edu reg = regs.srr; 3316576Sgblack@eecs.umich.edu break; 3326576Sgblack@eecs.umich.edu 3336576Sgblack@eecs.umich.edu case MIBC: 3344760Sgblack@eecs.umich.edu reg = regs.mibc; 3356576Sgblack@eecs.umich.edu reg &= ~(MIBC_MIBS | MIBC_ACLR); 3366576Sgblack@eecs.umich.edu break; 3376576Sgblack@eecs.umich.edu 3386576Sgblack@eecs.umich.edu case VRCR: 3396576Sgblack@eecs.umich.edu reg = regs.vrcr; 3406576Sgblack@eecs.umich.edu break; 3416576Sgblack@eecs.umich.edu 3426576Sgblack@eecs.umich.edu case VTCR: 3436576Sgblack@eecs.umich.edu reg = regs.vtcr; 3446576Sgblack@eecs.umich.edu break; 3456576Sgblack@eecs.umich.edu 3466576Sgblack@eecs.umich.edu case VDR: 3476576Sgblack@eecs.umich.edu reg = regs.vdr; 3486576Sgblack@eecs.umich.edu break; 3496576Sgblack@eecs.umich.edu 3506576Sgblack@eecs.umich.edu case CCSR: 3514760Sgblack@eecs.umich.edu reg = regs.ccsr; 3526576Sgblack@eecs.umich.edu break; 3536576Sgblack@eecs.umich.edu 3546576Sgblack@eecs.umich.edu case TBICR: 3556576Sgblack@eecs.umich.edu reg = regs.tbicr; 3566576Sgblack@eecs.umich.edu break; 3576576Sgblack@eecs.umich.edu 3586576Sgblack@eecs.umich.edu case TBISR: 3596576Sgblack@eecs.umich.edu reg = regs.tbisr; 3606576Sgblack@eecs.umich.edu break; 3616576Sgblack@eecs.umich.edu 3626576Sgblack@eecs.umich.edu case TANAR: 3636576Sgblack@eecs.umich.edu reg = regs.tanar; 3646576Sgblack@eecs.umich.edu break; 3656576Sgblack@eecs.umich.edu 3666576Sgblack@eecs.umich.edu case TANLPAR: 3676576Sgblack@eecs.umich.edu reg = regs.tanlpar; 3686576Sgblack@eecs.umich.edu break; 3694760Sgblack@eecs.umich.edu 3704276Sgblack@eecs.umich.edu case TANER: 3715020Sgblack@eecs.umich.edu reg = regs.taner; 3725020Sgblack@eecs.umich.edu break; 3735020Sgblack@eecs.umich.edu 3745031Sgblack@eecs.umich.edu case TESR: 3755031Sgblack@eecs.umich.edu reg = regs.tesr; 3765031Sgblack@eecs.umich.edu break; 3775031Sgblack@eecs.umich.edu 3786563Sgblack@eecs.umich.edu case M5REG: 3795020Sgblack@eecs.umich.edu reg = 0; 3806606Sgblack@eecs.umich.edu if (params()->rx_thread) 3816606Sgblack@eecs.umich.edu reg |= M5REG_RX_THREAD; 3826602Sgblack@eecs.umich.edu if (params()->tx_thread) 3836602Sgblack@eecs.umich.edu reg |= M5REG_TX_THREAD; 3845020Sgblack@eecs.umich.edu if (params()->rss) 3855020Sgblack@eecs.umich.edu reg |= M5REG_RSS; 3865020Sgblack@eecs.umich.edu break; 3876563Sgblack@eecs.umich.edu 3886606Sgblack@eecs.umich.edu default: 3896606Sgblack@eecs.umich.edu panic("reading unimplemented register: addr=%#x", daddr); 3905020Sgblack@eecs.umich.edu } 3915020Sgblack@eecs.umich.edu 3925020Sgblack@eecs.umich.edu DPRINTF(EthernetPIO, "read from %#x: data=%d data=%#x\n", 3935020Sgblack@eecs.umich.edu daddr, reg, reg); 3946564Sgblack@eecs.umich.edu 3956564Sgblack@eecs.umich.edu pkt->makeAtomicResponse(); 3966563Sgblack@eecs.umich.edu return pioDelay; 3975020Sgblack@eecs.umich.edu} 3986606Sgblack@eecs.umich.edu 3996606Sgblack@eecs.umich.eduTick 4005058Sgblack@eecs.umich.eduNSGigE::write(PacketPtr pkt) 4016602Sgblack@eecs.umich.edu{ 4025020Sgblack@eecs.umich.edu assert(ioEnable); 4035020Sgblack@eecs.umich.edu 4045020Sgblack@eecs.umich.edu Addr daddr = pkt->getAddr() & 0xfff; 4055046Sgblack@eecs.umich.edu DPRINTF(EthernetPIO, "write da=%#x pa=%#x size=%d\n", 4065046Sgblack@eecs.umich.edu daddr, pkt->getAddr(), pkt->getSize()); 4075046Sgblack@eecs.umich.edu 4085046Sgblack@eecs.umich.edu if (daddr > LAST && daddr <= RESERVED) { 4096606Sgblack@eecs.umich.edu panic("Accessing reserved register"); 4105020Sgblack@eecs.umich.edu } else if (daddr > RESERVED && daddr <= 0x3FC) { 4115020Sgblack@eecs.umich.edu return writeConfig(pkt); 4125020Sgblack@eecs.umich.edu } else if (daddr > 0x3FC) 4134276Sgblack@eecs.umich.edu panic("Something is messed up!\n"); 4144276Sgblack@eecs.umich.edu 4155149Sgblack@eecs.umich.edu if (pkt->getSize() == sizeof(uint32_t)) { 4165409Sgblack@eecs.umich.edu uint32_t reg = pkt->get<uint32_t>(); 4175149Sgblack@eecs.umich.edu uint16_t rfaddr; 4184712Sgblack@eecs.umich.edu 4195972Sgblack@eecs.umich.edu DPRINTF(EthernetPIO, "write data=%d data=%#x\n", reg, reg); 4204712Sgblack@eecs.umich.edu 4215972Sgblack@eecs.umich.edu switch (daddr) { 4225972Sgblack@eecs.umich.edu case CR: 4235972Sgblack@eecs.umich.edu regs.command = reg; 4244712Sgblack@eecs.umich.edu if (reg & CR_TXD) { 4254730Sgblack@eecs.umich.edu txEnable = false; 4264712Sgblack@eecs.umich.edu } else if (reg & CR_TXE) { 4274276Sgblack@eecs.umich.edu txEnable = true; 4284276Sgblack@eecs.umich.edu 4294712Sgblack@eecs.umich.edu // the kernel is enabling the transmit machine 4304712Sgblack@eecs.umich.edu if (txState == txIdle) 4314712Sgblack@eecs.umich.edu txKick(); 4324712Sgblack@eecs.umich.edu } 4334712Sgblack@eecs.umich.edu 4344712Sgblack@eecs.umich.edu if (reg & CR_RXD) { 4354712Sgblack@eecs.umich.edu rxEnable = false; 4364712Sgblack@eecs.umich.edu } else if (reg & CR_RXE) { 4374276Sgblack@eecs.umich.edu rxEnable = true; 4384760Sgblack@eecs.umich.edu 4394760Sgblack@eecs.umich.edu if (rxState == rxIdle) 4404760Sgblack@eecs.umich.edu rxKick(); 4414760Sgblack@eecs.umich.edu } 4424760Sgblack@eecs.umich.edu 4434760Sgblack@eecs.umich.edu if (reg & CR_TXR) 4444760Sgblack@eecs.umich.edu txReset(); 4454760Sgblack@eecs.umich.edu 4464760Sgblack@eecs.umich.edu if (reg & CR_RXR) 4474760Sgblack@eecs.umich.edu rxReset(); 4484760Sgblack@eecs.umich.edu 4494760Sgblack@eecs.umich.edu if (reg & CR_SWI) 4504760Sgblack@eecs.umich.edu devIntrPost(ISR_SWI); 4514760Sgblack@eecs.umich.edu 4524760Sgblack@eecs.umich.edu if (reg & CR_RST) { 4534760Sgblack@eecs.umich.edu txReset(); 4544760Sgblack@eecs.umich.edu rxReset(); 4554760Sgblack@eecs.umich.edu 4564760Sgblack@eecs.umich.edu regsReset(); 4574760Sgblack@eecs.umich.edu } 4584760Sgblack@eecs.umich.edu break; 4596576Sgblack@eecs.umich.edu 4606576Sgblack@eecs.umich.edu case CFGR: 4616576Sgblack@eecs.umich.edu if (reg & CFGR_LNKSTS || 4626593Sgblack@eecs.umich.edu reg & CFGR_SPDSTS || 4636576Sgblack@eecs.umich.edu reg & CFGR_DUPSTS || 4646576Sgblack@eecs.umich.edu reg & CFGR_RESERVED || 4656576Sgblack@eecs.umich.edu reg & CFGR_T64ADDR || 4666576Sgblack@eecs.umich.edu reg & CFGR_PCI64_DET) 4676576Sgblack@eecs.umich.edu 4686576Sgblack@eecs.umich.edu // First clear all writable bits 4696576Sgblack@eecs.umich.edu regs.config &= CFGR_LNKSTS | CFGR_SPDSTS | CFGR_DUPSTS | 4706576Sgblack@eecs.umich.edu CFGR_RESERVED | CFGR_T64ADDR | 4716576Sgblack@eecs.umich.edu CFGR_PCI64_DET; 4726576Sgblack@eecs.umich.edu // Now set the appropriate writable bits 4736576Sgblack@eecs.umich.edu regs.config |= reg & ~(CFGR_LNKSTS | CFGR_SPDSTS | CFGR_DUPSTS | 4746576Sgblack@eecs.umich.edu CFGR_RESERVED | CFGR_T64ADDR | 4756576Sgblack@eecs.umich.edu CFGR_PCI64_DET); 4766576Sgblack@eecs.umich.edu 4776576Sgblack@eecs.umich.edu// all these #if 0's are because i don't THINK the kernel needs to 4786576Sgblack@eecs.umich.edu// have these implemented. if there is a problem relating to one of 4796576Sgblack@eecs.umich.edu// these, you may need to add functionality in. 4806593Sgblack@eecs.umich.edu if (reg & CFGR_TBI_EN) ; 4816576Sgblack@eecs.umich.edu if (reg & CFGR_MODE_1000) ; 4826576Sgblack@eecs.umich.edu 4836576Sgblack@eecs.umich.edu if (reg & CFGR_AUTO_1000) 4846576Sgblack@eecs.umich.edu panic("CFGR_AUTO_1000 not implemented!\n"); 4856576Sgblack@eecs.umich.edu 4866576Sgblack@eecs.umich.edu if (reg & CFGR_PINT_DUPSTS || 4876576Sgblack@eecs.umich.edu reg & CFGR_PINT_LNKSTS || 4886576Sgblack@eecs.umich.edu reg & CFGR_PINT_SPDSTS) 4896576Sgblack@eecs.umich.edu ; 4905059Sgblack@eecs.umich.edu 4915059Sgblack@eecs.umich.edu if (reg & CFGR_TMRTEST) ; 4926576Sgblack@eecs.umich.edu if (reg & CFGR_MRM_DIS) ; 4935059Sgblack@eecs.umich.edu if (reg & CFGR_MWI_DIS) ; 4945059Sgblack@eecs.umich.edu 4955059Sgblack@eecs.umich.edu if (reg & CFGR_T64ADDR) ; 4965020Sgblack@eecs.umich.edu // panic("CFGR_T64ADDR is read only register!\n"); 4976576Sgblack@eecs.umich.edu 4986576Sgblack@eecs.umich.edu if (reg & CFGR_PCI64_DET) 4996576Sgblack@eecs.umich.edu panic("CFGR_PCI64_DET is read only register!\n"); 5006576Sgblack@eecs.umich.edu 5016576Sgblack@eecs.umich.edu if (reg & CFGR_DATA64_EN) ; 5026576Sgblack@eecs.umich.edu if (reg & CFGR_M64ADDR) ; 5036576Sgblack@eecs.umich.edu if (reg & CFGR_PHY_RST) ; 5046576Sgblack@eecs.umich.edu if (reg & CFGR_PHY_DIS) ; 5056576Sgblack@eecs.umich.edu 5066576Sgblack@eecs.umich.edu if (reg & CFGR_EXTSTS_EN) 5076576Sgblack@eecs.umich.edu extstsEnable = true; 5086576Sgblack@eecs.umich.edu else 5096576Sgblack@eecs.umich.edu extstsEnable = false; 5106576Sgblack@eecs.umich.edu 5116576Sgblack@eecs.umich.edu if (reg & CFGR_REQALG) ; 5126576Sgblack@eecs.umich.edu if (reg & CFGR_SB) ; 5136576Sgblack@eecs.umich.edu if (reg & CFGR_POW) ; 5146606Sgblack@eecs.umich.edu if (reg & CFGR_EXD) ; 5156576Sgblack@eecs.umich.edu if (reg & CFGR_PESEL) ; 5166576Sgblack@eecs.umich.edu if (reg & CFGR_BROM_DIS) ; 5176576Sgblack@eecs.umich.edu if (reg & CFGR_EXT_125) ; 5186576Sgblack@eecs.umich.edu if (reg & CFGR_BEM) ; 5196576Sgblack@eecs.umich.edu break; 5206576Sgblack@eecs.umich.edu 5216576Sgblack@eecs.umich.edu case MEAR: 5226576Sgblack@eecs.umich.edu // Clear writable bits 5236576Sgblack@eecs.umich.edu regs.mear &= MEAR_EEDO; 5246576Sgblack@eecs.umich.edu // Set appropriate writable bits 5256606Sgblack@eecs.umich.edu regs.mear |= reg & ~MEAR_EEDO; 5266576Sgblack@eecs.umich.edu 5276576Sgblack@eecs.umich.edu // FreeBSD uses the EEPROM to read PMATCH (for the MAC address) 5286576Sgblack@eecs.umich.edu // even though it could get it through RFDR 5296576Sgblack@eecs.umich.edu if (reg & MEAR_EESEL) { 5306576Sgblack@eecs.umich.edu // Rising edge of clock 5316576Sgblack@eecs.umich.edu if (reg & MEAR_EECLK && !eepromClk) 5326576Sgblack@eecs.umich.edu eepromKick(); 5336576Sgblack@eecs.umich.edu } 5346576Sgblack@eecs.umich.edu else { 5356576Sgblack@eecs.umich.edu eepromState = eepromStart; 5366576Sgblack@eecs.umich.edu regs.mear &= ~MEAR_EEDI; 5376576Sgblack@eecs.umich.edu } 5386576Sgblack@eecs.umich.edu 5396576Sgblack@eecs.umich.edu eepromClk = reg & MEAR_EECLK; 5406576Sgblack@eecs.umich.edu 5416576Sgblack@eecs.umich.edu // since phy is completely faked, MEAR_MD* don't matter 5426576Sgblack@eecs.umich.edu if (reg & MEAR_MDIO) ; 5435020Sgblack@eecs.umich.edu if (reg & MEAR_MDDIR) ; 5446576Sgblack@eecs.umich.edu if (reg & MEAR_MDC) ; 5456576Sgblack@eecs.umich.edu break; 5466576Sgblack@eecs.umich.edu 5476576Sgblack@eecs.umich.edu case PTSCR: 5486576Sgblack@eecs.umich.edu regs.ptscr = reg & ~(PTSCR_RBIST_RDONLY); 5496576Sgblack@eecs.umich.edu // these control BISTs for various parts of chip - we 5506576Sgblack@eecs.umich.edu // don't care or do just fake that the BIST is done 5516576Sgblack@eecs.umich.edu if (reg & PTSCR_RBIST_EN) 5526576Sgblack@eecs.umich.edu regs.ptscr |= PTSCR_RBIST_DONE; 5536576Sgblack@eecs.umich.edu if (reg & PTSCR_EEBIST_EN) 5546576Sgblack@eecs.umich.edu regs.ptscr &= ~PTSCR_EEBIST_EN; 5556576Sgblack@eecs.umich.edu if (reg & PTSCR_EELOAD_EN) 5566576Sgblack@eecs.umich.edu regs.ptscr &= ~PTSCR_EELOAD_EN; 5576576Sgblack@eecs.umich.edu break; 5586576Sgblack@eecs.umich.edu 5596576Sgblack@eecs.umich.edu case ISR: /* writing to the ISR has no effect */ 5606576Sgblack@eecs.umich.edu panic("ISR is a read only register!\n"); 5616576Sgblack@eecs.umich.edu 5626576Sgblack@eecs.umich.edu case IMR: 5636576Sgblack@eecs.umich.edu regs.imr = reg; 5646576Sgblack@eecs.umich.edu devIntrChangeMask(); 5656576Sgblack@eecs.umich.edu break; 5666576Sgblack@eecs.umich.edu 5676576Sgblack@eecs.umich.edu case IER: 5685020Sgblack@eecs.umich.edu regs.ier = reg; 5696576Sgblack@eecs.umich.edu break; 5706576Sgblack@eecs.umich.edu 5716576Sgblack@eecs.umich.edu case IHR: 5726576Sgblack@eecs.umich.edu regs.ihr = reg; 5736576Sgblack@eecs.umich.edu /* not going to implement real interrupt holdoff */ 5746576Sgblack@eecs.umich.edu break; 5756576Sgblack@eecs.umich.edu 5766576Sgblack@eecs.umich.edu case TXDP: 5776576Sgblack@eecs.umich.edu regs.txdp = (reg & 0xFFFFFFFC); 5786576Sgblack@eecs.umich.edu assert(txState == txIdle); 5796576Sgblack@eecs.umich.edu CTDD = false; 5806576Sgblack@eecs.umich.edu break; 5816576Sgblack@eecs.umich.edu 5826576Sgblack@eecs.umich.edu case TXDP_HI: 5836576Sgblack@eecs.umich.edu regs.txdp_hi = reg; 5846576Sgblack@eecs.umich.edu break; 5856576Sgblack@eecs.umich.edu 5866576Sgblack@eecs.umich.edu case TX_CFG: 5876576Sgblack@eecs.umich.edu regs.txcfg = reg; 5886576Sgblack@eecs.umich.edu#if 0 5896576Sgblack@eecs.umich.edu if (reg & TX_CFG_CSI) ; 5906576Sgblack@eecs.umich.edu if (reg & TX_CFG_HBI) ; 5916576Sgblack@eecs.umich.edu if (reg & TX_CFG_MLB) ; 5926576Sgblack@eecs.umich.edu if (reg & TX_CFG_ATP) ; 5936576Sgblack@eecs.umich.edu if (reg & TX_CFG_ECRETRY) { 5946576Sgblack@eecs.umich.edu /* 5956576Sgblack@eecs.umich.edu * this could easily be implemented, but considering 5966576Sgblack@eecs.umich.edu * the network is just a fake pipe, wouldn't make 5975020Sgblack@eecs.umich.edu * sense to do this 5986584Sgblack@eecs.umich.edu */ 5996584Sgblack@eecs.umich.edu } 6006584Sgblack@eecs.umich.edu 6016597Sgblack@eecs.umich.edu if (reg & TX_CFG_BRST_DIS) ; 6026584Sgblack@eecs.umich.edu#endif 6036584Sgblack@eecs.umich.edu 6046584Sgblack@eecs.umich.edu#if 0 6056584Sgblack@eecs.umich.edu /* we handle our own DMA, ignore the kernel's exhortations */ 6066584Sgblack@eecs.umich.edu if (reg & TX_CFG_MXDMA) ; 6076584Sgblack@eecs.umich.edu#endif 6086584Sgblack@eecs.umich.edu 6096584Sgblack@eecs.umich.edu // also, we currently don't care about fill/drain 6106584Sgblack@eecs.umich.edu // thresholds though this may change in the future with 6116584Sgblack@eecs.umich.edu // more realistic networks or a driver which changes it 6126584Sgblack@eecs.umich.edu // according to feedback 6136584Sgblack@eecs.umich.edu 6146584Sgblack@eecs.umich.edu break; 6156584Sgblack@eecs.umich.edu 6166584Sgblack@eecs.umich.edu case GPIOR: 6175238Sgblack@eecs.umich.edu // Only write writable bits 6186584Sgblack@eecs.umich.edu regs.gpior &= GPIOR_UNUSED | GPIOR_GP5_IN | GPIOR_GP4_IN 6196584Sgblack@eecs.umich.edu | GPIOR_GP3_IN | GPIOR_GP2_IN | GPIOR_GP1_IN; 6206584Sgblack@eecs.umich.edu regs.gpior |= reg & ~(GPIOR_UNUSED | GPIOR_GP5_IN | GPIOR_GP4_IN 6216584Sgblack@eecs.umich.edu | GPIOR_GP3_IN | GPIOR_GP2_IN | GPIOR_GP1_IN); 6226584Sgblack@eecs.umich.edu /* these just control general purpose i/o pins, don't matter */ 6236584Sgblack@eecs.umich.edu break; 6246584Sgblack@eecs.umich.edu 6256584Sgblack@eecs.umich.edu case RXDP: 6266584Sgblack@eecs.umich.edu regs.rxdp = reg; 6276584Sgblack@eecs.umich.edu CRDD = false; 6286584Sgblack@eecs.umich.edu break; 6296584Sgblack@eecs.umich.edu 6306584Sgblack@eecs.umich.edu case RXDP_HI: 6316584Sgblack@eecs.umich.edu regs.rxdp_hi = reg; 6326584Sgblack@eecs.umich.edu break; 6335238Sgblack@eecs.umich.edu 6346584Sgblack@eecs.umich.edu case RX_CFG: 6356584Sgblack@eecs.umich.edu regs.rxcfg = reg; 6366584Sgblack@eecs.umich.edu#if 0 6376584Sgblack@eecs.umich.edu if (reg & RX_CFG_AEP) ; 6386584Sgblack@eecs.umich.edu if (reg & RX_CFG_ARP) ; 6396584Sgblack@eecs.umich.edu if (reg & RX_CFG_STRIPCRC) ; 6406584Sgblack@eecs.umich.edu if (reg & RX_CFG_RX_RD) ; 6416584Sgblack@eecs.umich.edu if (reg & RX_CFG_ALP) ; 6426584Sgblack@eecs.umich.edu if (reg & RX_CFG_AIRL) ; 6436584Sgblack@eecs.umich.edu 6446584Sgblack@eecs.umich.edu /* we handle our own DMA, ignore what kernel says about it */ 6456584Sgblack@eecs.umich.edu if (reg & RX_CFG_MXDMA) ; 6466584Sgblack@eecs.umich.edu 6476584Sgblack@eecs.umich.edu //also, we currently don't care about fill/drain thresholds 6486584Sgblack@eecs.umich.edu //though this may change in the future with more realistic 6496584Sgblack@eecs.umich.edu //networks or a driver which changes it according to feedback 6506584Sgblack@eecs.umich.edu if (reg & (RX_CFG_DRTH | RX_CFG_DRTH0)) ; 6516584Sgblack@eecs.umich.edu#endif 6526584Sgblack@eecs.umich.edu break; 6535238Sgblack@eecs.umich.edu 6546584Sgblack@eecs.umich.edu case PQCR: 6556584Sgblack@eecs.umich.edu /* there is no priority queueing used in the linux 2.6 driver */ 6566584Sgblack@eecs.umich.edu regs.pqcr = reg; 6576584Sgblack@eecs.umich.edu break; 6585238Sgblack@eecs.umich.edu 6596584Sgblack@eecs.umich.edu case WCSR: 6606584Sgblack@eecs.umich.edu /* not going to implement wake on LAN */ 6616597Sgblack@eecs.umich.edu regs.wcsr = reg; 6626584Sgblack@eecs.umich.edu break; 6636584Sgblack@eecs.umich.edu 6646584Sgblack@eecs.umich.edu case PCR: 6656584Sgblack@eecs.umich.edu /* not going to implement pause control */ 6666597Sgblack@eecs.umich.edu regs.pcr = reg; 6676584Sgblack@eecs.umich.edu break; 6686584Sgblack@eecs.umich.edu 6696584Sgblack@eecs.umich.edu case RFCR: 6706584Sgblack@eecs.umich.edu regs.rfcr = reg; 6716584Sgblack@eecs.umich.edu 6726584Sgblack@eecs.umich.edu rxFilterEnable = (reg & RFCR_RFEN) ? true : false; 6736584Sgblack@eecs.umich.edu acceptBroadcast = (reg & RFCR_AAB) ? true : false; 6746584Sgblack@eecs.umich.edu acceptMulticast = (reg & RFCR_AAM) ? true : false; 6756584Sgblack@eecs.umich.edu acceptUnicast = (reg & RFCR_AAU) ? true : false; 6766584Sgblack@eecs.umich.edu acceptPerfect = (reg & RFCR_APM) ? true : false; 6776584Sgblack@eecs.umich.edu acceptArp = (reg & RFCR_AARP) ? true : false; 6786584Sgblack@eecs.umich.edu multicastHashEnable = (reg & RFCR_MHEN) ? true : false; 6796584Sgblack@eecs.umich.edu 6806584Sgblack@eecs.umich.edu#if 0 6816584Sgblack@eecs.umich.edu if (reg & RFCR_APAT) 6825238Sgblack@eecs.umich.edu panic("RFCR_APAT not implemented!\n"); 6836584Sgblack@eecs.umich.edu#endif 6846584Sgblack@eecs.umich.edu if (reg & RFCR_UHEN) 6856584Sgblack@eecs.umich.edu panic("Unicast hash filtering not used by drivers!\n"); 6866584Sgblack@eecs.umich.edu 6876584Sgblack@eecs.umich.edu if (reg & RFCR_ULM) 6886584Sgblack@eecs.umich.edu panic("RFCR_ULM not implemented!\n"); 6896584Sgblack@eecs.umich.edu 6906584Sgblack@eecs.umich.edu break; 6916584Sgblack@eecs.umich.edu 6926584Sgblack@eecs.umich.edu case RFDR: 6936584Sgblack@eecs.umich.edu rfaddr = (uint16_t)(regs.rfcr & RFCR_RFADDR); 6946584Sgblack@eecs.umich.edu switch (rfaddr) { 6956584Sgblack@eecs.umich.edu case 0x000: 6966584Sgblack@eecs.umich.edu rom.perfectMatch[0] = (uint8_t)reg; 6976584Sgblack@eecs.umich.edu rom.perfectMatch[1] = (uint8_t)(reg >> 8); 6985238Sgblack@eecs.umich.edu break; 6996584Sgblack@eecs.umich.edu case 0x002: 7006584Sgblack@eecs.umich.edu rom.perfectMatch[2] = (uint8_t)reg; 7016584Sgblack@eecs.umich.edu rom.perfectMatch[3] = (uint8_t)(reg >> 8); 7026584Sgblack@eecs.umich.edu break; 7036584Sgblack@eecs.umich.edu case 0x004: 7046584Sgblack@eecs.umich.edu rom.perfectMatch[4] = (uint8_t)reg; 7056584Sgblack@eecs.umich.edu rom.perfectMatch[5] = (uint8_t)(reg >> 8); 7066584Sgblack@eecs.umich.edu break; 7076584Sgblack@eecs.umich.edu default: 7086584Sgblack@eecs.umich.edu 7096584Sgblack@eecs.umich.edu if (rfaddr >= FHASH_ADDR && 7106584Sgblack@eecs.umich.edu rfaddr < FHASH_ADDR + FHASH_SIZE) { 7116584Sgblack@eecs.umich.edu 7126584Sgblack@eecs.umich.edu // Only word-aligned writes supported 7136584Sgblack@eecs.umich.edu if (rfaddr % 2) 7146584Sgblack@eecs.umich.edu panic("unaligned write to filter hash table!"); 7156584Sgblack@eecs.umich.edu 7166584Sgblack@eecs.umich.edu rom.filterHash[rfaddr - FHASH_ADDR] = (uint8_t)reg; 7176584Sgblack@eecs.umich.edu rom.filterHash[rfaddr - FHASH_ADDR + 1] 7185238Sgblack@eecs.umich.edu = (uint8_t)(reg >> 8); 7196584Sgblack@eecs.umich.edu break; 7206584Sgblack@eecs.umich.edu } 7216584Sgblack@eecs.umich.edu panic("writing RFDR for something other than pattern matching\ 7226584Sgblack@eecs.umich.edu or hashing! %#x\n", rfaddr); 7235238Sgblack@eecs.umich.edu } 7246584Sgblack@eecs.umich.edu 7256584Sgblack@eecs.umich.edu case BRAR: 7266597Sgblack@eecs.umich.edu regs.brar = reg; 7276584Sgblack@eecs.umich.edu break; 7285238Sgblack@eecs.umich.edu 7296584Sgblack@eecs.umich.edu case BRDR: 7305020Sgblack@eecs.umich.edu panic("the driver never uses BRDR, something is wrong!\n"); 7316584Sgblack@eecs.umich.edu 7326584Sgblack@eecs.umich.edu case SRR: 7336584Sgblack@eecs.umich.edu panic("SRR is read only register!\n"); 7346584Sgblack@eecs.umich.edu 7356584Sgblack@eecs.umich.edu case MIBC: 7366584Sgblack@eecs.umich.edu panic("the driver never uses MIBC, something is wrong!\n"); 7376584Sgblack@eecs.umich.edu 7386584Sgblack@eecs.umich.edu case VRCR: 7396584Sgblack@eecs.umich.edu regs.vrcr = reg; 7406584Sgblack@eecs.umich.edu break; 7416584Sgblack@eecs.umich.edu 7426584Sgblack@eecs.umich.edu case VTCR: 7436584Sgblack@eecs.umich.edu regs.vtcr = reg; 7446584Sgblack@eecs.umich.edu break; 7456584Sgblack@eecs.umich.edu 7466584Sgblack@eecs.umich.edu case VDR: 7476584Sgblack@eecs.umich.edu panic("the driver never uses VDR, something is wrong!\n"); 7486584Sgblack@eecs.umich.edu 7496584Sgblack@eecs.umich.edu case CCSR: 7506584Sgblack@eecs.umich.edu /* not going to implement clockrun stuff */ 7516584Sgblack@eecs.umich.edu regs.ccsr = reg; 7526584Sgblack@eecs.umich.edu break; 7536584Sgblack@eecs.umich.edu 7546584Sgblack@eecs.umich.edu case TBICR: 7556584Sgblack@eecs.umich.edu regs.tbicr = reg; 7566584Sgblack@eecs.umich.edu if (reg & TBICR_MR_LOOPBACK) 7576584Sgblack@eecs.umich.edu panic("TBICR_MR_LOOPBACK never used, something wrong!\n"); 7586584Sgblack@eecs.umich.edu 7596584Sgblack@eecs.umich.edu if (reg & TBICR_MR_AN_ENABLE) { 7606584Sgblack@eecs.umich.edu regs.tanlpar = regs.tanar; 7615020Sgblack@eecs.umich.edu regs.tbisr |= (TBISR_MR_AN_COMPLETE | TBISR_MR_LINK_STATUS); 7624727Sgblack@eecs.umich.edu } 7634727Sgblack@eecs.umich.edu 7644727Sgblack@eecs.umich.edu#if 0 7654727Sgblack@eecs.umich.edu if (reg & TBICR_MR_RESTART_AN) ; 7664727Sgblack@eecs.umich.edu#endif 7674727Sgblack@eecs.umich.edu 7684727Sgblack@eecs.umich.edu break; 7694727Sgblack@eecs.umich.edu 7704727Sgblack@eecs.umich.edu case TBISR: 7714727Sgblack@eecs.umich.edu panic("TBISR is read only register!\n"); 7724727Sgblack@eecs.umich.edu 7734727Sgblack@eecs.umich.edu case TANAR: 7744727Sgblack@eecs.umich.edu // Only write the writable bits 7754727Sgblack@eecs.umich.edu regs.tanar &= TANAR_RF1 | TANAR_RF2 | TANAR_UNUSED; 7764727Sgblack@eecs.umich.edu regs.tanar |= reg & ~(TANAR_RF1 | TANAR_RF2 | TANAR_UNUSED); 7774727Sgblack@eecs.umich.edu 7784727Sgblack@eecs.umich.edu // Pause capability unimplemented 7794727Sgblack@eecs.umich.edu#if 0 7804727Sgblack@eecs.umich.edu if (reg & TANAR_PS2) ; 7814727Sgblack@eecs.umich.edu if (reg & TANAR_PS1) ; 7824760Sgblack@eecs.umich.edu#endif 7834760Sgblack@eecs.umich.edu 7844760Sgblack@eecs.umich.edu break; 7854760Sgblack@eecs.umich.edu 7864760Sgblack@eecs.umich.edu case TANLPAR: 7874760Sgblack@eecs.umich.edu panic("this should only be written to by the fake phy!\n"); 7884760Sgblack@eecs.umich.edu 7894760Sgblack@eecs.umich.edu case TANER: 7904760Sgblack@eecs.umich.edu panic("TANER is read only register!\n"); 7914760Sgblack@eecs.umich.edu 7924760Sgblack@eecs.umich.edu case TESR: 7934760Sgblack@eecs.umich.edu regs.tesr = reg; 7944760Sgblack@eecs.umich.edu break; 7954760Sgblack@eecs.umich.edu 7964760Sgblack@eecs.umich.edu default: 7974760Sgblack@eecs.umich.edu panic("invalid register access daddr=%#x", daddr); 7984760Sgblack@eecs.umich.edu } 7994760Sgblack@eecs.umich.edu } else { 8004760Sgblack@eecs.umich.edu panic("Invalid Request Size"); 8014760Sgblack@eecs.umich.edu } 8024276Sgblack@eecs.umich.edu pkt->makeAtomicResponse(); 8034276Sgblack@eecs.umich.edu return pioDelay; 8044712Sgblack@eecs.umich.edu} 8054712Sgblack@eecs.umich.edu 8065659Sgblack@eecs.umich.eduvoid 8075659Sgblack@eecs.umich.eduNSGigE::devIntrPost(uint32_t interrupts) 8086052Sgblack@eecs.umich.edu{ 8095659Sgblack@eecs.umich.edu if (interrupts & ISR_RESERVE) 8105659Sgblack@eecs.umich.edu panic("Cannot set a reserved interrupt"); 8115659Sgblack@eecs.umich.edu 8125659Sgblack@eecs.umich.edu if (interrupts & ISR_NOIMPL) 8135659Sgblack@eecs.umich.edu warn("interrupt not implemented %#x\n", interrupts); 8145240Sgblack@eecs.umich.edu 8156480Sgblack@eecs.umich.edu interrupts &= ISR_IMPL; 8166480Sgblack@eecs.umich.edu regs.isr |= interrupts; 8174712Sgblack@eecs.umich.edu 8184712Sgblack@eecs.umich.edu if (interrupts & regs.imr) { 8194276Sgblack@eecs.umich.edu if (interrupts & ISR_SWI) { 8204276Sgblack@eecs.umich.edu totalSwi++; 8214712Sgblack@eecs.umich.edu } 8224712Sgblack@eecs.umich.edu if (interrupts & ISR_RXIDLE) { 8234712Sgblack@eecs.umich.edu totalRxIdle++; 8245240Sgblack@eecs.umich.edu } 8255977Sgblack@eecs.umich.edu if (interrupts & ISR_RXOK) { 8266481Sgblack@eecs.umich.edu totalRxOk++; 8275238Sgblack@eecs.umich.edu } 8285967Sgblack@eecs.umich.edu if (interrupts & ISR_RXDESC) { 8295967Sgblack@eecs.umich.edu totalRxDesc++; 8305967Sgblack@eecs.umich.edu } 8316599Sgblack@eecs.umich.edu if (interrupts & ISR_TXOK) { 8326598Sgblack@eecs.umich.edu totalTxOk++; 8335967Sgblack@eecs.umich.edu } 8345967Sgblack@eecs.umich.edu if (interrupts & ISR_TXIDLE) { 8355967Sgblack@eecs.umich.edu totalTxIdle++; 8365923Sgblack@eecs.umich.edu } 8375238Sgblack@eecs.umich.edu if (interrupts & ISR_TXDESC) { 8385238Sgblack@eecs.umich.edu totalTxDesc++; 8395967Sgblack@eecs.umich.edu } 8405967Sgblack@eecs.umich.edu if (interrupts & ISR_RXORN) { 8415967Sgblack@eecs.umich.edu totalRxOrn++; 8425967Sgblack@eecs.umich.edu } 8435967Sgblack@eecs.umich.edu } 8445967Sgblack@eecs.umich.edu 8455967Sgblack@eecs.umich.edu DPRINTF(EthernetIntr, 8465967Sgblack@eecs.umich.edu "interrupt written to ISR: intr=%#x isr=%#x imr=%#x\n", 8475238Sgblack@eecs.umich.edu interrupts, regs.isr, regs.imr); 8485238Sgblack@eecs.umich.edu 8495238Sgblack@eecs.umich.edu if ((regs.isr & regs.imr)) { 8504724Sgblack@eecs.umich.edu Tick when = curTick; 8514276Sgblack@eecs.umich.edu if ((regs.isr & regs.imr & ISR_NODELAY) == 0) 8526593Sgblack@eecs.umich.edu when += intrDelay; 8536593Sgblack@eecs.umich.edu postedInterrupts++; 8546593Sgblack@eecs.umich.edu cpuIntrPost(when); 8556593Sgblack@eecs.umich.edu } 8566593Sgblack@eecs.umich.edu} 8576593Sgblack@eecs.umich.edu 8586593Sgblack@eecs.umich.edu/* writing this interrupt counting stats inside this means that this function 8596593Sgblack@eecs.umich.edu is now limited to being used to clear all interrupts upon the kernel 8606593Sgblack@eecs.umich.edu reading isr and servicing. just telling you in case you were thinking 8616593Sgblack@eecs.umich.edu of expanding use. 8626593Sgblack@eecs.umich.edu*/ 8636593Sgblack@eecs.umich.eduvoid 8646593Sgblack@eecs.umich.eduNSGigE::devIntrClear(uint32_t interrupts) 8656593Sgblack@eecs.umich.edu{ 8666593Sgblack@eecs.umich.edu if (interrupts & ISR_RESERVE) 8676593Sgblack@eecs.umich.edu panic("Cannot clear a reserved interrupt"); 8686593Sgblack@eecs.umich.edu 8695240Sgblack@eecs.umich.edu if (regs.isr & regs.imr & ISR_SWI) { 8705240Sgblack@eecs.umich.edu postedSwi++; 8715240Sgblack@eecs.umich.edu } 8725240Sgblack@eecs.umich.edu if (regs.isr & regs.imr & ISR_RXIDLE) { 8735240Sgblack@eecs.umich.edu postedRxIdle++; 8745240Sgblack@eecs.umich.edu } 8755240Sgblack@eecs.umich.edu if (regs.isr & regs.imr & ISR_RXOK) { 8765240Sgblack@eecs.umich.edu postedRxOk++; 8775240Sgblack@eecs.umich.edu } 8785240Sgblack@eecs.umich.edu if (regs.isr & regs.imr & ISR_RXDESC) { 8795240Sgblack@eecs.umich.edu postedRxDesc++; 8806593Sgblack@eecs.umich.edu } 8816593Sgblack@eecs.umich.edu if (regs.isr & regs.imr & ISR_TXOK) { 8826593Sgblack@eecs.umich.edu postedTxOk++; 8836593Sgblack@eecs.umich.edu } 8846593Sgblack@eecs.umich.edu if (regs.isr & regs.imr & ISR_TXIDLE) { 8856593Sgblack@eecs.umich.edu postedTxIdle++; 8866593Sgblack@eecs.umich.edu } 8876593Sgblack@eecs.umich.edu if (regs.isr & regs.imr & ISR_TXDESC) { 8885238Sgblack@eecs.umich.edu postedTxDesc++; 8896576Sgblack@eecs.umich.edu } 8906576Sgblack@eecs.umich.edu if (regs.isr & regs.imr & ISR_RXORN) { 8916576Sgblack@eecs.umich.edu postedRxOrn++; 8926576Sgblack@eecs.umich.edu } 8936576Sgblack@eecs.umich.edu 8946576Sgblack@eecs.umich.edu interrupts &= ~ISR_NOIMPL; 8956576Sgblack@eecs.umich.edu regs.isr &= ~interrupts; 8966576Sgblack@eecs.umich.edu 8976576Sgblack@eecs.umich.edu DPRINTF(EthernetIntr, 8986576Sgblack@eecs.umich.edu "interrupt cleared from ISR: intr=%x isr=%x imr=%x\n", 8996576Sgblack@eecs.umich.edu interrupts, regs.isr, regs.imr); 9006576Sgblack@eecs.umich.edu 9016576Sgblack@eecs.umich.edu if (!(regs.isr & regs.imr)) 9025238Sgblack@eecs.umich.edu cpuIntrClear(); 9036576Sgblack@eecs.umich.edu} 9046576Sgblack@eecs.umich.edu 9055238Sgblack@eecs.umich.eduvoid 9066576Sgblack@eecs.umich.eduNSGigE::devIntrChangeMask() 9076576Sgblack@eecs.umich.edu{ 9086576Sgblack@eecs.umich.edu DPRINTF(EthernetIntr, "interrupt mask changed: isr=%x imr=%x masked=%x\n", 9096604Sgblack@eecs.umich.edu regs.isr, regs.imr, regs.isr & regs.imr); 9106590Sgblack@eecs.umich.edu 9116591Sgblack@eecs.umich.edu if (regs.isr & regs.imr) 9126591Sgblack@eecs.umich.edu cpuIntrPost(curTick); 9136597Sgblack@eecs.umich.edu else 9146576Sgblack@eecs.umich.edu cpuIntrClear(); 9156576Sgblack@eecs.umich.edu} 9166576Sgblack@eecs.umich.edu 9176604Sgblack@eecs.umich.eduvoid 9186576Sgblack@eecs.umich.eduNSGigE::cpuIntrPost(Tick when) 9196576Sgblack@eecs.umich.edu{ 9206576Sgblack@eecs.umich.edu // If the interrupt you want to post is later than an interrupt 9216576Sgblack@eecs.umich.edu // already scheduled, just let it post in the coming one and don't 9226604Sgblack@eecs.umich.edu // schedule another. 9236591Sgblack@eecs.umich.edu // HOWEVER, must be sure that the scheduled intrTick is in the 9246591Sgblack@eecs.umich.edu // future (this was formerly the source of a bug) 9256597Sgblack@eecs.umich.edu /** 9266576Sgblack@eecs.umich.edu * @todo this warning should be removed and the intrTick code should 9276576Sgblack@eecs.umich.edu * be fixed. 9286576Sgblack@eecs.umich.edu */ 9296576Sgblack@eecs.umich.edu assert(when >= curTick); 9306604Sgblack@eecs.umich.edu assert(intrTick >= curTick || intrTick == 0); 9316576Sgblack@eecs.umich.edu if (when > intrTick && intrTick != 0) { 9326576Sgblack@eecs.umich.edu DPRINTF(EthernetIntr, "don't need to schedule event...intrTick=%d\n", 9336576Sgblack@eecs.umich.edu intrTick); 9346576Sgblack@eecs.umich.edu return; 9355238Sgblack@eecs.umich.edu } 9366576Sgblack@eecs.umich.edu 9376576Sgblack@eecs.umich.edu intrTick = when; 9386576Sgblack@eecs.umich.edu if (intrTick < curTick) { 9396576Sgblack@eecs.umich.edu debug_break(); 9405020Sgblack@eecs.umich.edu intrTick = curTick; 9416593Sgblack@eecs.umich.edu } 9426593Sgblack@eecs.umich.edu 9436593Sgblack@eecs.umich.edu DPRINTF(EthernetIntr, "going to schedule an interrupt for intrTick=%d\n", 9446593Sgblack@eecs.umich.edu intrTick); 9456593Sgblack@eecs.umich.edu 9466593Sgblack@eecs.umich.edu if (intrEvent) 9476593Sgblack@eecs.umich.edu intrEvent->squash(); 9486593Sgblack@eecs.umich.edu intrEvent = new IntrEvent(this, true); 9496593Sgblack@eecs.umich.edu schedule(intrEvent, intrTick); 9506593Sgblack@eecs.umich.edu} 9516593Sgblack@eecs.umich.edu 9526593Sgblack@eecs.umich.eduvoid 9536593Sgblack@eecs.umich.eduNSGigE::cpuInterrupt() 9546608Sgblack@eecs.umich.edu{ 9556593Sgblack@eecs.umich.edu assert(intrTick == curTick); 9566593Sgblack@eecs.umich.edu 9576593Sgblack@eecs.umich.edu // Whether or not there's a pending interrupt, we don't care about 9586593Sgblack@eecs.umich.edu // it anymore 9596593Sgblack@eecs.umich.edu intrEvent = 0; 9606593Sgblack@eecs.umich.edu intrTick = 0; 9616593Sgblack@eecs.umich.edu 9626593Sgblack@eecs.umich.edu // Don't send an interrupt if there's already one 9636593Sgblack@eecs.umich.edu if (cpuPendingIntr) { 9646593Sgblack@eecs.umich.edu DPRINTF(EthernetIntr, 9656593Sgblack@eecs.umich.edu "would send an interrupt now, but there's already pending\n"); 9666593Sgblack@eecs.umich.edu } else { 9676593Sgblack@eecs.umich.edu // Send interrupt 9686593Sgblack@eecs.umich.edu cpuPendingIntr = true; 9696593Sgblack@eecs.umich.edu 9706593Sgblack@eecs.umich.edu DPRINTF(EthernetIntr, "posting interrupt\n"); 9716607Sgblack@eecs.umich.edu intrPost(); 9726593Sgblack@eecs.umich.edu } 9736593Sgblack@eecs.umich.edu} 9746593Sgblack@eecs.umich.edu 9755020Sgblack@eecs.umich.eduvoid 9766576Sgblack@eecs.umich.eduNSGigE::cpuIntrClear() 9776576Sgblack@eecs.umich.edu{ 9786576Sgblack@eecs.umich.edu if (!cpuPendingIntr) 9796580Sgblack@eecs.umich.edu return; 9806580Sgblack@eecs.umich.edu 9816576Sgblack@eecs.umich.edu if (intrEvent) { 9826576Sgblack@eecs.umich.edu intrEvent->squash(); 9836576Sgblack@eecs.umich.edu intrEvent = 0; 9846576Sgblack@eecs.umich.edu } 9856576Sgblack@eecs.umich.edu 9866576Sgblack@eecs.umich.edu intrTick = 0; 9876576Sgblack@eecs.umich.edu 9886576Sgblack@eecs.umich.edu cpuPendingIntr = false; 9896576Sgblack@eecs.umich.edu 9906580Sgblack@eecs.umich.edu DPRINTF(EthernetIntr, "clearing interrupt\n"); 9916580Sgblack@eecs.umich.edu intrClear(); 9926576Sgblack@eecs.umich.edu} 9936576Sgblack@eecs.umich.edu 9946576Sgblack@eecs.umich.edubool 9956576Sgblack@eecs.umich.eduNSGigE::cpuIntrPending() const 9966576Sgblack@eecs.umich.edu{ return cpuPendingIntr; } 9976576Sgblack@eecs.umich.edu 9986576Sgblack@eecs.umich.eduvoid 9996576Sgblack@eecs.umich.eduNSGigE::txReset() 10005020Sgblack@eecs.umich.edu{ 10016588Sgblack@eecs.umich.edu 10026588Sgblack@eecs.umich.edu DPRINTF(Ethernet, "transmit reset\n"); 10036588Sgblack@eecs.umich.edu 10046588Sgblack@eecs.umich.edu CTDD = false; 10056588Sgblack@eecs.umich.edu txEnable = false;; 10066588Sgblack@eecs.umich.edu txFragPtr = 0; 10076588Sgblack@eecs.umich.edu assert(txDescCnt == 0); 10086588Sgblack@eecs.umich.edu txFifo.clear(); 10096588Sgblack@eecs.umich.edu txState = txIdle; 10106588Sgblack@eecs.umich.edu assert(txDmaState == dmaIdle); 10116588Sgblack@eecs.umich.edu} 10126588Sgblack@eecs.umich.edu 10136588Sgblack@eecs.umich.eduvoid 10146588Sgblack@eecs.umich.eduNSGigE::rxReset() 10156588Sgblack@eecs.umich.edu{ 10166588Sgblack@eecs.umich.edu DPRINTF(Ethernet, "receive reset\n"); 10176588Sgblack@eecs.umich.edu 10186588Sgblack@eecs.umich.edu CRDD = false; 10196588Sgblack@eecs.umich.edu assert(rxPktBytes == 0); 10206588Sgblack@eecs.umich.edu rxEnable = false; 10216588Sgblack@eecs.umich.edu rxFragPtr = 0; 10226588Sgblack@eecs.umich.edu assert(rxDescCnt == 0); 10236588Sgblack@eecs.umich.edu assert(rxDmaState == dmaIdle); 10246588Sgblack@eecs.umich.edu rxFifo.clear(); 10256588Sgblack@eecs.umich.edu rxState = rxIdle; 10266606Sgblack@eecs.umich.edu} 10276588Sgblack@eecs.umich.edu 10286588Sgblack@eecs.umich.eduvoid 10296588Sgblack@eecs.umich.eduNSGigE::regsReset() 10306588Sgblack@eecs.umich.edu{ 10316606Sgblack@eecs.umich.edu memset(®s, 0, sizeof(regs)); 10326588Sgblack@eecs.umich.edu regs.config = (CFGR_LNKSTS | CFGR_TBI_EN | CFGR_MODE_1000); 10336588Sgblack@eecs.umich.edu regs.mear = 0x12; 10346588Sgblack@eecs.umich.edu regs.txcfg = 0x120; // set drain threshold to 1024 bytes and 10355022Sgblack@eecs.umich.edu // fill threshold to 32 bytes 10366576Sgblack@eecs.umich.edu regs.rxcfg = 0x4; // set drain threshold to 16 bytes 10376576Sgblack@eecs.umich.edu regs.srr = 0x0103; // set the silicon revision to rev B or 0x103 10386576Sgblack@eecs.umich.edu regs.mibc = MIBC_FRZ; 10396580Sgblack@eecs.umich.edu regs.vdr = 0x81; // set the vlan tag type to 802.1q 10406580Sgblack@eecs.umich.edu regs.tesr = 0xc000; // TBI capable of both full and half duplex 10416576Sgblack@eecs.umich.edu regs.brar = 0xffffffff; 10426576Sgblack@eecs.umich.edu 10436576Sgblack@eecs.umich.edu extstsEnable = false; 10446576Sgblack@eecs.umich.edu acceptBroadcast = false; 10456576Sgblack@eecs.umich.edu acceptMulticast = false; 10466576Sgblack@eecs.umich.edu acceptUnicast = false; 10476576Sgblack@eecs.umich.edu acceptPerfect = false; 10486576Sgblack@eecs.umich.edu acceptArp = false; 10496576Sgblack@eecs.umich.edu} 10506580Sgblack@eecs.umich.edu 10516580Sgblack@eecs.umich.edubool 10526576Sgblack@eecs.umich.eduNSGigE::doRxDmaRead() 10536576Sgblack@eecs.umich.edu{ 10546576Sgblack@eecs.umich.edu assert(rxDmaState == dmaIdle || rxDmaState == dmaReadWaiting); 10556576Sgblack@eecs.umich.edu rxDmaState = dmaReading; 10566576Sgblack@eecs.umich.edu 10576576Sgblack@eecs.umich.edu if (dmaPending() || getState() != Running) 10586576Sgblack@eecs.umich.edu rxDmaState = dmaReadWaiting; 10596576Sgblack@eecs.umich.edu else 10605020Sgblack@eecs.umich.edu dmaRead(rxDmaAddr, rxDmaLen, &rxDmaReadEvent, (uint8_t*)rxDmaData); 10616586Sgblack@eecs.umich.edu 10626586Sgblack@eecs.umich.edu return true; 10636586Sgblack@eecs.umich.edu} 10646586Sgblack@eecs.umich.edu 10656586Sgblack@eecs.umich.eduvoid 10666586Sgblack@eecs.umich.eduNSGigE::rxDmaReadDone() 10676586Sgblack@eecs.umich.edu{ 10686586Sgblack@eecs.umich.edu assert(rxDmaState == dmaReading); 10696586Sgblack@eecs.umich.edu rxDmaState = dmaIdle; 10706595Sgblack@eecs.umich.edu 10716586Sgblack@eecs.umich.edu DPRINTF(EthernetDMA, "rx dma read paddr=%#x len=%d\n", 10726586Sgblack@eecs.umich.edu rxDmaAddr, rxDmaLen); 10736586Sgblack@eecs.umich.edu DDUMP(EthernetDMA, rxDmaData, rxDmaLen); 10746586Sgblack@eecs.umich.edu 10756586Sgblack@eecs.umich.edu // If the transmit state machine has a pending DMA, let it go first 10766586Sgblack@eecs.umich.edu if (txDmaState == dmaReadWaiting || txDmaState == dmaWriteWaiting) 10776586Sgblack@eecs.umich.edu txKick(); 10786586Sgblack@eecs.umich.edu 10796586Sgblack@eecs.umich.edu rxKick(); 10806586Sgblack@eecs.umich.edu} 10816595Sgblack@eecs.umich.edu 10826586Sgblack@eecs.umich.edubool 10836586Sgblack@eecs.umich.eduNSGigE::doRxDmaWrite() 10846586Sgblack@eecs.umich.edu{ 10856586Sgblack@eecs.umich.edu assert(rxDmaState == dmaIdle || rxDmaState == dmaWriteWaiting); 10866586Sgblack@eecs.umich.edu rxDmaState = dmaWriting; 10876586Sgblack@eecs.umich.edu 10886586Sgblack@eecs.umich.edu if (dmaPending() || getState() != Running) 10896586Sgblack@eecs.umich.edu rxDmaState = dmaWriteWaiting; 10905022Sgblack@eecs.umich.edu else 10916576Sgblack@eecs.umich.edu dmaWrite(rxDmaAddr, rxDmaLen, &rxDmaWriteEvent, (uint8_t*)rxDmaData); 10926576Sgblack@eecs.umich.edu return true; 10936576Sgblack@eecs.umich.edu} 10946580Sgblack@eecs.umich.edu 10956580Sgblack@eecs.umich.eduvoid 10966580Sgblack@eecs.umich.eduNSGigE::rxDmaWriteDone() 10976580Sgblack@eecs.umich.edu{ 10986576Sgblack@eecs.umich.edu assert(rxDmaState == dmaWriting); 10996576Sgblack@eecs.umich.edu rxDmaState = dmaIdle; 11006576Sgblack@eecs.umich.edu 11016576Sgblack@eecs.umich.edu DPRINTF(EthernetDMA, "rx dma write paddr=%#x len=%d\n", 11026576Sgblack@eecs.umich.edu rxDmaAddr, rxDmaLen); 11036576Sgblack@eecs.umich.edu DDUMP(EthernetDMA, rxDmaData, rxDmaLen); 11046576Sgblack@eecs.umich.edu 11056580Sgblack@eecs.umich.edu // If the transmit state machine has a pending DMA, let it go first 11066580Sgblack@eecs.umich.edu if (txDmaState == dmaReadWaiting || txDmaState == dmaWriteWaiting) 11076580Sgblack@eecs.umich.edu txKick(); 11086580Sgblack@eecs.umich.edu 11096576Sgblack@eecs.umich.edu rxKick(); 11106576Sgblack@eecs.umich.edu} 11116576Sgblack@eecs.umich.edu 11126576Sgblack@eecs.umich.eduvoid 11136576Sgblack@eecs.umich.eduNSGigE::rxKick() 11146576Sgblack@eecs.umich.edu{ 11155020Sgblack@eecs.umich.edu bool is64bit = (bool)(regs.config & CFGR_M64ADDR); 11164276Sgblack@eecs.umich.edu 11174276Sgblack@eecs.umich.edu DPRINTF(EthernetSM, 11184276Sgblack@eecs.umich.edu "receive kick rxState=%s (rxBuf.size=%d) %d-bit\n", 11194276Sgblack@eecs.umich.edu NsRxStateStrings[rxState], rxFifo.size(), is64bit ? 64 : 32); 11204276Sgblack@eecs.umich.edu 11214276Sgblack@eecs.umich.edu Addr link, bufptr; 11224276Sgblack@eecs.umich.edu uint32_t &cmdsts = is64bit ? rxDesc64.cmdsts : rxDesc32.cmdsts; 1123 uint32_t &extsts = is64bit ? rxDesc64.extsts : rxDesc32.extsts; 1124 1125 next: 1126 if (clock) { 1127 if (rxKickTick > curTick) { 1128 DPRINTF(EthernetSM, "receive kick exiting, can't run till %d\n", 1129 rxKickTick); 1130 1131 goto exit; 1132 } 1133 1134 // Go to the next state machine clock tick. 1135 rxKickTick = curTick + ticks(1); 1136 } 1137 1138 switch(rxDmaState) { 1139 case dmaReadWaiting: 1140 if (doRxDmaRead()) 1141 goto exit; 1142 break; 1143 case dmaWriteWaiting: 1144 if (doRxDmaWrite()) 1145 goto exit; 1146 break; 1147 default: 1148 break; 1149 } 1150 1151 link = is64bit ? (Addr)rxDesc64.link : (Addr)rxDesc32.link; 1152 bufptr = is64bit ? (Addr)rxDesc64.bufptr : (Addr)rxDesc32.bufptr; 1153 1154 // see state machine from spec for details 1155 // the way this works is, if you finish work on one state and can 1156 // go directly to another, you do that through jumping to the 1157 // label "next". however, if you have intermediate work, like DMA 1158 // so that you can't go to the next state yet, you go to exit and 1159 // exit the loop. however, when the DMA is done it will trigger 1160 // an event and come back to this loop. 1161 switch (rxState) { 1162 case rxIdle: 1163 if (!rxEnable) { 1164 DPRINTF(EthernetSM, "Receive Disabled! Nothing to do.\n"); 1165 goto exit; 1166 } 1167 1168 if (CRDD) { 1169 rxState = rxDescRefr; 1170 1171 rxDmaAddr = regs.rxdp & 0x3fffffff; 1172 rxDmaData = 1173 is64bit ? (void *)&rxDesc64.link : (void *)&rxDesc32.link; 1174 rxDmaLen = is64bit ? sizeof(rxDesc64.link) : sizeof(rxDesc32.link); 1175 rxDmaFree = dmaDescFree; 1176 1177 descDmaReads++; 1178 descDmaRdBytes += rxDmaLen; 1179 1180 if (doRxDmaRead()) 1181 goto exit; 1182 } else { 1183 rxState = rxDescRead; 1184 1185 rxDmaAddr = regs.rxdp & 0x3fffffff; 1186 rxDmaData = is64bit ? (void *)&rxDesc64 : (void *)&rxDesc32; 1187 rxDmaLen = is64bit ? sizeof(rxDesc64) : sizeof(rxDesc32); 1188 rxDmaFree = dmaDescFree; 1189 1190 descDmaReads++; 1191 descDmaRdBytes += rxDmaLen; 1192 1193 if (doRxDmaRead()) 1194 goto exit; 1195 } 1196 break; 1197 1198 case rxDescRefr: 1199 if (rxDmaState != dmaIdle) 1200 goto exit; 1201 1202 rxState = rxAdvance; 1203 break; 1204 1205 case rxDescRead: 1206 if (rxDmaState != dmaIdle) 1207 goto exit; 1208 1209 DPRINTF(EthernetDesc, "rxDesc: addr=%08x read descriptor\n", 1210 regs.rxdp & 0x3fffffff); 1211 DPRINTF(EthernetDesc, 1212 "rxDesc: link=%#x bufptr=%#x cmdsts=%08x extsts=%08x\n", 1213 link, bufptr, cmdsts, extsts); 1214 1215 if (cmdsts & CMDSTS_OWN) { 1216 devIntrPost(ISR_RXIDLE); 1217 rxState = rxIdle; 1218 goto exit; 1219 } else { 1220 rxState = rxFifoBlock; 1221 rxFragPtr = bufptr; 1222 rxDescCnt = cmdsts & CMDSTS_LEN_MASK; 1223 } 1224 break; 1225 1226 case rxFifoBlock: 1227 if (!rxPacket) { 1228 /** 1229 * @todo in reality, we should be able to start processing 1230 * the packet as it arrives, and not have to wait for the 1231 * full packet ot be in the receive fifo. 1232 */ 1233 if (rxFifo.empty()) 1234 goto exit; 1235 1236 DPRINTF(EthernetSM, "****processing receive of new packet****\n"); 1237 1238 // If we don't have a packet, grab a new one from the fifo. 1239 rxPacket = rxFifo.front(); 1240 rxPktBytes = rxPacket->length; 1241 rxPacketBufPtr = rxPacket->data; 1242 1243#if TRACING_ON 1244 if (DTRACE(Ethernet)) { 1245 IpPtr ip(rxPacket); 1246 if (ip) { 1247 DPRINTF(Ethernet, "ID is %d\n", ip->id()); 1248 TcpPtr tcp(ip); 1249 if (tcp) { 1250 DPRINTF(Ethernet, 1251 "Src Port=%d, Dest Port=%d, Seq=%d, Ack=%d\n", 1252 tcp->sport(), tcp->dport(), tcp->seq(), 1253 tcp->ack()); 1254 } 1255 } 1256 } 1257#endif 1258 1259 // sanity check - i think the driver behaves like this 1260 assert(rxDescCnt >= rxPktBytes); 1261 rxFifo.pop(); 1262 } 1263 1264 1265 // dont' need the && rxDescCnt > 0 if driver sanity check 1266 // above holds 1267 if (rxPktBytes > 0) { 1268 rxState = rxFragWrite; 1269 // don't need min<>(rxPktBytes,rxDescCnt) if above sanity 1270 // check holds 1271 rxXferLen = rxPktBytes; 1272 1273 rxDmaAddr = rxFragPtr & 0x3fffffff; 1274 rxDmaData = rxPacketBufPtr; 1275 rxDmaLen = rxXferLen; 1276 rxDmaFree = dmaDataFree; 1277 1278 if (doRxDmaWrite()) 1279 goto exit; 1280 1281 } else { 1282 rxState = rxDescWrite; 1283 1284 //if (rxPktBytes == 0) { /* packet is done */ 1285 assert(rxPktBytes == 0); 1286 DPRINTF(EthernetSM, "done with receiving packet\n"); 1287 1288 cmdsts |= CMDSTS_OWN; 1289 cmdsts &= ~CMDSTS_MORE; 1290 cmdsts |= CMDSTS_OK; 1291 cmdsts &= 0xffff0000; 1292 cmdsts += rxPacket->length; //i.e. set CMDSTS_SIZE 1293 1294#if 0 1295 /* 1296 * all the driver uses these are for its own stats keeping 1297 * which we don't care about, aren't necessary for 1298 * functionality and doing this would just slow us down. 1299 * if they end up using this in a later version for 1300 * functional purposes, just undef 1301 */ 1302 if (rxFilterEnable) { 1303 cmdsts &= ~CMDSTS_DEST_MASK; 1304 const EthAddr &dst = rxFifoFront()->dst(); 1305 if (dst->unicast()) 1306 cmdsts |= CMDSTS_DEST_SELF; 1307 if (dst->multicast()) 1308 cmdsts |= CMDSTS_DEST_MULTI; 1309 if (dst->broadcast()) 1310 cmdsts |= CMDSTS_DEST_MASK; 1311 } 1312#endif 1313 1314 IpPtr ip(rxPacket); 1315 if (extstsEnable && ip) { 1316 extsts |= EXTSTS_IPPKT; 1317 rxIpChecksums++; 1318 if (cksum(ip) != 0) { 1319 DPRINTF(EthernetCksum, "Rx IP Checksum Error\n"); 1320 extsts |= EXTSTS_IPERR; 1321 } 1322 TcpPtr tcp(ip); 1323 UdpPtr udp(ip); 1324 if (tcp) { 1325 extsts |= EXTSTS_TCPPKT; 1326 rxTcpChecksums++; 1327 if (cksum(tcp) != 0) { 1328 DPRINTF(EthernetCksum, "Rx TCP Checksum Error\n"); 1329 extsts |= EXTSTS_TCPERR; 1330 1331 } 1332 } else if (udp) { 1333 extsts |= EXTSTS_UDPPKT; 1334 rxUdpChecksums++; 1335 if (cksum(udp) != 0) { 1336 DPRINTF(EthernetCksum, "Rx UDP Checksum Error\n"); 1337 extsts |= EXTSTS_UDPERR; 1338 } 1339 } 1340 } 1341 rxPacket = 0; 1342 1343 /* 1344 * the driver seems to always receive into desc buffers 1345 * of size 1514, so you never have a pkt that is split 1346 * into multiple descriptors on the receive side, so 1347 * i don't implement that case, hence the assert above. 1348 */ 1349 1350 DPRINTF(EthernetDesc, 1351 "rxDesc: addr=%08x writeback cmdsts extsts\n", 1352 regs.rxdp & 0x3fffffff); 1353 DPRINTF(EthernetDesc, 1354 "rxDesc: link=%#x bufptr=%#x cmdsts=%08x extsts=%08x\n", 1355 link, bufptr, cmdsts, extsts); 1356 1357 rxDmaAddr = regs.rxdp & 0x3fffffff; 1358 rxDmaData = &cmdsts; 1359 if (is64bit) { 1360 rxDmaAddr += offsetof(ns_desc64, cmdsts); 1361 rxDmaLen = sizeof(rxDesc64.cmdsts) + sizeof(rxDesc64.extsts); 1362 } else { 1363 rxDmaAddr += offsetof(ns_desc32, cmdsts); 1364 rxDmaLen = sizeof(rxDesc32.cmdsts) + sizeof(rxDesc32.extsts); 1365 } 1366 rxDmaFree = dmaDescFree; 1367 1368 descDmaWrites++; 1369 descDmaWrBytes += rxDmaLen; 1370 1371 if (doRxDmaWrite()) 1372 goto exit; 1373 } 1374 break; 1375 1376 case rxFragWrite: 1377 if (rxDmaState != dmaIdle) 1378 goto exit; 1379 1380 rxPacketBufPtr += rxXferLen; 1381 rxFragPtr += rxXferLen; 1382 rxPktBytes -= rxXferLen; 1383 1384 rxState = rxFifoBlock; 1385 break; 1386 1387 case rxDescWrite: 1388 if (rxDmaState != dmaIdle) 1389 goto exit; 1390 1391 assert(cmdsts & CMDSTS_OWN); 1392 1393 assert(rxPacket == 0); 1394 devIntrPost(ISR_RXOK); 1395 1396 if (cmdsts & CMDSTS_INTR) 1397 devIntrPost(ISR_RXDESC); 1398 1399 if (!rxEnable) { 1400 DPRINTF(EthernetSM, "Halting the RX state machine\n"); 1401 rxState = rxIdle; 1402 goto exit; 1403 } else 1404 rxState = rxAdvance; 1405 break; 1406 1407 case rxAdvance: 1408 if (link == 0) { 1409 devIntrPost(ISR_RXIDLE); 1410 rxState = rxIdle; 1411 CRDD = true; 1412 goto exit; 1413 } else { 1414 if (rxDmaState != dmaIdle) 1415 goto exit; 1416 rxState = rxDescRead; 1417 regs.rxdp = link; 1418 CRDD = false; 1419 1420 rxDmaAddr = regs.rxdp & 0x3fffffff; 1421 rxDmaData = is64bit ? (void *)&rxDesc64 : (void *)&rxDesc32; 1422 rxDmaLen = is64bit ? sizeof(rxDesc64) : sizeof(rxDesc32); 1423 rxDmaFree = dmaDescFree; 1424 1425 if (doRxDmaRead()) 1426 goto exit; 1427 } 1428 break; 1429 1430 default: 1431 panic("Invalid rxState!"); 1432 } 1433 1434 DPRINTF(EthernetSM, "entering next rxState=%s\n", 1435 NsRxStateStrings[rxState]); 1436 goto next; 1437 1438 exit: 1439 /** 1440 * @todo do we want to schedule a future kick? 1441 */ 1442 DPRINTF(EthernetSM, "rx state machine exited rxState=%s\n", 1443 NsRxStateStrings[rxState]); 1444 1445 if (clock && !rxKickEvent.scheduled()) 1446 schedule(rxKickEvent, rxKickTick); 1447} 1448 1449void 1450NSGigE::transmit() 1451{ 1452 if (txFifo.empty()) { 1453 DPRINTF(Ethernet, "nothing to transmit\n"); 1454 return; 1455 } 1456 1457 DPRINTF(Ethernet, "Attempt Pkt Transmit: txFifo length=%d\n", 1458 txFifo.size()); 1459 if (interface->sendPacket(txFifo.front())) { 1460#if TRACING_ON 1461 if (DTRACE(Ethernet)) { 1462 IpPtr ip(txFifo.front()); 1463 if (ip) { 1464 DPRINTF(Ethernet, "ID is %d\n", ip->id()); 1465 TcpPtr tcp(ip); 1466 if (tcp) { 1467 DPRINTF(Ethernet, 1468 "Src Port=%d, Dest Port=%d, Seq=%d, Ack=%d\n", 1469 tcp->sport(), tcp->dport(), tcp->seq(), 1470 tcp->ack()); 1471 } 1472 } 1473 } 1474#endif 1475 1476 DDUMP(EthernetData, txFifo.front()->data, txFifo.front()->length); 1477 txBytes += txFifo.front()->length; 1478 txPackets++; 1479 1480 DPRINTF(Ethernet, "Successful Xmit! now txFifoAvail is %d\n", 1481 txFifo.avail()); 1482 txFifo.pop(); 1483 1484 /* 1485 * normally do a writeback of the descriptor here, and ONLY 1486 * after that is done, send this interrupt. but since our 1487 * stuff never actually fails, just do this interrupt here, 1488 * otherwise the code has to stray from this nice format. 1489 * besides, it's functionally the same. 1490 */ 1491 devIntrPost(ISR_TXOK); 1492 } 1493 1494 if (!txFifo.empty() && !txEvent.scheduled()) { 1495 DPRINTF(Ethernet, "reschedule transmit\n"); 1496 schedule(txEvent, curTick + retryTime); 1497 } 1498} 1499 1500bool 1501NSGigE::doTxDmaRead() 1502{ 1503 assert(txDmaState == dmaIdle || txDmaState == dmaReadWaiting); 1504 txDmaState = dmaReading; 1505 1506 if (dmaPending() || getState() != Running) 1507 txDmaState = dmaReadWaiting; 1508 else 1509 dmaRead(txDmaAddr, txDmaLen, &txDmaReadEvent, (uint8_t*)txDmaData); 1510 1511 return true; 1512} 1513 1514void 1515NSGigE::txDmaReadDone() 1516{ 1517 assert(txDmaState == dmaReading); 1518 txDmaState = dmaIdle; 1519 1520 DPRINTF(EthernetDMA, "tx dma read paddr=%#x len=%d\n", 1521 txDmaAddr, txDmaLen); 1522 DDUMP(EthernetDMA, txDmaData, txDmaLen); 1523 1524 // If the receive state machine has a pending DMA, let it go first 1525 if (rxDmaState == dmaReadWaiting || rxDmaState == dmaWriteWaiting) 1526 rxKick(); 1527 1528 txKick(); 1529} 1530 1531bool 1532NSGigE::doTxDmaWrite() 1533{ 1534 assert(txDmaState == dmaIdle || txDmaState == dmaWriteWaiting); 1535 txDmaState = dmaWriting; 1536 1537 if (dmaPending() || getState() != Running) 1538 txDmaState = dmaWriteWaiting; 1539 else 1540 dmaWrite(txDmaAddr, txDmaLen, &txDmaWriteEvent, (uint8_t*)txDmaData); 1541 return true; 1542} 1543 1544void 1545NSGigE::txDmaWriteDone() 1546{ 1547 assert(txDmaState == dmaWriting); 1548 txDmaState = dmaIdle; 1549 1550 DPRINTF(EthernetDMA, "tx dma write paddr=%#x len=%d\n", 1551 txDmaAddr, txDmaLen); 1552 DDUMP(EthernetDMA, txDmaData, txDmaLen); 1553 1554 // If the receive state machine has a pending DMA, let it go first 1555 if (rxDmaState == dmaReadWaiting || rxDmaState == dmaWriteWaiting) 1556 rxKick(); 1557 1558 txKick(); 1559} 1560 1561void 1562NSGigE::txKick() 1563{ 1564 bool is64bit = (bool)(regs.config & CFGR_M64ADDR); 1565 1566 DPRINTF(EthernetSM, "transmit kick txState=%s %d-bit\n", 1567 NsTxStateStrings[txState], is64bit ? 64 : 32); 1568 1569 Addr link, bufptr; 1570 uint32_t &cmdsts = is64bit ? txDesc64.cmdsts : txDesc32.cmdsts; 1571 uint32_t &extsts = is64bit ? txDesc64.extsts : txDesc32.extsts; 1572 1573 next: 1574 if (clock) { 1575 if (txKickTick > curTick) { 1576 DPRINTF(EthernetSM, "transmit kick exiting, can't run till %d\n", 1577 txKickTick); 1578 goto exit; 1579 } 1580 1581 // Go to the next state machine clock tick. 1582 txKickTick = curTick + ticks(1); 1583 } 1584 1585 switch(txDmaState) { 1586 case dmaReadWaiting: 1587 if (doTxDmaRead()) 1588 goto exit; 1589 break; 1590 case dmaWriteWaiting: 1591 if (doTxDmaWrite()) 1592 goto exit; 1593 break; 1594 default: 1595 break; 1596 } 1597 1598 link = is64bit ? (Addr)txDesc64.link : (Addr)txDesc32.link; 1599 bufptr = is64bit ? (Addr)txDesc64.bufptr : (Addr)txDesc32.bufptr; 1600 switch (txState) { 1601 case txIdle: 1602 if (!txEnable) { 1603 DPRINTF(EthernetSM, "Transmit disabled. Nothing to do.\n"); 1604 goto exit; 1605 } 1606 1607 if (CTDD) { 1608 txState = txDescRefr; 1609 1610 txDmaAddr = regs.txdp & 0x3fffffff; 1611 txDmaData = 1612 is64bit ? (void *)&txDesc64.link : (void *)&txDesc32.link; 1613 txDmaLen = is64bit ? sizeof(txDesc64.link) : sizeof(txDesc32.link); 1614 txDmaFree = dmaDescFree; 1615 1616 descDmaReads++; 1617 descDmaRdBytes += txDmaLen; 1618 1619 if (doTxDmaRead()) 1620 goto exit; 1621 1622 } else { 1623 txState = txDescRead; 1624 1625 txDmaAddr = regs.txdp & 0x3fffffff; 1626 txDmaData = is64bit ? (void *)&txDesc64 : (void *)&txDesc32; 1627 txDmaLen = is64bit ? sizeof(txDesc64) : sizeof(txDesc32); 1628 txDmaFree = dmaDescFree; 1629 1630 descDmaReads++; 1631 descDmaRdBytes += txDmaLen; 1632 1633 if (doTxDmaRead()) 1634 goto exit; 1635 } 1636 break; 1637 1638 case txDescRefr: 1639 if (txDmaState != dmaIdle) 1640 goto exit; 1641 1642 txState = txAdvance; 1643 break; 1644 1645 case txDescRead: 1646 if (txDmaState != dmaIdle) 1647 goto exit; 1648 1649 DPRINTF(EthernetDesc, "txDesc: addr=%08x read descriptor\n", 1650 regs.txdp & 0x3fffffff); 1651 DPRINTF(EthernetDesc, 1652 "txDesc: link=%#x bufptr=%#x cmdsts=%#08x extsts=%#08x\n", 1653 link, bufptr, cmdsts, extsts); 1654 1655 if (cmdsts & CMDSTS_OWN) { 1656 txState = txFifoBlock; 1657 txFragPtr = bufptr; 1658 txDescCnt = cmdsts & CMDSTS_LEN_MASK; 1659 } else { 1660 devIntrPost(ISR_TXIDLE); 1661 txState = txIdle; 1662 goto exit; 1663 } 1664 break; 1665 1666 case txFifoBlock: 1667 if (!txPacket) { 1668 DPRINTF(EthernetSM, "****starting the tx of a new packet****\n"); 1669 txPacket = new EthPacketData(16384); 1670 txPacketBufPtr = txPacket->data; 1671 } 1672 1673 if (txDescCnt == 0) { 1674 DPRINTF(EthernetSM, "the txDescCnt == 0, done with descriptor\n"); 1675 if (cmdsts & CMDSTS_MORE) { 1676 DPRINTF(EthernetSM, "there are more descriptors to come\n"); 1677 txState = txDescWrite; 1678 1679 cmdsts &= ~CMDSTS_OWN; 1680 1681 txDmaAddr = regs.txdp & 0x3fffffff; 1682 txDmaData = &cmdsts; 1683 if (is64bit) { 1684 txDmaAddr += offsetof(ns_desc64, cmdsts); 1685 txDmaLen = sizeof(txDesc64.cmdsts); 1686 } else { 1687 txDmaAddr += offsetof(ns_desc32, cmdsts); 1688 txDmaLen = sizeof(txDesc32.cmdsts); 1689 } 1690 txDmaFree = dmaDescFree; 1691 1692 if (doTxDmaWrite()) 1693 goto exit; 1694 1695 } else { /* this packet is totally done */ 1696 DPRINTF(EthernetSM, "This packet is done, let's wrap it up\n"); 1697 /* deal with the the packet that just finished */ 1698 if ((regs.vtcr & VTCR_PPCHK) && extstsEnable) { 1699 IpPtr ip(txPacket); 1700 if (extsts & EXTSTS_UDPPKT) { 1701 UdpPtr udp(ip); 1702 if (udp) { 1703 udp->sum(0); 1704 udp->sum(cksum(udp)); 1705 txUdpChecksums++; 1706 } else { 1707 debug_break(); 1708 warn_once("UDPPKT set, but not UDP!\n"); 1709 } 1710 } else if (extsts & EXTSTS_TCPPKT) { 1711 TcpPtr tcp(ip); 1712 if (tcp) { 1713 tcp->sum(0); 1714 tcp->sum(cksum(tcp)); 1715 txTcpChecksums++; 1716 } else { 1717 debug_break(); 1718 warn_once("TCPPKT set, but not UDP!\n"); 1719 } 1720 } 1721 if (extsts & EXTSTS_IPPKT) { 1722 if (ip) { 1723 ip->sum(0); 1724 ip->sum(cksum(ip)); 1725 txIpChecksums++; 1726 } else { 1727 debug_break(); 1728 warn_once("IPPKT set, but not UDP!\n"); 1729 } 1730 } 1731 } 1732 1733 txPacket->length = txPacketBufPtr - txPacket->data; 1734 // this is just because the receive can't handle a 1735 // packet bigger want to make sure 1736 if (txPacket->length > 1514) 1737 panic("transmit packet too large, %s > 1514\n", 1738 txPacket->length); 1739 1740#ifndef NDEBUG 1741 bool success = 1742#endif 1743 txFifo.push(txPacket); 1744 assert(success); 1745 1746 /* 1747 * this following section is not tqo spec, but 1748 * functionally shouldn't be any different. normally, 1749 * the chip will wait til the transmit has occurred 1750 * before writing back the descriptor because it has 1751 * to wait to see that it was successfully transmitted 1752 * to decide whether to set CMDSTS_OK or not. 1753 * however, in the simulator since it is always 1754 * successfully transmitted, and writing it exactly to 1755 * spec would complicate the code, we just do it here 1756 */ 1757 1758 cmdsts &= ~CMDSTS_OWN; 1759 cmdsts |= CMDSTS_OK; 1760 1761 DPRINTF(EthernetDesc, 1762 "txDesc writeback: cmdsts=%08x extsts=%08x\n", 1763 cmdsts, extsts); 1764 1765 txDmaFree = dmaDescFree; 1766 txDmaAddr = regs.txdp & 0x3fffffff; 1767 txDmaData = &cmdsts; 1768 if (is64bit) { 1769 txDmaAddr += offsetof(ns_desc64, cmdsts); 1770 txDmaLen = 1771 sizeof(txDesc64.cmdsts) + sizeof(txDesc64.extsts); 1772 } else { 1773 txDmaAddr += offsetof(ns_desc32, cmdsts); 1774 txDmaLen = 1775 sizeof(txDesc32.cmdsts) + sizeof(txDesc32.extsts); 1776 } 1777 1778 descDmaWrites++; 1779 descDmaWrBytes += txDmaLen; 1780 1781 transmit(); 1782 txPacket = 0; 1783 1784 if (!txEnable) { 1785 DPRINTF(EthernetSM, "halting TX state machine\n"); 1786 txState = txIdle; 1787 goto exit; 1788 } else 1789 txState = txAdvance; 1790 1791 if (doTxDmaWrite()) 1792 goto exit; 1793 } 1794 } else { 1795 DPRINTF(EthernetSM, "this descriptor isn't done yet\n"); 1796 if (!txFifo.full()) { 1797 txState = txFragRead; 1798 1799 /* 1800 * The number of bytes transferred is either whatever 1801 * is left in the descriptor (txDescCnt), or if there 1802 * is not enough room in the fifo, just whatever room 1803 * is left in the fifo 1804 */ 1805 txXferLen = min<uint32_t>(txDescCnt, txFifo.avail()); 1806 1807 txDmaAddr = txFragPtr & 0x3fffffff; 1808 txDmaData = txPacketBufPtr; 1809 txDmaLen = txXferLen; 1810 txDmaFree = dmaDataFree; 1811 1812 if (doTxDmaRead()) 1813 goto exit; 1814 } else { 1815 txState = txFifoBlock; 1816 transmit(); 1817 1818 goto exit; 1819 } 1820 1821 } 1822 break; 1823 1824 case txFragRead: 1825 if (txDmaState != dmaIdle) 1826 goto exit; 1827 1828 txPacketBufPtr += txXferLen; 1829 txFragPtr += txXferLen; 1830 txDescCnt -= txXferLen; 1831 txFifo.reserve(txXferLen); 1832 1833 txState = txFifoBlock; 1834 break; 1835 1836 case txDescWrite: 1837 if (txDmaState != dmaIdle) 1838 goto exit; 1839 1840 if (cmdsts & CMDSTS_INTR) 1841 devIntrPost(ISR_TXDESC); 1842 1843 if (!txEnable) { 1844 DPRINTF(EthernetSM, "halting TX state machine\n"); 1845 txState = txIdle; 1846 goto exit; 1847 } else 1848 txState = txAdvance; 1849 break; 1850 1851 case txAdvance: 1852 if (link == 0) { 1853 devIntrPost(ISR_TXIDLE); 1854 txState = txIdle; 1855 goto exit; 1856 } else { 1857 if (txDmaState != dmaIdle) 1858 goto exit; 1859 txState = txDescRead; 1860 regs.txdp = link; 1861 CTDD = false; 1862 1863 txDmaAddr = link & 0x3fffffff; 1864 txDmaData = is64bit ? (void *)&txDesc64 : (void *)&txDesc32; 1865 txDmaLen = is64bit ? sizeof(txDesc64) : sizeof(txDesc32); 1866 txDmaFree = dmaDescFree; 1867 1868 if (doTxDmaRead()) 1869 goto exit; 1870 } 1871 break; 1872 1873 default: 1874 panic("invalid state"); 1875 } 1876 1877 DPRINTF(EthernetSM, "entering next txState=%s\n", 1878 NsTxStateStrings[txState]); 1879 goto next; 1880 1881 exit: 1882 /** 1883 * @todo do we want to schedule a future kick? 1884 */ 1885 DPRINTF(EthernetSM, "tx state machine exited txState=%s\n", 1886 NsTxStateStrings[txState]); 1887 1888 if (clock && !txKickEvent.scheduled()) 1889 schedule(txKickEvent, txKickTick); 1890} 1891 1892/** 1893 * Advance the EEPROM state machine 1894 * Called on rising edge of EEPROM clock bit in MEAR 1895 */ 1896void 1897NSGigE::eepromKick() 1898{ 1899 switch (eepromState) { 1900 1901 case eepromStart: 1902 1903 // Wait for start bit 1904 if (regs.mear & MEAR_EEDI) { 1905 // Set up to get 2 opcode bits 1906 eepromState = eepromGetOpcode; 1907 eepromBitsToRx = 2; 1908 eepromOpcode = 0; 1909 } 1910 break; 1911 1912 case eepromGetOpcode: 1913 eepromOpcode <<= 1; 1914 eepromOpcode += (regs.mear & MEAR_EEDI) ? 1 : 0; 1915 --eepromBitsToRx; 1916 1917 // Done getting opcode 1918 if (eepromBitsToRx == 0) { 1919 if (eepromOpcode != EEPROM_READ) 1920 panic("only EEPROM reads are implemented!"); 1921 1922 // Set up to get address 1923 eepromState = eepromGetAddress; 1924 eepromBitsToRx = 6; 1925 eepromAddress = 0; 1926 } 1927 break; 1928 1929 case eepromGetAddress: 1930 eepromAddress <<= 1; 1931 eepromAddress += (regs.mear & MEAR_EEDI) ? 1 : 0; 1932 --eepromBitsToRx; 1933 1934 // Done getting address 1935 if (eepromBitsToRx == 0) { 1936 1937 if (eepromAddress >= EEPROM_SIZE) 1938 panic("EEPROM read access out of range!"); 1939 1940 switch (eepromAddress) { 1941 1942 case EEPROM_PMATCH2_ADDR: 1943 eepromData = rom.perfectMatch[5]; 1944 eepromData <<= 8; 1945 eepromData += rom.perfectMatch[4]; 1946 break; 1947 1948 case EEPROM_PMATCH1_ADDR: 1949 eepromData = rom.perfectMatch[3]; 1950 eepromData <<= 8; 1951 eepromData += rom.perfectMatch[2]; 1952 break; 1953 1954 case EEPROM_PMATCH0_ADDR: 1955 eepromData = rom.perfectMatch[1]; 1956 eepromData <<= 8; 1957 eepromData += rom.perfectMatch[0]; 1958 break; 1959 1960 default: 1961 panic("FreeBSD driver only uses EEPROM to read PMATCH!"); 1962 } 1963 // Set up to read data 1964 eepromState = eepromRead; 1965 eepromBitsToRx = 16; 1966 1967 // Clear data in bit 1968 regs.mear &= ~MEAR_EEDI; 1969 } 1970 break; 1971 1972 case eepromRead: 1973 // Clear Data Out bit 1974 regs.mear &= ~MEAR_EEDO; 1975 // Set bit to value of current EEPROM bit 1976 regs.mear |= (eepromData & 0x8000) ? MEAR_EEDO : 0x0; 1977 1978 eepromData <<= 1; 1979 --eepromBitsToRx; 1980 1981 // All done 1982 if (eepromBitsToRx == 0) { 1983 eepromState = eepromStart; 1984 } 1985 break; 1986 1987 default: 1988 panic("invalid EEPROM state"); 1989 } 1990 1991} 1992 1993void 1994NSGigE::transferDone() 1995{ 1996 if (txFifo.empty()) { 1997 DPRINTF(Ethernet, "transfer complete: txFifo empty...nothing to do\n"); 1998 return; 1999 } 2000 2001 DPRINTF(Ethernet, "transfer complete: data in txFifo...schedule xmit\n"); 2002 2003 reschedule(txEvent, curTick + ticks(1), true); 2004} 2005 2006bool 2007NSGigE::rxFilter(const EthPacketPtr &packet) 2008{ 2009 EthPtr eth = packet; 2010 bool drop = true; 2011 string type; 2012 2013 const EthAddr &dst = eth->dst(); 2014 if (dst.unicast()) { 2015 // If we're accepting all unicast addresses 2016 if (acceptUnicast) 2017 drop = false; 2018 2019 // If we make a perfect match 2020 if (acceptPerfect && dst == rom.perfectMatch) 2021 drop = false; 2022 2023 if (acceptArp && eth->type() == ETH_TYPE_ARP) 2024 drop = false; 2025 2026 } else if (dst.broadcast()) { 2027 // if we're accepting broadcasts 2028 if (acceptBroadcast) 2029 drop = false; 2030 2031 } else if (dst.multicast()) { 2032 // if we're accepting all multicasts 2033 if (acceptMulticast) 2034 drop = false; 2035 2036 // Multicast hashing faked - all packets accepted 2037 if (multicastHashEnable) 2038 drop = false; 2039 } 2040 2041 if (drop) { 2042 DPRINTF(Ethernet, "rxFilter drop\n"); 2043 DDUMP(EthernetData, packet->data, packet->length); 2044 } 2045 2046 return drop; 2047} 2048 2049bool 2050NSGigE::recvPacket(EthPacketPtr packet) 2051{ 2052 rxBytes += packet->length; 2053 rxPackets++; 2054 2055 DPRINTF(Ethernet, "Receiving packet from wire, rxFifoAvail=%d\n", 2056 rxFifo.avail()); 2057 2058 if (!rxEnable) { 2059 DPRINTF(Ethernet, "receive disabled...packet dropped\n"); 2060 return true; 2061 } 2062 2063 if (!rxFilterEnable) { 2064 DPRINTF(Ethernet, 2065 "receive packet filtering disabled . . . packet dropped\n"); 2066 return true; 2067 } 2068 2069 if (rxFilter(packet)) { 2070 DPRINTF(Ethernet, "packet filtered...dropped\n"); 2071 return true; 2072 } 2073 2074 if (rxFifo.avail() < packet->length) { 2075#if TRACING_ON 2076 IpPtr ip(packet); 2077 TcpPtr tcp(ip); 2078 if (ip) { 2079 DPRINTF(Ethernet, 2080 "packet won't fit in receive buffer...pkt ID %d dropped\n", 2081 ip->id()); 2082 if (tcp) { 2083 DPRINTF(Ethernet, "Seq=%d\n", tcp->seq()); 2084 } 2085 } 2086#endif 2087 droppedPackets++; 2088 devIntrPost(ISR_RXORN); 2089 return false; 2090 } 2091 2092 rxFifo.push(packet); 2093 2094 rxKick(); 2095 return true; 2096} 2097 2098 2099void 2100NSGigE::resume() 2101{ 2102 SimObject::resume(); 2103 2104 // During drain we could have left the state machines in a waiting state and 2105 // they wouldn't get out until some other event occured to kick them. 2106 // This way they'll get out immediately 2107 txKick(); 2108 rxKick(); 2109} 2110 2111 2112//===================================================================== 2113// 2114// 2115void 2116NSGigE::serialize(ostream &os) 2117{ 2118 // Serialize the PciDev base class 2119 PciDev::serialize(os); 2120 2121 /* 2122 * Finalize any DMA events now. 2123 */ 2124 // @todo will mem system save pending dma? 2125 2126 /* 2127 * Serialize the device registers 2128 */ 2129 SERIALIZE_SCALAR(regs.command); 2130 SERIALIZE_SCALAR(regs.config); 2131 SERIALIZE_SCALAR(regs.mear); 2132 SERIALIZE_SCALAR(regs.ptscr); 2133 SERIALIZE_SCALAR(regs.isr); 2134 SERIALIZE_SCALAR(regs.imr); 2135 SERIALIZE_SCALAR(regs.ier); 2136 SERIALIZE_SCALAR(regs.ihr); 2137 SERIALIZE_SCALAR(regs.txdp); 2138 SERIALIZE_SCALAR(regs.txdp_hi); 2139 SERIALIZE_SCALAR(regs.txcfg); 2140 SERIALIZE_SCALAR(regs.gpior); 2141 SERIALIZE_SCALAR(regs.rxdp); 2142 SERIALIZE_SCALAR(regs.rxdp_hi); 2143 SERIALIZE_SCALAR(regs.rxcfg); 2144 SERIALIZE_SCALAR(regs.pqcr); 2145 SERIALIZE_SCALAR(regs.wcsr); 2146 SERIALIZE_SCALAR(regs.pcr); 2147 SERIALIZE_SCALAR(regs.rfcr); 2148 SERIALIZE_SCALAR(regs.rfdr); 2149 SERIALIZE_SCALAR(regs.brar); 2150 SERIALIZE_SCALAR(regs.brdr); 2151 SERIALIZE_SCALAR(regs.srr); 2152 SERIALIZE_SCALAR(regs.mibc); 2153 SERIALIZE_SCALAR(regs.vrcr); 2154 SERIALIZE_SCALAR(regs.vtcr); 2155 SERIALIZE_SCALAR(regs.vdr); 2156 SERIALIZE_SCALAR(regs.ccsr); 2157 SERIALIZE_SCALAR(regs.tbicr); 2158 SERIALIZE_SCALAR(regs.tbisr); 2159 SERIALIZE_SCALAR(regs.tanar); 2160 SERIALIZE_SCALAR(regs.tanlpar); 2161 SERIALIZE_SCALAR(regs.taner); 2162 SERIALIZE_SCALAR(regs.tesr); 2163 2164 SERIALIZE_ARRAY(rom.perfectMatch, ETH_ADDR_LEN); 2165 SERIALIZE_ARRAY(rom.filterHash, FHASH_SIZE); 2166 2167 SERIALIZE_SCALAR(ioEnable); 2168 2169 /* 2170 * Serialize the data Fifos 2171 */ 2172 rxFifo.serialize("rxFifo", os); 2173 txFifo.serialize("txFifo", os); 2174 2175 /* 2176 * Serialize the various helper variables 2177 */ 2178 bool txPacketExists = txPacket; 2179 SERIALIZE_SCALAR(txPacketExists); 2180 if (txPacketExists) { 2181 txPacket->length = txPacketBufPtr - txPacket->data; 2182 txPacket->serialize("txPacket", os); 2183 uint32_t txPktBufPtr = (uint32_t) (txPacketBufPtr - txPacket->data); 2184 SERIALIZE_SCALAR(txPktBufPtr); 2185 } 2186 2187 bool rxPacketExists = rxPacket; 2188 SERIALIZE_SCALAR(rxPacketExists); 2189 if (rxPacketExists) { 2190 rxPacket->serialize("rxPacket", os); 2191 uint32_t rxPktBufPtr = (uint32_t) (rxPacketBufPtr - rxPacket->data); 2192 SERIALIZE_SCALAR(rxPktBufPtr); 2193 } 2194 2195 SERIALIZE_SCALAR(txXferLen); 2196 SERIALIZE_SCALAR(rxXferLen); 2197 2198 /* 2199 * Serialize Cached Descriptors 2200 */ 2201 SERIALIZE_SCALAR(rxDesc64.link); 2202 SERIALIZE_SCALAR(rxDesc64.bufptr); 2203 SERIALIZE_SCALAR(rxDesc64.cmdsts); 2204 SERIALIZE_SCALAR(rxDesc64.extsts); 2205 SERIALIZE_SCALAR(txDesc64.link); 2206 SERIALIZE_SCALAR(txDesc64.bufptr); 2207 SERIALIZE_SCALAR(txDesc64.cmdsts); 2208 SERIALIZE_SCALAR(txDesc64.extsts); 2209 SERIALIZE_SCALAR(rxDesc32.link); 2210 SERIALIZE_SCALAR(rxDesc32.bufptr); 2211 SERIALIZE_SCALAR(rxDesc32.cmdsts); 2212 SERIALIZE_SCALAR(rxDesc32.extsts); 2213 SERIALIZE_SCALAR(txDesc32.link); 2214 SERIALIZE_SCALAR(txDesc32.bufptr); 2215 SERIALIZE_SCALAR(txDesc32.cmdsts); 2216 SERIALIZE_SCALAR(txDesc32.extsts); 2217 SERIALIZE_SCALAR(extstsEnable); 2218 2219 /* 2220 * Serialize tx state machine 2221 */ 2222 int txState = this->txState; 2223 SERIALIZE_SCALAR(txState); 2224 SERIALIZE_SCALAR(txEnable); 2225 SERIALIZE_SCALAR(CTDD); 2226 SERIALIZE_SCALAR(txFragPtr); 2227 SERIALIZE_SCALAR(txDescCnt); 2228 int txDmaState = this->txDmaState; 2229 SERIALIZE_SCALAR(txDmaState); 2230 SERIALIZE_SCALAR(txKickTick); 2231 2232 /* 2233 * Serialize rx state machine 2234 */ 2235 int rxState = this->rxState; 2236 SERIALIZE_SCALAR(rxState); 2237 SERIALIZE_SCALAR(rxEnable); 2238 SERIALIZE_SCALAR(CRDD); 2239 SERIALIZE_SCALAR(rxPktBytes); 2240 SERIALIZE_SCALAR(rxFragPtr); 2241 SERIALIZE_SCALAR(rxDescCnt); 2242 int rxDmaState = this->rxDmaState; 2243 SERIALIZE_SCALAR(rxDmaState); 2244 SERIALIZE_SCALAR(rxKickTick); 2245 2246 /* 2247 * Serialize EEPROM state machine 2248 */ 2249 int eepromState = this->eepromState; 2250 SERIALIZE_SCALAR(eepromState); 2251 SERIALIZE_SCALAR(eepromClk); 2252 SERIALIZE_SCALAR(eepromBitsToRx); 2253 SERIALIZE_SCALAR(eepromOpcode); 2254 SERIALIZE_SCALAR(eepromAddress); 2255 SERIALIZE_SCALAR(eepromData); 2256 2257 /* 2258 * If there's a pending transmit, store the time so we can 2259 * reschedule it later 2260 */ 2261 Tick transmitTick = txEvent.scheduled() ? txEvent.when() - curTick : 0; 2262 SERIALIZE_SCALAR(transmitTick); 2263 2264 /* 2265 * receive address filter settings 2266 */ 2267 SERIALIZE_SCALAR(rxFilterEnable); 2268 SERIALIZE_SCALAR(acceptBroadcast); 2269 SERIALIZE_SCALAR(acceptMulticast); 2270 SERIALIZE_SCALAR(acceptUnicast); 2271 SERIALIZE_SCALAR(acceptPerfect); 2272 SERIALIZE_SCALAR(acceptArp); 2273 SERIALIZE_SCALAR(multicastHashEnable); 2274 2275 /* 2276 * Keep track of pending interrupt status. 2277 */ 2278 SERIALIZE_SCALAR(intrTick); 2279 SERIALIZE_SCALAR(cpuPendingIntr); 2280 Tick intrEventTick = 0; 2281 if (intrEvent) 2282 intrEventTick = intrEvent->when(); 2283 SERIALIZE_SCALAR(intrEventTick); 2284 2285} 2286 2287void 2288NSGigE::unserialize(Checkpoint *cp, const std::string §ion) 2289{ 2290 // Unserialize the PciDev base class 2291 PciDev::unserialize(cp, section); 2292 2293 UNSERIALIZE_SCALAR(regs.command); 2294 UNSERIALIZE_SCALAR(regs.config); 2295 UNSERIALIZE_SCALAR(regs.mear); 2296 UNSERIALIZE_SCALAR(regs.ptscr); 2297 UNSERIALIZE_SCALAR(regs.isr); 2298 UNSERIALIZE_SCALAR(regs.imr); 2299 UNSERIALIZE_SCALAR(regs.ier); 2300 UNSERIALIZE_SCALAR(regs.ihr); 2301 UNSERIALIZE_SCALAR(regs.txdp); 2302 UNSERIALIZE_SCALAR(regs.txdp_hi); 2303 UNSERIALIZE_SCALAR(regs.txcfg); 2304 UNSERIALIZE_SCALAR(regs.gpior); 2305 UNSERIALIZE_SCALAR(regs.rxdp); 2306 UNSERIALIZE_SCALAR(regs.rxdp_hi); 2307 UNSERIALIZE_SCALAR(regs.rxcfg); 2308 UNSERIALIZE_SCALAR(regs.pqcr); 2309 UNSERIALIZE_SCALAR(regs.wcsr); 2310 UNSERIALIZE_SCALAR(regs.pcr); 2311 UNSERIALIZE_SCALAR(regs.rfcr); 2312 UNSERIALIZE_SCALAR(regs.rfdr); 2313 UNSERIALIZE_SCALAR(regs.brar); 2314 UNSERIALIZE_SCALAR(regs.brdr); 2315 UNSERIALIZE_SCALAR(regs.srr); 2316 UNSERIALIZE_SCALAR(regs.mibc); 2317 UNSERIALIZE_SCALAR(regs.vrcr); 2318 UNSERIALIZE_SCALAR(regs.vtcr); 2319 UNSERIALIZE_SCALAR(regs.vdr); 2320 UNSERIALIZE_SCALAR(regs.ccsr); 2321 UNSERIALIZE_SCALAR(regs.tbicr); 2322 UNSERIALIZE_SCALAR(regs.tbisr); 2323 UNSERIALIZE_SCALAR(regs.tanar); 2324 UNSERIALIZE_SCALAR(regs.tanlpar); 2325 UNSERIALIZE_SCALAR(regs.taner); 2326 UNSERIALIZE_SCALAR(regs.tesr); 2327 2328 UNSERIALIZE_ARRAY(rom.perfectMatch, ETH_ADDR_LEN); 2329 UNSERIALIZE_ARRAY(rom.filterHash, FHASH_SIZE); 2330 2331 UNSERIALIZE_SCALAR(ioEnable); 2332 2333 /* 2334 * unserialize the data fifos 2335 */ 2336 rxFifo.unserialize("rxFifo", cp, section); 2337 txFifo.unserialize("txFifo", cp, section); 2338 2339 /* 2340 * unserialize the various helper variables 2341 */ 2342 bool txPacketExists; 2343 UNSERIALIZE_SCALAR(txPacketExists); 2344 if (txPacketExists) { 2345 txPacket = new EthPacketData(16384); 2346 txPacket->unserialize("txPacket", cp, section); 2347 uint32_t txPktBufPtr; 2348 UNSERIALIZE_SCALAR(txPktBufPtr); 2349 txPacketBufPtr = (uint8_t *) txPacket->data + txPktBufPtr; 2350 } else 2351 txPacket = 0; 2352 2353 bool rxPacketExists; 2354 UNSERIALIZE_SCALAR(rxPacketExists); 2355 rxPacket = 0; 2356 if (rxPacketExists) { 2357 rxPacket = new EthPacketData(16384); 2358 rxPacket->unserialize("rxPacket", cp, section); 2359 uint32_t rxPktBufPtr; 2360 UNSERIALIZE_SCALAR(rxPktBufPtr); 2361 rxPacketBufPtr = (uint8_t *) rxPacket->data + rxPktBufPtr; 2362 } else 2363 rxPacket = 0; 2364 2365 UNSERIALIZE_SCALAR(txXferLen); 2366 UNSERIALIZE_SCALAR(rxXferLen); 2367 2368 /* 2369 * Unserialize Cached Descriptors 2370 */ 2371 UNSERIALIZE_SCALAR(rxDesc64.link); 2372 UNSERIALIZE_SCALAR(rxDesc64.bufptr); 2373 UNSERIALIZE_SCALAR(rxDesc64.cmdsts); 2374 UNSERIALIZE_SCALAR(rxDesc64.extsts); 2375 UNSERIALIZE_SCALAR(txDesc64.link); 2376 UNSERIALIZE_SCALAR(txDesc64.bufptr); 2377 UNSERIALIZE_SCALAR(txDesc64.cmdsts); 2378 UNSERIALIZE_SCALAR(txDesc64.extsts); 2379 UNSERIALIZE_SCALAR(rxDesc32.link); 2380 UNSERIALIZE_SCALAR(rxDesc32.bufptr); 2381 UNSERIALIZE_SCALAR(rxDesc32.cmdsts); 2382 UNSERIALIZE_SCALAR(rxDesc32.extsts); 2383 UNSERIALIZE_SCALAR(txDesc32.link); 2384 UNSERIALIZE_SCALAR(txDesc32.bufptr); 2385 UNSERIALIZE_SCALAR(txDesc32.cmdsts); 2386 UNSERIALIZE_SCALAR(txDesc32.extsts); 2387 UNSERIALIZE_SCALAR(extstsEnable); 2388 2389 /* 2390 * unserialize tx state machine 2391 */ 2392 int txState; 2393 UNSERIALIZE_SCALAR(txState); 2394 this->txState = (TxState) txState; 2395 UNSERIALIZE_SCALAR(txEnable); 2396 UNSERIALIZE_SCALAR(CTDD); 2397 UNSERIALIZE_SCALAR(txFragPtr); 2398 UNSERIALIZE_SCALAR(txDescCnt); 2399 int txDmaState; 2400 UNSERIALIZE_SCALAR(txDmaState); 2401 this->txDmaState = (DmaState) txDmaState; 2402 UNSERIALIZE_SCALAR(txKickTick); 2403 if (txKickTick) 2404 schedule(txKickEvent, txKickTick); 2405 2406 /* 2407 * unserialize rx state machine 2408 */ 2409 int rxState; 2410 UNSERIALIZE_SCALAR(rxState); 2411 this->rxState = (RxState) rxState; 2412 UNSERIALIZE_SCALAR(rxEnable); 2413 UNSERIALIZE_SCALAR(CRDD); 2414 UNSERIALIZE_SCALAR(rxPktBytes); 2415 UNSERIALIZE_SCALAR(rxFragPtr); 2416 UNSERIALIZE_SCALAR(rxDescCnt); 2417 int rxDmaState; 2418 UNSERIALIZE_SCALAR(rxDmaState); 2419 this->rxDmaState = (DmaState) rxDmaState; 2420 UNSERIALIZE_SCALAR(rxKickTick); 2421 if (rxKickTick) 2422 schedule(rxKickEvent, rxKickTick); 2423 2424 /* 2425 * Unserialize EEPROM state machine 2426 */ 2427 int eepromState; 2428 UNSERIALIZE_SCALAR(eepromState); 2429 this->eepromState = (EEPROMState) eepromState; 2430 UNSERIALIZE_SCALAR(eepromClk); 2431 UNSERIALIZE_SCALAR(eepromBitsToRx); 2432 UNSERIALIZE_SCALAR(eepromOpcode); 2433 UNSERIALIZE_SCALAR(eepromAddress); 2434 UNSERIALIZE_SCALAR(eepromData); 2435 2436 /* 2437 * If there's a pending transmit, reschedule it now 2438 */ 2439 Tick transmitTick; 2440 UNSERIALIZE_SCALAR(transmitTick); 2441 if (transmitTick) 2442 schedule(txEvent, curTick + transmitTick); 2443 2444 /* 2445 * unserialize receive address filter settings 2446 */ 2447 UNSERIALIZE_SCALAR(rxFilterEnable); 2448 UNSERIALIZE_SCALAR(acceptBroadcast); 2449 UNSERIALIZE_SCALAR(acceptMulticast); 2450 UNSERIALIZE_SCALAR(acceptUnicast); 2451 UNSERIALIZE_SCALAR(acceptPerfect); 2452 UNSERIALIZE_SCALAR(acceptArp); 2453 UNSERIALIZE_SCALAR(multicastHashEnable); 2454 2455 /* 2456 * Keep track of pending interrupt status. 2457 */ 2458 UNSERIALIZE_SCALAR(intrTick); 2459 UNSERIALIZE_SCALAR(cpuPendingIntr); 2460 Tick intrEventTick; 2461 UNSERIALIZE_SCALAR(intrEventTick); 2462 if (intrEventTick) { 2463 intrEvent = new IntrEvent(this, true); 2464 schedule(intrEvent, intrEventTick); 2465 } 2466} 2467 2468NSGigE * 2469NSGigEParams::create() 2470{ 2471 return new NSGigE(this); 2472} 2473