ns_gige.cc revision 10913
17119Sgblack@eecs.umich.edu/* 27119Sgblack@eecs.umich.edu * Copyright (c) 2004-2005 The Regents of The University of Michigan 37120Sgblack@eecs.umich.edu * All rights reserved. 47120Sgblack@eecs.umich.edu * 57120Sgblack@eecs.umich.edu * Redistribution and use in source and binary forms, with or without 67120Sgblack@eecs.umich.edu * modification, are permitted provided that the following conditions are 77120Sgblack@eecs.umich.edu * met: redistributions of source code must retain the above copyright 87120Sgblack@eecs.umich.edu * notice, this list of conditions and the following disclaimer; 97120Sgblack@eecs.umich.edu * redistributions in binary form must reproduce the above copyright 107120Sgblack@eecs.umich.edu * notice, this list of conditions and the following disclaimer in the 117120Sgblack@eecs.umich.edu * documentation and/or other materials provided with the distribution; 127120Sgblack@eecs.umich.edu * neither the name of the copyright holders nor the names of its 137120Sgblack@eecs.umich.edu * contributors may be used to endorse or promote products derived from 147120Sgblack@eecs.umich.edu * this software without specific prior written permission. 157119Sgblack@eecs.umich.edu * 167119Sgblack@eecs.umich.edu * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 177119Sgblack@eecs.umich.edu * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 187119Sgblack@eecs.umich.edu * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR 197119Sgblack@eecs.umich.edu * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT 207119Sgblack@eecs.umich.edu * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 217119Sgblack@eecs.umich.edu * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT 227119Sgblack@eecs.umich.edu * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 237119Sgblack@eecs.umich.edu * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 247119Sgblack@eecs.umich.edu * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 257119Sgblack@eecs.umich.edu * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 267119Sgblack@eecs.umich.edu * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 277119Sgblack@eecs.umich.edu * 287119Sgblack@eecs.umich.edu * Authors: Nathan Binkert 297119Sgblack@eecs.umich.edu * Lisa Hsu 307119Sgblack@eecs.umich.edu */ 317119Sgblack@eecs.umich.edu 327119Sgblack@eecs.umich.edu/** @file 337119Sgblack@eecs.umich.edu * Device module for modelling the National Semiconductor 347119Sgblack@eecs.umich.edu * DP83820 ethernet controller. Does not support priority queueing 357119Sgblack@eecs.umich.edu */ 367119Sgblack@eecs.umich.edu#include <deque> 377119Sgblack@eecs.umich.edu#include <memory> 387119Sgblack@eecs.umich.edu#include <string> 397119Sgblack@eecs.umich.edu 407119Sgblack@eecs.umich.edu#include "base/debug.hh" 417119Sgblack@eecs.umich.edu#include "base/inet.hh" 427119Sgblack@eecs.umich.edu#include "base/types.hh" 437119Sgblack@eecs.umich.edu#include "config/the_isa.hh" 447646Sgene.wu@arm.com#include "debug/EthernetAll.hh" 457646Sgene.wu@arm.com#include "dev/etherlink.hh" 467646Sgene.wu@arm.com#include "dev/ns_gige.hh" 477646Sgene.wu@arm.com#include "dev/pciconfigall.hh" 487646Sgene.wu@arm.com#include "mem/packet.hh" 497646Sgene.wu@arm.com#include "mem/packet_access.hh" 507646Sgene.wu@arm.com#include "params/NSGigE.hh" 517646Sgene.wu@arm.com#include "sim/system.hh" 527646Sgene.wu@arm.com 537646Sgene.wu@arm.com// clang complains about std::set being overloaded with Packet::set if 547646Sgene.wu@arm.com// we open up the entire namespace std 557646Sgene.wu@arm.comusing std::make_shared; 567646Sgene.wu@arm.comusing std::min; 577646Sgene.wu@arm.comusing std::ostream; 587646Sgene.wu@arm.comusing std::string; 597646Sgene.wu@arm.com 607646Sgene.wu@arm.comconst char *NsRxStateStrings[] = 617646Sgene.wu@arm.com{ 627646Sgene.wu@arm.com "rxIdle", 637646Sgene.wu@arm.com "rxDescRefr", 647646Sgene.wu@arm.com "rxDescRead", 657646Sgene.wu@arm.com "rxFifoBlock", 667646Sgene.wu@arm.com "rxFragWrite", 677646Sgene.wu@arm.com "rxDescWrite", 687646Sgene.wu@arm.com "rxAdvance" 697646Sgene.wu@arm.com}; 707646Sgene.wu@arm.com 717646Sgene.wu@arm.comconst char *NsTxStateStrings[] = 727646Sgene.wu@arm.com{ 737205Sgblack@eecs.umich.edu "txIdle", 747205Sgblack@eecs.umich.edu "txDescRefr", 757205Sgblack@eecs.umich.edu "txDescRead", 767205Sgblack@eecs.umich.edu "txFifoBlock", 777205Sgblack@eecs.umich.edu "txFragRead", 787205Sgblack@eecs.umich.edu "txDescWrite", 797205Sgblack@eecs.umich.edu "txAdvance" 807205Sgblack@eecs.umich.edu}; 817205Sgblack@eecs.umich.edu 827205Sgblack@eecs.umich.educonst char *NsDmaState[] = 837205Sgblack@eecs.umich.edu{ 847205Sgblack@eecs.umich.edu "dmaIdle", 857205Sgblack@eecs.umich.edu "dmaReading", 867205Sgblack@eecs.umich.edu "dmaWriting", 877205Sgblack@eecs.umich.edu "dmaReadWaiting", 887205Sgblack@eecs.umich.edu "dmaWriteWaiting" 897205Sgblack@eecs.umich.edu}; 908442Sgblack@eecs.umich.edu 918442Sgblack@eecs.umich.eduusing namespace Net; 927205Sgblack@eecs.umich.eduusing namespace TheISA; 937205Sgblack@eecs.umich.edu 947205Sgblack@eecs.umich.edu/////////////////////////////////////////////////////////////////////// 957205Sgblack@eecs.umich.edu// 967205Sgblack@eecs.umich.edu// NSGigE PCI Device 977205Sgblack@eecs.umich.edu// 987205Sgblack@eecs.umich.eduNSGigE::NSGigE(Params *p) 997205Sgblack@eecs.umich.edu : EtherDevBase(p), ioEnable(false), 1007205Sgblack@eecs.umich.edu txFifo(p->tx_fifo_size), rxFifo(p->rx_fifo_size), 1017597Sminkyu.jeong@arm.com txPacket(0), rxPacket(0), txPacketBufPtr(NULL), rxPacketBufPtr(NULL), 1027597Sminkyu.jeong@arm.com txXferLen(0), rxXferLen(0), rxDmaFree(false), txDmaFree(false), 1037205Sgblack@eecs.umich.edu txState(txIdle), txEnable(false), CTDD(false), txHalt(false), 1047205Sgblack@eecs.umich.edu txFragPtr(0), txDescCnt(0), txDmaState(dmaIdle), rxState(rxIdle), 1057205Sgblack@eecs.umich.edu rxEnable(false), CRDD(false), rxPktBytes(0), rxHalt(false), 1067205Sgblack@eecs.umich.edu rxFragPtr(0), rxDescCnt(0), rxDmaState(dmaIdle), extstsEnable(false), 1077205Sgblack@eecs.umich.edu eepromState(eepromStart), eepromClk(false), eepromBitsToRx(0), 1087205Sgblack@eecs.umich.edu eepromOpcode(0), eepromAddress(0), eepromData(0), 1097205Sgblack@eecs.umich.edu dmaReadDelay(p->dma_read_delay), dmaWriteDelay(p->dma_write_delay), 1107205Sgblack@eecs.umich.edu dmaReadFactor(p->dma_read_factor), dmaWriteFactor(p->dma_write_factor), 1117205Sgblack@eecs.umich.edu rxDmaData(NULL), rxDmaAddr(0), rxDmaLen(0), 1127205Sgblack@eecs.umich.edu txDmaData(NULL), txDmaAddr(0), txDmaLen(0), 1137205Sgblack@eecs.umich.edu rxDmaReadEvent(this), rxDmaWriteEvent(this), 1147205Sgblack@eecs.umich.edu txDmaReadEvent(this), txDmaWriteEvent(this), 1157205Sgblack@eecs.umich.edu dmaDescFree(p->dma_desc_free), dmaDataFree(p->dma_data_free), 1167205Sgblack@eecs.umich.edu txDelay(p->tx_delay), rxDelay(p->rx_delay), 1177205Sgblack@eecs.umich.edu rxKickTick(0), rxKickEvent(this), txKickTick(0), txKickEvent(this), 1187205Sgblack@eecs.umich.edu txEvent(this), rxFilterEnable(p->rx_filter), 1197205Sgblack@eecs.umich.edu acceptBroadcast(false), acceptMulticast(false), acceptUnicast(false), 1207205Sgblack@eecs.umich.edu acceptPerfect(false), acceptArp(false), multicastHashEnable(false), 1217205Sgblack@eecs.umich.edu intrDelay(p->intr_delay), intrTick(0), cpuPendingIntr(false), 1227205Sgblack@eecs.umich.edu intrEvent(0), interface(0) 1237205Sgblack@eecs.umich.edu{ 1247205Sgblack@eecs.umich.edu 1257205Sgblack@eecs.umich.edu 1268442Sgblack@eecs.umich.edu interface = new NSGigEInt(name() + ".int0", this); 1278442Sgblack@eecs.umich.edu 1287205Sgblack@eecs.umich.edu regsReset(); 1297597Sminkyu.jeong@arm.com memcpy(&rom.perfectMatch, p->hardware_address.bytes(), ETH_ADDR_LEN); 1307597Sminkyu.jeong@arm.com 1317205Sgblack@eecs.umich.edu memset(&rxDesc32, 0, sizeof(rxDesc32)); 1327205Sgblack@eecs.umich.edu memset(&txDesc32, 0, sizeof(txDesc32)); 1337205Sgblack@eecs.umich.edu memset(&rxDesc64, 0, sizeof(rxDesc64)); 1347205Sgblack@eecs.umich.edu memset(&txDesc64, 0, sizeof(txDesc64)); 1357205Sgblack@eecs.umich.edu} 1367205Sgblack@eecs.umich.edu 1377205Sgblack@eecs.umich.eduNSGigE::~NSGigE() 1387205Sgblack@eecs.umich.edu{ 1397205Sgblack@eecs.umich.edu delete interface; 1407205Sgblack@eecs.umich.edu} 1417205Sgblack@eecs.umich.edu 1427205Sgblack@eecs.umich.edu/** 1437205Sgblack@eecs.umich.edu * This is to write to the PCI general configuration registers 1447205Sgblack@eecs.umich.edu */ 1457205Sgblack@eecs.umich.eduTick 1467205Sgblack@eecs.umich.eduNSGigE::writeConfig(PacketPtr pkt) 1477205Sgblack@eecs.umich.edu{ 1487205Sgblack@eecs.umich.edu int offset = pkt->getAddr() & PCI_CONFIG_SIZE; 1497205Sgblack@eecs.umich.edu if (offset < PCI_DEVICE_SPECIFIC) 1508442Sgblack@eecs.umich.edu PciDevice::writeConfig(pkt); 1518442Sgblack@eecs.umich.edu else 1527205Sgblack@eecs.umich.edu panic("Device specific PCI config space not implemented!\n"); 1537205Sgblack@eecs.umich.edu 1547205Sgblack@eecs.umich.edu switch (offset) { 1557205Sgblack@eecs.umich.edu // seems to work fine without all these PCI settings, but i 1567205Sgblack@eecs.umich.edu // put in the IO to double check, an assertion will fail if we 1577205Sgblack@eecs.umich.edu // need to properly implement it 1587205Sgblack@eecs.umich.edu case PCI_COMMAND: 1597205Sgblack@eecs.umich.edu if (config.data[offset] & PCI_CMD_IOSE) 1607205Sgblack@eecs.umich.edu ioEnable = true; 1617205Sgblack@eecs.umich.edu else 1627205Sgblack@eecs.umich.edu ioEnable = false; 1637205Sgblack@eecs.umich.edu break; 1647119Sgblack@eecs.umich.edu } 1657119Sgblack@eecs.umich.edu 1667119Sgblack@eecs.umich.edu return configDelay; 1677119Sgblack@eecs.umich.edu} 1687119Sgblack@eecs.umich.edu 1697119Sgblack@eecs.umich.eduEtherInt* 1707119Sgblack@eecs.umich.eduNSGigE::getEthPort(const std::string &if_name, int idx) 1717119Sgblack@eecs.umich.edu{ 1727119Sgblack@eecs.umich.edu if (if_name == "interface") { 1737119Sgblack@eecs.umich.edu if (interface->getPeer()) 1747119Sgblack@eecs.umich.edu panic("interface already connected to\n"); 1757119Sgblack@eecs.umich.edu return interface; 1767119Sgblack@eecs.umich.edu } 1777119Sgblack@eecs.umich.edu return NULL; 1788442Sgblack@eecs.umich.edu} 1797119Sgblack@eecs.umich.edu 1807119Sgblack@eecs.umich.edu/** 1817119Sgblack@eecs.umich.edu * This reads the device registers, which are detailed in the NS83820 1827119Sgblack@eecs.umich.edu * spec sheet 1837119Sgblack@eecs.umich.edu */ 1847119Sgblack@eecs.umich.eduTick 1857597Sminkyu.jeong@arm.comNSGigE::read(PacketPtr pkt) 1867597Sminkyu.jeong@arm.com{ 1877119Sgblack@eecs.umich.edu assert(ioEnable); 1887119Sgblack@eecs.umich.edu 1897119Sgblack@eecs.umich.edu //The mask is to give you only the offset into the device register file 1907119Sgblack@eecs.umich.edu Addr daddr = pkt->getAddr() & 0xfff; 1917119Sgblack@eecs.umich.edu DPRINTF(EthernetPIO, "read da=%#x pa=%#x size=%d\n", 1927119Sgblack@eecs.umich.edu daddr, pkt->getAddr(), pkt->getSize()); 1937639Sgblack@eecs.umich.edu 1947639Sgblack@eecs.umich.edu 1957639Sgblack@eecs.umich.edu // there are some reserved registers, you can see ns_gige_reg.h and 1967639Sgblack@eecs.umich.edu // the spec sheet for details 1977639Sgblack@eecs.umich.edu if (daddr > LAST && daddr <= RESERVED) { 1987639Sgblack@eecs.umich.edu panic("Accessing reserved register"); 1997639Sgblack@eecs.umich.edu } else if (daddr > RESERVED && daddr <= 0x3FC) { 2007639Sgblack@eecs.umich.edu return readConfig(pkt); 2017639Sgblack@eecs.umich.edu } else if (daddr >= MIB_START && daddr <= MIB_END) { 2027639Sgblack@eecs.umich.edu // don't implement all the MIB's. hopefully the kernel 2037639Sgblack@eecs.umich.edu // doesn't actually DEPEND upon their values 2047639Sgblack@eecs.umich.edu // MIB are just hardware stats keepers 2057639Sgblack@eecs.umich.edu pkt->set<uint32_t>(0); 2067639Sgblack@eecs.umich.edu pkt->makeAtomicResponse(); 2077639Sgblack@eecs.umich.edu return pioDelay; 2087639Sgblack@eecs.umich.edu } else if (daddr > 0x3FC) 2097639Sgblack@eecs.umich.edu panic("Something is messed up!\n"); 2107639Sgblack@eecs.umich.edu 2117639Sgblack@eecs.umich.edu assert(pkt->getSize() == sizeof(uint32_t)); 2128444Sgblack@eecs.umich.edu uint32_t ® = *pkt->getPtr<uint32_t>(); 2137639Sgblack@eecs.umich.edu uint16_t rfaddr; 2147639Sgblack@eecs.umich.edu 2157639Sgblack@eecs.umich.edu switch (daddr) { 2167639Sgblack@eecs.umich.edu case CR: 2177639Sgblack@eecs.umich.edu reg = regs.command; 2187639Sgblack@eecs.umich.edu //these are supposed to be cleared on a read 2198072SGiacomo.Gabrielli@arm.com reg &= ~(CR_RXD | CR_TXD | CR_TXR | CR_RXR); 2208072SGiacomo.Gabrielli@arm.com break; 2217639Sgblack@eecs.umich.edu 2227639Sgblack@eecs.umich.edu case CFGR: 2237639Sgblack@eecs.umich.edu reg = regs.config; 2247639Sgblack@eecs.umich.edu break; 2257639Sgblack@eecs.umich.edu 2267639Sgblack@eecs.umich.edu case MEAR: 2277120Sgblack@eecs.umich.edu reg = regs.mear; 2287120Sgblack@eecs.umich.edu break; 2297120Sgblack@eecs.umich.edu 2307120Sgblack@eecs.umich.edu case PTSCR: 2317120Sgblack@eecs.umich.edu reg = regs.ptscr; 2327120Sgblack@eecs.umich.edu break; 2337120Sgblack@eecs.umich.edu 2347120Sgblack@eecs.umich.edu case ISR: 2357120Sgblack@eecs.umich.edu reg = regs.isr; 2367120Sgblack@eecs.umich.edu devIntrClear(ISR_ALL); 2377120Sgblack@eecs.umich.edu break; 2387120Sgblack@eecs.umich.edu 2397120Sgblack@eecs.umich.edu case IMR: 2407120Sgblack@eecs.umich.edu reg = regs.imr; 2417120Sgblack@eecs.umich.edu break; 2427120Sgblack@eecs.umich.edu 2437120Sgblack@eecs.umich.edu case IER: 2447120Sgblack@eecs.umich.edu reg = regs.ier; 2458442Sgblack@eecs.umich.edu break; 2468442Sgblack@eecs.umich.edu 2477120Sgblack@eecs.umich.edu case IHR: 2487120Sgblack@eecs.umich.edu reg = regs.ihr; 2497120Sgblack@eecs.umich.edu break; 2507120Sgblack@eecs.umich.edu 2517120Sgblack@eecs.umich.edu case TXDP: 2527597Sminkyu.jeong@arm.com reg = regs.txdp; 2537597Sminkyu.jeong@arm.com break; 2547120Sgblack@eecs.umich.edu 2557120Sgblack@eecs.umich.edu case TXDP_HI: 2567120Sgblack@eecs.umich.edu reg = regs.txdp_hi; 2577120Sgblack@eecs.umich.edu break; 2587120Sgblack@eecs.umich.edu 2597120Sgblack@eecs.umich.edu case TX_CFG: 2607639Sgblack@eecs.umich.edu reg = regs.txcfg; 2617639Sgblack@eecs.umich.edu break; 2627639Sgblack@eecs.umich.edu 2637639Sgblack@eecs.umich.edu case GPIOR: 2647639Sgblack@eecs.umich.edu reg = regs.gpior; 2657639Sgblack@eecs.umich.edu break; 2667639Sgblack@eecs.umich.edu 2677639Sgblack@eecs.umich.edu case RXDP: 2687639Sgblack@eecs.umich.edu reg = regs.rxdp; 2697639Sgblack@eecs.umich.edu break; 2707639Sgblack@eecs.umich.edu 2717639Sgblack@eecs.umich.edu case RXDP_HI: 2727639Sgblack@eecs.umich.edu reg = regs.rxdp_hi; 2737639Sgblack@eecs.umich.edu break; 2747639Sgblack@eecs.umich.edu 2757639Sgblack@eecs.umich.edu case RX_CFG: 2767639Sgblack@eecs.umich.edu reg = regs.rxcfg; 2777639Sgblack@eecs.umich.edu break; 2787639Sgblack@eecs.umich.edu 2797639Sgblack@eecs.umich.edu case PQCR: 2807639Sgblack@eecs.umich.edu reg = regs.pqcr; 2817639Sgblack@eecs.umich.edu break; 2827639Sgblack@eecs.umich.edu 2838444Sgblack@eecs.umich.edu case WCSR: 2848444Sgblack@eecs.umich.edu reg = regs.wcsr; 2857639Sgblack@eecs.umich.edu break; 2867639Sgblack@eecs.umich.edu 2877639Sgblack@eecs.umich.edu case PCR: 2887639Sgblack@eecs.umich.edu reg = regs.pcr; 2897639Sgblack@eecs.umich.edu break; 2908072SGiacomo.Gabrielli@arm.com 2918072SGiacomo.Gabrielli@arm.com // see the spec sheet for how RFCR and RFDR work 2927639Sgblack@eecs.umich.edu // basically, you write to RFCR to tell the machine 2937639Sgblack@eecs.umich.edu // what you want to do next, then you act upon RFDR, 2947639Sgblack@eecs.umich.edu // and the device will be prepared b/c of what you 2957639Sgblack@eecs.umich.edu // wrote to RFCR 2967639Sgblack@eecs.umich.edu case RFCR: 2977639Sgblack@eecs.umich.edu reg = regs.rfcr; 2987303Sgblack@eecs.umich.edu break; 2997303Sgblack@eecs.umich.edu 3007303Sgblack@eecs.umich.edu case RFDR: 3017303Sgblack@eecs.umich.edu rfaddr = (uint16_t)(regs.rfcr & RFCR_RFADDR); 3027303Sgblack@eecs.umich.edu switch (rfaddr) { 3037303Sgblack@eecs.umich.edu // Read from perfect match ROM octets 3047303Sgblack@eecs.umich.edu case 0x000: 3057303Sgblack@eecs.umich.edu reg = rom.perfectMatch[1]; 3067303Sgblack@eecs.umich.edu reg = reg << 8; 3077303Sgblack@eecs.umich.edu reg += rom.perfectMatch[0]; 3087303Sgblack@eecs.umich.edu break; 3097303Sgblack@eecs.umich.edu case 0x002: 3107303Sgblack@eecs.umich.edu reg = rom.perfectMatch[3] << 8; 3117303Sgblack@eecs.umich.edu reg += rom.perfectMatch[2]; 3127303Sgblack@eecs.umich.edu break; 3137303Sgblack@eecs.umich.edu case 0x004: 3147303Sgblack@eecs.umich.edu reg = rom.perfectMatch[5] << 8; 3157303Sgblack@eecs.umich.edu reg += rom.perfectMatch[4]; 3167303Sgblack@eecs.umich.edu break; 3177303Sgblack@eecs.umich.edu default: 3188442Sgblack@eecs.umich.edu // Read filter hash table 3198442Sgblack@eecs.umich.edu if (rfaddr >= FHASH_ADDR && 3207303Sgblack@eecs.umich.edu rfaddr < FHASH_ADDR + FHASH_SIZE) { 3217303Sgblack@eecs.umich.edu 3227303Sgblack@eecs.umich.edu // Only word-aligned reads supported 3237303Sgblack@eecs.umich.edu if (rfaddr % 2) 3247303Sgblack@eecs.umich.edu panic("unaligned read from filter hash table!"); 3257303Sgblack@eecs.umich.edu 3267303Sgblack@eecs.umich.edu reg = rom.filterHash[rfaddr - FHASH_ADDR + 1] << 8; 3277303Sgblack@eecs.umich.edu reg += rom.filterHash[rfaddr - FHASH_ADDR]; 3287303Sgblack@eecs.umich.edu break; 3297597Sminkyu.jeong@arm.com } 3307597Sminkyu.jeong@arm.com 3317303Sgblack@eecs.umich.edu panic("reading RFDR for something other than pattern" 3327303Sgblack@eecs.umich.edu " matching or hashing! %#x\n", rfaddr); 3337303Sgblack@eecs.umich.edu } 3347303Sgblack@eecs.umich.edu break; 3357303Sgblack@eecs.umich.edu 3367303Sgblack@eecs.umich.edu case SRR: 3377303Sgblack@eecs.umich.edu reg = regs.srr; 3387303Sgblack@eecs.umich.edu break; 3397303Sgblack@eecs.umich.edu 3407303Sgblack@eecs.umich.edu case MIBC: 3417303Sgblack@eecs.umich.edu reg = regs.mibc; 3427303Sgblack@eecs.umich.edu reg &= ~(MIBC_MIBS | MIBC_ACLR); 3437303Sgblack@eecs.umich.edu break; 3447303Sgblack@eecs.umich.edu 3457303Sgblack@eecs.umich.edu case VRCR: 3467303Sgblack@eecs.umich.edu reg = regs.vrcr; 3477303Sgblack@eecs.umich.edu break; 3487303Sgblack@eecs.umich.edu 3497303Sgblack@eecs.umich.edu case VTCR: 3507303Sgblack@eecs.umich.edu reg = regs.vtcr; 3517303Sgblack@eecs.umich.edu break; 3527303Sgblack@eecs.umich.edu 3537303Sgblack@eecs.umich.edu case VDR: 3547303Sgblack@eecs.umich.edu reg = regs.vdr; 3558442Sgblack@eecs.umich.edu break; 3568442Sgblack@eecs.umich.edu 3577303Sgblack@eecs.umich.edu case CCSR: 3587597Sminkyu.jeong@arm.com reg = regs.ccsr; 3597597Sminkyu.jeong@arm.com break; 3607303Sgblack@eecs.umich.edu 3617408Sgblack@eecs.umich.edu case TBICR: 3627303Sgblack@eecs.umich.edu reg = regs.tbicr; 3637303Sgblack@eecs.umich.edu break; 3647303Sgblack@eecs.umich.edu 3657303Sgblack@eecs.umich.edu case TBISR: 3667120Sgblack@eecs.umich.edu reg = regs.tbisr; 3677120Sgblack@eecs.umich.edu break; 3687120Sgblack@eecs.umich.edu 3697120Sgblack@eecs.umich.edu case TANAR: 3707120Sgblack@eecs.umich.edu reg = regs.tanar; 3717120Sgblack@eecs.umich.edu break; 3727120Sgblack@eecs.umich.edu 3737120Sgblack@eecs.umich.edu case TANLPAR: 3747120Sgblack@eecs.umich.edu reg = regs.tanlpar; 3757120Sgblack@eecs.umich.edu break; 3767120Sgblack@eecs.umich.edu 3777120Sgblack@eecs.umich.edu case TANER: 3787120Sgblack@eecs.umich.edu reg = regs.taner; 3797120Sgblack@eecs.umich.edu break; 3807120Sgblack@eecs.umich.edu 3817120Sgblack@eecs.umich.edu case TESR: 3827120Sgblack@eecs.umich.edu reg = regs.tesr; 3837120Sgblack@eecs.umich.edu break; 3848442Sgblack@eecs.umich.edu 3858442Sgblack@eecs.umich.edu case M5REG: 3867120Sgblack@eecs.umich.edu reg = 0; 3877597Sminkyu.jeong@arm.com if (params()->rx_thread) 3887597Sminkyu.jeong@arm.com reg |= M5REG_RX_THREAD; 3897120Sgblack@eecs.umich.edu if (params()->tx_thread) 3907120Sgblack@eecs.umich.edu reg |= M5REG_TX_THREAD; 3917120Sgblack@eecs.umich.edu if (params()->rss) 3927120Sgblack@eecs.umich.edu reg |= M5REG_RSS; 3937120Sgblack@eecs.umich.edu break; 3947120Sgblack@eecs.umich.edu 3957639Sgblack@eecs.umich.edu default: 3967639Sgblack@eecs.umich.edu panic("reading unimplemented register: addr=%#x", daddr); 3977639Sgblack@eecs.umich.edu } 3987639Sgblack@eecs.umich.edu 3997639Sgblack@eecs.umich.edu DPRINTF(EthernetPIO, "read from %#x: data=%d data=%#x\n", 4007639Sgblack@eecs.umich.edu daddr, reg, reg); 4017639Sgblack@eecs.umich.edu 4027639Sgblack@eecs.umich.edu pkt->makeAtomicResponse(); 4037639Sgblack@eecs.umich.edu return pioDelay; 4047639Sgblack@eecs.umich.edu} 4057639Sgblack@eecs.umich.edu 4067639Sgblack@eecs.umich.eduTick 4077639Sgblack@eecs.umich.eduNSGigE::write(PacketPtr pkt) 4087639Sgblack@eecs.umich.edu{ 4097639Sgblack@eecs.umich.edu assert(ioEnable); 4107639Sgblack@eecs.umich.edu 4117639Sgblack@eecs.umich.edu Addr daddr = pkt->getAddr() & 0xfff; 4127639Sgblack@eecs.umich.edu DPRINTF(EthernetPIO, "write da=%#x pa=%#x size=%d\n", 4137639Sgblack@eecs.umich.edu daddr, pkt->getAddr(), pkt->getSize()); 4147639Sgblack@eecs.umich.edu 4157639Sgblack@eecs.umich.edu if (daddr > LAST && daddr <= RESERVED) { 4168444Sgblack@eecs.umich.edu panic("Accessing reserved register"); 4178444Sgblack@eecs.umich.edu } else if (daddr > RESERVED && daddr <= 0x3FC) { 4187639Sgblack@eecs.umich.edu return writeConfig(pkt); 4198072SGiacomo.Gabrielli@arm.com } else if (daddr > 0x3FC) 4208072SGiacomo.Gabrielli@arm.com panic("Something is messed up!\n"); 4217639Sgblack@eecs.umich.edu 4227639Sgblack@eecs.umich.edu if (pkt->getSize() == sizeof(uint32_t)) { 4237639Sgblack@eecs.umich.edu uint32_t reg = pkt->get<uint32_t>(); 4247639Sgblack@eecs.umich.edu uint16_t rfaddr; 4257639Sgblack@eecs.umich.edu 4267639Sgblack@eecs.umich.edu DPRINTF(EthernetPIO, "write data=%d data=%#x\n", reg, reg); 4277119Sgblack@eecs.umich.edu 4287119Sgblack@eecs.umich.edu switch (daddr) { 4297119Sgblack@eecs.umich.edu case CR: 4307119Sgblack@eecs.umich.edu regs.command = reg; 4317119Sgblack@eecs.umich.edu if (reg & CR_TXD) { 4327119Sgblack@eecs.umich.edu txEnable = false; 4337119Sgblack@eecs.umich.edu } else if (reg & CR_TXE) { 4347119Sgblack@eecs.umich.edu txEnable = true; 4357119Sgblack@eecs.umich.edu 4367119Sgblack@eecs.umich.edu // the kernel is enabling the transmit machine 4377119Sgblack@eecs.umich.edu if (txState == txIdle) 4387119Sgblack@eecs.umich.edu txKick(); 4397119Sgblack@eecs.umich.edu } 4407119Sgblack@eecs.umich.edu 4418442Sgblack@eecs.umich.edu if (reg & CR_RXD) { 4427119Sgblack@eecs.umich.edu rxEnable = false; 4437597Sminkyu.jeong@arm.com } else if (reg & CR_RXE) { 4447597Sminkyu.jeong@arm.com rxEnable = true; 4457119Sgblack@eecs.umich.edu 4467119Sgblack@eecs.umich.edu if (rxState == rxIdle) 4477119Sgblack@eecs.umich.edu rxKick(); 4487119Sgblack@eecs.umich.edu } 4497119Sgblack@eecs.umich.edu 4507119Sgblack@eecs.umich.edu if (reg & CR_TXR) 4517639Sgblack@eecs.umich.edu txReset(); 4527639Sgblack@eecs.umich.edu 4537639Sgblack@eecs.umich.edu if (reg & CR_RXR) 4547639Sgblack@eecs.umich.edu rxReset(); 4557639Sgblack@eecs.umich.edu 4567639Sgblack@eecs.umich.edu if (reg & CR_SWI) 4577639Sgblack@eecs.umich.edu devIntrPost(ISR_SWI); 4587639Sgblack@eecs.umich.edu 4598207SAli.Saidi@ARM.com if (reg & CR_RST) { 4608207SAli.Saidi@ARM.com txReset(); 4617639Sgblack@eecs.umich.edu rxReset(); 4627639Sgblack@eecs.umich.edu 4637639Sgblack@eecs.umich.edu regsReset(); 4648207SAli.Saidi@ARM.com } 4658207SAli.Saidi@ARM.com break; 4668207SAli.Saidi@ARM.com 4677639Sgblack@eecs.umich.edu case CFGR: 4687639Sgblack@eecs.umich.edu if (reg & CFGR_LNKSTS || 4697639Sgblack@eecs.umich.edu reg & CFGR_SPDSTS || 4708444Sgblack@eecs.umich.edu reg & CFGR_DUPSTS || 4717639Sgblack@eecs.umich.edu reg & CFGR_RESERVED || 4728072SGiacomo.Gabrielli@arm.com reg & CFGR_T64ADDR || 4738072SGiacomo.Gabrielli@arm.com reg & CFGR_PCI64_DET) { 4747639Sgblack@eecs.umich.edu // First clear all writable bits 4757639Sgblack@eecs.umich.edu regs.config &= CFGR_LNKSTS | CFGR_SPDSTS | CFGR_DUPSTS | 4767639Sgblack@eecs.umich.edu CFGR_RESERVED | CFGR_T64ADDR | 4777639Sgblack@eecs.umich.edu CFGR_PCI64_DET; 4787639Sgblack@eecs.umich.edu // Now set the appropriate writable bits 4797639Sgblack@eecs.umich.edu regs.config |= reg & ~(CFGR_LNKSTS | CFGR_SPDSTS | CFGR_DUPSTS | 4807119Sgblack@eecs.umich.edu CFGR_RESERVED | CFGR_T64ADDR | 4817119Sgblack@eecs.umich.edu CFGR_PCI64_DET); 4827119Sgblack@eecs.umich.edu } 4837119Sgblack@eecs.umich.edu 4847119Sgblack@eecs.umich.edu// all these #if 0's are because i don't THINK the kernel needs to 4857119Sgblack@eecs.umich.edu// have these implemented. if there is a problem relating to one of 4867119Sgblack@eecs.umich.edu// these, you may need to add functionality in. 4877119Sgblack@eecs.umich.edu 4887119Sgblack@eecs.umich.edu// grouped together and #if 0'ed to avoid empty if body and make clang happy 4897119Sgblack@eecs.umich.edu#if 0 4907119Sgblack@eecs.umich.edu if (reg & CFGR_TBI_EN) ; 4917119Sgblack@eecs.umich.edu if (reg & CFGR_MODE_1000) ; 4927119Sgblack@eecs.umich.edu 4938442Sgblack@eecs.umich.edu if (reg & CFGR_PINT_DUPSTS || 4947119Sgblack@eecs.umich.edu reg & CFGR_PINT_LNKSTS || 4957119Sgblack@eecs.umich.edu reg & CFGR_PINT_SPDSTS) 4967119Sgblack@eecs.umich.edu ; 4977119Sgblack@eecs.umich.edu 4987119Sgblack@eecs.umich.edu if (reg & CFGR_TMRTEST) ; 4997119Sgblack@eecs.umich.edu if (reg & CFGR_MRM_DIS) ; 5007119Sgblack@eecs.umich.edu if (reg & CFGR_MWI_DIS) ; 5017119Sgblack@eecs.umich.edu 5027119Sgblack@eecs.umich.edu if (reg & CFGR_DATA64_EN) ; 5037119Sgblack@eecs.umich.edu if (reg & CFGR_M64ADDR) ; 5047119Sgblack@eecs.umich.edu if (reg & CFGR_PHY_RST) ; 5057119Sgblack@eecs.umich.edu if (reg & CFGR_PHY_DIS) ; 5067119Sgblack@eecs.umich.edu 5077119Sgblack@eecs.umich.edu if (reg & CFGR_REQALG) ; 5087639Sgblack@eecs.umich.edu if (reg & CFGR_SB) ; 5097639Sgblack@eecs.umich.edu if (reg & CFGR_POW) ; 5107639Sgblack@eecs.umich.edu if (reg & CFGR_EXD) ; 5117639Sgblack@eecs.umich.edu if (reg & CFGR_PESEL) ; 5127639Sgblack@eecs.umich.edu if (reg & CFGR_BROM_DIS) ; 5137639Sgblack@eecs.umich.edu if (reg & CFGR_EXT_125) ; 5147639Sgblack@eecs.umich.edu if (reg & CFGR_BEM) ; 5157639Sgblack@eecs.umich.edu 5167639Sgblack@eecs.umich.edu if (reg & CFGR_T64ADDR) ; 5177639Sgblack@eecs.umich.edu // panic("CFGR_T64ADDR is read only register!\n"); 5187639Sgblack@eecs.umich.edu#endif 5197639Sgblack@eecs.umich.edu if (reg & CFGR_AUTO_1000) 5207639Sgblack@eecs.umich.edu panic("CFGR_AUTO_1000 not implemented!\n"); 5217639Sgblack@eecs.umich.edu 5227639Sgblack@eecs.umich.edu if (reg & CFGR_PCI64_DET) 5237639Sgblack@eecs.umich.edu panic("CFGR_PCI64_DET is read only register!\n"); 5247639Sgblack@eecs.umich.edu 5257639Sgblack@eecs.umich.edu if (reg & CFGR_EXTSTS_EN) 5267639Sgblack@eecs.umich.edu extstsEnable = true; 5277639Sgblack@eecs.umich.edu else 5287639Sgblack@eecs.umich.edu extstsEnable = false; 5297639Sgblack@eecs.umich.edu break; 5307639Sgblack@eecs.umich.edu 5317639Sgblack@eecs.umich.edu case MEAR: 5327639Sgblack@eecs.umich.edu // Clear writable bits 5337639Sgblack@eecs.umich.edu regs.mear &= MEAR_EEDO; 5347639Sgblack@eecs.umich.edu // Set appropriate writable bits 5357639Sgblack@eecs.umich.edu regs.mear |= reg & ~MEAR_EEDO; 5367639Sgblack@eecs.umich.edu 5377639Sgblack@eecs.umich.edu // FreeBSD uses the EEPROM to read PMATCH (for the MAC address) 5387120Sgblack@eecs.umich.edu // even though it could get it through RFDR 5397120Sgblack@eecs.umich.edu if (reg & MEAR_EESEL) { 5407120Sgblack@eecs.umich.edu // Rising edge of clock 5417120Sgblack@eecs.umich.edu if (reg & MEAR_EECLK && !eepromClk) 5427120Sgblack@eecs.umich.edu eepromKick(); 5437712Sgblack@eecs.umich.edu } 5447120Sgblack@eecs.umich.edu else { 5457120Sgblack@eecs.umich.edu eepromState = eepromStart; 5467120Sgblack@eecs.umich.edu regs.mear &= ~MEAR_EEDI; 5477639Sgblack@eecs.umich.edu } 5487639Sgblack@eecs.umich.edu 5497639Sgblack@eecs.umich.edu eepromClk = reg & MEAR_EECLK; 5507639Sgblack@eecs.umich.edu 5517639Sgblack@eecs.umich.edu // since phy is completely faked, MEAR_MD* don't matter 5527639Sgblack@eecs.umich.edu 5537712Sgblack@eecs.umich.edu// grouped together and #if 0'ed to avoid empty if body and make clang happy 5547639Sgblack@eecs.umich.edu#if 0 5557639Sgblack@eecs.umich.edu if (reg & MEAR_MDIO) ; 5567639Sgblack@eecs.umich.edu if (reg & MEAR_MDDIR) ; 5577303Sgblack@eecs.umich.edu if (reg & MEAR_MDC) ; 5587303Sgblack@eecs.umich.edu#endif 5597303Sgblack@eecs.umich.edu break; 5607303Sgblack@eecs.umich.edu 5617303Sgblack@eecs.umich.edu case PTSCR: 5627303Sgblack@eecs.umich.edu regs.ptscr = reg & ~(PTSCR_RBIST_RDONLY); 5637303Sgblack@eecs.umich.edu // these control BISTs for various parts of chip - we 5647303Sgblack@eecs.umich.edu // don't care or do just fake that the BIST is done 5657303Sgblack@eecs.umich.edu if (reg & PTSCR_RBIST_EN) 5667303Sgblack@eecs.umich.edu regs.ptscr |= PTSCR_RBIST_DONE; 5677303Sgblack@eecs.umich.edu if (reg & PTSCR_EEBIST_EN) 5687303Sgblack@eecs.umich.edu regs.ptscr &= ~PTSCR_EEBIST_EN; 5697303Sgblack@eecs.umich.edu if (reg & PTSCR_EELOAD_EN) 5707303Sgblack@eecs.umich.edu regs.ptscr &= ~PTSCR_EELOAD_EN; 5717303Sgblack@eecs.umich.edu break; 5727303Sgblack@eecs.umich.edu 5737303Sgblack@eecs.umich.edu case ISR: /* writing to the ISR has no effect */ 5747303Sgblack@eecs.umich.edu panic("ISR is a read only register!\n"); 5757303Sgblack@eecs.umich.edu 5767303Sgblack@eecs.umich.edu case IMR: 5777303Sgblack@eecs.umich.edu regs.imr = reg; 5787303Sgblack@eecs.umich.edu devIntrChangeMask(); 5797303Sgblack@eecs.umich.edu break; 5807303Sgblack@eecs.umich.edu 5817291Sgblack@eecs.umich.edu case IER: 5827291Sgblack@eecs.umich.edu regs.ier = reg; 5837291Sgblack@eecs.umich.edu break; 5847291Sgblack@eecs.umich.edu 5857291Sgblack@eecs.umich.edu case IHR: 5867291Sgblack@eecs.umich.edu regs.ihr = reg; 5877291Sgblack@eecs.umich.edu /* not going to implement real interrupt holdoff */ 5887291Sgblack@eecs.umich.edu break; 5897291Sgblack@eecs.umich.edu 5907291Sgblack@eecs.umich.edu case TXDP: 5917291Sgblack@eecs.umich.edu regs.txdp = (reg & 0xFFFFFFFC); 5927291Sgblack@eecs.umich.edu assert(txState == txIdle); 5937291Sgblack@eecs.umich.edu CTDD = false; 5947291Sgblack@eecs.umich.edu break; 5957291Sgblack@eecs.umich.edu 5967291Sgblack@eecs.umich.edu case TXDP_HI: 5977291Sgblack@eecs.umich.edu regs.txdp_hi = reg; 5987291Sgblack@eecs.umich.edu break; 5997291Sgblack@eecs.umich.edu 6007291Sgblack@eecs.umich.edu case TX_CFG: 6017312Sgblack@eecs.umich.edu regs.txcfg = reg; 6027312Sgblack@eecs.umich.edu#if 0 6037312Sgblack@eecs.umich.edu if (reg & TX_CFG_CSI) ; 6047312Sgblack@eecs.umich.edu if (reg & TX_CFG_HBI) ; 6057312Sgblack@eecs.umich.edu if (reg & TX_CFG_MLB) ; 6067312Sgblack@eecs.umich.edu if (reg & TX_CFG_ATP) ; 6077312Sgblack@eecs.umich.edu if (reg & TX_CFG_ECRETRY) { 6087312Sgblack@eecs.umich.edu /* 6097312Sgblack@eecs.umich.edu * this could easily be implemented, but considering 6107312Sgblack@eecs.umich.edu * the network is just a fake pipe, wouldn't make 6117312Sgblack@eecs.umich.edu * sense to do this 6127312Sgblack@eecs.umich.edu */ 6137312Sgblack@eecs.umich.edu } 6147312Sgblack@eecs.umich.edu 6157312Sgblack@eecs.umich.edu if (reg & TX_CFG_BRST_DIS) ; 6167312Sgblack@eecs.umich.edu#endif 6177312Sgblack@eecs.umich.edu 6187312Sgblack@eecs.umich.edu#if 0 6197312Sgblack@eecs.umich.edu /* we handle our own DMA, ignore the kernel's exhortations */ 6207312Sgblack@eecs.umich.edu if (reg & TX_CFG_MXDMA) ; 6217205Sgblack@eecs.umich.edu#endif 6227205Sgblack@eecs.umich.edu 6237205Sgblack@eecs.umich.edu // also, we currently don't care about fill/drain 6247205Sgblack@eecs.umich.edu // thresholds though this may change in the future with 6257205Sgblack@eecs.umich.edu // more realistic networks or a driver which changes it 6267205Sgblack@eecs.umich.edu // according to feedback 6277205Sgblack@eecs.umich.edu 6287205Sgblack@eecs.umich.edu break; 6297205Sgblack@eecs.umich.edu 6307205Sgblack@eecs.umich.edu case GPIOR: 6317205Sgblack@eecs.umich.edu // Only write writable bits 6327205Sgblack@eecs.umich.edu regs.gpior &= GPIOR_UNUSED | GPIOR_GP5_IN | GPIOR_GP4_IN 6337205Sgblack@eecs.umich.edu | GPIOR_GP3_IN | GPIOR_GP2_IN | GPIOR_GP1_IN; 6347205Sgblack@eecs.umich.edu regs.gpior |= reg & ~(GPIOR_UNUSED | GPIOR_GP5_IN | GPIOR_GP4_IN 6357205Sgblack@eecs.umich.edu | GPIOR_GP3_IN | GPIOR_GP2_IN | GPIOR_GP1_IN); 6367205Sgblack@eecs.umich.edu /* these just control general purpose i/o pins, don't matter */ 6377205Sgblack@eecs.umich.edu break; 6387205Sgblack@eecs.umich.edu 6397205Sgblack@eecs.umich.edu case RXDP: 6407205Sgblack@eecs.umich.edu regs.rxdp = reg; 6417279Sgblack@eecs.umich.edu CRDD = false; 6427279Sgblack@eecs.umich.edu break; 6437279Sgblack@eecs.umich.edu 6447279Sgblack@eecs.umich.edu case RXDP_HI: 6457279Sgblack@eecs.umich.edu regs.rxdp_hi = reg; 6467279Sgblack@eecs.umich.edu break; 6477279Sgblack@eecs.umich.edu 6487279Sgblack@eecs.umich.edu case RX_CFG: 6497279Sgblack@eecs.umich.edu regs.rxcfg = reg; 6507279Sgblack@eecs.umich.edu#if 0 6517279Sgblack@eecs.umich.edu if (reg & RX_CFG_AEP) ; 6527279Sgblack@eecs.umich.edu if (reg & RX_CFG_ARP) ; 6537279Sgblack@eecs.umich.edu if (reg & RX_CFG_STRIPCRC) ; 6547279Sgblack@eecs.umich.edu if (reg & RX_CFG_RX_RD) ; 6557279Sgblack@eecs.umich.edu if (reg & RX_CFG_ALP) ; 6567279Sgblack@eecs.umich.edu if (reg & RX_CFG_AIRL) ; 6577279Sgblack@eecs.umich.edu 6587279Sgblack@eecs.umich.edu /* we handle our own DMA, ignore what kernel says about it */ 6597279Sgblack@eecs.umich.edu if (reg & RX_CFG_MXDMA) ; 6607279Sgblack@eecs.umich.edu 6617279Sgblack@eecs.umich.edu //also, we currently don't care about fill/drain thresholds 6627303Sgblack@eecs.umich.edu //though this may change in the future with more realistic 6637303Sgblack@eecs.umich.edu //networks or a driver which changes it according to feedback 6647303Sgblack@eecs.umich.edu if (reg & (RX_CFG_DRTH | RX_CFG_DRTH0)) ; 6657303Sgblack@eecs.umich.edu#endif 6667303Sgblack@eecs.umich.edu break; 6677303Sgblack@eecs.umich.edu 6687303Sgblack@eecs.umich.edu case PQCR: 6697303Sgblack@eecs.umich.edu /* there is no priority queueing used in the linux 2.6 driver */ 6707303Sgblack@eecs.umich.edu regs.pqcr = reg; 6717303Sgblack@eecs.umich.edu break; 6727303Sgblack@eecs.umich.edu 6737303Sgblack@eecs.umich.edu case WCSR: 6747303Sgblack@eecs.umich.edu /* not going to implement wake on LAN */ 6757303Sgblack@eecs.umich.edu regs.wcsr = reg; 6767303Sgblack@eecs.umich.edu break; 6777303Sgblack@eecs.umich.edu 6787303Sgblack@eecs.umich.edu case PCR: 6797303Sgblack@eecs.umich.edu /* not going to implement pause control */ 6807303Sgblack@eecs.umich.edu regs.pcr = reg; 6817303Sgblack@eecs.umich.edu break; 6827303Sgblack@eecs.umich.edu 6837119Sgblack@eecs.umich.edu case RFCR: 6847119Sgblack@eecs.umich.edu regs.rfcr = reg; 6857119Sgblack@eecs.umich.edu 6867119Sgblack@eecs.umich.edu rxFilterEnable = (reg & RFCR_RFEN) ? true : false; 6877119Sgblack@eecs.umich.edu acceptBroadcast = (reg & RFCR_AAB) ? true : false; 6887119Sgblack@eecs.umich.edu acceptMulticast = (reg & RFCR_AAM) ? true : false; 6897119Sgblack@eecs.umich.edu acceptUnicast = (reg & RFCR_AAU) ? true : false; 6907119Sgblack@eecs.umich.edu acceptPerfect = (reg & RFCR_APM) ? true : false; 6917119Sgblack@eecs.umich.edu acceptArp = (reg & RFCR_AARP) ? true : false; 6927119Sgblack@eecs.umich.edu multicastHashEnable = (reg & RFCR_MHEN) ? true : false; 6937119Sgblack@eecs.umich.edu 6947119Sgblack@eecs.umich.edu#if 0 6957119Sgblack@eecs.umich.edu if (reg & RFCR_APAT) 6967119Sgblack@eecs.umich.edu panic("RFCR_APAT not implemented!\n"); 6977119Sgblack@eecs.umich.edu#endif 6987119Sgblack@eecs.umich.edu if (reg & RFCR_UHEN) 6997119Sgblack@eecs.umich.edu panic("Unicast hash filtering not used by drivers!\n"); 7007119Sgblack@eecs.umich.edu 7017119Sgblack@eecs.umich.edu if (reg & RFCR_ULM) 7027119Sgblack@eecs.umich.edu panic("RFCR_ULM not implemented!\n"); 7037303Sgblack@eecs.umich.edu 7047303Sgblack@eecs.umich.edu break; 7057303Sgblack@eecs.umich.edu 7067303Sgblack@eecs.umich.edu case RFDR: 7077303Sgblack@eecs.umich.edu rfaddr = (uint16_t)(regs.rfcr & RFCR_RFADDR); 7087303Sgblack@eecs.umich.edu switch (rfaddr) { 7097303Sgblack@eecs.umich.edu case 0x000: 7107303Sgblack@eecs.umich.edu rom.perfectMatch[0] = (uint8_t)reg; 7117303Sgblack@eecs.umich.edu rom.perfectMatch[1] = (uint8_t)(reg >> 8); 7127303Sgblack@eecs.umich.edu break; 7137303Sgblack@eecs.umich.edu case 0x002: 7147303Sgblack@eecs.umich.edu rom.perfectMatch[2] = (uint8_t)reg; 7157303Sgblack@eecs.umich.edu rom.perfectMatch[3] = (uint8_t)(reg >> 8); 7167303Sgblack@eecs.umich.edu break; 7177303Sgblack@eecs.umich.edu case 0x004: 7187303Sgblack@eecs.umich.edu rom.perfectMatch[4] = (uint8_t)reg; 7197303Sgblack@eecs.umich.edu rom.perfectMatch[5] = (uint8_t)(reg >> 8); 7207303Sgblack@eecs.umich.edu break; 7217303Sgblack@eecs.umich.edu default: 7227303Sgblack@eecs.umich.edu 7237303Sgblack@eecs.umich.edu if (rfaddr >= FHASH_ADDR && 7247646Sgene.wu@arm.com rfaddr < FHASH_ADDR + FHASH_SIZE) { 7257279Sgblack@eecs.umich.edu 7267279Sgblack@eecs.umich.edu // Only word-aligned writes supported 7277279Sgblack@eecs.umich.edu if (rfaddr % 2) 7287279Sgblack@eecs.umich.edu panic("unaligned write to filter hash table!"); 7297279Sgblack@eecs.umich.edu 7307279Sgblack@eecs.umich.edu rom.filterHash[rfaddr - FHASH_ADDR] = (uint8_t)reg; 7317279Sgblack@eecs.umich.edu rom.filterHash[rfaddr - FHASH_ADDR + 1] 7327279Sgblack@eecs.umich.edu = (uint8_t)(reg >> 8); 7337279Sgblack@eecs.umich.edu break; 7347279Sgblack@eecs.umich.edu } 7357279Sgblack@eecs.umich.edu panic("writing RFDR for something other than pattern matching " 7367279Sgblack@eecs.umich.edu "or hashing! %#x\n", rfaddr); 7377279Sgblack@eecs.umich.edu } 7387279Sgblack@eecs.umich.edu 7397279Sgblack@eecs.umich.edu case BRAR: 7407279Sgblack@eecs.umich.edu regs.brar = reg; 7417279Sgblack@eecs.umich.edu break; 7427279Sgblack@eecs.umich.edu 7437279Sgblack@eecs.umich.edu case BRDR: 7447279Sgblack@eecs.umich.edu panic("the driver never uses BRDR, something is wrong!\n"); 7457279Sgblack@eecs.umich.edu 7467279Sgblack@eecs.umich.edu case SRR: 7477646Sgene.wu@arm.com panic("SRR is read only register!\n"); 7487119Sgblack@eecs.umich.edu 7497119Sgblack@eecs.umich.edu case MIBC: 7507119Sgblack@eecs.umich.edu panic("the driver never uses MIBC, something is wrong!\n"); 7517119Sgblack@eecs.umich.edu 7527119Sgblack@eecs.umich.edu case VRCR: 7537119Sgblack@eecs.umich.edu regs.vrcr = reg; 7547119Sgblack@eecs.umich.edu break; 7557119Sgblack@eecs.umich.edu 7567119Sgblack@eecs.umich.edu case VTCR: 7577119Sgblack@eecs.umich.edu regs.vtcr = reg; 7587119Sgblack@eecs.umich.edu break; 7597119Sgblack@eecs.umich.edu 7607119Sgblack@eecs.umich.edu case VDR: 7617119Sgblack@eecs.umich.edu panic("the driver never uses VDR, something is wrong!\n"); 7627119Sgblack@eecs.umich.edu 7637119Sgblack@eecs.umich.edu case CCSR: 7647119Sgblack@eecs.umich.edu /* not going to implement clockrun stuff */ 7657119Sgblack@eecs.umich.edu regs.ccsr = reg; 7667119Sgblack@eecs.umich.edu break; 7677119Sgblack@eecs.umich.edu 7687119Sgblack@eecs.umich.edu case TBICR: 7697646Sgene.wu@arm.com regs.tbicr = reg; 7707646Sgene.wu@arm.com if (reg & TBICR_MR_LOOPBACK) 7717646Sgene.wu@arm.com panic("TBICR_MR_LOOPBACK never used, something wrong!\n"); 7727646Sgene.wu@arm.com 7737646Sgene.wu@arm.com if (reg & TBICR_MR_AN_ENABLE) { 7747646Sgene.wu@arm.com regs.tanlpar = regs.tanar; 7757646Sgene.wu@arm.com regs.tbisr |= (TBISR_MR_AN_COMPLETE | TBISR_MR_LINK_STATUS); 7767646Sgene.wu@arm.com } 7777646Sgene.wu@arm.com 7787646Sgene.wu@arm.com#if 0 7797646Sgene.wu@arm.com if (reg & TBICR_MR_RESTART_AN) ; 7807646Sgene.wu@arm.com#endif 7817646Sgene.wu@arm.com 7827646Sgene.wu@arm.com break; 7837646Sgene.wu@arm.com 7847646Sgene.wu@arm.com case TBISR: 7857646Sgene.wu@arm.com panic("TBISR is read only register!\n"); 7867646Sgene.wu@arm.com 7877646Sgene.wu@arm.com case TANAR: 7887646Sgene.wu@arm.com // Only write the writable bits 7897646Sgene.wu@arm.com regs.tanar &= TANAR_RF1 | TANAR_RF2 | TANAR_UNUSED; 7907646Sgene.wu@arm.com regs.tanar |= reg & ~(TANAR_RF1 | TANAR_RF2 | TANAR_UNUSED); 7917646Sgene.wu@arm.com 7927646Sgene.wu@arm.com // Pause capability unimplemented 7937646Sgene.wu@arm.com#if 0 7947646Sgene.wu@arm.com if (reg & TANAR_PS2) ; 7957646Sgene.wu@arm.com if (reg & TANAR_PS1) ; 7967646Sgene.wu@arm.com#endif 7977646Sgene.wu@arm.com 7987646Sgene.wu@arm.com break; 7997646Sgene.wu@arm.com 8007646Sgene.wu@arm.com case TANLPAR: 8017646Sgene.wu@arm.com panic("this should only be written to by the fake phy!\n"); 8027646Sgene.wu@arm.com 8037646Sgene.wu@arm.com case TANER: 8047646Sgene.wu@arm.com panic("TANER is read only register!\n"); 8057646Sgene.wu@arm.com 8067646Sgene.wu@arm.com case TESR: 8077646Sgene.wu@arm.com regs.tesr = reg; 8087646Sgene.wu@arm.com break; 8097646Sgene.wu@arm.com 8107646Sgene.wu@arm.com default: 8117646Sgene.wu@arm.com panic("invalid register access daddr=%#x", daddr); 8127646Sgene.wu@arm.com } 8137646Sgene.wu@arm.com } else { 8147646Sgene.wu@arm.com panic("Invalid Request Size"); 8157646Sgene.wu@arm.com } 8167646Sgene.wu@arm.com pkt->makeAtomicResponse(); 8177646Sgene.wu@arm.com return pioDelay; 8187646Sgene.wu@arm.com} 8197646Sgene.wu@arm.com 8207646Sgene.wu@arm.comvoid 8217646Sgene.wu@arm.comNSGigE::devIntrPost(uint32_t interrupts) 8227646Sgene.wu@arm.com{ 8237646Sgene.wu@arm.com if (interrupts & ISR_RESERVE) 8247646Sgene.wu@arm.com panic("Cannot set a reserved interrupt"); 8257646Sgene.wu@arm.com 8267646Sgene.wu@arm.com if (interrupts & ISR_NOIMPL) 8277646Sgene.wu@arm.com warn("interrupt not implemented %#x\n", interrupts); 8287646Sgene.wu@arm.com 8297646Sgene.wu@arm.com interrupts &= ISR_IMPL; 8307646Sgene.wu@arm.com regs.isr |= interrupts; 8317646Sgene.wu@arm.com 8327646Sgene.wu@arm.com if (interrupts & regs.imr) { 8337646Sgene.wu@arm.com if (interrupts & ISR_SWI) { 8347119Sgblack@eecs.umich.edu totalSwi++; 8357119Sgblack@eecs.umich.edu } 8367119Sgblack@eecs.umich.edu if (interrupts & ISR_RXIDLE) { 8377119Sgblack@eecs.umich.edu totalRxIdle++; 8387119Sgblack@eecs.umich.edu } 8397119Sgblack@eecs.umich.edu if (interrupts & ISR_RXOK) { 8407119Sgblack@eecs.umich.edu totalRxOk++; 8417119Sgblack@eecs.umich.edu } 8427291Sgblack@eecs.umich.edu if (interrupts & ISR_RXDESC) { 8437291Sgblack@eecs.umich.edu totalRxDesc++; 8448140SMatt.Horsnell@arm.com } 8458140SMatt.Horsnell@arm.com if (interrupts & ISR_TXOK) { 8468140SMatt.Horsnell@arm.com totalTxOk++; 8477291Sgblack@eecs.umich.edu } 8487291Sgblack@eecs.umich.edu if (interrupts & ISR_TXIDLE) { 8497848SAli.Saidi@ARM.com totalTxIdle++; 8507848SAli.Saidi@ARM.com } 8517848SAli.Saidi@ARM.com if (interrupts & ISR_TXDESC) { 8527848SAli.Saidi@ARM.com totalTxDesc++; 8537848SAli.Saidi@ARM.com } 8547646Sgene.wu@arm.com if (interrupts & ISR_RXORN) { 8558140SMatt.Horsnell@arm.com totalRxOrn++; 8568140SMatt.Horsnell@arm.com } 8578140SMatt.Horsnell@arm.com } 8588140SMatt.Horsnell@arm.com 8598140SMatt.Horsnell@arm.com DPRINTF(EthernetIntr, 8608140SMatt.Horsnell@arm.com "interrupt written to ISR: intr=%#x isr=%#x imr=%#x\n", 8618140SMatt.Horsnell@arm.com interrupts, regs.isr, regs.imr); 8628140SMatt.Horsnell@arm.com 8638140SMatt.Horsnell@arm.com if ((regs.isr & regs.imr)) { 8648140SMatt.Horsnell@arm.com Tick when = curTick(); 8658140SMatt.Horsnell@arm.com if ((regs.isr & regs.imr & ISR_NODELAY) == 0) 8668140SMatt.Horsnell@arm.com when += intrDelay; 8677646Sgene.wu@arm.com postedInterrupts++; 8687291Sgblack@eecs.umich.edu cpuIntrPost(when); 8697291Sgblack@eecs.umich.edu } 8707291Sgblack@eecs.umich.edu} 8717312Sgblack@eecs.umich.edu 8727312Sgblack@eecs.umich.edu/* writing this interrupt counting stats inside this means that this function 8737312Sgblack@eecs.umich.edu is now limited to being used to clear all interrupts upon the kernel 8747312Sgblack@eecs.umich.edu reading isr and servicing. just telling you in case you were thinking 8757312Sgblack@eecs.umich.edu of expanding use. 8767312Sgblack@eecs.umich.edu*/ 8777312Sgblack@eecs.umich.eduvoid 8787848SAli.Saidi@ARM.comNSGigE::devIntrClear(uint32_t interrupts) 8797848SAli.Saidi@ARM.com{ 8807848SAli.Saidi@ARM.com if (interrupts & ISR_RESERVE) 8817848SAli.Saidi@ARM.com panic("Cannot clear a reserved interrupt"); 8827848SAli.Saidi@ARM.com 8837646Sgene.wu@arm.com if (regs.isr & regs.imr & ISR_SWI) { 8847646Sgene.wu@arm.com postedSwi++; 8857646Sgene.wu@arm.com } 8867646Sgene.wu@arm.com if (regs.isr & regs.imr & ISR_RXIDLE) { 8877724SAli.Saidi@ARM.com postedRxIdle++; 8887646Sgene.wu@arm.com } 8897646Sgene.wu@arm.com if (regs.isr & regs.imr & ISR_RXOK) { 8907646Sgene.wu@arm.com postedRxOk++; 8917312Sgblack@eecs.umich.edu } 8927312Sgblack@eecs.umich.edu if (regs.isr & regs.imr & ISR_RXDESC) { 8937312Sgblack@eecs.umich.edu postedRxDesc++; 8947205Sgblack@eecs.umich.edu } 8957205Sgblack@eecs.umich.edu if (regs.isr & regs.imr & ISR_TXOK) { 8967205Sgblack@eecs.umich.edu postedTxOk++; 8977205Sgblack@eecs.umich.edu } 8987205Sgblack@eecs.umich.edu if (regs.isr & regs.imr & ISR_TXIDLE) { 8997205Sgblack@eecs.umich.edu postedTxIdle++; 9007205Sgblack@eecs.umich.edu } 9017848SAli.Saidi@ARM.com if (regs.isr & regs.imr & ISR_TXDESC) { 9027848SAli.Saidi@ARM.com postedTxDesc++; 9037848SAli.Saidi@ARM.com } 9047848SAli.Saidi@ARM.com if (regs.isr & regs.imr & ISR_RXORN) { 9057848SAli.Saidi@ARM.com postedRxOrn++; 9067205Sgblack@eecs.umich.edu } 9077205Sgblack@eecs.umich.edu 9087205Sgblack@eecs.umich.edu interrupts &= ~ISR_NOIMPL; 9097279Sgblack@eecs.umich.edu regs.isr &= ~interrupts; 9107279Sgblack@eecs.umich.edu 9117279Sgblack@eecs.umich.edu DPRINTF(EthernetIntr, 9127279Sgblack@eecs.umich.edu "interrupt cleared from ISR: intr=%x isr=%x imr=%x\n", 9137279Sgblack@eecs.umich.edu interrupts, regs.isr, regs.imr); 9147279Sgblack@eecs.umich.edu 9157279Sgblack@eecs.umich.edu if (!(regs.isr & regs.imr)) 9167279Sgblack@eecs.umich.edu cpuIntrClear(); 9177279Sgblack@eecs.umich.edu} 9187848SAli.Saidi@ARM.com 9197848SAli.Saidi@ARM.comvoid 9207848SAli.Saidi@ARM.comNSGigE::devIntrChangeMask() 9217848SAli.Saidi@ARM.com{ 9227848SAli.Saidi@ARM.com DPRINTF(EthernetIntr, "interrupt mask changed: isr=%x imr=%x masked=%x\n", 9237646Sgene.wu@arm.com regs.isr, regs.imr, regs.isr & regs.imr); 9247646Sgene.wu@arm.com 9257646Sgene.wu@arm.com if (regs.isr & regs.imr) 9267646Sgene.wu@arm.com cpuIntrPost(curTick()); 9277724SAli.Saidi@ARM.com else 9287646Sgene.wu@arm.com cpuIntrClear(); 9297646Sgene.wu@arm.com} 9307646Sgene.wu@arm.com 9317279Sgblack@eecs.umich.eduvoid 9327279Sgblack@eecs.umich.eduNSGigE::cpuIntrPost(Tick when) 9337279Sgblack@eecs.umich.edu{ 9347303Sgblack@eecs.umich.edu // If the interrupt you want to post is later than an interrupt 9357303Sgblack@eecs.umich.edu // already scheduled, just let it post in the coming one and don't 9367303Sgblack@eecs.umich.edu // schedule another. 9377303Sgblack@eecs.umich.edu // HOWEVER, must be sure that the scheduled intrTick is in the 9387303Sgblack@eecs.umich.edu // future (this was formerly the source of a bug) 9397303Sgblack@eecs.umich.edu /** 9407303Sgblack@eecs.umich.edu * @todo this warning should be removed and the intrTick code should 9417303Sgblack@eecs.umich.edu * be fixed. 9427303Sgblack@eecs.umich.edu */ 9437303Sgblack@eecs.umich.edu assert(when >= curTick()); 9447848SAli.Saidi@ARM.com assert(intrTick >= curTick() || intrTick == 0); 9457848SAli.Saidi@ARM.com if (when > intrTick && intrTick != 0) { 9467848SAli.Saidi@ARM.com DPRINTF(EthernetIntr, "don't need to schedule event...intrTick=%d\n", 9477848SAli.Saidi@ARM.com intrTick); 9487848SAli.Saidi@ARM.com return; 9497646Sgene.wu@arm.com } 9507646Sgene.wu@arm.com 9517646Sgene.wu@arm.com intrTick = when; 9527646Sgene.wu@arm.com if (intrTick < curTick()) { 9537646Sgene.wu@arm.com Debug::breakpoint(); 9547724SAli.Saidi@ARM.com intrTick = curTick(); 9557646Sgene.wu@arm.com } 9567646Sgene.wu@arm.com 9577646Sgene.wu@arm.com DPRINTF(EthernetIntr, "going to schedule an interrupt for intrTick=%d\n", 9587303Sgblack@eecs.umich.edu intrTick); 9597303Sgblack@eecs.umich.edu 9607303Sgblack@eecs.umich.edu if (intrEvent) 9617119Sgblack@eecs.umich.edu intrEvent->squash(); 9627119Sgblack@eecs.umich.edu intrEvent = new IntrEvent(this, true); 9637119Sgblack@eecs.umich.edu schedule(intrEvent, intrTick); 9647119Sgblack@eecs.umich.edu} 9657119Sgblack@eecs.umich.edu 9667119Sgblack@eecs.umich.eduvoid 9677119Sgblack@eecs.umich.eduNSGigE::cpuInterrupt() 9687848SAli.Saidi@ARM.com{ 9697848SAli.Saidi@ARM.com assert(intrTick == curTick()); 9707848SAli.Saidi@ARM.com 9717848SAli.Saidi@ARM.com // Whether or not there's a pending interrupt, we don't care about 9727848SAli.Saidi@ARM.com // it anymore 9737646Sgene.wu@arm.com intrEvent = 0; 9747646Sgene.wu@arm.com intrTick = 0; 9757646Sgene.wu@arm.com 9767646Sgene.wu@arm.com // Don't send an interrupt if there's already one 9777724SAli.Saidi@ARM.com if (cpuPendingIntr) { 9787646Sgene.wu@arm.com DPRINTF(EthernetIntr, 9797646Sgene.wu@arm.com "would send an interrupt now, but there's already pending\n"); 9807646Sgene.wu@arm.com } else { 9817119Sgblack@eecs.umich.edu // Send interrupt 9827119Sgblack@eecs.umich.edu cpuPendingIntr = true; 9837119Sgblack@eecs.umich.edu 9847303Sgblack@eecs.umich.edu DPRINTF(EthernetIntr, "posting interrupt\n"); 9857303Sgblack@eecs.umich.edu intrPost(); 9867303Sgblack@eecs.umich.edu } 9877303Sgblack@eecs.umich.edu} 9887303Sgblack@eecs.umich.edu 9897303Sgblack@eecs.umich.eduvoid 9907303Sgblack@eecs.umich.eduNSGigE::cpuIntrClear() 9917303Sgblack@eecs.umich.edu{ 9927303Sgblack@eecs.umich.edu if (!cpuPendingIntr) 9937848SAli.Saidi@ARM.com return; 9947848SAli.Saidi@ARM.com 9957848SAli.Saidi@ARM.com if (intrEvent) { 9967848SAli.Saidi@ARM.com intrEvent->squash(); 9977848SAli.Saidi@ARM.com intrEvent = 0; 9987646Sgene.wu@arm.com } 9997646Sgene.wu@arm.com 10007646Sgene.wu@arm.com intrTick = 0; 10017646Sgene.wu@arm.com 10027646Sgene.wu@arm.com cpuPendingIntr = false; 10037724SAli.Saidi@ARM.com 10047646Sgene.wu@arm.com DPRINTF(EthernetIntr, "clearing interrupt\n"); 10057646Sgene.wu@arm.com intrClear(); 10067646Sgene.wu@arm.com} 10077303Sgblack@eecs.umich.edu 10087303Sgblack@eecs.umich.edubool 10097303Sgblack@eecs.umich.eduNSGigE::cpuIntrPending() const 10107646Sgene.wu@arm.com{ return cpuPendingIntr; } 10117279Sgblack@eecs.umich.edu 10127279Sgblack@eecs.umich.eduvoid 10137279Sgblack@eecs.umich.eduNSGigE::txReset() 10147279Sgblack@eecs.umich.edu{ 10157279Sgblack@eecs.umich.edu 10167279Sgblack@eecs.umich.edu DPRINTF(Ethernet, "transmit reset\n"); 10177279Sgblack@eecs.umich.edu 10187279Sgblack@eecs.umich.edu CTDD = false; 10197279Sgblack@eecs.umich.edu txEnable = false;; 10207279Sgblack@eecs.umich.edu txFragPtr = 0; 10217848SAli.Saidi@ARM.com assert(txDescCnt == 0); 10227848SAli.Saidi@ARM.com txFifo.clear(); 10237848SAli.Saidi@ARM.com txState = txIdle; 10247848SAli.Saidi@ARM.com assert(txDmaState == dmaIdle); 10257848SAli.Saidi@ARM.com} 10267646Sgene.wu@arm.com 10277646Sgene.wu@arm.comvoid 10287646Sgene.wu@arm.comNSGigE::rxReset() 10297646Sgene.wu@arm.com{ 10307646Sgene.wu@arm.com DPRINTF(Ethernet, "receive reset\n"); 10317724SAli.Saidi@ARM.com 10327646Sgene.wu@arm.com CRDD = false; 10337646Sgene.wu@arm.com assert(rxPktBytes == 0); 10347646Sgene.wu@arm.com rxEnable = false; 10357279Sgblack@eecs.umich.edu rxFragPtr = 0; 10367279Sgblack@eecs.umich.edu assert(rxDescCnt == 0); 10377279Sgblack@eecs.umich.edu assert(rxDmaState == dmaIdle); 10387646Sgene.wu@arm.com rxFifo.clear(); 10397119Sgblack@eecs.umich.edu rxState = rxIdle; 10407119Sgblack@eecs.umich.edu} 10417119Sgblack@eecs.umich.edu 10427119Sgblack@eecs.umich.eduvoid 10437119Sgblack@eecs.umich.eduNSGigE::regsReset() 10447119Sgblack@eecs.umich.edu{ 10457119Sgblack@eecs.umich.edu memset(®s, 0, sizeof(regs)); 10467119Sgblack@eecs.umich.edu regs.config = (CFGR_LNKSTS | CFGR_TBI_EN | CFGR_MODE_1000); 10477119Sgblack@eecs.umich.edu regs.mear = 0x12; 10487848SAli.Saidi@ARM.com regs.txcfg = 0x120; // set drain threshold to 1024 bytes and 10497848SAli.Saidi@ARM.com // fill threshold to 32 bytes 10507848SAli.Saidi@ARM.com regs.rxcfg = 0x4; // set drain threshold to 16 bytes 10517848SAli.Saidi@ARM.com regs.srr = 0x0103; // set the silicon revision to rev B or 0x103 10527848SAli.Saidi@ARM.com regs.mibc = MIBC_FRZ; 10537646Sgene.wu@arm.com regs.vdr = 0x81; // set the vlan tag type to 802.1q 10547646Sgene.wu@arm.com regs.tesr = 0xc000; // TBI capable of both full and half duplex 10557646Sgene.wu@arm.com regs.brar = 0xffffffff; 10567646Sgene.wu@arm.com 10577646Sgene.wu@arm.com extstsEnable = false; 10587724SAli.Saidi@ARM.com acceptBroadcast = false; 10597646Sgene.wu@arm.com acceptMulticast = false; 10607646Sgene.wu@arm.com acceptUnicast = false; 10617646Sgene.wu@arm.com acceptPerfect = false; 10627119Sgblack@eecs.umich.edu acceptArp = false; 10637119Sgblack@eecs.umich.edu} 10647646Sgene.wu@arm.com 10657646Sgene.wu@arm.combool 10667646Sgene.wu@arm.comNSGigE::doRxDmaRead() 10677646Sgene.wu@arm.com{ 10687646Sgene.wu@arm.com assert(rxDmaState == dmaIdle || rxDmaState == dmaReadWaiting); 10697646Sgene.wu@arm.com rxDmaState = dmaReading; 10707646Sgene.wu@arm.com 10717646Sgene.wu@arm.com if (dmaPending() || drainState() != DrainState::Running) 10727646Sgene.wu@arm.com rxDmaState = dmaReadWaiting; 10737646Sgene.wu@arm.com else 10747646Sgene.wu@arm.com dmaRead(rxDmaAddr, rxDmaLen, &rxDmaReadEvent, (uint8_t*)rxDmaData); 10757646Sgene.wu@arm.com 10767848SAli.Saidi@ARM.com return true; 10777848SAli.Saidi@ARM.com} 10787848SAli.Saidi@ARM.com 10797848SAli.Saidi@ARM.comvoid 10807848SAli.Saidi@ARM.comNSGigE::rxDmaReadDone() 10817646Sgene.wu@arm.com{ 10827646Sgene.wu@arm.com assert(rxDmaState == dmaReading); 10837646Sgene.wu@arm.com rxDmaState = dmaIdle; 10847646Sgene.wu@arm.com 10857646Sgene.wu@arm.com DPRINTF(EthernetDMA, "rx dma read paddr=%#x len=%d\n", 10867646Sgene.wu@arm.com rxDmaAddr, rxDmaLen); 10877724SAli.Saidi@ARM.com DDUMP(EthernetDMA, rxDmaData, rxDmaLen); 10887646Sgene.wu@arm.com 10897646Sgene.wu@arm.com // If the transmit state machine has a pending DMA, let it go first 10907724SAli.Saidi@ARM.com if (txDmaState == dmaReadWaiting || txDmaState == dmaWriteWaiting) 10917646Sgene.wu@arm.com txKick(); 10927646Sgene.wu@arm.com 10937646Sgene.wu@arm.com rxKick(); 10947646Sgene.wu@arm.com} 10957646Sgene.wu@arm.com 10967646Sgene.wu@arm.combool 10977724SAli.Saidi@ARM.comNSGigE::doRxDmaWrite() 10987646Sgene.wu@arm.com{ 10997646Sgene.wu@arm.com assert(rxDmaState == dmaIdle || rxDmaState == dmaWriteWaiting); 11007646Sgene.wu@arm.com rxDmaState = dmaWriting; 11017646Sgene.wu@arm.com 11027646Sgene.wu@arm.com if (dmaPending() || drainState() != DrainState::Running) 11037646Sgene.wu@arm.com rxDmaState = dmaWriteWaiting; 11047646Sgene.wu@arm.com else 11057646Sgene.wu@arm.com dmaWrite(rxDmaAddr, rxDmaLen, &rxDmaWriteEvent, (uint8_t*)rxDmaData); 11067646Sgene.wu@arm.com return true; 11077646Sgene.wu@arm.com} 11087646Sgene.wu@arm.com 11097646Sgene.wu@arm.comvoid 11107646Sgene.wu@arm.comNSGigE::rxDmaWriteDone() 11117646Sgene.wu@arm.com{ 11127646Sgene.wu@arm.com assert(rxDmaState == dmaWriting); 11137646Sgene.wu@arm.com rxDmaState = dmaIdle; 11147646Sgene.wu@arm.com 11158607Sgblack@eecs.umich.edu DPRINTF(EthernetDMA, "rx dma write paddr=%#x len=%d\n", 11167848SAli.Saidi@ARM.com rxDmaAddr, rxDmaLen); 11178203SAli.Saidi@ARM.com DDUMP(EthernetDMA, rxDmaData, rxDmaLen); 11187848SAli.Saidi@ARM.com 11197848SAli.Saidi@ARM.com // If the transmit state machine has a pending DMA, let it go first 11207848SAli.Saidi@ARM.com if (txDmaState == dmaReadWaiting || txDmaState == dmaWriteWaiting) 11217848SAli.Saidi@ARM.com txKick(); 11227646Sgene.wu@arm.com 11237646Sgene.wu@arm.com rxKick(); 11247646Sgene.wu@arm.com} 11257646Sgene.wu@arm.com 11267646Sgene.wu@arm.comvoid 11277646Sgene.wu@arm.comNSGigE::rxKick() 11287646Sgene.wu@arm.com{ 11297724SAli.Saidi@ARM.com bool is64bit = (bool)(regs.config & CFGR_M64ADDR); 11307646Sgene.wu@arm.com 11317724SAli.Saidi@ARM.com DPRINTF(EthernetSM, 11327646Sgene.wu@arm.com "receive kick rxState=%s (rxBuf.size=%d) %d-bit\n", 11338203SAli.Saidi@ARM.com NsRxStateStrings[rxState], rxFifo.size(), is64bit ? 64 : 32); 11348203SAli.Saidi@ARM.com 11358203SAli.Saidi@ARM.com Addr link, bufptr; 11368203SAli.Saidi@ARM.com uint32_t &cmdsts = is64bit ? rxDesc64.cmdsts : rxDesc32.cmdsts; 11378203SAli.Saidi@ARM.com uint32_t &extsts = is64bit ? rxDesc64.extsts : rxDesc32.extsts; 11388203SAli.Saidi@ARM.com 11397646Sgene.wu@arm.com next: 11407646Sgene.wu@arm.com if (rxKickTick > curTick()) { 11417646Sgene.wu@arm.com DPRINTF(EthernetSM, "receive kick exiting, can't run till %d\n", 11427646Sgene.wu@arm.com rxKickTick); 11437724SAli.Saidi@ARM.com 11447646Sgene.wu@arm.com goto exit; 11457646Sgene.wu@arm.com } 11467724SAli.Saidi@ARM.com 11477646Sgene.wu@arm.com // Go to the next state machine clock tick. 11487646Sgene.wu@arm.com rxKickTick = clockEdge(Cycles(1)); 11497646Sgene.wu@arm.com 11507646Sgene.wu@arm.com switch(rxDmaState) { 11517646Sgene.wu@arm.com case dmaReadWaiting: 11527646Sgene.wu@arm.com if (doRxDmaRead()) 11537724SAli.Saidi@ARM.com goto exit; 11547646Sgene.wu@arm.com break; 11557646Sgene.wu@arm.com case dmaWriteWaiting: 11567646Sgene.wu@arm.com if (doRxDmaWrite()) 11577646Sgene.wu@arm.com goto exit; 11589250SAli.Saidi@ARM.com break; 11599250SAli.Saidi@ARM.com default: 11609250SAli.Saidi@ARM.com break; 11619250SAli.Saidi@ARM.com } 11629250SAli.Saidi@ARM.com 11639250SAli.Saidi@ARM.com link = is64bit ? (Addr)rxDesc64.link : (Addr)rxDesc32.link; 11649250SAli.Saidi@ARM.com bufptr = is64bit ? (Addr)rxDesc64.bufptr : (Addr)rxDesc32.bufptr; 11659250SAli.Saidi@ARM.com 11669250SAli.Saidi@ARM.com // see state machine from spec for details 11677646Sgene.wu@arm.com // the way this works is, if you finish work on one state and can 11687646Sgene.wu@arm.com // go directly to another, you do that through jumping to the 11697646Sgene.wu@arm.com // label "next". however, if you have intermediate work, like DMA 11707646Sgene.wu@arm.com // so that you can't go to the next state yet, you go to exit and 11717646Sgene.wu@arm.com // exit the loop. however, when the DMA is done it will trigger 11727646Sgene.wu@arm.com // an event and come back to this loop. 11737646Sgene.wu@arm.com switch (rxState) { 11747646Sgene.wu@arm.com case rxIdle: 11757646Sgene.wu@arm.com if (!rxEnable) { 11767646Sgene.wu@arm.com DPRINTF(EthernetSM, "Receive Disabled! Nothing to do.\n"); 11777646Sgene.wu@arm.com goto exit; 11788607Sgblack@eecs.umich.edu } 11797848SAli.Saidi@ARM.com 11808203SAli.Saidi@ARM.com if (CRDD) { 11817848SAli.Saidi@ARM.com rxState = rxDescRefr; 11827848SAli.Saidi@ARM.com 11837848SAli.Saidi@ARM.com rxDmaAddr = regs.rxdp & 0x3fffffff; 11847848SAli.Saidi@ARM.com rxDmaData = 11857646Sgene.wu@arm.com is64bit ? (void *)&rxDesc64.link : (void *)&rxDesc32.link; 11867646Sgene.wu@arm.com rxDmaLen = is64bit ? sizeof(rxDesc64.link) : sizeof(rxDesc32.link); 11877646Sgene.wu@arm.com rxDmaFree = dmaDescFree; 11887646Sgene.wu@arm.com 11897646Sgene.wu@arm.com descDmaReads++; 11907646Sgene.wu@arm.com descDmaRdBytes += rxDmaLen; 11917724SAli.Saidi@ARM.com 11927646Sgene.wu@arm.com if (doRxDmaRead()) 11937724SAli.Saidi@ARM.com goto exit; 11947646Sgene.wu@arm.com } else { 11958203SAli.Saidi@ARM.com rxState = rxDescRead; 11968203SAli.Saidi@ARM.com 11978203SAli.Saidi@ARM.com rxDmaAddr = regs.rxdp & 0x3fffffff; 11988203SAli.Saidi@ARM.com rxDmaData = is64bit ? (void *)&rxDesc64 : (void *)&rxDesc32; 11998203SAli.Saidi@ARM.com rxDmaLen = is64bit ? sizeof(rxDesc64) : sizeof(rxDesc32); 12008203SAli.Saidi@ARM.com rxDmaFree = dmaDescFree; 12018203SAli.Saidi@ARM.com 12028203SAli.Saidi@ARM.com descDmaReads++; 12037646Sgene.wu@arm.com descDmaRdBytes += rxDmaLen; 12047646Sgene.wu@arm.com 12057646Sgene.wu@arm.com if (doRxDmaRead()) 12067724SAli.Saidi@ARM.com goto exit; 12077646Sgene.wu@arm.com } 12087646Sgene.wu@arm.com break; 12097646Sgene.wu@arm.com 12109250SAli.Saidi@ARM.com case rxDescRefr: 12119250SAli.Saidi@ARM.com if (rxDmaState != dmaIdle) 12129250SAli.Saidi@ARM.com goto exit; 12139250SAli.Saidi@ARM.com 12149250SAli.Saidi@ARM.com rxState = rxAdvance; 12159250SAli.Saidi@ARM.com break; 12169250SAli.Saidi@ARM.com 12179250SAli.Saidi@ARM.com case rxDescRead: 12189250SAli.Saidi@ARM.com if (rxDmaState != dmaIdle) 12197646Sgene.wu@arm.com goto exit; 12207646Sgene.wu@arm.com 12217646Sgene.wu@arm.com DPRINTF(EthernetDesc, "rxDesc: addr=%08x read descriptor\n", 12227646Sgene.wu@arm.com regs.rxdp & 0x3fffffff); 1223 DPRINTF(EthernetDesc, 1224 "rxDesc: link=%#x bufptr=%#x cmdsts=%08x extsts=%08x\n", 1225 link, bufptr, cmdsts, extsts); 1226 1227 if (cmdsts & CMDSTS_OWN) { 1228 devIntrPost(ISR_RXIDLE); 1229 rxState = rxIdle; 1230 goto exit; 1231 } else { 1232 rxState = rxFifoBlock; 1233 rxFragPtr = bufptr; 1234 rxDescCnt = cmdsts & CMDSTS_LEN_MASK; 1235 } 1236 break; 1237 1238 case rxFifoBlock: 1239 if (!rxPacket) { 1240 /** 1241 * @todo in reality, we should be able to start processing 1242 * the packet as it arrives, and not have to wait for the 1243 * full packet ot be in the receive fifo. 1244 */ 1245 if (rxFifo.empty()) 1246 goto exit; 1247 1248 DPRINTF(EthernetSM, "****processing receive of new packet****\n"); 1249 1250 // If we don't have a packet, grab a new one from the fifo. 1251 rxPacket = rxFifo.front(); 1252 rxPktBytes = rxPacket->length; 1253 rxPacketBufPtr = rxPacket->data; 1254 1255#if TRACING_ON 1256 if (DTRACE(Ethernet)) { 1257 IpPtr ip(rxPacket); 1258 if (ip) { 1259 DPRINTF(Ethernet, "ID is %d\n", ip->id()); 1260 TcpPtr tcp(ip); 1261 if (tcp) { 1262 DPRINTF(Ethernet, 1263 "Src Port=%d, Dest Port=%d, Seq=%d, Ack=%d\n", 1264 tcp->sport(), tcp->dport(), tcp->seq(), 1265 tcp->ack()); 1266 } 1267 } 1268 } 1269#endif 1270 1271 // sanity check - i think the driver behaves like this 1272 assert(rxDescCnt >= rxPktBytes); 1273 rxFifo.pop(); 1274 } 1275 1276 1277 // dont' need the && rxDescCnt > 0 if driver sanity check 1278 // above holds 1279 if (rxPktBytes > 0) { 1280 rxState = rxFragWrite; 1281 // don't need min<>(rxPktBytes,rxDescCnt) if above sanity 1282 // check holds 1283 rxXferLen = rxPktBytes; 1284 1285 rxDmaAddr = rxFragPtr & 0x3fffffff; 1286 rxDmaData = rxPacketBufPtr; 1287 rxDmaLen = rxXferLen; 1288 rxDmaFree = dmaDataFree; 1289 1290 if (doRxDmaWrite()) 1291 goto exit; 1292 1293 } else { 1294 rxState = rxDescWrite; 1295 1296 //if (rxPktBytes == 0) { /* packet is done */ 1297 assert(rxPktBytes == 0); 1298 DPRINTF(EthernetSM, "done with receiving packet\n"); 1299 1300 cmdsts |= CMDSTS_OWN; 1301 cmdsts &= ~CMDSTS_MORE; 1302 cmdsts |= CMDSTS_OK; 1303 cmdsts &= 0xffff0000; 1304 cmdsts += rxPacket->length; //i.e. set CMDSTS_SIZE 1305 1306#if 0 1307 /* 1308 * all the driver uses these are for its own stats keeping 1309 * which we don't care about, aren't necessary for 1310 * functionality and doing this would just slow us down. 1311 * if they end up using this in a later version for 1312 * functional purposes, just undef 1313 */ 1314 if (rxFilterEnable) { 1315 cmdsts &= ~CMDSTS_DEST_MASK; 1316 const EthAddr &dst = rxFifoFront()->dst(); 1317 if (dst->unicast()) 1318 cmdsts |= CMDSTS_DEST_SELF; 1319 if (dst->multicast()) 1320 cmdsts |= CMDSTS_DEST_MULTI; 1321 if (dst->broadcast()) 1322 cmdsts |= CMDSTS_DEST_MASK; 1323 } 1324#endif 1325 1326 IpPtr ip(rxPacket); 1327 if (extstsEnable && ip) { 1328 extsts |= EXTSTS_IPPKT; 1329 rxIpChecksums++; 1330 if (cksum(ip) != 0) { 1331 DPRINTF(EthernetCksum, "Rx IP Checksum Error\n"); 1332 extsts |= EXTSTS_IPERR; 1333 } 1334 TcpPtr tcp(ip); 1335 UdpPtr udp(ip); 1336 if (tcp) { 1337 extsts |= EXTSTS_TCPPKT; 1338 rxTcpChecksums++; 1339 if (cksum(tcp) != 0) { 1340 DPRINTF(EthernetCksum, "Rx TCP Checksum Error\n"); 1341 extsts |= EXTSTS_TCPERR; 1342 1343 } 1344 } else if (udp) { 1345 extsts |= EXTSTS_UDPPKT; 1346 rxUdpChecksums++; 1347 if (cksum(udp) != 0) { 1348 DPRINTF(EthernetCksum, "Rx UDP Checksum Error\n"); 1349 extsts |= EXTSTS_UDPERR; 1350 } 1351 } 1352 } 1353 rxPacket = 0; 1354 1355 /* 1356 * the driver seems to always receive into desc buffers 1357 * of size 1514, so you never have a pkt that is split 1358 * into multiple descriptors on the receive side, so 1359 * i don't implement that case, hence the assert above. 1360 */ 1361 1362 DPRINTF(EthernetDesc, 1363 "rxDesc: addr=%08x writeback cmdsts extsts\n", 1364 regs.rxdp & 0x3fffffff); 1365 DPRINTF(EthernetDesc, 1366 "rxDesc: link=%#x bufptr=%#x cmdsts=%08x extsts=%08x\n", 1367 link, bufptr, cmdsts, extsts); 1368 1369 rxDmaAddr = regs.rxdp & 0x3fffffff; 1370 rxDmaData = &cmdsts; 1371 if (is64bit) { 1372 rxDmaAddr += offsetof(ns_desc64, cmdsts); 1373 rxDmaLen = sizeof(rxDesc64.cmdsts) + sizeof(rxDesc64.extsts); 1374 } else { 1375 rxDmaAddr += offsetof(ns_desc32, cmdsts); 1376 rxDmaLen = sizeof(rxDesc32.cmdsts) + sizeof(rxDesc32.extsts); 1377 } 1378 rxDmaFree = dmaDescFree; 1379 1380 descDmaWrites++; 1381 descDmaWrBytes += rxDmaLen; 1382 1383 if (doRxDmaWrite()) 1384 goto exit; 1385 } 1386 break; 1387 1388 case rxFragWrite: 1389 if (rxDmaState != dmaIdle) 1390 goto exit; 1391 1392 rxPacketBufPtr += rxXferLen; 1393 rxFragPtr += rxXferLen; 1394 rxPktBytes -= rxXferLen; 1395 1396 rxState = rxFifoBlock; 1397 break; 1398 1399 case rxDescWrite: 1400 if (rxDmaState != dmaIdle) 1401 goto exit; 1402 1403 assert(cmdsts & CMDSTS_OWN); 1404 1405 assert(rxPacket == 0); 1406 devIntrPost(ISR_RXOK); 1407 1408 if (cmdsts & CMDSTS_INTR) 1409 devIntrPost(ISR_RXDESC); 1410 1411 if (!rxEnable) { 1412 DPRINTF(EthernetSM, "Halting the RX state machine\n"); 1413 rxState = rxIdle; 1414 goto exit; 1415 } else 1416 rxState = rxAdvance; 1417 break; 1418 1419 case rxAdvance: 1420 if (link == 0) { 1421 devIntrPost(ISR_RXIDLE); 1422 rxState = rxIdle; 1423 CRDD = true; 1424 goto exit; 1425 } else { 1426 if (rxDmaState != dmaIdle) 1427 goto exit; 1428 rxState = rxDescRead; 1429 regs.rxdp = link; 1430 CRDD = false; 1431 1432 rxDmaAddr = regs.rxdp & 0x3fffffff; 1433 rxDmaData = is64bit ? (void *)&rxDesc64 : (void *)&rxDesc32; 1434 rxDmaLen = is64bit ? sizeof(rxDesc64) : sizeof(rxDesc32); 1435 rxDmaFree = dmaDescFree; 1436 1437 if (doRxDmaRead()) 1438 goto exit; 1439 } 1440 break; 1441 1442 default: 1443 panic("Invalid rxState!"); 1444 } 1445 1446 DPRINTF(EthernetSM, "entering next rxState=%s\n", 1447 NsRxStateStrings[rxState]); 1448 goto next; 1449 1450 exit: 1451 /** 1452 * @todo do we want to schedule a future kick? 1453 */ 1454 DPRINTF(EthernetSM, "rx state machine exited rxState=%s\n", 1455 NsRxStateStrings[rxState]); 1456 1457 if (!rxKickEvent.scheduled()) 1458 schedule(rxKickEvent, rxKickTick); 1459} 1460 1461void 1462NSGigE::transmit() 1463{ 1464 if (txFifo.empty()) { 1465 DPRINTF(Ethernet, "nothing to transmit\n"); 1466 return; 1467 } 1468 1469 DPRINTF(Ethernet, "Attempt Pkt Transmit: txFifo length=%d\n", 1470 txFifo.size()); 1471 if (interface->sendPacket(txFifo.front())) { 1472#if TRACING_ON 1473 if (DTRACE(Ethernet)) { 1474 IpPtr ip(txFifo.front()); 1475 if (ip) { 1476 DPRINTF(Ethernet, "ID is %d\n", ip->id()); 1477 TcpPtr tcp(ip); 1478 if (tcp) { 1479 DPRINTF(Ethernet, 1480 "Src Port=%d, Dest Port=%d, Seq=%d, Ack=%d\n", 1481 tcp->sport(), tcp->dport(), tcp->seq(), 1482 tcp->ack()); 1483 } 1484 } 1485 } 1486#endif 1487 1488 DDUMP(EthernetData, txFifo.front()->data, txFifo.front()->length); 1489 txBytes += txFifo.front()->length; 1490 txPackets++; 1491 1492 DPRINTF(Ethernet, "Successful Xmit! now txFifoAvail is %d\n", 1493 txFifo.avail()); 1494 txFifo.pop(); 1495 1496 /* 1497 * normally do a writeback of the descriptor here, and ONLY 1498 * after that is done, send this interrupt. but since our 1499 * stuff never actually fails, just do this interrupt here, 1500 * otherwise the code has to stray from this nice format. 1501 * besides, it's functionally the same. 1502 */ 1503 devIntrPost(ISR_TXOK); 1504 } 1505 1506 if (!txFifo.empty() && !txEvent.scheduled()) { 1507 DPRINTF(Ethernet, "reschedule transmit\n"); 1508 schedule(txEvent, curTick() + retryTime); 1509 } 1510} 1511 1512bool 1513NSGigE::doTxDmaRead() 1514{ 1515 assert(txDmaState == dmaIdle || txDmaState == dmaReadWaiting); 1516 txDmaState = dmaReading; 1517 1518 if (dmaPending() || drainState() != DrainState::Running) 1519 txDmaState = dmaReadWaiting; 1520 else 1521 dmaRead(txDmaAddr, txDmaLen, &txDmaReadEvent, (uint8_t*)txDmaData); 1522 1523 return true; 1524} 1525 1526void 1527NSGigE::txDmaReadDone() 1528{ 1529 assert(txDmaState == dmaReading); 1530 txDmaState = dmaIdle; 1531 1532 DPRINTF(EthernetDMA, "tx dma read paddr=%#x len=%d\n", 1533 txDmaAddr, txDmaLen); 1534 DDUMP(EthernetDMA, txDmaData, txDmaLen); 1535 1536 // If the receive state machine has a pending DMA, let it go first 1537 if (rxDmaState == dmaReadWaiting || rxDmaState == dmaWriteWaiting) 1538 rxKick(); 1539 1540 txKick(); 1541} 1542 1543bool 1544NSGigE::doTxDmaWrite() 1545{ 1546 assert(txDmaState == dmaIdle || txDmaState == dmaWriteWaiting); 1547 txDmaState = dmaWriting; 1548 1549 if (dmaPending() || drainState() != DrainState::Running) 1550 txDmaState = dmaWriteWaiting; 1551 else 1552 dmaWrite(txDmaAddr, txDmaLen, &txDmaWriteEvent, (uint8_t*)txDmaData); 1553 return true; 1554} 1555 1556void 1557NSGigE::txDmaWriteDone() 1558{ 1559 assert(txDmaState == dmaWriting); 1560 txDmaState = dmaIdle; 1561 1562 DPRINTF(EthernetDMA, "tx dma write paddr=%#x len=%d\n", 1563 txDmaAddr, txDmaLen); 1564 DDUMP(EthernetDMA, txDmaData, txDmaLen); 1565 1566 // If the receive state machine has a pending DMA, let it go first 1567 if (rxDmaState == dmaReadWaiting || rxDmaState == dmaWriteWaiting) 1568 rxKick(); 1569 1570 txKick(); 1571} 1572 1573void 1574NSGigE::txKick() 1575{ 1576 bool is64bit = (bool)(regs.config & CFGR_M64ADDR); 1577 1578 DPRINTF(EthernetSM, "transmit kick txState=%s %d-bit\n", 1579 NsTxStateStrings[txState], is64bit ? 64 : 32); 1580 1581 Addr link, bufptr; 1582 uint32_t &cmdsts = is64bit ? txDesc64.cmdsts : txDesc32.cmdsts; 1583 uint32_t &extsts = is64bit ? txDesc64.extsts : txDesc32.extsts; 1584 1585 next: 1586 if (txKickTick > curTick()) { 1587 DPRINTF(EthernetSM, "transmit kick exiting, can't run till %d\n", 1588 txKickTick); 1589 goto exit; 1590 } 1591 1592 // Go to the next state machine clock tick. 1593 txKickTick = clockEdge(Cycles(1)); 1594 1595 switch(txDmaState) { 1596 case dmaReadWaiting: 1597 if (doTxDmaRead()) 1598 goto exit; 1599 break; 1600 case dmaWriteWaiting: 1601 if (doTxDmaWrite()) 1602 goto exit; 1603 break; 1604 default: 1605 break; 1606 } 1607 1608 link = is64bit ? (Addr)txDesc64.link : (Addr)txDesc32.link; 1609 bufptr = is64bit ? (Addr)txDesc64.bufptr : (Addr)txDesc32.bufptr; 1610 switch (txState) { 1611 case txIdle: 1612 if (!txEnable) { 1613 DPRINTF(EthernetSM, "Transmit disabled. Nothing to do.\n"); 1614 goto exit; 1615 } 1616 1617 if (CTDD) { 1618 txState = txDescRefr; 1619 1620 txDmaAddr = regs.txdp & 0x3fffffff; 1621 txDmaData = 1622 is64bit ? (void *)&txDesc64.link : (void *)&txDesc32.link; 1623 txDmaLen = is64bit ? sizeof(txDesc64.link) : sizeof(txDesc32.link); 1624 txDmaFree = dmaDescFree; 1625 1626 descDmaReads++; 1627 descDmaRdBytes += txDmaLen; 1628 1629 if (doTxDmaRead()) 1630 goto exit; 1631 1632 } else { 1633 txState = txDescRead; 1634 1635 txDmaAddr = regs.txdp & 0x3fffffff; 1636 txDmaData = is64bit ? (void *)&txDesc64 : (void *)&txDesc32; 1637 txDmaLen = is64bit ? sizeof(txDesc64) : sizeof(txDesc32); 1638 txDmaFree = dmaDescFree; 1639 1640 descDmaReads++; 1641 descDmaRdBytes += txDmaLen; 1642 1643 if (doTxDmaRead()) 1644 goto exit; 1645 } 1646 break; 1647 1648 case txDescRefr: 1649 if (txDmaState != dmaIdle) 1650 goto exit; 1651 1652 txState = txAdvance; 1653 break; 1654 1655 case txDescRead: 1656 if (txDmaState != dmaIdle) 1657 goto exit; 1658 1659 DPRINTF(EthernetDesc, "txDesc: addr=%08x read descriptor\n", 1660 regs.txdp & 0x3fffffff); 1661 DPRINTF(EthernetDesc, 1662 "txDesc: link=%#x bufptr=%#x cmdsts=%#08x extsts=%#08x\n", 1663 link, bufptr, cmdsts, extsts); 1664 1665 if (cmdsts & CMDSTS_OWN) { 1666 txState = txFifoBlock; 1667 txFragPtr = bufptr; 1668 txDescCnt = cmdsts & CMDSTS_LEN_MASK; 1669 } else { 1670 devIntrPost(ISR_TXIDLE); 1671 txState = txIdle; 1672 goto exit; 1673 } 1674 break; 1675 1676 case txFifoBlock: 1677 if (!txPacket) { 1678 DPRINTF(EthernetSM, "****starting the tx of a new packet****\n"); 1679 txPacket = make_shared<EthPacketData>(16384); 1680 txPacketBufPtr = txPacket->data; 1681 } 1682 1683 if (txDescCnt == 0) { 1684 DPRINTF(EthernetSM, "the txDescCnt == 0, done with descriptor\n"); 1685 if (cmdsts & CMDSTS_MORE) { 1686 DPRINTF(EthernetSM, "there are more descriptors to come\n"); 1687 txState = txDescWrite; 1688 1689 cmdsts &= ~CMDSTS_OWN; 1690 1691 txDmaAddr = regs.txdp & 0x3fffffff; 1692 txDmaData = &cmdsts; 1693 if (is64bit) { 1694 txDmaAddr += offsetof(ns_desc64, cmdsts); 1695 txDmaLen = sizeof(txDesc64.cmdsts); 1696 } else { 1697 txDmaAddr += offsetof(ns_desc32, cmdsts); 1698 txDmaLen = sizeof(txDesc32.cmdsts); 1699 } 1700 txDmaFree = dmaDescFree; 1701 1702 if (doTxDmaWrite()) 1703 goto exit; 1704 1705 } else { /* this packet is totally done */ 1706 DPRINTF(EthernetSM, "This packet is done, let's wrap it up\n"); 1707 /* deal with the the packet that just finished */ 1708 if ((regs.vtcr & VTCR_PPCHK) && extstsEnable) { 1709 IpPtr ip(txPacket); 1710 if (extsts & EXTSTS_UDPPKT) { 1711 UdpPtr udp(ip); 1712 if (udp) { 1713 udp->sum(0); 1714 udp->sum(cksum(udp)); 1715 txUdpChecksums++; 1716 } else { 1717 Debug::breakpoint(); 1718 warn_once("UDPPKT set, but not UDP!\n"); 1719 } 1720 } else if (extsts & EXTSTS_TCPPKT) { 1721 TcpPtr tcp(ip); 1722 if (tcp) { 1723 tcp->sum(0); 1724 tcp->sum(cksum(tcp)); 1725 txTcpChecksums++; 1726 } else { 1727 Debug::breakpoint(); 1728 warn_once("TCPPKT set, but not UDP!\n"); 1729 } 1730 } 1731 if (extsts & EXTSTS_IPPKT) { 1732 if (ip) { 1733 ip->sum(0); 1734 ip->sum(cksum(ip)); 1735 txIpChecksums++; 1736 } else { 1737 Debug::breakpoint(); 1738 warn_once("IPPKT set, but not UDP!\n"); 1739 } 1740 } 1741 } 1742 1743 txPacket->length = txPacketBufPtr - txPacket->data; 1744 // this is just because the receive can't handle a 1745 // packet bigger want to make sure 1746 if (txPacket->length > 1514) 1747 panic("transmit packet too large, %s > 1514\n", 1748 txPacket->length); 1749 1750#ifndef NDEBUG 1751 bool success = 1752#endif 1753 txFifo.push(txPacket); 1754 assert(success); 1755 1756 /* 1757 * this following section is not tqo spec, but 1758 * functionally shouldn't be any different. normally, 1759 * the chip will wait til the transmit has occurred 1760 * before writing back the descriptor because it has 1761 * to wait to see that it was successfully transmitted 1762 * to decide whether to set CMDSTS_OK or not. 1763 * however, in the simulator since it is always 1764 * successfully transmitted, and writing it exactly to 1765 * spec would complicate the code, we just do it here 1766 */ 1767 1768 cmdsts &= ~CMDSTS_OWN; 1769 cmdsts |= CMDSTS_OK; 1770 1771 DPRINTF(EthernetDesc, 1772 "txDesc writeback: cmdsts=%08x extsts=%08x\n", 1773 cmdsts, extsts); 1774 1775 txDmaFree = dmaDescFree; 1776 txDmaAddr = regs.txdp & 0x3fffffff; 1777 txDmaData = &cmdsts; 1778 if (is64bit) { 1779 txDmaAddr += offsetof(ns_desc64, cmdsts); 1780 txDmaLen = 1781 sizeof(txDesc64.cmdsts) + sizeof(txDesc64.extsts); 1782 } else { 1783 txDmaAddr += offsetof(ns_desc32, cmdsts); 1784 txDmaLen = 1785 sizeof(txDesc32.cmdsts) + sizeof(txDesc32.extsts); 1786 } 1787 1788 descDmaWrites++; 1789 descDmaWrBytes += txDmaLen; 1790 1791 transmit(); 1792 txPacket = 0; 1793 1794 if (!txEnable) { 1795 DPRINTF(EthernetSM, "halting TX state machine\n"); 1796 txState = txIdle; 1797 goto exit; 1798 } else 1799 txState = txAdvance; 1800 1801 if (doTxDmaWrite()) 1802 goto exit; 1803 } 1804 } else { 1805 DPRINTF(EthernetSM, "this descriptor isn't done yet\n"); 1806 if (!txFifo.full()) { 1807 txState = txFragRead; 1808 1809 /* 1810 * The number of bytes transferred is either whatever 1811 * is left in the descriptor (txDescCnt), or if there 1812 * is not enough room in the fifo, just whatever room 1813 * is left in the fifo 1814 */ 1815 txXferLen = min<uint32_t>(txDescCnt, txFifo.avail()); 1816 1817 txDmaAddr = txFragPtr & 0x3fffffff; 1818 txDmaData = txPacketBufPtr; 1819 txDmaLen = txXferLen; 1820 txDmaFree = dmaDataFree; 1821 1822 if (doTxDmaRead()) 1823 goto exit; 1824 } else { 1825 txState = txFifoBlock; 1826 transmit(); 1827 1828 goto exit; 1829 } 1830 1831 } 1832 break; 1833 1834 case txFragRead: 1835 if (txDmaState != dmaIdle) 1836 goto exit; 1837 1838 txPacketBufPtr += txXferLen; 1839 txFragPtr += txXferLen; 1840 txDescCnt -= txXferLen; 1841 txFifo.reserve(txXferLen); 1842 1843 txState = txFifoBlock; 1844 break; 1845 1846 case txDescWrite: 1847 if (txDmaState != dmaIdle) 1848 goto exit; 1849 1850 if (cmdsts & CMDSTS_INTR) 1851 devIntrPost(ISR_TXDESC); 1852 1853 if (!txEnable) { 1854 DPRINTF(EthernetSM, "halting TX state machine\n"); 1855 txState = txIdle; 1856 goto exit; 1857 } else 1858 txState = txAdvance; 1859 break; 1860 1861 case txAdvance: 1862 if (link == 0) { 1863 devIntrPost(ISR_TXIDLE); 1864 txState = txIdle; 1865 goto exit; 1866 } else { 1867 if (txDmaState != dmaIdle) 1868 goto exit; 1869 txState = txDescRead; 1870 regs.txdp = link; 1871 CTDD = false; 1872 1873 txDmaAddr = link & 0x3fffffff; 1874 txDmaData = is64bit ? (void *)&txDesc64 : (void *)&txDesc32; 1875 txDmaLen = is64bit ? sizeof(txDesc64) : sizeof(txDesc32); 1876 txDmaFree = dmaDescFree; 1877 1878 if (doTxDmaRead()) 1879 goto exit; 1880 } 1881 break; 1882 1883 default: 1884 panic("invalid state"); 1885 } 1886 1887 DPRINTF(EthernetSM, "entering next txState=%s\n", 1888 NsTxStateStrings[txState]); 1889 goto next; 1890 1891 exit: 1892 /** 1893 * @todo do we want to schedule a future kick? 1894 */ 1895 DPRINTF(EthernetSM, "tx state machine exited txState=%s\n", 1896 NsTxStateStrings[txState]); 1897 1898 if (!txKickEvent.scheduled()) 1899 schedule(txKickEvent, txKickTick); 1900} 1901 1902/** 1903 * Advance the EEPROM state machine 1904 * Called on rising edge of EEPROM clock bit in MEAR 1905 */ 1906void 1907NSGigE::eepromKick() 1908{ 1909 switch (eepromState) { 1910 1911 case eepromStart: 1912 1913 // Wait for start bit 1914 if (regs.mear & MEAR_EEDI) { 1915 // Set up to get 2 opcode bits 1916 eepromState = eepromGetOpcode; 1917 eepromBitsToRx = 2; 1918 eepromOpcode = 0; 1919 } 1920 break; 1921 1922 case eepromGetOpcode: 1923 eepromOpcode <<= 1; 1924 eepromOpcode += (regs.mear & MEAR_EEDI) ? 1 : 0; 1925 --eepromBitsToRx; 1926 1927 // Done getting opcode 1928 if (eepromBitsToRx == 0) { 1929 if (eepromOpcode != EEPROM_READ) 1930 panic("only EEPROM reads are implemented!"); 1931 1932 // Set up to get address 1933 eepromState = eepromGetAddress; 1934 eepromBitsToRx = 6; 1935 eepromAddress = 0; 1936 } 1937 break; 1938 1939 case eepromGetAddress: 1940 eepromAddress <<= 1; 1941 eepromAddress += (regs.mear & MEAR_EEDI) ? 1 : 0; 1942 --eepromBitsToRx; 1943 1944 // Done getting address 1945 if (eepromBitsToRx == 0) { 1946 1947 if (eepromAddress >= EEPROM_SIZE) 1948 panic("EEPROM read access out of range!"); 1949 1950 switch (eepromAddress) { 1951 1952 case EEPROM_PMATCH2_ADDR: 1953 eepromData = rom.perfectMatch[5]; 1954 eepromData <<= 8; 1955 eepromData += rom.perfectMatch[4]; 1956 break; 1957 1958 case EEPROM_PMATCH1_ADDR: 1959 eepromData = rom.perfectMatch[3]; 1960 eepromData <<= 8; 1961 eepromData += rom.perfectMatch[2]; 1962 break; 1963 1964 case EEPROM_PMATCH0_ADDR: 1965 eepromData = rom.perfectMatch[1]; 1966 eepromData <<= 8; 1967 eepromData += rom.perfectMatch[0]; 1968 break; 1969 1970 default: 1971 panic("FreeBSD driver only uses EEPROM to read PMATCH!"); 1972 } 1973 // Set up to read data 1974 eepromState = eepromRead; 1975 eepromBitsToRx = 16; 1976 1977 // Clear data in bit 1978 regs.mear &= ~MEAR_EEDI; 1979 } 1980 break; 1981 1982 case eepromRead: 1983 // Clear Data Out bit 1984 regs.mear &= ~MEAR_EEDO; 1985 // Set bit to value of current EEPROM bit 1986 regs.mear |= (eepromData & 0x8000) ? MEAR_EEDO : 0x0; 1987 1988 eepromData <<= 1; 1989 --eepromBitsToRx; 1990 1991 // All done 1992 if (eepromBitsToRx == 0) { 1993 eepromState = eepromStart; 1994 } 1995 break; 1996 1997 default: 1998 panic("invalid EEPROM state"); 1999 } 2000 2001} 2002 2003void 2004NSGigE::transferDone() 2005{ 2006 if (txFifo.empty()) { 2007 DPRINTF(Ethernet, "transfer complete: txFifo empty...nothing to do\n"); 2008 return; 2009 } 2010 2011 DPRINTF(Ethernet, "transfer complete: data in txFifo...schedule xmit\n"); 2012 2013 reschedule(txEvent, clockEdge(Cycles(1)), true); 2014} 2015 2016bool 2017NSGigE::rxFilter(const EthPacketPtr &packet) 2018{ 2019 EthPtr eth = packet; 2020 bool drop = true; 2021 string type; 2022 2023 const EthAddr &dst = eth->dst(); 2024 if (dst.unicast()) { 2025 // If we're accepting all unicast addresses 2026 if (acceptUnicast) 2027 drop = false; 2028 2029 // If we make a perfect match 2030 if (acceptPerfect && dst == rom.perfectMatch) 2031 drop = false; 2032 2033 if (acceptArp && eth->type() == ETH_TYPE_ARP) 2034 drop = false; 2035 2036 } else if (dst.broadcast()) { 2037 // if we're accepting broadcasts 2038 if (acceptBroadcast) 2039 drop = false; 2040 2041 } else if (dst.multicast()) { 2042 // if we're accepting all multicasts 2043 if (acceptMulticast) 2044 drop = false; 2045 2046 // Multicast hashing faked - all packets accepted 2047 if (multicastHashEnable) 2048 drop = false; 2049 } 2050 2051 if (drop) { 2052 DPRINTF(Ethernet, "rxFilter drop\n"); 2053 DDUMP(EthernetData, packet->data, packet->length); 2054 } 2055 2056 return drop; 2057} 2058 2059bool 2060NSGigE::recvPacket(EthPacketPtr packet) 2061{ 2062 rxBytes += packet->length; 2063 rxPackets++; 2064 2065 DPRINTF(Ethernet, "Receiving packet from wire, rxFifoAvail=%d\n", 2066 rxFifo.avail()); 2067 2068 if (!rxEnable) { 2069 DPRINTF(Ethernet, "receive disabled...packet dropped\n"); 2070 return true; 2071 } 2072 2073 if (!rxFilterEnable) { 2074 DPRINTF(Ethernet, 2075 "receive packet filtering disabled . . . packet dropped\n"); 2076 return true; 2077 } 2078 2079 if (rxFilter(packet)) { 2080 DPRINTF(Ethernet, "packet filtered...dropped\n"); 2081 return true; 2082 } 2083 2084 if (rxFifo.avail() < packet->length) { 2085#if TRACING_ON 2086 IpPtr ip(packet); 2087 TcpPtr tcp(ip); 2088 if (ip) { 2089 DPRINTF(Ethernet, 2090 "packet won't fit in receive buffer...pkt ID %d dropped\n", 2091 ip->id()); 2092 if (tcp) { 2093 DPRINTF(Ethernet, "Seq=%d\n", tcp->seq()); 2094 } 2095 } 2096#endif 2097 droppedPackets++; 2098 devIntrPost(ISR_RXORN); 2099 return false; 2100 } 2101 2102 rxFifo.push(packet); 2103 2104 rxKick(); 2105 return true; 2106} 2107 2108 2109void 2110NSGigE::drainResume() 2111{ 2112 Drainable::drainResume(); 2113 2114 // During drain we could have left the state machines in a waiting state and 2115 // they wouldn't get out until some other event occured to kick them. 2116 // This way they'll get out immediately 2117 txKick(); 2118 rxKick(); 2119} 2120 2121 2122//===================================================================== 2123// 2124// 2125void 2126NSGigE::serialize(CheckpointOut &cp) const 2127{ 2128 // Serialize the PciDevice base class 2129 PciDevice::serialize(cp); 2130 2131 /* 2132 * Finalize any DMA events now. 2133 */ 2134 // @todo will mem system save pending dma? 2135 2136 /* 2137 * Serialize the device registers 2138 */ 2139 SERIALIZE_SCALAR(regs.command); 2140 SERIALIZE_SCALAR(regs.config); 2141 SERIALIZE_SCALAR(regs.mear); 2142 SERIALIZE_SCALAR(regs.ptscr); 2143 SERIALIZE_SCALAR(regs.isr); 2144 SERIALIZE_SCALAR(regs.imr); 2145 SERIALIZE_SCALAR(regs.ier); 2146 SERIALIZE_SCALAR(regs.ihr); 2147 SERIALIZE_SCALAR(regs.txdp); 2148 SERIALIZE_SCALAR(regs.txdp_hi); 2149 SERIALIZE_SCALAR(regs.txcfg); 2150 SERIALIZE_SCALAR(regs.gpior); 2151 SERIALIZE_SCALAR(regs.rxdp); 2152 SERIALIZE_SCALAR(regs.rxdp_hi); 2153 SERIALIZE_SCALAR(regs.rxcfg); 2154 SERIALIZE_SCALAR(regs.pqcr); 2155 SERIALIZE_SCALAR(regs.wcsr); 2156 SERIALIZE_SCALAR(regs.pcr); 2157 SERIALIZE_SCALAR(regs.rfcr); 2158 SERIALIZE_SCALAR(regs.rfdr); 2159 SERIALIZE_SCALAR(regs.brar); 2160 SERIALIZE_SCALAR(regs.brdr); 2161 SERIALIZE_SCALAR(regs.srr); 2162 SERIALIZE_SCALAR(regs.mibc); 2163 SERIALIZE_SCALAR(regs.vrcr); 2164 SERIALIZE_SCALAR(regs.vtcr); 2165 SERIALIZE_SCALAR(regs.vdr); 2166 SERIALIZE_SCALAR(regs.ccsr); 2167 SERIALIZE_SCALAR(regs.tbicr); 2168 SERIALIZE_SCALAR(regs.tbisr); 2169 SERIALIZE_SCALAR(regs.tanar); 2170 SERIALIZE_SCALAR(regs.tanlpar); 2171 SERIALIZE_SCALAR(regs.taner); 2172 SERIALIZE_SCALAR(regs.tesr); 2173 2174 SERIALIZE_ARRAY(rom.perfectMatch, ETH_ADDR_LEN); 2175 SERIALIZE_ARRAY(rom.filterHash, FHASH_SIZE); 2176 2177 SERIALIZE_SCALAR(ioEnable); 2178 2179 /* 2180 * Serialize the data Fifos 2181 */ 2182 rxFifo.serialize("rxFifo", cp); 2183 txFifo.serialize("txFifo", cp); 2184 2185 /* 2186 * Serialize the various helper variables 2187 */ 2188 bool txPacketExists = txPacket != nullptr; 2189 SERIALIZE_SCALAR(txPacketExists); 2190 if (txPacketExists) { 2191 txPacket->length = txPacketBufPtr - txPacket->data; 2192 txPacket->serialize("txPacket", cp); 2193 uint32_t txPktBufPtr = (uint32_t) (txPacketBufPtr - txPacket->data); 2194 SERIALIZE_SCALAR(txPktBufPtr); 2195 } 2196 2197 bool rxPacketExists = rxPacket != nullptr; 2198 SERIALIZE_SCALAR(rxPacketExists); 2199 if (rxPacketExists) { 2200 rxPacket->serialize("rxPacket", cp); 2201 uint32_t rxPktBufPtr = (uint32_t) (rxPacketBufPtr - rxPacket->data); 2202 SERIALIZE_SCALAR(rxPktBufPtr); 2203 } 2204 2205 SERIALIZE_SCALAR(txXferLen); 2206 SERIALIZE_SCALAR(rxXferLen); 2207 2208 /* 2209 * Serialize Cached Descriptors 2210 */ 2211 SERIALIZE_SCALAR(rxDesc64.link); 2212 SERIALIZE_SCALAR(rxDesc64.bufptr); 2213 SERIALIZE_SCALAR(rxDesc64.cmdsts); 2214 SERIALIZE_SCALAR(rxDesc64.extsts); 2215 SERIALIZE_SCALAR(txDesc64.link); 2216 SERIALIZE_SCALAR(txDesc64.bufptr); 2217 SERIALIZE_SCALAR(txDesc64.cmdsts); 2218 SERIALIZE_SCALAR(txDesc64.extsts); 2219 SERIALIZE_SCALAR(rxDesc32.link); 2220 SERIALIZE_SCALAR(rxDesc32.bufptr); 2221 SERIALIZE_SCALAR(rxDesc32.cmdsts); 2222 SERIALIZE_SCALAR(rxDesc32.extsts); 2223 SERIALIZE_SCALAR(txDesc32.link); 2224 SERIALIZE_SCALAR(txDesc32.bufptr); 2225 SERIALIZE_SCALAR(txDesc32.cmdsts); 2226 SERIALIZE_SCALAR(txDesc32.extsts); 2227 SERIALIZE_SCALAR(extstsEnable); 2228 2229 /* 2230 * Serialize tx state machine 2231 */ 2232 int txState = this->txState; 2233 SERIALIZE_SCALAR(txState); 2234 SERIALIZE_SCALAR(txEnable); 2235 SERIALIZE_SCALAR(CTDD); 2236 SERIALIZE_SCALAR(txFragPtr); 2237 SERIALIZE_SCALAR(txDescCnt); 2238 int txDmaState = this->txDmaState; 2239 SERIALIZE_SCALAR(txDmaState); 2240 SERIALIZE_SCALAR(txKickTick); 2241 2242 /* 2243 * Serialize rx state machine 2244 */ 2245 int rxState = this->rxState; 2246 SERIALIZE_SCALAR(rxState); 2247 SERIALIZE_SCALAR(rxEnable); 2248 SERIALIZE_SCALAR(CRDD); 2249 SERIALIZE_SCALAR(rxPktBytes); 2250 SERIALIZE_SCALAR(rxFragPtr); 2251 SERIALIZE_SCALAR(rxDescCnt); 2252 int rxDmaState = this->rxDmaState; 2253 SERIALIZE_SCALAR(rxDmaState); 2254 SERIALIZE_SCALAR(rxKickTick); 2255 2256 /* 2257 * Serialize EEPROM state machine 2258 */ 2259 int eepromState = this->eepromState; 2260 SERIALIZE_SCALAR(eepromState); 2261 SERIALIZE_SCALAR(eepromClk); 2262 SERIALIZE_SCALAR(eepromBitsToRx); 2263 SERIALIZE_SCALAR(eepromOpcode); 2264 SERIALIZE_SCALAR(eepromAddress); 2265 SERIALIZE_SCALAR(eepromData); 2266 2267 /* 2268 * If there's a pending transmit, store the time so we can 2269 * reschedule it later 2270 */ 2271 Tick transmitTick = txEvent.scheduled() ? txEvent.when() - curTick() : 0; 2272 SERIALIZE_SCALAR(transmitTick); 2273 2274 /* 2275 * receive address filter settings 2276 */ 2277 SERIALIZE_SCALAR(rxFilterEnable); 2278 SERIALIZE_SCALAR(acceptBroadcast); 2279 SERIALIZE_SCALAR(acceptMulticast); 2280 SERIALIZE_SCALAR(acceptUnicast); 2281 SERIALIZE_SCALAR(acceptPerfect); 2282 SERIALIZE_SCALAR(acceptArp); 2283 SERIALIZE_SCALAR(multicastHashEnable); 2284 2285 /* 2286 * Keep track of pending interrupt status. 2287 */ 2288 SERIALIZE_SCALAR(intrTick); 2289 SERIALIZE_SCALAR(cpuPendingIntr); 2290 Tick intrEventTick = 0; 2291 if (intrEvent) 2292 intrEventTick = intrEvent->when(); 2293 SERIALIZE_SCALAR(intrEventTick); 2294 2295} 2296 2297void 2298NSGigE::unserialize(CheckpointIn &cp) 2299{ 2300 // Unserialize the PciDevice base class 2301 PciDevice::unserialize(cp); 2302 2303 UNSERIALIZE_SCALAR(regs.command); 2304 UNSERIALIZE_SCALAR(regs.config); 2305 UNSERIALIZE_SCALAR(regs.mear); 2306 UNSERIALIZE_SCALAR(regs.ptscr); 2307 UNSERIALIZE_SCALAR(regs.isr); 2308 UNSERIALIZE_SCALAR(regs.imr); 2309 UNSERIALIZE_SCALAR(regs.ier); 2310 UNSERIALIZE_SCALAR(regs.ihr); 2311 UNSERIALIZE_SCALAR(regs.txdp); 2312 UNSERIALIZE_SCALAR(regs.txdp_hi); 2313 UNSERIALIZE_SCALAR(regs.txcfg); 2314 UNSERIALIZE_SCALAR(regs.gpior); 2315 UNSERIALIZE_SCALAR(regs.rxdp); 2316 UNSERIALIZE_SCALAR(regs.rxdp_hi); 2317 UNSERIALIZE_SCALAR(regs.rxcfg); 2318 UNSERIALIZE_SCALAR(regs.pqcr); 2319 UNSERIALIZE_SCALAR(regs.wcsr); 2320 UNSERIALIZE_SCALAR(regs.pcr); 2321 UNSERIALIZE_SCALAR(regs.rfcr); 2322 UNSERIALIZE_SCALAR(regs.rfdr); 2323 UNSERIALIZE_SCALAR(regs.brar); 2324 UNSERIALIZE_SCALAR(regs.brdr); 2325 UNSERIALIZE_SCALAR(regs.srr); 2326 UNSERIALIZE_SCALAR(regs.mibc); 2327 UNSERIALIZE_SCALAR(regs.vrcr); 2328 UNSERIALIZE_SCALAR(regs.vtcr); 2329 UNSERIALIZE_SCALAR(regs.vdr); 2330 UNSERIALIZE_SCALAR(regs.ccsr); 2331 UNSERIALIZE_SCALAR(regs.tbicr); 2332 UNSERIALIZE_SCALAR(regs.tbisr); 2333 UNSERIALIZE_SCALAR(regs.tanar); 2334 UNSERIALIZE_SCALAR(regs.tanlpar); 2335 UNSERIALIZE_SCALAR(regs.taner); 2336 UNSERIALIZE_SCALAR(regs.tesr); 2337 2338 UNSERIALIZE_ARRAY(rom.perfectMatch, ETH_ADDR_LEN); 2339 UNSERIALIZE_ARRAY(rom.filterHash, FHASH_SIZE); 2340 2341 UNSERIALIZE_SCALAR(ioEnable); 2342 2343 /* 2344 * unserialize the data fifos 2345 */ 2346 rxFifo.unserialize("rxFifo", cp); 2347 txFifo.unserialize("txFifo", cp); 2348 2349 /* 2350 * unserialize the various helper variables 2351 */ 2352 bool txPacketExists; 2353 UNSERIALIZE_SCALAR(txPacketExists); 2354 if (txPacketExists) { 2355 txPacket = make_shared<EthPacketData>(16384); 2356 txPacket->unserialize("txPacket", cp); 2357 uint32_t txPktBufPtr; 2358 UNSERIALIZE_SCALAR(txPktBufPtr); 2359 txPacketBufPtr = (uint8_t *) txPacket->data + txPktBufPtr; 2360 } else 2361 txPacket = 0; 2362 2363 bool rxPacketExists; 2364 UNSERIALIZE_SCALAR(rxPacketExists); 2365 rxPacket = 0; 2366 if (rxPacketExists) { 2367 rxPacket = make_shared<EthPacketData>(16384); 2368 rxPacket->unserialize("rxPacket", cp); 2369 uint32_t rxPktBufPtr; 2370 UNSERIALIZE_SCALAR(rxPktBufPtr); 2371 rxPacketBufPtr = (uint8_t *) rxPacket->data + rxPktBufPtr; 2372 } else 2373 rxPacket = 0; 2374 2375 UNSERIALIZE_SCALAR(txXferLen); 2376 UNSERIALIZE_SCALAR(rxXferLen); 2377 2378 /* 2379 * Unserialize Cached Descriptors 2380 */ 2381 UNSERIALIZE_SCALAR(rxDesc64.link); 2382 UNSERIALIZE_SCALAR(rxDesc64.bufptr); 2383 UNSERIALIZE_SCALAR(rxDesc64.cmdsts); 2384 UNSERIALIZE_SCALAR(rxDesc64.extsts); 2385 UNSERIALIZE_SCALAR(txDesc64.link); 2386 UNSERIALIZE_SCALAR(txDesc64.bufptr); 2387 UNSERIALIZE_SCALAR(txDesc64.cmdsts); 2388 UNSERIALIZE_SCALAR(txDesc64.extsts); 2389 UNSERIALIZE_SCALAR(rxDesc32.link); 2390 UNSERIALIZE_SCALAR(rxDesc32.bufptr); 2391 UNSERIALIZE_SCALAR(rxDesc32.cmdsts); 2392 UNSERIALIZE_SCALAR(rxDesc32.extsts); 2393 UNSERIALIZE_SCALAR(txDesc32.link); 2394 UNSERIALIZE_SCALAR(txDesc32.bufptr); 2395 UNSERIALIZE_SCALAR(txDesc32.cmdsts); 2396 UNSERIALIZE_SCALAR(txDesc32.extsts); 2397 UNSERIALIZE_SCALAR(extstsEnable); 2398 2399 /* 2400 * unserialize tx state machine 2401 */ 2402 int txState; 2403 UNSERIALIZE_SCALAR(txState); 2404 this->txState = (TxState) txState; 2405 UNSERIALIZE_SCALAR(txEnable); 2406 UNSERIALIZE_SCALAR(CTDD); 2407 UNSERIALIZE_SCALAR(txFragPtr); 2408 UNSERIALIZE_SCALAR(txDescCnt); 2409 int txDmaState; 2410 UNSERIALIZE_SCALAR(txDmaState); 2411 this->txDmaState = (DmaState) txDmaState; 2412 UNSERIALIZE_SCALAR(txKickTick); 2413 if (txKickTick) 2414 schedule(txKickEvent, txKickTick); 2415 2416 /* 2417 * unserialize rx state machine 2418 */ 2419 int rxState; 2420 UNSERIALIZE_SCALAR(rxState); 2421 this->rxState = (RxState) rxState; 2422 UNSERIALIZE_SCALAR(rxEnable); 2423 UNSERIALIZE_SCALAR(CRDD); 2424 UNSERIALIZE_SCALAR(rxPktBytes); 2425 UNSERIALIZE_SCALAR(rxFragPtr); 2426 UNSERIALIZE_SCALAR(rxDescCnt); 2427 int rxDmaState; 2428 UNSERIALIZE_SCALAR(rxDmaState); 2429 this->rxDmaState = (DmaState) rxDmaState; 2430 UNSERIALIZE_SCALAR(rxKickTick); 2431 if (rxKickTick) 2432 schedule(rxKickEvent, rxKickTick); 2433 2434 /* 2435 * Unserialize EEPROM state machine 2436 */ 2437 int eepromState; 2438 UNSERIALIZE_SCALAR(eepromState); 2439 this->eepromState = (EEPROMState) eepromState; 2440 UNSERIALIZE_SCALAR(eepromClk); 2441 UNSERIALIZE_SCALAR(eepromBitsToRx); 2442 UNSERIALIZE_SCALAR(eepromOpcode); 2443 UNSERIALIZE_SCALAR(eepromAddress); 2444 UNSERIALIZE_SCALAR(eepromData); 2445 2446 /* 2447 * If there's a pending transmit, reschedule it now 2448 */ 2449 Tick transmitTick; 2450 UNSERIALIZE_SCALAR(transmitTick); 2451 if (transmitTick) 2452 schedule(txEvent, curTick() + transmitTick); 2453 2454 /* 2455 * unserialize receive address filter settings 2456 */ 2457 UNSERIALIZE_SCALAR(rxFilterEnable); 2458 UNSERIALIZE_SCALAR(acceptBroadcast); 2459 UNSERIALIZE_SCALAR(acceptMulticast); 2460 UNSERIALIZE_SCALAR(acceptUnicast); 2461 UNSERIALIZE_SCALAR(acceptPerfect); 2462 UNSERIALIZE_SCALAR(acceptArp); 2463 UNSERIALIZE_SCALAR(multicastHashEnable); 2464 2465 /* 2466 * Keep track of pending interrupt status. 2467 */ 2468 UNSERIALIZE_SCALAR(intrTick); 2469 UNSERIALIZE_SCALAR(cpuPendingIntr); 2470 Tick intrEventTick; 2471 UNSERIALIZE_SCALAR(intrEventTick); 2472 if (intrEventTick) { 2473 intrEvent = new IntrEvent(this, true); 2474 schedule(intrEvent, intrEventTick); 2475 } 2476} 2477 2478NSGigE * 2479NSGigEParams::create() 2480{ 2481 return new NSGigE(this); 2482} 2483