ns_gige.cc revision 7823
14661Sksewell@umich.edu/* 25222Sksewell@umich.edu * Copyright (c) 2004-2005 The Regents of The University of Michigan 34661Sksewell@umich.edu * All rights reserved. 44661Sksewell@umich.edu * 54661Sksewell@umich.edu * Redistribution and use in source and binary forms, with or without 64661Sksewell@umich.edu * modification, are permitted provided that the following conditions are 74661Sksewell@umich.edu * met: redistributions of source code must retain the above copyright 84661Sksewell@umich.edu * notice, this list of conditions and the following disclaimer; 94661Sksewell@umich.edu * redistributions in binary form must reproduce the above copyright 104661Sksewell@umich.edu * notice, this list of conditions and the following disclaimer in the 114661Sksewell@umich.edu * documentation and/or other materials provided with the distribution; 124661Sksewell@umich.edu * neither the name of the copyright holders nor the names of its 134661Sksewell@umich.edu * contributors may be used to endorse or promote products derived from 144661Sksewell@umich.edu * this software without specific prior written permission. 154661Sksewell@umich.edu * 164661Sksewell@umich.edu * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 174661Sksewell@umich.edu * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 184661Sksewell@umich.edu * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR 194661Sksewell@umich.edu * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT 204661Sksewell@umich.edu * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 214661Sksewell@umich.edu * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT 224661Sksewell@umich.edu * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 234661Sksewell@umich.edu * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 244661Sksewell@umich.edu * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 254661Sksewell@umich.edu * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 264661Sksewell@umich.edu * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 274661Sksewell@umich.edu * 284661Sksewell@umich.edu * Authors: Nathan Binkert 294661Sksewell@umich.edu * Lisa Hsu 304661Sksewell@umich.edu */ 314661Sksewell@umich.edu 324661Sksewell@umich.edu/** @file 334661Sksewell@umich.edu * Device module for modelling the National Semiconductor 344661Sksewell@umich.edu * DP83820 ethernet controller. Does not support priority queueing 354661Sksewell@umich.edu */ 364661Sksewell@umich.edu#include <deque> 374661Sksewell@umich.edu#include <string> 384661Sksewell@umich.edu 394661Sksewell@umich.edu#include "base/debug.hh" 404661Sksewell@umich.edu#include "base/inet.hh" 414661Sksewell@umich.edu#include "base/types.hh" 424661Sksewell@umich.edu#include "config/the_isa.hh" 434661Sksewell@umich.edu#include "cpu/thread_context.hh" 444661Sksewell@umich.edu#include "dev/etherlink.hh" 454661Sksewell@umich.edu#include "dev/ns_gige.hh" 464661Sksewell@umich.edu#include "dev/pciconfigall.hh" 474661Sksewell@umich.edu#include "mem/packet.hh" 484661Sksewell@umich.edu#include "mem/packet_access.hh" 494661Sksewell@umich.edu#include "params/NSGigE.hh" 504661Sksewell@umich.edu#include "sim/system.hh" 514661Sksewell@umich.edu 524661Sksewell@umich.educonst char *NsRxStateStrings[] = 534661Sksewell@umich.edu{ 544661Sksewell@umich.edu "rxIdle", 554661Sksewell@umich.edu "rxDescRefr", 564661Sksewell@umich.edu "rxDescRead", 574661Sksewell@umich.edu "rxFifoBlock", 584661Sksewell@umich.edu "rxFragWrite", 594661Sksewell@umich.edu "rxDescWrite", 604661Sksewell@umich.edu "rxAdvance" 614661Sksewell@umich.edu}; 624661Sksewell@umich.edu 634661Sksewell@umich.educonst char *NsTxStateStrings[] = 644661Sksewell@umich.edu{ 654661Sksewell@umich.edu "txIdle", 665222Sksewell@umich.edu "txDescRefr", 675222Sksewell@umich.edu "txDescRead", 685222Sksewell@umich.edu "txFifoBlock", 695222Sksewell@umich.edu "txFragRead", 705222Sksewell@umich.edu "txDescWrite", 715222Sksewell@umich.edu "txAdvance" 724661Sksewell@umich.edu}; 734661Sksewell@umich.edu 744661Sksewell@umich.educonst char *NsDmaState[] = 754661Sksewell@umich.edu{ 764661Sksewell@umich.edu "dmaIdle", 774661Sksewell@umich.edu "dmaReading", 785222Sksewell@umich.edu "dmaWriting", 795222Sksewell@umich.edu "dmaReadWaiting", 805222Sksewell@umich.edu "dmaWriteWaiting" 815222Sksewell@umich.edu}; 825222Sksewell@umich.edu 835222Sksewell@umich.eduusing namespace std; 844661Sksewell@umich.eduusing namespace Net; 854661Sksewell@umich.eduusing namespace TheISA; 864661Sksewell@umich.edu 874661Sksewell@umich.edu/////////////////////////////////////////////////////////////////////// 884661Sksewell@umich.edu// 894661Sksewell@umich.edu// NSGigE PCI Device 904661Sksewell@umich.edu// 914661Sksewell@umich.eduNSGigE::NSGigE(Params *p) 924661Sksewell@umich.edu : EtherDevice(p), ioEnable(false), 934661Sksewell@umich.edu txFifo(p->tx_fifo_size), rxFifo(p->rx_fifo_size), 944661Sksewell@umich.edu txPacket(0), rxPacket(0), txPacketBufPtr(NULL), rxPacketBufPtr(NULL), 954661Sksewell@umich.edu txXferLen(0), rxXferLen(0), rxDmaFree(false), txDmaFree(false), 964661Sksewell@umich.edu clock(p->clock), 974661Sksewell@umich.edu txState(txIdle), txEnable(false), CTDD(false), txHalt(false), 984661Sksewell@umich.edu txFragPtr(0), txDescCnt(0), txDmaState(dmaIdle), rxState(rxIdle), 994661Sksewell@umich.edu rxEnable(false), CRDD(false), rxPktBytes(0), rxHalt(false), 1004661Sksewell@umich.edu rxFragPtr(0), rxDescCnt(0), rxDmaState(dmaIdle), extstsEnable(false), 1014661Sksewell@umich.edu eepromState(eepromStart), eepromClk(false), eepromBitsToRx(0), 1024661Sksewell@umich.edu eepromOpcode(0), eepromAddress(0), eepromData(0), 1034661Sksewell@umich.edu dmaReadDelay(p->dma_read_delay), dmaWriteDelay(p->dma_write_delay), 1044661Sksewell@umich.edu dmaReadFactor(p->dma_read_factor), dmaWriteFactor(p->dma_write_factor), 1054661Sksewell@umich.edu rxDmaData(NULL), rxDmaAddr(0), rxDmaLen(0), 1064661Sksewell@umich.edu txDmaData(NULL), txDmaAddr(0), txDmaLen(0), 1074661Sksewell@umich.edu rxDmaReadEvent(this), rxDmaWriteEvent(this), 1084661Sksewell@umich.edu txDmaReadEvent(this), txDmaWriteEvent(this), 1094661Sksewell@umich.edu dmaDescFree(p->dma_desc_free), dmaDataFree(p->dma_data_free), 1104661Sksewell@umich.edu txDelay(p->tx_delay), rxDelay(p->rx_delay), 1114661Sksewell@umich.edu rxKickTick(0), rxKickEvent(this), txKickTick(0), txKickEvent(this), 1124661Sksewell@umich.edu txEvent(this), rxFilterEnable(p->rx_filter), 1135222Sksewell@umich.edu acceptBroadcast(false), acceptMulticast(false), acceptUnicast(false), 1145222Sksewell@umich.edu acceptPerfect(false), acceptArp(false), multicastHashEnable(false), 1154661Sksewell@umich.edu intrDelay(p->intr_delay), intrTick(0), cpuPendingIntr(false), 1164661Sksewell@umich.edu intrEvent(0), interface(0) 1174661Sksewell@umich.edu{ 1184661Sksewell@umich.edu 1194661Sksewell@umich.edu 1204661Sksewell@umich.edu interface = new NSGigEInt(name() + ".int0", this); 1214661Sksewell@umich.edu 1224661Sksewell@umich.edu regsReset(); 1234661Sksewell@umich.edu memcpy(&rom.perfectMatch, p->hardware_address.bytes(), ETH_ADDR_LEN); 1244661Sksewell@umich.edu 1254661Sksewell@umich.edu memset(&rxDesc32, 0, sizeof(rxDesc32)); 1264661Sksewell@umich.edu memset(&txDesc32, 0, sizeof(txDesc32)); 1274661Sksewell@umich.edu memset(&rxDesc64, 0, sizeof(rxDesc64)); 1284661Sksewell@umich.edu memset(&txDesc64, 0, sizeof(txDesc64)); 1294661Sksewell@umich.edu} 1304661Sksewell@umich.edu 1314661Sksewell@umich.eduNSGigE::~NSGigE() 1324661Sksewell@umich.edu{} 1334661Sksewell@umich.edu 1344661Sksewell@umich.edu/** 1354661Sksewell@umich.edu * This is to write to the PCI general configuration registers 1364661Sksewell@umich.edu */ 1374661Sksewell@umich.eduTick 1384661Sksewell@umich.eduNSGigE::writeConfig(PacketPtr pkt) 1394661Sksewell@umich.edu{ 1404661Sksewell@umich.edu int offset = pkt->getAddr() & PCI_CONFIG_SIZE; 1415222Sksewell@umich.edu if (offset < PCI_DEVICE_SPECIFIC) 1425222Sksewell@umich.edu PciDev::writeConfig(pkt); 1435222Sksewell@umich.edu else 1445222Sksewell@umich.edu panic("Device specific PCI config space not implemented!\n"); 1455222Sksewell@umich.edu 1465222Sksewell@umich.edu switch (offset) { 1474661Sksewell@umich.edu // seems to work fine without all these PCI settings, but i 1484661Sksewell@umich.edu // put in the IO to double check, an assertion will fail if we 1494661Sksewell@umich.edu // need to properly implement it 1504661Sksewell@umich.edu case PCI_COMMAND: 1514661Sksewell@umich.edu if (config.data[offset] & PCI_CMD_IOSE) 1524661Sksewell@umich.edu ioEnable = true; 1534661Sksewell@umich.edu else 1544661Sksewell@umich.edu ioEnable = false; 1554661Sksewell@umich.edu break; 1565222Sksewell@umich.edu } 1574661Sksewell@umich.edu 1584661Sksewell@umich.edu return configDelay; 1594661Sksewell@umich.edu} 1604661Sksewell@umich.edu 1614661Sksewell@umich.eduEtherInt* 1624661Sksewell@umich.eduNSGigE::getEthPort(const std::string &if_name, int idx) 1634661Sksewell@umich.edu{ 1644661Sksewell@umich.edu if (if_name == "interface") { 1654661Sksewell@umich.edu if (interface->getPeer()) 1664661Sksewell@umich.edu panic("interface already connected to\n"); 1674661Sksewell@umich.edu return interface; 1684661Sksewell@umich.edu } 1694661Sksewell@umich.edu return NULL; 1704661Sksewell@umich.edu} 1714661Sksewell@umich.edu 1724661Sksewell@umich.edu/** 1734661Sksewell@umich.edu * This reads the device registers, which are detailed in the NS83820 1744661Sksewell@umich.edu * spec sheet 1754661Sksewell@umich.edu */ 1764661Sksewell@umich.eduTick 1774661Sksewell@umich.eduNSGigE::read(PacketPtr pkt) 1784661Sksewell@umich.edu{ 1794661Sksewell@umich.edu assert(ioEnable); 1804661Sksewell@umich.edu 1814661Sksewell@umich.edu pkt->allocate(); 1824661Sksewell@umich.edu 1834661Sksewell@umich.edu //The mask is to give you only the offset into the device register file 1845222Sksewell@umich.edu Addr daddr = pkt->getAddr() & 0xfff; 1855222Sksewell@umich.edu DPRINTF(EthernetPIO, "read da=%#x pa=%#x size=%d\n", 1864661Sksewell@umich.edu daddr, pkt->getAddr(), pkt->getSize()); 1874661Sksewell@umich.edu 1884661Sksewell@umich.edu 1894661Sksewell@umich.edu // there are some reserved registers, you can see ns_gige_reg.h and 1904661Sksewell@umich.edu // the spec sheet for details 1914661Sksewell@umich.edu if (daddr > LAST && daddr <= RESERVED) { 1924661Sksewell@umich.edu panic("Accessing reserved register"); 1934661Sksewell@umich.edu } else if (daddr > RESERVED && daddr <= 0x3FC) { 1944661Sksewell@umich.edu return readConfig(pkt); 1954661Sksewell@umich.edu } else if (daddr >= MIB_START && daddr <= MIB_END) { 1964661Sksewell@umich.edu // don't implement all the MIB's. hopefully the kernel 1974661Sksewell@umich.edu // doesn't actually DEPEND upon their values 1984661Sksewell@umich.edu // MIB are just hardware stats keepers 1994661Sksewell@umich.edu pkt->set<uint32_t>(0); 2004661Sksewell@umich.edu pkt->makeAtomicResponse(); 2014661Sksewell@umich.edu return pioDelay; 2024661Sksewell@umich.edu } else if (daddr > 0x3FC) 2034661Sksewell@umich.edu panic("Something is messed up!\n"); 2044661Sksewell@umich.edu 2054661Sksewell@umich.edu assert(pkt->getSize() == sizeof(uint32_t)); 2064661Sksewell@umich.edu uint32_t ® = *pkt->getPtr<uint32_t>(); 2074661Sksewell@umich.edu uint16_t rfaddr; 2084661Sksewell@umich.edu 2094661Sksewell@umich.edu switch (daddr) { 2104661Sksewell@umich.edu case CR: 2114661Sksewell@umich.edu reg = regs.command; 2124661Sksewell@umich.edu //these are supposed to be cleared on a read 2134661Sksewell@umich.edu reg &= ~(CR_RXD | CR_TXD | CR_TXR | CR_RXR); 2144661Sksewell@umich.edu break; 2154661Sksewell@umich.edu 2164661Sksewell@umich.edu case CFGR: 2174661Sksewell@umich.edu reg = regs.config; 2184661Sksewell@umich.edu break; 2194661Sksewell@umich.edu 2204661Sksewell@umich.edu case MEAR: 2214661Sksewell@umich.edu reg = regs.mear; 2224661Sksewell@umich.edu break; 2234661Sksewell@umich.edu 2244661Sksewell@umich.edu case PTSCR: 2254661Sksewell@umich.edu reg = regs.ptscr; 2264661Sksewell@umich.edu break; 2274661Sksewell@umich.edu 2284661Sksewell@umich.edu case ISR: 2294661Sksewell@umich.edu reg = regs.isr; 2304661Sksewell@umich.edu devIntrClear(ISR_ALL); 2314661Sksewell@umich.edu break; 2324661Sksewell@umich.edu 2334661Sksewell@umich.edu case IMR: 2344661Sksewell@umich.edu reg = regs.imr; 2354661Sksewell@umich.edu break; 2364661Sksewell@umich.edu 2374661Sksewell@umich.edu case IER: 2384661Sksewell@umich.edu reg = regs.ier; 2394661Sksewell@umich.edu break; 2404661Sksewell@umich.edu 2414661Sksewell@umich.edu case IHR: 2424661Sksewell@umich.edu reg = regs.ihr; 2435222Sksewell@umich.edu break; 2445222Sksewell@umich.edu 2455222Sksewell@umich.edu case TXDP: 2465222Sksewell@umich.edu reg = regs.txdp; 2474661Sksewell@umich.edu break; 2484661Sksewell@umich.edu 2494661Sksewell@umich.edu case TXDP_HI: 2504661Sksewell@umich.edu reg = regs.txdp_hi; 2514661Sksewell@umich.edu break; 2524661Sksewell@umich.edu 2534661Sksewell@umich.edu case TX_CFG: 2544661Sksewell@umich.edu reg = regs.txcfg; 2554661Sksewell@umich.edu break; 2564661Sksewell@umich.edu 2574661Sksewell@umich.edu case GPIOR: 2584661Sksewell@umich.edu reg = regs.gpior; 2594661Sksewell@umich.edu break; 2604661Sksewell@umich.edu 2614661Sksewell@umich.edu case RXDP: 2624661Sksewell@umich.edu reg = regs.rxdp; 2634661Sksewell@umich.edu break; 2644661Sksewell@umich.edu 2654661Sksewell@umich.edu case RXDP_HI: 2664661Sksewell@umich.edu reg = regs.rxdp_hi; 2674661Sksewell@umich.edu break; 2684661Sksewell@umich.edu 2694661Sksewell@umich.edu case RX_CFG: 2704661Sksewell@umich.edu reg = regs.rxcfg; 2714661Sksewell@umich.edu break; 2724661Sksewell@umich.edu 2734661Sksewell@umich.edu case PQCR: 2744661Sksewell@umich.edu reg = regs.pqcr; 2754661Sksewell@umich.edu break; 2764661Sksewell@umich.edu 2774661Sksewell@umich.edu case WCSR: 2784661Sksewell@umich.edu reg = regs.wcsr; 2794661Sksewell@umich.edu break; 2804661Sksewell@umich.edu 2814661Sksewell@umich.edu case PCR: 2824661Sksewell@umich.edu reg = regs.pcr; 2834661Sksewell@umich.edu break; 2844661Sksewell@umich.edu 2854661Sksewell@umich.edu // see the spec sheet for how RFCR and RFDR work 2864661Sksewell@umich.edu // basically, you write to RFCR to tell the machine 2874661Sksewell@umich.edu // what you want to do next, then you act upon RFDR, 2884661Sksewell@umich.edu // and the device will be prepared b/c of what you 2894661Sksewell@umich.edu // wrote to RFCR 2904661Sksewell@umich.edu case RFCR: 2914661Sksewell@umich.edu reg = regs.rfcr; 2924661Sksewell@umich.edu break; 2934661Sksewell@umich.edu 2944661Sksewell@umich.edu case RFDR: 2954661Sksewell@umich.edu rfaddr = (uint16_t)(regs.rfcr & RFCR_RFADDR); 2964661Sksewell@umich.edu switch (rfaddr) { 2974661Sksewell@umich.edu // Read from perfect match ROM octets 2984661Sksewell@umich.edu case 0x000: 2994661Sksewell@umich.edu reg = rom.perfectMatch[1]; 3004661Sksewell@umich.edu reg = reg << 8; 3014661Sksewell@umich.edu reg += rom.perfectMatch[0]; 3025222Sksewell@umich.edu break; 3035222Sksewell@umich.edu case 0x002: 3044661Sksewell@umich.edu reg = rom.perfectMatch[3] << 8; 3054661Sksewell@umich.edu reg += rom.perfectMatch[2]; 3064661Sksewell@umich.edu break; 3074661Sksewell@umich.edu case 0x004: 3084661Sksewell@umich.edu reg = rom.perfectMatch[5] << 8; 3094661Sksewell@umich.edu reg += rom.perfectMatch[4]; 3105222Sksewell@umich.edu break; 3115222Sksewell@umich.edu default: 3124661Sksewell@umich.edu // Read filter hash table 3134661Sksewell@umich.edu if (rfaddr >= FHASH_ADDR && 3144661Sksewell@umich.edu rfaddr < FHASH_ADDR + FHASH_SIZE) { 3154661Sksewell@umich.edu 3164661Sksewell@umich.edu // Only word-aligned reads supported 3174661Sksewell@umich.edu if (rfaddr % 2) 3184661Sksewell@umich.edu panic("unaligned read from filter hash table!"); 3194661Sksewell@umich.edu 3204661Sksewell@umich.edu reg = rom.filterHash[rfaddr - FHASH_ADDR + 1] << 8; 3214661Sksewell@umich.edu reg += rom.filterHash[rfaddr - FHASH_ADDR]; 3224661Sksewell@umich.edu break; 3234661Sksewell@umich.edu } 3244661Sksewell@umich.edu 3254661Sksewell@umich.edu panic("reading RFDR for something other than pattern" 3264661Sksewell@umich.edu " matching or hashing! %#x\n", rfaddr); 3274661Sksewell@umich.edu } 3284661Sksewell@umich.edu break; 3294661Sksewell@umich.edu 3304661Sksewell@umich.edu case SRR: 3315222Sksewell@umich.edu reg = regs.srr; 3325222Sksewell@umich.edu break; 3335222Sksewell@umich.edu 3345222Sksewell@umich.edu case MIBC: 3355222Sksewell@umich.edu reg = regs.mibc; 3365222Sksewell@umich.edu reg &= ~(MIBC_MIBS | MIBC_ACLR); 3375222Sksewell@umich.edu break; 3385222Sksewell@umich.edu 3395222Sksewell@umich.edu case VRCR: 3405222Sksewell@umich.edu reg = regs.vrcr; 3415222Sksewell@umich.edu break; 3425222Sksewell@umich.edu 3435222Sksewell@umich.edu case VTCR: 3445222Sksewell@umich.edu reg = regs.vtcr; 3454661Sksewell@umich.edu break; 3464661Sksewell@umich.edu 3474661Sksewell@umich.edu case VDR: 3484661Sksewell@umich.edu reg = regs.vdr; 3494661Sksewell@umich.edu break; 3504661Sksewell@umich.edu 3514661Sksewell@umich.edu case CCSR: 3524661Sksewell@umich.edu reg = regs.ccsr; 3534661Sksewell@umich.edu break; 3544661Sksewell@umich.edu 3554661Sksewell@umich.edu case TBICR: 3564661Sksewell@umich.edu reg = regs.tbicr; 3574661Sksewell@umich.edu break; 3584661Sksewell@umich.edu 3594661Sksewell@umich.edu case TBISR: 3604661Sksewell@umich.edu reg = regs.tbisr; 3614661Sksewell@umich.edu break; 3624661Sksewell@umich.edu 3634661Sksewell@umich.edu case TANAR: 3644661Sksewell@umich.edu reg = regs.tanar; 3654661Sksewell@umich.edu break; 3664661Sksewell@umich.edu 3674661Sksewell@umich.edu case TANLPAR: 3685222Sksewell@umich.edu reg = regs.tanlpar; 3695222Sksewell@umich.edu break; 3705222Sksewell@umich.edu 3715222Sksewell@umich.edu case TANER: 3725222Sksewell@umich.edu reg = regs.taner; 3735222Sksewell@umich.edu break; 3745222Sksewell@umich.edu 3755222Sksewell@umich.edu case TESR: 3764661Sksewell@umich.edu reg = regs.tesr; 3775222Sksewell@umich.edu break; 3785222Sksewell@umich.edu 3795222Sksewell@umich.edu case M5REG: 3805222Sksewell@umich.edu reg = 0; 3815222Sksewell@umich.edu if (params()->rx_thread) 3825222Sksewell@umich.edu reg |= M5REG_RX_THREAD; 3835222Sksewell@umich.edu if (params()->tx_thread) 3845222Sksewell@umich.edu reg |= M5REG_TX_THREAD; 3854661Sksewell@umich.edu if (params()->rss) 3864661Sksewell@umich.edu reg |= M5REG_RSS; 3874661Sksewell@umich.edu break; 3884661Sksewell@umich.edu 3894661Sksewell@umich.edu default: 3904661Sksewell@umich.edu panic("reading unimplemented register: addr=%#x", daddr); 3914661Sksewell@umich.edu } 3924661Sksewell@umich.edu 3934661Sksewell@umich.edu DPRINTF(EthernetPIO, "read from %#x: data=%d data=%#x\n", 3944661Sksewell@umich.edu daddr, reg, reg); 3954661Sksewell@umich.edu 3964661Sksewell@umich.edu pkt->makeAtomicResponse(); 3974661Sksewell@umich.edu return pioDelay; 3984661Sksewell@umich.edu} 3994661Sksewell@umich.edu 4004661Sksewell@umich.eduTick 4014661Sksewell@umich.eduNSGigE::write(PacketPtr pkt) 4024661Sksewell@umich.edu{ 4034661Sksewell@umich.edu assert(ioEnable); 4044661Sksewell@umich.edu 4054661Sksewell@umich.edu Addr daddr = pkt->getAddr() & 0xfff; 4064661Sksewell@umich.edu DPRINTF(EthernetPIO, "write da=%#x pa=%#x size=%d\n", 4074661Sksewell@umich.edu daddr, pkt->getAddr(), pkt->getSize()); 4084661Sksewell@umich.edu 4094661Sksewell@umich.edu if (daddr > LAST && daddr <= RESERVED) { 4104661Sksewell@umich.edu panic("Accessing reserved register"); 4114661Sksewell@umich.edu } else if (daddr > RESERVED && daddr <= 0x3FC) { 4124661Sksewell@umich.edu return writeConfig(pkt); 4134661Sksewell@umich.edu } else if (daddr > 0x3FC) 4144661Sksewell@umich.edu panic("Something is messed up!\n"); 4154661Sksewell@umich.edu 4164661Sksewell@umich.edu if (pkt->getSize() == sizeof(uint32_t)) { 4174661Sksewell@umich.edu uint32_t reg = pkt->get<uint32_t>(); 4184661Sksewell@umich.edu uint16_t rfaddr; 4194661Sksewell@umich.edu 4204661Sksewell@umich.edu DPRINTF(EthernetPIO, "write data=%d data=%#x\n", reg, reg); 4214661Sksewell@umich.edu 4224661Sksewell@umich.edu switch (daddr) { 4234661Sksewell@umich.edu case CR: 4244661Sksewell@umich.edu regs.command = reg; 4254661Sksewell@umich.edu if (reg & CR_TXD) { 4264661Sksewell@umich.edu txEnable = false; 4274661Sksewell@umich.edu } else if (reg & CR_TXE) { 4284661Sksewell@umich.edu txEnable = true; 4294661Sksewell@umich.edu 4304661Sksewell@umich.edu // the kernel is enabling the transmit machine 4314661Sksewell@umich.edu if (txState == txIdle) 4324661Sksewell@umich.edu txKick(); 4334661Sksewell@umich.edu } 4344661Sksewell@umich.edu 4354661Sksewell@umich.edu if (reg & CR_RXD) { 4364661Sksewell@umich.edu rxEnable = false; 4374661Sksewell@umich.edu } else if (reg & CR_RXE) { 4384661Sksewell@umich.edu rxEnable = true; 4394661Sksewell@umich.edu 4404661Sksewell@umich.edu if (rxState == rxIdle) 4414661Sksewell@umich.edu rxKick(); 4424661Sksewell@umich.edu } 4434661Sksewell@umich.edu 4444661Sksewell@umich.edu if (reg & CR_TXR) 4454661Sksewell@umich.edu txReset(); 4464661Sksewell@umich.edu 4474661Sksewell@umich.edu if (reg & CR_RXR) 4484661Sksewell@umich.edu rxReset(); 4494661Sksewell@umich.edu 4504661Sksewell@umich.edu if (reg & CR_SWI) 4514661Sksewell@umich.edu devIntrPost(ISR_SWI); 4524661Sksewell@umich.edu 4534661Sksewell@umich.edu if (reg & CR_RST) { 4544661Sksewell@umich.edu txReset(); 4554661Sksewell@umich.edu rxReset(); 4564661Sksewell@umich.edu 4574661Sksewell@umich.edu regsReset(); 4584661Sksewell@umich.edu } 4594661Sksewell@umich.edu break; 4604661Sksewell@umich.edu 4614661Sksewell@umich.edu case CFGR: 4624661Sksewell@umich.edu if (reg & CFGR_LNKSTS || 4634661Sksewell@umich.edu reg & CFGR_SPDSTS || 4644661Sksewell@umich.edu reg & CFGR_DUPSTS || 4654661Sksewell@umich.edu reg & CFGR_RESERVED || 4664661Sksewell@umich.edu reg & CFGR_T64ADDR || 4674661Sksewell@umich.edu reg & CFGR_PCI64_DET) 4684661Sksewell@umich.edu 4694661Sksewell@umich.edu // First clear all writable bits 4704661Sksewell@umich.edu regs.config &= CFGR_LNKSTS | CFGR_SPDSTS | CFGR_DUPSTS | 4714661Sksewell@umich.edu CFGR_RESERVED | CFGR_T64ADDR | 4724661Sksewell@umich.edu CFGR_PCI64_DET; 4734661Sksewell@umich.edu // Now set the appropriate writable bits 4744661Sksewell@umich.edu regs.config |= reg & ~(CFGR_LNKSTS | CFGR_SPDSTS | CFGR_DUPSTS | 4754661Sksewell@umich.edu CFGR_RESERVED | CFGR_T64ADDR | 4764661Sksewell@umich.edu CFGR_PCI64_DET); 4774661Sksewell@umich.edu 4784661Sksewell@umich.edu// all these #if 0's are because i don't THINK the kernel needs to 4794661Sksewell@umich.edu// have these implemented. if there is a problem relating to one of 4804661Sksewell@umich.edu// these, you may need to add functionality in. 4814661Sksewell@umich.edu if (reg & CFGR_TBI_EN) ; 4824661Sksewell@umich.edu if (reg & CFGR_MODE_1000) ; 4834661Sksewell@umich.edu 4844661Sksewell@umich.edu if (reg & CFGR_AUTO_1000) 4854661Sksewell@umich.edu panic("CFGR_AUTO_1000 not implemented!\n"); 4864661Sksewell@umich.edu 4874661Sksewell@umich.edu if (reg & CFGR_PINT_DUPSTS || 4884661Sksewell@umich.edu reg & CFGR_PINT_LNKSTS || 4894661Sksewell@umich.edu reg & CFGR_PINT_SPDSTS) 4904661Sksewell@umich.edu ; 4914661Sksewell@umich.edu 4924661Sksewell@umich.edu if (reg & CFGR_TMRTEST) ; 4934661Sksewell@umich.edu if (reg & CFGR_MRM_DIS) ; 4944661Sksewell@umich.edu if (reg & CFGR_MWI_DIS) ; 4954661Sksewell@umich.edu 496 if (reg & CFGR_T64ADDR) ; 497 // panic("CFGR_T64ADDR is read only register!\n"); 498 499 if (reg & CFGR_PCI64_DET) 500 panic("CFGR_PCI64_DET is read only register!\n"); 501 502 if (reg & CFGR_DATA64_EN) ; 503 if (reg & CFGR_M64ADDR) ; 504 if (reg & CFGR_PHY_RST) ; 505 if (reg & CFGR_PHY_DIS) ; 506 507 if (reg & CFGR_EXTSTS_EN) 508 extstsEnable = true; 509 else 510 extstsEnable = false; 511 512 if (reg & CFGR_REQALG) ; 513 if (reg & CFGR_SB) ; 514 if (reg & CFGR_POW) ; 515 if (reg & CFGR_EXD) ; 516 if (reg & CFGR_PESEL) ; 517 if (reg & CFGR_BROM_DIS) ; 518 if (reg & CFGR_EXT_125) ; 519 if (reg & CFGR_BEM) ; 520 break; 521 522 case MEAR: 523 // Clear writable bits 524 regs.mear &= MEAR_EEDO; 525 // Set appropriate writable bits 526 regs.mear |= reg & ~MEAR_EEDO; 527 528 // FreeBSD uses the EEPROM to read PMATCH (for the MAC address) 529 // even though it could get it through RFDR 530 if (reg & MEAR_EESEL) { 531 // Rising edge of clock 532 if (reg & MEAR_EECLK && !eepromClk) 533 eepromKick(); 534 } 535 else { 536 eepromState = eepromStart; 537 regs.mear &= ~MEAR_EEDI; 538 } 539 540 eepromClk = reg & MEAR_EECLK; 541 542 // since phy is completely faked, MEAR_MD* don't matter 543 if (reg & MEAR_MDIO) ; 544 if (reg & MEAR_MDDIR) ; 545 if (reg & MEAR_MDC) ; 546 break; 547 548 case PTSCR: 549 regs.ptscr = reg & ~(PTSCR_RBIST_RDONLY); 550 // these control BISTs for various parts of chip - we 551 // don't care or do just fake that the BIST is done 552 if (reg & PTSCR_RBIST_EN) 553 regs.ptscr |= PTSCR_RBIST_DONE; 554 if (reg & PTSCR_EEBIST_EN) 555 regs.ptscr &= ~PTSCR_EEBIST_EN; 556 if (reg & PTSCR_EELOAD_EN) 557 regs.ptscr &= ~PTSCR_EELOAD_EN; 558 break; 559 560 case ISR: /* writing to the ISR has no effect */ 561 panic("ISR is a read only register!\n"); 562 563 case IMR: 564 regs.imr = reg; 565 devIntrChangeMask(); 566 break; 567 568 case IER: 569 regs.ier = reg; 570 break; 571 572 case IHR: 573 regs.ihr = reg; 574 /* not going to implement real interrupt holdoff */ 575 break; 576 577 case TXDP: 578 regs.txdp = (reg & 0xFFFFFFFC); 579 assert(txState == txIdle); 580 CTDD = false; 581 break; 582 583 case TXDP_HI: 584 regs.txdp_hi = reg; 585 break; 586 587 case TX_CFG: 588 regs.txcfg = reg; 589#if 0 590 if (reg & TX_CFG_CSI) ; 591 if (reg & TX_CFG_HBI) ; 592 if (reg & TX_CFG_MLB) ; 593 if (reg & TX_CFG_ATP) ; 594 if (reg & TX_CFG_ECRETRY) { 595 /* 596 * this could easily be implemented, but considering 597 * the network is just a fake pipe, wouldn't make 598 * sense to do this 599 */ 600 } 601 602 if (reg & TX_CFG_BRST_DIS) ; 603#endif 604 605#if 0 606 /* we handle our own DMA, ignore the kernel's exhortations */ 607 if (reg & TX_CFG_MXDMA) ; 608#endif 609 610 // also, we currently don't care about fill/drain 611 // thresholds though this may change in the future with 612 // more realistic networks or a driver which changes it 613 // according to feedback 614 615 break; 616 617 case GPIOR: 618 // Only write writable bits 619 regs.gpior &= GPIOR_UNUSED | GPIOR_GP5_IN | GPIOR_GP4_IN 620 | GPIOR_GP3_IN | GPIOR_GP2_IN | GPIOR_GP1_IN; 621 regs.gpior |= reg & ~(GPIOR_UNUSED | GPIOR_GP5_IN | GPIOR_GP4_IN 622 | GPIOR_GP3_IN | GPIOR_GP2_IN | GPIOR_GP1_IN); 623 /* these just control general purpose i/o pins, don't matter */ 624 break; 625 626 case RXDP: 627 regs.rxdp = reg; 628 CRDD = false; 629 break; 630 631 case RXDP_HI: 632 regs.rxdp_hi = reg; 633 break; 634 635 case RX_CFG: 636 regs.rxcfg = reg; 637#if 0 638 if (reg & RX_CFG_AEP) ; 639 if (reg & RX_CFG_ARP) ; 640 if (reg & RX_CFG_STRIPCRC) ; 641 if (reg & RX_CFG_RX_RD) ; 642 if (reg & RX_CFG_ALP) ; 643 if (reg & RX_CFG_AIRL) ; 644 645 /* we handle our own DMA, ignore what kernel says about it */ 646 if (reg & RX_CFG_MXDMA) ; 647 648 //also, we currently don't care about fill/drain thresholds 649 //though this may change in the future with more realistic 650 //networks or a driver which changes it according to feedback 651 if (reg & (RX_CFG_DRTH | RX_CFG_DRTH0)) ; 652#endif 653 break; 654 655 case PQCR: 656 /* there is no priority queueing used in the linux 2.6 driver */ 657 regs.pqcr = reg; 658 break; 659 660 case WCSR: 661 /* not going to implement wake on LAN */ 662 regs.wcsr = reg; 663 break; 664 665 case PCR: 666 /* not going to implement pause control */ 667 regs.pcr = reg; 668 break; 669 670 case RFCR: 671 regs.rfcr = reg; 672 673 rxFilterEnable = (reg & RFCR_RFEN) ? true : false; 674 acceptBroadcast = (reg & RFCR_AAB) ? true : false; 675 acceptMulticast = (reg & RFCR_AAM) ? true : false; 676 acceptUnicast = (reg & RFCR_AAU) ? true : false; 677 acceptPerfect = (reg & RFCR_APM) ? true : false; 678 acceptArp = (reg & RFCR_AARP) ? true : false; 679 multicastHashEnable = (reg & RFCR_MHEN) ? true : false; 680 681#if 0 682 if (reg & RFCR_APAT) 683 panic("RFCR_APAT not implemented!\n"); 684#endif 685 if (reg & RFCR_UHEN) 686 panic("Unicast hash filtering not used by drivers!\n"); 687 688 if (reg & RFCR_ULM) 689 panic("RFCR_ULM not implemented!\n"); 690 691 break; 692 693 case RFDR: 694 rfaddr = (uint16_t)(regs.rfcr & RFCR_RFADDR); 695 switch (rfaddr) { 696 case 0x000: 697 rom.perfectMatch[0] = (uint8_t)reg; 698 rom.perfectMatch[1] = (uint8_t)(reg >> 8); 699 break; 700 case 0x002: 701 rom.perfectMatch[2] = (uint8_t)reg; 702 rom.perfectMatch[3] = (uint8_t)(reg >> 8); 703 break; 704 case 0x004: 705 rom.perfectMatch[4] = (uint8_t)reg; 706 rom.perfectMatch[5] = (uint8_t)(reg >> 8); 707 break; 708 default: 709 710 if (rfaddr >= FHASH_ADDR && 711 rfaddr < FHASH_ADDR + FHASH_SIZE) { 712 713 // Only word-aligned writes supported 714 if (rfaddr % 2) 715 panic("unaligned write to filter hash table!"); 716 717 rom.filterHash[rfaddr - FHASH_ADDR] = (uint8_t)reg; 718 rom.filterHash[rfaddr - FHASH_ADDR + 1] 719 = (uint8_t)(reg >> 8); 720 break; 721 } 722 panic("writing RFDR for something other than pattern matching\ 723 or hashing! %#x\n", rfaddr); 724 } 725 726 case BRAR: 727 regs.brar = reg; 728 break; 729 730 case BRDR: 731 panic("the driver never uses BRDR, something is wrong!\n"); 732 733 case SRR: 734 panic("SRR is read only register!\n"); 735 736 case MIBC: 737 panic("the driver never uses MIBC, something is wrong!\n"); 738 739 case VRCR: 740 regs.vrcr = reg; 741 break; 742 743 case VTCR: 744 regs.vtcr = reg; 745 break; 746 747 case VDR: 748 panic("the driver never uses VDR, something is wrong!\n"); 749 750 case CCSR: 751 /* not going to implement clockrun stuff */ 752 regs.ccsr = reg; 753 break; 754 755 case TBICR: 756 regs.tbicr = reg; 757 if (reg & TBICR_MR_LOOPBACK) 758 panic("TBICR_MR_LOOPBACK never used, something wrong!\n"); 759 760 if (reg & TBICR_MR_AN_ENABLE) { 761 regs.tanlpar = regs.tanar; 762 regs.tbisr |= (TBISR_MR_AN_COMPLETE | TBISR_MR_LINK_STATUS); 763 } 764 765#if 0 766 if (reg & TBICR_MR_RESTART_AN) ; 767#endif 768 769 break; 770 771 case TBISR: 772 panic("TBISR is read only register!\n"); 773 774 case TANAR: 775 // Only write the writable bits 776 regs.tanar &= TANAR_RF1 | TANAR_RF2 | TANAR_UNUSED; 777 regs.tanar |= reg & ~(TANAR_RF1 | TANAR_RF2 | TANAR_UNUSED); 778 779 // Pause capability unimplemented 780#if 0 781 if (reg & TANAR_PS2) ; 782 if (reg & TANAR_PS1) ; 783#endif 784 785 break; 786 787 case TANLPAR: 788 panic("this should only be written to by the fake phy!\n"); 789 790 case TANER: 791 panic("TANER is read only register!\n"); 792 793 case TESR: 794 regs.tesr = reg; 795 break; 796 797 default: 798 panic("invalid register access daddr=%#x", daddr); 799 } 800 } else { 801 panic("Invalid Request Size"); 802 } 803 pkt->makeAtomicResponse(); 804 return pioDelay; 805} 806 807void 808NSGigE::devIntrPost(uint32_t interrupts) 809{ 810 if (interrupts & ISR_RESERVE) 811 panic("Cannot set a reserved interrupt"); 812 813 if (interrupts & ISR_NOIMPL) 814 warn("interrupt not implemented %#x\n", interrupts); 815 816 interrupts &= ISR_IMPL; 817 regs.isr |= interrupts; 818 819 if (interrupts & regs.imr) { 820 if (interrupts & ISR_SWI) { 821 totalSwi++; 822 } 823 if (interrupts & ISR_RXIDLE) { 824 totalRxIdle++; 825 } 826 if (interrupts & ISR_RXOK) { 827 totalRxOk++; 828 } 829 if (interrupts & ISR_RXDESC) { 830 totalRxDesc++; 831 } 832 if (interrupts & ISR_TXOK) { 833 totalTxOk++; 834 } 835 if (interrupts & ISR_TXIDLE) { 836 totalTxIdle++; 837 } 838 if (interrupts & ISR_TXDESC) { 839 totalTxDesc++; 840 } 841 if (interrupts & ISR_RXORN) { 842 totalRxOrn++; 843 } 844 } 845 846 DPRINTF(EthernetIntr, 847 "interrupt written to ISR: intr=%#x isr=%#x imr=%#x\n", 848 interrupts, regs.isr, regs.imr); 849 850 if ((regs.isr & regs.imr)) { 851 Tick when = curTick(); 852 if ((regs.isr & regs.imr & ISR_NODELAY) == 0) 853 when += intrDelay; 854 postedInterrupts++; 855 cpuIntrPost(when); 856 } 857} 858 859/* writing this interrupt counting stats inside this means that this function 860 is now limited to being used to clear all interrupts upon the kernel 861 reading isr and servicing. just telling you in case you were thinking 862 of expanding use. 863*/ 864void 865NSGigE::devIntrClear(uint32_t interrupts) 866{ 867 if (interrupts & ISR_RESERVE) 868 panic("Cannot clear a reserved interrupt"); 869 870 if (regs.isr & regs.imr & ISR_SWI) { 871 postedSwi++; 872 } 873 if (regs.isr & regs.imr & ISR_RXIDLE) { 874 postedRxIdle++; 875 } 876 if (regs.isr & regs.imr & ISR_RXOK) { 877 postedRxOk++; 878 } 879 if (regs.isr & regs.imr & ISR_RXDESC) { 880 postedRxDesc++; 881 } 882 if (regs.isr & regs.imr & ISR_TXOK) { 883 postedTxOk++; 884 } 885 if (regs.isr & regs.imr & ISR_TXIDLE) { 886 postedTxIdle++; 887 } 888 if (regs.isr & regs.imr & ISR_TXDESC) { 889 postedTxDesc++; 890 } 891 if (regs.isr & regs.imr & ISR_RXORN) { 892 postedRxOrn++; 893 } 894 895 interrupts &= ~ISR_NOIMPL; 896 regs.isr &= ~interrupts; 897 898 DPRINTF(EthernetIntr, 899 "interrupt cleared from ISR: intr=%x isr=%x imr=%x\n", 900 interrupts, regs.isr, regs.imr); 901 902 if (!(regs.isr & regs.imr)) 903 cpuIntrClear(); 904} 905 906void 907NSGigE::devIntrChangeMask() 908{ 909 DPRINTF(EthernetIntr, "interrupt mask changed: isr=%x imr=%x masked=%x\n", 910 regs.isr, regs.imr, regs.isr & regs.imr); 911 912 if (regs.isr & regs.imr) 913 cpuIntrPost(curTick()); 914 else 915 cpuIntrClear(); 916} 917 918void 919NSGigE::cpuIntrPost(Tick when) 920{ 921 // If the interrupt you want to post is later than an interrupt 922 // already scheduled, just let it post in the coming one and don't 923 // schedule another. 924 // HOWEVER, must be sure that the scheduled intrTick is in the 925 // future (this was formerly the source of a bug) 926 /** 927 * @todo this warning should be removed and the intrTick code should 928 * be fixed. 929 */ 930 assert(when >= curTick()); 931 assert(intrTick >= curTick() || intrTick == 0); 932 if (when > intrTick && intrTick != 0) { 933 DPRINTF(EthernetIntr, "don't need to schedule event...intrTick=%d\n", 934 intrTick); 935 return; 936 } 937 938 intrTick = when; 939 if (intrTick < curTick()) { 940 debug_break(); 941 intrTick = curTick(); 942 } 943 944 DPRINTF(EthernetIntr, "going to schedule an interrupt for intrTick=%d\n", 945 intrTick); 946 947 if (intrEvent) 948 intrEvent->squash(); 949 intrEvent = new IntrEvent(this, true); 950 schedule(intrEvent, intrTick); 951} 952 953void 954NSGigE::cpuInterrupt() 955{ 956 assert(intrTick == curTick()); 957 958 // Whether or not there's a pending interrupt, we don't care about 959 // it anymore 960 intrEvent = 0; 961 intrTick = 0; 962 963 // Don't send an interrupt if there's already one 964 if (cpuPendingIntr) { 965 DPRINTF(EthernetIntr, 966 "would send an interrupt now, but there's already pending\n"); 967 } else { 968 // Send interrupt 969 cpuPendingIntr = true; 970 971 DPRINTF(EthernetIntr, "posting interrupt\n"); 972 intrPost(); 973 } 974} 975 976void 977NSGigE::cpuIntrClear() 978{ 979 if (!cpuPendingIntr) 980 return; 981 982 if (intrEvent) { 983 intrEvent->squash(); 984 intrEvent = 0; 985 } 986 987 intrTick = 0; 988 989 cpuPendingIntr = false; 990 991 DPRINTF(EthernetIntr, "clearing interrupt\n"); 992 intrClear(); 993} 994 995bool 996NSGigE::cpuIntrPending() const 997{ return cpuPendingIntr; } 998 999void 1000NSGigE::txReset() 1001{ 1002 1003 DPRINTF(Ethernet, "transmit reset\n"); 1004 1005 CTDD = false; 1006 txEnable = false;; 1007 txFragPtr = 0; 1008 assert(txDescCnt == 0); 1009 txFifo.clear(); 1010 txState = txIdle; 1011 assert(txDmaState == dmaIdle); 1012} 1013 1014void 1015NSGigE::rxReset() 1016{ 1017 DPRINTF(Ethernet, "receive reset\n"); 1018 1019 CRDD = false; 1020 assert(rxPktBytes == 0); 1021 rxEnable = false; 1022 rxFragPtr = 0; 1023 assert(rxDescCnt == 0); 1024 assert(rxDmaState == dmaIdle); 1025 rxFifo.clear(); 1026 rxState = rxIdle; 1027} 1028 1029void 1030NSGigE::regsReset() 1031{ 1032 memset(®s, 0, sizeof(regs)); 1033 regs.config = (CFGR_LNKSTS | CFGR_TBI_EN | CFGR_MODE_1000); 1034 regs.mear = 0x12; 1035 regs.txcfg = 0x120; // set drain threshold to 1024 bytes and 1036 // fill threshold to 32 bytes 1037 regs.rxcfg = 0x4; // set drain threshold to 16 bytes 1038 regs.srr = 0x0103; // set the silicon revision to rev B or 0x103 1039 regs.mibc = MIBC_FRZ; 1040 regs.vdr = 0x81; // set the vlan tag type to 802.1q 1041 regs.tesr = 0xc000; // TBI capable of both full and half duplex 1042 regs.brar = 0xffffffff; 1043 1044 extstsEnable = false; 1045 acceptBroadcast = false; 1046 acceptMulticast = false; 1047 acceptUnicast = false; 1048 acceptPerfect = false; 1049 acceptArp = false; 1050} 1051 1052bool 1053NSGigE::doRxDmaRead() 1054{ 1055 assert(rxDmaState == dmaIdle || rxDmaState == dmaReadWaiting); 1056 rxDmaState = dmaReading; 1057 1058 if (dmaPending() || getState() != Running) 1059 rxDmaState = dmaReadWaiting; 1060 else 1061 dmaRead(rxDmaAddr, rxDmaLen, &rxDmaReadEvent, (uint8_t*)rxDmaData); 1062 1063 return true; 1064} 1065 1066void 1067NSGigE::rxDmaReadDone() 1068{ 1069 assert(rxDmaState == dmaReading); 1070 rxDmaState = dmaIdle; 1071 1072 DPRINTF(EthernetDMA, "rx dma read paddr=%#x len=%d\n", 1073 rxDmaAddr, rxDmaLen); 1074 DDUMP(EthernetDMA, rxDmaData, rxDmaLen); 1075 1076 // If the transmit state machine has a pending DMA, let it go first 1077 if (txDmaState == dmaReadWaiting || txDmaState == dmaWriteWaiting) 1078 txKick(); 1079 1080 rxKick(); 1081} 1082 1083bool 1084NSGigE::doRxDmaWrite() 1085{ 1086 assert(rxDmaState == dmaIdle || rxDmaState == dmaWriteWaiting); 1087 rxDmaState = dmaWriting; 1088 1089 if (dmaPending() || getState() != Running) 1090 rxDmaState = dmaWriteWaiting; 1091 else 1092 dmaWrite(rxDmaAddr, rxDmaLen, &rxDmaWriteEvent, (uint8_t*)rxDmaData); 1093 return true; 1094} 1095 1096void 1097NSGigE::rxDmaWriteDone() 1098{ 1099 assert(rxDmaState == dmaWriting); 1100 rxDmaState = dmaIdle; 1101 1102 DPRINTF(EthernetDMA, "rx dma write paddr=%#x len=%d\n", 1103 rxDmaAddr, rxDmaLen); 1104 DDUMP(EthernetDMA, rxDmaData, rxDmaLen); 1105 1106 // If the transmit state machine has a pending DMA, let it go first 1107 if (txDmaState == dmaReadWaiting || txDmaState == dmaWriteWaiting) 1108 txKick(); 1109 1110 rxKick(); 1111} 1112 1113void 1114NSGigE::rxKick() 1115{ 1116 bool is64bit = (bool)(regs.config & CFGR_M64ADDR); 1117 1118 DPRINTF(EthernetSM, 1119 "receive kick rxState=%s (rxBuf.size=%d) %d-bit\n", 1120 NsRxStateStrings[rxState], rxFifo.size(), is64bit ? 64 : 32); 1121 1122 Addr link, bufptr; 1123 uint32_t &cmdsts = is64bit ? rxDesc64.cmdsts : rxDesc32.cmdsts; 1124 uint32_t &extsts = is64bit ? rxDesc64.extsts : rxDesc32.extsts; 1125 1126 next: 1127 if (clock) { 1128 if (rxKickTick > curTick()) { 1129 DPRINTF(EthernetSM, "receive kick exiting, can't run till %d\n", 1130 rxKickTick); 1131 1132 goto exit; 1133 } 1134 1135 // Go to the next state machine clock tick. 1136 rxKickTick = curTick() + ticks(1); 1137 } 1138 1139 switch(rxDmaState) { 1140 case dmaReadWaiting: 1141 if (doRxDmaRead()) 1142 goto exit; 1143 break; 1144 case dmaWriteWaiting: 1145 if (doRxDmaWrite()) 1146 goto exit; 1147 break; 1148 default: 1149 break; 1150 } 1151 1152 link = is64bit ? (Addr)rxDesc64.link : (Addr)rxDesc32.link; 1153 bufptr = is64bit ? (Addr)rxDesc64.bufptr : (Addr)rxDesc32.bufptr; 1154 1155 // see state machine from spec for details 1156 // the way this works is, if you finish work on one state and can 1157 // go directly to another, you do that through jumping to the 1158 // label "next". however, if you have intermediate work, like DMA 1159 // so that you can't go to the next state yet, you go to exit and 1160 // exit the loop. however, when the DMA is done it will trigger 1161 // an event and come back to this loop. 1162 switch (rxState) { 1163 case rxIdle: 1164 if (!rxEnable) { 1165 DPRINTF(EthernetSM, "Receive Disabled! Nothing to do.\n"); 1166 goto exit; 1167 } 1168 1169 if (CRDD) { 1170 rxState = rxDescRefr; 1171 1172 rxDmaAddr = regs.rxdp & 0x3fffffff; 1173 rxDmaData = 1174 is64bit ? (void *)&rxDesc64.link : (void *)&rxDesc32.link; 1175 rxDmaLen = is64bit ? sizeof(rxDesc64.link) : sizeof(rxDesc32.link); 1176 rxDmaFree = dmaDescFree; 1177 1178 descDmaReads++; 1179 descDmaRdBytes += rxDmaLen; 1180 1181 if (doRxDmaRead()) 1182 goto exit; 1183 } else { 1184 rxState = rxDescRead; 1185 1186 rxDmaAddr = regs.rxdp & 0x3fffffff; 1187 rxDmaData = is64bit ? (void *)&rxDesc64 : (void *)&rxDesc32; 1188 rxDmaLen = is64bit ? sizeof(rxDesc64) : sizeof(rxDesc32); 1189 rxDmaFree = dmaDescFree; 1190 1191 descDmaReads++; 1192 descDmaRdBytes += rxDmaLen; 1193 1194 if (doRxDmaRead()) 1195 goto exit; 1196 } 1197 break; 1198 1199 case rxDescRefr: 1200 if (rxDmaState != dmaIdle) 1201 goto exit; 1202 1203 rxState = rxAdvance; 1204 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