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