X-Git-Url: https://git.libre-soc.org/?a=blobdiff_plain;f=dev%2Fns_gige.cc;h=ae129c2493d8981d62c36f5e6ba3bd2e6870c36b;hb=49063eb24f8fd2ad010224cc282c55dd5471dd65;hp=613677875052007aa1ddd37c83329f365624746a;hpb=886f905785561372413ea95dc551a0f269e28bac;p=gem5.git diff --git a/dev/ns_gige.cc b/dev/ns_gige.cc index 613677875..ae129c249 100644 --- a/dev/ns_gige.cc +++ b/dev/ns_gige.cc @@ -1,5 +1,5 @@ /* - * Copyright (c) 2004 The Regents of The University of Michigan + * Copyright (c) 2004-2005 The Regents of The University of Michigan * All rights reserved. * * Redistribution and use in source and binary forms, with or without @@ -26,7 +26,7 @@ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ -/* @file +/** @file * Device module for modelling the National Semiconductor * DP83820 ethernet controller. Does not support priority queueing */ @@ -36,7 +36,6 @@ #include "base/inet.hh" #include "cpu/exec_context.hh" -#include "dev/dma.hh" #include "dev/etherlink.hh" #include "dev/ns_gige.hh" #include "dev/pciconfigall.hh" @@ -44,8 +43,8 @@ #include "mem/bus/dma_interface.hh" #include "mem/bus/pio_interface.hh" #include "mem/bus/pio_interface_impl.hh" -#include "mem/functional_mem/memory_control.hh" -#include "mem/functional_mem/physical_memory.hh" +#include "mem/functional/memory_control.hh" +#include "mem/functional/physical.hh" #include "sim/builder.hh" #include "sim/debug.hh" #include "sim/host.hh" @@ -94,19 +93,19 @@ NSGigE::NSGigE(Params *p) : PciDev(p), ioEnable(false), txFifo(p->tx_fifo_size), rxFifo(p->rx_fifo_size), txPacket(0), rxPacket(0), txPacketBufPtr(NULL), rxPacketBufPtr(NULL), - txXferLen(0), rxXferLen(0), txState(txIdle), txEnable(false), - CTDD(false), + txXferLen(0), rxXferLen(0), clock(p->clock), + txState(txIdle), txEnable(false), CTDD(false), txFragPtr(0), txDescCnt(0), txDmaState(dmaIdle), rxState(rxIdle), rxEnable(false), CRDD(false), rxPktBytes(0), rxFragPtr(0), rxDescCnt(0), rxDmaState(dmaIdle), extstsEnable(false), - rxDmaReadEvent(this), rxDmaWriteEvent(this), + eepromState(eepromStart), rxDmaReadEvent(this), rxDmaWriteEvent(this), txDmaReadEvent(this), txDmaWriteEvent(this), dmaDescFree(p->dma_desc_free), dmaDataFree(p->dma_data_free), txDelay(p->tx_delay), rxDelay(p->rx_delay), - rxKickTick(0), txKickTick(0), + rxKickTick(0), rxKickEvent(this), txKickTick(0), txKickEvent(this), txEvent(this), rxFilterEnable(p->rx_filter), acceptBroadcast(false), acceptMulticast(false), acceptUnicast(false), - acceptPerfect(false), acceptArp(false), + acceptPerfect(false), acceptArp(false), multicastHashEnable(false), physmem(p->pmem), intrTick(0), cpuPendingIntr(false), intrEvent(0), interface(0) { @@ -115,30 +114,33 @@ NSGigE::NSGigE(Params *p) p->header_bus, this, &NSGigE::cacheAccess); - pioLatency = p->pio_latency * p->header_bus->clockRatio; + pioLatency = p->pio_latency * p->header_bus->clockRate; if (p->payload_bus) dmaInterface = new DMAInterface(name() + ".dma", p->header_bus, - p->payload_bus, 1); + p->payload_bus, 1, + p->dma_no_allocate); else dmaInterface = new DMAInterface(name() + ".dma", p->header_bus, - p->header_bus, 1); + p->header_bus, 1, + p->dma_no_allocate); } else if (p->payload_bus) { pioInterface = newPioInterface(name(), p->hier, p->payload_bus, this, &NSGigE::cacheAccess); - pioLatency = p->pio_latency * p->payload_bus->clockRatio; + pioLatency = p->pio_latency * p->payload_bus->clockRate; dmaInterface = new DMAInterface(name() + ".dma", p->payload_bus, - p->payload_bus, 1); + p->payload_bus, 1, + p->dma_no_allocate); } - intrDelay = US2Ticks(p->intr_delay); + intrDelay = p->intr_delay; dmaReadDelay = p->dma_read_delay; dmaWriteDelay = p->dma_write_delay; dmaReadFactor = p->dma_read_factor; @@ -471,8 +473,9 @@ NSGigE::regStats() coalescedTxDesc = totalTxDesc / postedInterrupts; coalescedRxOrn = totalRxOrn / postedInterrupts; - coalescedTotal = (totalSwi + totalRxIdle + totalRxOk + totalRxDesc + totalTxOk - + totalTxIdle + totalTxDesc + totalRxOrn) / postedInterrupts; + coalescedTotal = (totalSwi + totalRxIdle + totalRxOk + totalRxDesc + + totalTxOk + totalTxIdle + totalTxDesc + + totalRxOrn) / postedInterrupts; txBandwidth = txBytes * Stats::constant(8) / simSeconds; rxBandwidth = rxBytes * Stats::constant(8) / simSeconds; @@ -598,7 +601,7 @@ NSGigE::read(MemReqPtr &req, uint8_t *data) reg &= ~(CR_RXD | CR_TXD | CR_TXR | CR_RXR); break; - case CFG: + case CFGR: reg = regs.config; break; @@ -635,7 +638,7 @@ NSGigE::read(MemReqPtr &req, uint8_t *data) reg = regs.txdp_hi; break; - case TXCFG: + case TX_CFG: reg = regs.txcfg; break; @@ -651,7 +654,7 @@ NSGigE::read(MemReqPtr &req, uint8_t *data) reg = regs.rxdp_hi; break; - case RXCFG: + case RX_CFG: reg = regs.rxcfg; break; @@ -677,7 +680,9 @@ NSGigE::read(MemReqPtr &req, uint8_t *data) break; case RFDR: - switch (regs.rfcr & RFCR_RFADDR) { + uint16_t rfaddr = (uint16_t)(regs.rfcr & RFCR_RFADDR); + switch (rfaddr) { + // Read from perfect match ROM octets case 0x000: reg = rom.perfectMatch[1]; reg = reg << 8; @@ -692,9 +697,21 @@ NSGigE::read(MemReqPtr &req, uint8_t *data) reg += rom.perfectMatch[4]; break; default: - panic("reading RFDR for something other than PMATCH!\n"); - // didn't implement other RFDR functionality b/c - // driver didn't use it + // Read filter hash table + if (rfaddr >= FHASH_ADDR && + rfaddr < FHASH_ADDR + FHASH_SIZE) { + + // Only word-aligned reads supported + if (rfaddr % 2) + panic("unaligned read from filter hash table!"); + + reg = rom.filterHash[rfaddr - FHASH_ADDR + 1] << 8; + reg += rom.filterHash[rfaddr - FHASH_ADDR]; + break; + } + + panic("reading RFDR for something other than pattern\ + matching or hashing! %#x\n", rfaddr); } break; @@ -747,6 +764,10 @@ NSGigE::read(MemReqPtr &req, uint8_t *data) reg = regs.tesr; break; + case M5REG: + reg = params()->m5reg; + break; + default: panic("reading unimplemented register: addr=%#x", daddr); } @@ -824,78 +845,95 @@ NSGigE::write(MemReqPtr &req, const uint8_t *data) } break; - case CFG: - if (reg & CFG_LNKSTS || - reg & CFG_SPDSTS || - reg & CFG_DUPSTS || - reg & CFG_RESERVED || - reg & CFG_T64ADDR || - reg & CFG_PCI64_DET) - panic("writing to read-only or reserved CFG bits!\n"); - - regs.config |= reg & ~(CFG_LNKSTS | CFG_SPDSTS | CFG_DUPSTS | - CFG_RESERVED | CFG_T64ADDR | CFG_PCI64_DET); + case CFGR: + if (reg & CFGR_LNKSTS || + reg & CFGR_SPDSTS || + reg & CFGR_DUPSTS || + reg & CFGR_RESERVED || + reg & CFGR_T64ADDR || + reg & CFGR_PCI64_DET) + + // First clear all writable bits + regs.config &= CFGR_LNKSTS | CFGR_SPDSTS | CFGR_DUPSTS | + CFGR_RESERVED | CFGR_T64ADDR | + CFGR_PCI64_DET; + // Now set the appropriate writable bits + regs.config |= reg & ~(CFGR_LNKSTS | CFGR_SPDSTS | CFGR_DUPSTS | + CFGR_RESERVED | CFGR_T64ADDR | + CFGR_PCI64_DET); // all these #if 0's are because i don't THINK the kernel needs to // have these implemented. if there is a problem relating to one of // these, you may need to add functionality in. #if 0 - if (reg & CFG_TBI_EN) ; - if (reg & CFG_MODE_1000) ; + if (reg & CFGR_TBI_EN) ; + if (reg & CFGR_MODE_1000) ; #endif - if (reg & CFG_AUTO_1000) - panic("CFG_AUTO_1000 not implemented!\n"); + if (reg & CFGR_AUTO_1000) + panic("CFGR_AUTO_1000 not implemented!\n"); #if 0 - if (reg & CFG_PINT_DUPSTS || - reg & CFG_PINT_LNKSTS || - reg & CFG_PINT_SPDSTS) + if (reg & CFGR_PINT_DUPSTS || + reg & CFGR_PINT_LNKSTS || + reg & CFGR_PINT_SPDSTS) ; - if (reg & CFG_TMRTEST) ; - if (reg & CFG_MRM_DIS) ; - if (reg & CFG_MWI_DIS) ; + if (reg & CFGR_TMRTEST) ; + if (reg & CFGR_MRM_DIS) ; + if (reg & CFGR_MWI_DIS) ; - if (reg & CFG_T64ADDR) - panic("CFG_T64ADDR is read only register!\n"); + if (reg & CFGR_T64ADDR) + panic("CFGR_T64ADDR is read only register!\n"); - if (reg & CFG_PCI64_DET) - panic("CFG_PCI64_DET is read only register!\n"); + if (reg & CFGR_PCI64_DET) + panic("CFGR_PCI64_DET is read only register!\n"); - if (reg & CFG_DATA64_EN) ; - if (reg & CFG_M64ADDR) ; - if (reg & CFG_PHY_RST) ; - if (reg & CFG_PHY_DIS) ; + if (reg & CFGR_DATA64_EN) ; + if (reg & CFGR_M64ADDR) ; + if (reg & CFGR_PHY_RST) ; + if (reg & CFGR_PHY_DIS) ; #endif - if (reg & CFG_EXTSTS_EN) + if (reg & CFGR_EXTSTS_EN) extstsEnable = true; else extstsEnable = false; #if 0 - if (reg & CFG_REQALG) ; - if (reg & CFG_SB) ; - if (reg & CFG_POW) ; - if (reg & CFG_EXD) ; - if (reg & CFG_PESEL) ; - if (reg & CFG_BROM_DIS) ; - if (reg & CFG_EXT_125) ; - if (reg & CFG_BEM) ; + if (reg & CFGR_REQALG) ; + if (reg & CFGR_SB) ; + if (reg & CFGR_POW) ; + if (reg & CFGR_EXD) ; + if (reg & CFGR_PESEL) ; + if (reg & CFGR_BROM_DIS) ; + if (reg & CFGR_EXT_125) ; + if (reg & CFGR_BEM) ; #endif break; case MEAR: - regs.mear = reg; + // Clear writable bits + regs.mear &= MEAR_EEDO; + // Set appropriate writable bits + regs.mear |= reg & ~MEAR_EEDO; + + // FreeBSD uses the EEPROM to read PMATCH (for the MAC address) + // even though it could get it through RFDR + if (reg & MEAR_EESEL) { + // Rising edge of clock + if (reg & MEAR_EECLK && !eepromClk) + eepromKick(); + } + else { + eepromState = eepromStart; + regs.mear &= ~MEAR_EEDI; + } + + eepromClk = reg & MEAR_EECLK; + // since phy is completely faked, MEAR_MD* don't matter - // and since the driver never uses MEAR_EE*, they don't - // matter #if 0 - if (reg & MEAR_EEDI) ; - if (reg & MEAR_EEDO) ; // this one is read only - if (reg & MEAR_EECLK) ; - if (reg & MEAR_EESEL) ; if (reg & MEAR_MDIO) ; if (reg & MEAR_MDDIR) ; if (reg & MEAR_MDC) ; @@ -941,14 +979,14 @@ NSGigE::write(MemReqPtr &req, const uint8_t *data) regs.txdp_hi = reg; break; - case TXCFG: + case TX_CFG: regs.txcfg = reg; #if 0 - if (reg & TXCFG_CSI) ; - if (reg & TXCFG_HBI) ; - if (reg & TXCFG_MLB) ; - if (reg & TXCFG_ATP) ; - if (reg & TXCFG_ECRETRY) { + if (reg & TX_CFG_CSI) ; + if (reg & TX_CFG_HBI) ; + if (reg & TX_CFG_MLB) ; + if (reg & TX_CFG_ATP) ; + if (reg & TX_CFG_ECRETRY) { /* * this could easily be implemented, but considering * the network is just a fake pipe, wouldn't make @@ -956,12 +994,12 @@ NSGigE::write(MemReqPtr &req, const uint8_t *data) */ } - if (reg & TXCFG_BRST_DIS) ; + if (reg & TX_CFG_BRST_DIS) ; #endif #if 0 /* we handle our own DMA, ignore the kernel's exhortations */ - if (reg & TXCFG_MXDMA) ; + if (reg & TX_CFG_MXDMA) ; #endif // also, we currently don't care about fill/drain @@ -972,7 +1010,11 @@ NSGigE::write(MemReqPtr &req, const uint8_t *data) break; case GPIOR: - regs.gpior = reg; + // Only write writable bits + regs.gpior &= GPIOR_UNUSED | GPIOR_GP5_IN | GPIOR_GP4_IN + | GPIOR_GP3_IN | GPIOR_GP2_IN | GPIOR_GP1_IN; + regs.gpior |= reg & ~(GPIOR_UNUSED | GPIOR_GP5_IN | GPIOR_GP4_IN + | GPIOR_GP3_IN | GPIOR_GP2_IN | GPIOR_GP1_IN); /* these just control general purpose i/o pins, don't matter */ break; @@ -985,23 +1027,23 @@ NSGigE::write(MemReqPtr &req, const uint8_t *data) regs.rxdp_hi = reg; break; - case RXCFG: + case RX_CFG: regs.rxcfg = reg; #if 0 - if (reg & RXCFG_AEP) ; - if (reg & RXCFG_ARP) ; - if (reg & RXCFG_STRIPCRC) ; - if (reg & RXCFG_RX_RD) ; - if (reg & RXCFG_ALP) ; - if (reg & RXCFG_AIRL) ; + if (reg & RX_CFG_AEP) ; + if (reg & RX_CFG_ARP) ; + if (reg & RX_CFG_STRIPCRC) ; + if (reg & RX_CFG_RX_RD) ; + if (reg & RX_CFG_ALP) ; + if (reg & RX_CFG_AIRL) ; /* we handle our own DMA, ignore what kernel says about it */ - if (reg & RXCFG_MXDMA) ; + if (reg & RX_CFG_MXDMA) ; //also, we currently don't care about fill/drain thresholds //though this may change in the future with more realistic //networks or a driver which changes it according to feedback - if (reg & (RXCFG_DRTH | RXCFG_DRTH0)) ; + if (reg & (RX_CFG_DRTH | RX_CFG_DRTH0)) ; #endif break; @@ -1029,14 +1071,14 @@ NSGigE::write(MemReqPtr &req, const uint8_t *data) acceptUnicast = (reg & RFCR_AAU) ? true : false; acceptPerfect = (reg & RFCR_APM) ? true : false; acceptArp = (reg & RFCR_AARP) ? true : false; + multicastHashEnable = (reg & RFCR_MHEN) ? true : false; #if 0 if (reg & RFCR_APAT) panic("RFCR_APAT not implemented!\n"); #endif - - if (reg & RFCR_MHEN || reg & RFCR_UHEN) - panic("hash filtering not implemented!\n"); + if (reg & RFCR_UHEN) + panic("Unicast hash filtering not used by drivers!\n"); if (reg & RFCR_ULM) panic("RFCR_ULM not implemented!\n"); @@ -1044,10 +1086,41 @@ NSGigE::write(MemReqPtr &req, const uint8_t *data) break; case RFDR: - panic("the driver never writes to RFDR, something is wrong!\n"); + uint16_t rfaddr = (uint16_t)(regs.rfcr & RFCR_RFADDR); + switch (rfaddr) { + case 0x000: + rom.perfectMatch[0] = (uint8_t)reg; + rom.perfectMatch[1] = (uint8_t)(reg >> 8); + break; + case 0x002: + rom.perfectMatch[2] = (uint8_t)reg; + rom.perfectMatch[3] = (uint8_t)(reg >> 8); + break; + case 0x004: + rom.perfectMatch[4] = (uint8_t)reg; + rom.perfectMatch[5] = (uint8_t)(reg >> 8); + break; + default: + + if (rfaddr >= FHASH_ADDR && + rfaddr < FHASH_ADDR + FHASH_SIZE) { + + // Only word-aligned writes supported + if (rfaddr % 2) + panic("unaligned write to filter hash table!"); + + rom.filterHash[rfaddr - FHASH_ADDR] = (uint8_t)reg; + rom.filterHash[rfaddr - FHASH_ADDR + 1] + = (uint8_t)(reg >> 8); + break; + } + panic("writing RFDR for something other than pattern matching\ + or hashing! %#x\n", rfaddr); + } case BRAR: - panic("the driver never uses BRAR, something is wrong!\n"); + regs.brar = reg; + break; case BRDR: panic("the driver never uses BRDR, something is wrong!\n"); @@ -1068,7 +1141,6 @@ NSGigE::write(MemReqPtr &req, const uint8_t *data) case VDR: panic("the driver never uses VDR, something is wrong!\n"); - break; case CCSR: /* not going to implement clockrun stuff */ @@ -1095,12 +1167,16 @@ NSGigE::write(MemReqPtr &req, const uint8_t *data) panic("TBISR is read only register!\n"); case TANAR: - regs.tanar = reg; - if (reg & TANAR_PS2) - panic("this isn't used in driver, something wrong!\n"); + // Only write the writable bits + regs.tanar &= TANAR_RF1 | TANAR_RF2 | TANAR_UNUSED; + regs.tanar |= reg & ~(TANAR_RF1 | TANAR_RF2 | TANAR_UNUSED); + + // Pause capability unimplemented +#if 0 + if (reg & TANAR_PS2) ; + if (reg & TANAR_PS1) ; +#endif - if (reg & TANAR_PS1) - panic("this isn't used in driver, something wrong!\n"); break; case TANLPAR: @@ -1352,8 +1428,8 @@ void NSGigE::regsReset() { memset(®s, 0, sizeof(regs)); - regs.config = CFG_LNKSTS; - regs.mear = MEAR_MDDIR | MEAR_EEDO; + regs.config = (CFGR_LNKSTS | CFGR_TBI_EN | CFGR_MODE_1000); + regs.mear = 0x12; regs.txcfg = 0x120; // set drain threshold to 1024 bytes and // fill threshold to 32 bytes regs.rxcfg = 0x4; // set drain threshold to 16 bytes @@ -1361,6 +1437,7 @@ NSGigE::regsReset() regs.mibc = MIBC_FRZ; regs.vdr = 0x81; // set the vlan tag type to 802.1q regs.tesr = 0xc000; // TBI capable of both full and half duplex + regs.brar = 0xffffffff; extstsEnable = false; acceptBroadcast = false; @@ -1480,13 +1557,19 @@ NSGigE::rxKick() DPRINTF(EthernetSM, "receive kick rxState=%s (rxBuf.size=%d)\n", NsRxStateStrings[rxState], rxFifo.size()); - if (rxKickTick > curTick) { - DPRINTF(EthernetSM, "receive kick exiting, can't run till %d\n", - rxKickTick); - return; + next: + if (clock) { + if (rxKickTick > curTick) { + DPRINTF(EthernetSM, "receive kick exiting, can't run till %d\n", + rxKickTick); + + goto exit; + } + + // Go to the next state machine clock tick. + rxKickTick = curTick + cycles(1); } - next: switch(rxDmaState) { case dmaReadWaiting: if (doRxDmaRead()) @@ -1554,8 +1637,7 @@ NSGigE::rxKick() if (rxDmaState != dmaIdle) goto exit; - DPRINTF(EthernetDesc, - "rxDescCache: addr=%08x read descriptor\n", + DPRINTF(EthernetDesc, "rxDescCache: addr=%08x read descriptor\n", regs.rxdp & 0x3fffffff); DPRINTF(EthernetDesc, "rxDescCache: link=%08x bufptr=%08x cmdsts=%08x extsts=%08x\n", @@ -1597,8 +1679,10 @@ NSGigE::rxKick() DPRINTF(Ethernet, "ID is %d\n", ip->id()); TcpPtr tcp(ip); if (tcp) { - DPRINTF(Ethernet, "Src Port=%d, Dest Port=%d\n", - tcp->sport(), tcp->dport()); + DPRINTF(Ethernet, + "Src Port=%d, Dest Port=%d, Seq=%d, Ack=%d\n", + tcp->sport(), tcp->dport(), tcp->seq(), + tcp->ack()); } } } @@ -1774,7 +1858,6 @@ NSGigE::rxKick() DPRINTF(EthernetSM, "entering next rxState=%s\n", NsRxStateStrings[rxState]); - goto next; exit: @@ -1783,6 +1866,9 @@ NSGigE::rxKick() */ DPRINTF(EthernetSM, "rx state machine exited rxState=%s\n", NsRxStateStrings[rxState]); + + if (clock && !rxKickEvent.scheduled()) + rxKickEvent.schedule(rxKickTick); } void @@ -1803,14 +1889,15 @@ NSGigE::transmit() DPRINTF(Ethernet, "ID is %d\n", ip->id()); TcpPtr tcp(ip); if (tcp) { - DPRINTF(Ethernet, "Src Port=%d, Dest Port=%d\n", - tcp->sport(), tcp->dport()); + DPRINTF(Ethernet, + "Src Port=%d, Dest Port=%d, Seq=%d, Ack=%d\n", + tcp->sport(), tcp->dport(), tcp->seq(), tcp->ack()); } } } #endif - DDUMP(Ethernet, txFifo.front()->data, txFifo.front()->length); + DDUMP(EthernetData, txFifo.front()->data, txFifo.front()->length); txBytes += txFifo.front()->length; txPackets++; @@ -1830,7 +1917,7 @@ NSGigE::transmit() if (!txFifo.empty() && !txEvent.scheduled()) { DPRINTF(Ethernet, "reschedule transmit\n"); - txEvent.schedule(curTick + 1000); + txEvent.schedule(curTick + retryTime); } } @@ -1944,14 +2031,18 @@ NSGigE::txKick() DPRINTF(EthernetSM, "transmit kick txState=%s\n", NsTxStateStrings[txState]); - if (txKickTick > curTick) { - DPRINTF(EthernetSM, "transmit kick exiting, can't run till %d\n", - txKickTick); + next: + if (clock) { + if (txKickTick > curTick) { + DPRINTF(EthernetSM, "transmit kick exiting, can't run till %d\n", + txKickTick); + goto exit; + } - return; + // Go to the next state machine clock tick. + txKickTick = curTick + cycles(1); } - next: switch(txDmaState) { case dmaReadWaiting: if (doTxDmaRead()) @@ -2013,6 +2104,8 @@ NSGigE::txKick() if (txDmaState != dmaIdle) goto exit; + DPRINTF(EthernetDesc, "txDescCache: addr=%08x read descriptor\n", + regs.txdp & 0x3fffffff); DPRINTF(EthernetDesc, "txDescCache: link=%08x bufptr=%08x cmdsts=%08x extsts=%08x\n", txDescCache.link, txDescCache.bufptr, txDescCache.cmdsts, @@ -2177,7 +2270,12 @@ NSGigE::txKick() if (txDescCache.cmdsts & CMDSTS_INTR) devIntrPost(ISR_TXDESC); - txState = txAdvance; + if (!txEnable) { + DPRINTF(EthernetSM, "halting TX state machine\n"); + txState = txIdle; + goto exit; + } else + txState = txAdvance; break; case txAdvance: @@ -2206,7 +2304,6 @@ NSGigE::txKick() DPRINTF(EthernetSM, "entering next txState=%s\n", NsTxStateStrings[txState]); - goto next; exit: @@ -2215,6 +2312,110 @@ NSGigE::txKick() */ DPRINTF(EthernetSM, "tx state machine exited txState=%s\n", NsTxStateStrings[txState]); + + if (clock && !txKickEvent.scheduled()) + txKickEvent.schedule(txKickTick); +} + +/** + * Advance the EEPROM state machine + * Called on rising edge of EEPROM clock bit in MEAR + */ +void +NSGigE::eepromKick() +{ + switch (eepromState) { + + case eepromStart: + + // Wait for start bit + if (regs.mear & MEAR_EEDI) { + // Set up to get 2 opcode bits + eepromState = eepromGetOpcode; + eepromBitsToRx = 2; + eepromOpcode = 0; + } + break; + + case eepromGetOpcode: + eepromOpcode <<= 1; + eepromOpcode += (regs.mear & MEAR_EEDI) ? 1 : 0; + --eepromBitsToRx; + + // Done getting opcode + if (eepromBitsToRx == 0) { + if (eepromOpcode != EEPROM_READ) + panic("only EEPROM reads are implemented!"); + + // Set up to get address + eepromState = eepromGetAddress; + eepromBitsToRx = 6; + eepromAddress = 0; + } + break; + + case eepromGetAddress: + eepromAddress <<= 1; + eepromAddress += (regs.mear & MEAR_EEDI) ? 1 : 0; + --eepromBitsToRx; + + // Done getting address + if (eepromBitsToRx == 0) { + + if (eepromAddress >= EEPROM_SIZE) + panic("EEPROM read access out of range!"); + + switch (eepromAddress) { + + case EEPROM_PMATCH2_ADDR: + eepromData = rom.perfectMatch[5]; + eepromData <<= 8; + eepromData += rom.perfectMatch[4]; + break; + + case EEPROM_PMATCH1_ADDR: + eepromData = rom.perfectMatch[3]; + eepromData <<= 8; + eepromData += rom.perfectMatch[2]; + break; + + case EEPROM_PMATCH0_ADDR: + eepromData = rom.perfectMatch[1]; + eepromData <<= 8; + eepromData += rom.perfectMatch[0]; + break; + + default: + panic("FreeBSD driver only uses EEPROM to read PMATCH!"); + } + // Set up to read data + eepromState = eepromRead; + eepromBitsToRx = 16; + + // Clear data in bit + regs.mear &= ~MEAR_EEDI; + } + break; + + case eepromRead: + // Clear Data Out bit + regs.mear &= ~MEAR_EEDO; + // Set bit to value of current EEPROM bit + regs.mear |= (eepromData & 0x8000) ? MEAR_EEDO : 0x0; + + eepromData <<= 1; + --eepromBitsToRx; + + // All done + if (eepromBitsToRx == 0) { + eepromState = eepromStart; + } + break; + + default: + panic("invalid EEPROM state"); + } + } void @@ -2228,9 +2429,9 @@ NSGigE::transferDone() DPRINTF(Ethernet, "transfer complete: data in txFifo...schedule xmit\n"); if (txEvent.scheduled()) - txEvent.reschedule(curTick + 1); + txEvent.reschedule(curTick + cycles(1)); else - txEvent.schedule(curTick + 1); + txEvent.schedule(curTick + cycles(1)); } bool @@ -2263,6 +2464,9 @@ NSGigE::rxFilter(const PacketPtr &packet) if (acceptMulticast) drop = false; + // Multicast hashing faked - all packets accepted + if (multicastHashEnable) + drop = false; } if (drop) { @@ -2284,20 +2488,36 @@ NSGigE::recvPacket(PacketPtr packet) if (!rxEnable) { DPRINTF(Ethernet, "receive disabled...packet dropped\n"); - debug_break(); interface->recvDone(); return true; } - if (rxFilterEnable && rxFilter(packet)) { + if (!rxFilterEnable) { + DPRINTF(Ethernet, + "receive packet filtering disabled . . . packet dropped\n"); + interface->recvDone(); + return true; + } + + if (rxFilter(packet)) { DPRINTF(Ethernet, "packet filtered...dropped\n"); interface->recvDone(); return true; } if (rxFifo.avail() < packet->length) { - DPRINTF(Ethernet, - "packet will not fit in receive buffer...packet dropped\n"); +#if TRACING_ON + IpPtr ip(packet); + TcpPtr tcp(ip); + if (ip) { + DPRINTF(Ethernet, + "packet won't fit in receive buffer...pkt ID %d dropped\n", + ip->id()); + if (tcp) { + DPRINTF(Ethernet, "Seq=%d\n", tcp->seq()); + } + } +#endif droppedPackets++; devIntrPost(ISR_RXORN); return false; @@ -2354,6 +2574,8 @@ NSGigE::serialize(ostream &os) SERIALIZE_SCALAR(regs.pcr); SERIALIZE_SCALAR(regs.rfcr); SERIALIZE_SCALAR(regs.rfdr); + SERIALIZE_SCALAR(regs.brar); + SERIALIZE_SCALAR(regs.brdr); SERIALIZE_SCALAR(regs.srr); SERIALIZE_SCALAR(regs.mibc); SERIALIZE_SCALAR(regs.vrcr); @@ -2368,6 +2590,7 @@ NSGigE::serialize(ostream &os) SERIALIZE_SCALAR(regs.tesr); SERIALIZE_ARRAY(rom.perfectMatch, ETH_ADDR_LEN); + SERIALIZE_ARRAY(rom.filterHash, FHASH_SIZE); SERIALIZE_SCALAR(ioEnable); @@ -2383,6 +2606,7 @@ NSGigE::serialize(ostream &os) bool txPacketExists = txPacket; SERIALIZE_SCALAR(txPacketExists); if (txPacketExists) { + txPacket->length = txPacketBufPtr - txPacket->data; txPacket->serialize("txPacket", os); uint32_t txPktBufPtr = (uint32_t) (txPacketBufPtr - txPacket->data); SERIALIZE_SCALAR(txPktBufPtr); @@ -2410,6 +2634,7 @@ NSGigE::serialize(ostream &os) SERIALIZE_SCALAR(rxDescCache.bufptr); SERIALIZE_SCALAR(rxDescCache.cmdsts); SERIALIZE_SCALAR(rxDescCache.extsts); + SERIALIZE_SCALAR(extstsEnable); /* * Serialize tx state machine @@ -2422,6 +2647,7 @@ NSGigE::serialize(ostream &os) SERIALIZE_SCALAR(txDescCnt); int txDmaState = this->txDmaState; SERIALIZE_SCALAR(txDmaState); + SERIALIZE_SCALAR(txKickTick); /* * Serialize rx state machine @@ -2435,8 +2661,18 @@ NSGigE::serialize(ostream &os) SERIALIZE_SCALAR(rxDescCnt); int rxDmaState = this->rxDmaState; SERIALIZE_SCALAR(rxDmaState); + SERIALIZE_SCALAR(rxKickTick); - SERIALIZE_SCALAR(extstsEnable); + /* + * Serialize EEPROM state machine + */ + int eepromState = this->eepromState; + SERIALIZE_SCALAR(eepromState); + SERIALIZE_SCALAR(eepromClk); + SERIALIZE_SCALAR(eepromBitsToRx); + SERIALIZE_SCALAR(eepromOpcode); + SERIALIZE_SCALAR(eepromAddress); + SERIALIZE_SCALAR(eepromData); /* * If there's a pending transmit, store the time so we can @@ -2454,6 +2690,7 @@ NSGigE::serialize(ostream &os) SERIALIZE_SCALAR(acceptUnicast); SERIALIZE_SCALAR(acceptPerfect); SERIALIZE_SCALAR(acceptArp); + SERIALIZE_SCALAR(multicastHashEnable); /* * Keep track of pending interrupt status. @@ -2493,6 +2730,8 @@ NSGigE::unserialize(Checkpoint *cp, const std::string §ion) UNSERIALIZE_SCALAR(regs.pcr); UNSERIALIZE_SCALAR(regs.rfcr); UNSERIALIZE_SCALAR(regs.rfdr); + UNSERIALIZE_SCALAR(regs.brar); + UNSERIALIZE_SCALAR(regs.brdr); UNSERIALIZE_SCALAR(regs.srr); UNSERIALIZE_SCALAR(regs.mibc); UNSERIALIZE_SCALAR(regs.vrcr); @@ -2507,6 +2746,7 @@ NSGigE::unserialize(Checkpoint *cp, const std::string §ion) UNSERIALIZE_SCALAR(regs.tesr); UNSERIALIZE_ARRAY(rom.perfectMatch, ETH_ADDR_LEN); + UNSERIALIZE_ARRAY(rom.filterHash, FHASH_SIZE); UNSERIALIZE_SCALAR(ioEnable); @@ -2556,6 +2796,7 @@ NSGigE::unserialize(Checkpoint *cp, const std::string §ion) UNSERIALIZE_SCALAR(rxDescCache.bufptr); UNSERIALIZE_SCALAR(rxDescCache.cmdsts); UNSERIALIZE_SCALAR(rxDescCache.extsts); + UNSERIALIZE_SCALAR(extstsEnable); /* * unserialize tx state machine @@ -2570,6 +2811,9 @@ NSGigE::unserialize(Checkpoint *cp, const std::string §ion) int txDmaState; UNSERIALIZE_SCALAR(txDmaState); this->txDmaState = (DmaState) txDmaState; + UNSERIALIZE_SCALAR(txKickTick); + if (txKickTick) + txKickEvent.schedule(txKickTick); /* * unserialize rx state machine @@ -2585,10 +2829,23 @@ NSGigE::unserialize(Checkpoint *cp, const std::string §ion) int rxDmaState; UNSERIALIZE_SCALAR(rxDmaState); this->rxDmaState = (DmaState) rxDmaState; + UNSERIALIZE_SCALAR(rxKickTick); + if (rxKickTick) + rxKickEvent.schedule(rxKickTick); - UNSERIALIZE_SCALAR(extstsEnable); + /* + * Unserialize EEPROM state machine + */ + int eepromState; + UNSERIALIZE_SCALAR(eepromState); + this->eepromState = (EEPROMState) eepromState; + UNSERIALIZE_SCALAR(eepromClk); + UNSERIALIZE_SCALAR(eepromBitsToRx); + UNSERIALIZE_SCALAR(eepromOpcode); + UNSERIALIZE_SCALAR(eepromAddress); + UNSERIALIZE_SCALAR(eepromData); - /* + /* * If there's a pending transmit, reschedule it now */ Tick transmitTick; @@ -2605,6 +2862,7 @@ NSGigE::unserialize(Checkpoint *cp, const std::string §ion) UNSERIALIZE_SCALAR(acceptUnicast); UNSERIALIZE_SCALAR(acceptPerfect); UNSERIALIZE_SCALAR(acceptArp); + UNSERIALIZE_SCALAR(multicastHashEnable); /* * Keep track of pending interrupt status. @@ -2668,6 +2926,7 @@ REGISTER_SIM_OBJECT("NSGigEInt", NSGigEInt) BEGIN_DECLARE_SIM_OBJECT_PARAMS(NSGigE) Param addr; + Param clock; Param tx_delay; Param rx_delay; Param intr_delay; @@ -2693,20 +2952,22 @@ BEGIN_DECLARE_SIM_OBJECT_PARAMS(NSGigE) Param pci_func; Param tx_fifo_size; Param rx_fifo_size; + Param m5reg; + Param dma_no_allocate; END_DECLARE_SIM_OBJECT_PARAMS(NSGigE) BEGIN_INIT_SIM_OBJECT_PARAMS(NSGigE) INIT_PARAM(addr, "Device Address"), - INIT_PARAM_DFLT(tx_delay, "Transmit Delay", 1000), - INIT_PARAM_DFLT(rx_delay, "Receive Delay", 1000), - INIT_PARAM_DFLT(intr_delay, "Interrupt Delay in microseconds", 0), + INIT_PARAM(clock, "State machine processor frequency"), + INIT_PARAM(tx_delay, "Transmit Delay"), + INIT_PARAM(rx_delay, "Receive Delay"), + INIT_PARAM(intr_delay, "Interrupt Delay in microseconds"), INIT_PARAM(mmu, "Memory Controller"), INIT_PARAM(physmem, "Physical Memory"), INIT_PARAM_DFLT(rx_filter, "Enable Receive Filter", true), - INIT_PARAM_DFLT(hardware_address, "Ethernet Hardware Address", - "00:99:00:00:00:01"), + INIT_PARAM(hardware_address, "Ethernet Hardware Address"), INIT_PARAM_DFLT(io_bus, "The IO Bus to attach to for headers", NULL), INIT_PARAM_DFLT(payload_bus, "The IO Bus to attach to for payload", NULL), INIT_PARAM_DFLT(hier, "Hierarchy global variables", &defaultHierParams), @@ -2724,7 +2985,9 @@ BEGIN_INIT_SIM_OBJECT_PARAMS(NSGigE) INIT_PARAM(pci_dev, "PCI device number"), INIT_PARAM(pci_func, "PCI function code"), INIT_PARAM_DFLT(tx_fifo_size, "max size in bytes of txFifo", 131072), - INIT_PARAM_DFLT(rx_fifo_size, "max size in bytes of rxFifo", 131072) + INIT_PARAM_DFLT(rx_fifo_size, "max size in bytes of rxFifo", 131072), + INIT_PARAM(m5reg, "m5 register"), + INIT_PARAM_DFLT(dma_no_allocate, "Should DMA reads allocate cache lines", true) END_INIT_SIM_OBJECT_PARAMS(NSGigE) @@ -2742,6 +3005,7 @@ CREATE_SIM_OBJECT(NSGigE) params->deviceNum = pci_dev; params->functionNum = pci_func; + params->clock = clock; params->intr_delay = intr_delay; params->pmem = physmem; params->tx_delay = tx_delay; @@ -2760,6 +3024,8 @@ CREATE_SIM_OBJECT(NSGigE) params->eaddr = hardware_address; params->tx_fifo_size = tx_fifo_size; params->rx_fifo_size = rx_fifo_size; + params->m5reg = m5reg; + params->dma_no_allocate = dma_no_allocate; return new NSGigE(params); }