X-Git-Url: https://git.libre-soc.org/?a=blobdiff_plain;f=dev%2Fns_gige.cc;h=9010850ab8a67cc1e09c497d768cbf1540cc0022;hb=1166d4f0bfe67a9dc178be3454b4f0eac38663ad;hp=7260ecde49698ba32c2f0feb14987034ffc04bcf;hpb=3402411661caff075890c20a6c59fa471d5e68ac;p=gem5.git diff --git a/dev/ns_gige.cc b/dev/ns_gige.cc index 7260ecde4..9010850ab 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,22 +36,19 @@ #include "base/inet.hh" #include "cpu/exec_context.hh" -#include "cpu/intr_control.hh" -#include "dev/dma.hh" #include "dev/etherlink.hh" #include "dev/ns_gige.hh" #include "dev/pciconfigall.hh" -#include "dev/tsunami_cchip.hh" #include "mem/bus/bus.hh" #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" -#include "sim/sim_stats.hh" +#include "sim/stats.hh" #include "targetarch/vtophys.hh" const char *NsRxStateStrings[] = @@ -86,77 +83,68 @@ const char *NsDmaState[] = }; using namespace std; - +using namespace Net; /////////////////////////////////////////////////////////////////////// // // NSGigE PCI Device // -NSGigE::NSGigE(const std::string &name, IntrControl *i, Tick intr_delay, - PhysicalMemory *pmem, Tick tx_delay, Tick rx_delay, - MemoryController *mmu, HierParams *hier, Bus *header_bus, - Bus *payload_bus, Tick pio_latency, bool dma_desc_free, - bool dma_data_free, Tick dma_read_delay, Tick dma_write_delay, - Tick dma_read_factor, Tick dma_write_factor, PciConfigAll *cf, - PciConfigData *cd, Tsunami *t, uint32_t bus, uint32_t dev, - uint32_t func, bool rx_filter, const int eaddr[6], - uint32_t tx_fifo_size, uint32_t rx_fifo_size) - : PciDev(name, mmu, cf, cd, bus, dev, func), tsunami(t), ioEnable(false), - maxTxFifoSize(tx_fifo_size), maxRxFifoSize(rx_fifo_size), +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), txFifoAvail(tx_fifo_size), + 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), rxFifoCnt(0), + 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(dma_desc_free), dmaDataFree(dma_data_free), - txDelay(tx_delay), rxDelay(rx_delay), rxKickTick(0), txKickTick(0), - txEvent(this), rxFilterEnable(rx_filter), acceptBroadcast(false), + dmaDescFree(p->dma_desc_free), dmaDataFree(p->dma_data_free), + txDelay(p->tx_delay), rxDelay(p->rx_delay), + rxKickTick(0), rxKickEvent(this), txKickTick(0), txKickEvent(this), + txEvent(this), rxFilterEnable(p->rx_filter), acceptBroadcast(false), acceptMulticast(false), acceptUnicast(false), - acceptPerfect(false), acceptArp(false), - physmem(pmem), intctrl(i), intrTick(0), cpuPendingIntr(false), + acceptPerfect(false), acceptArp(false), multicastHashEnable(false), + physmem(p->pmem), intrTick(0), cpuPendingIntr(false), intrEvent(0), interface(0) { - tsunami->ethernet = this; - - if (header_bus) { - pioInterface = newPioInterface(name, hier, header_bus, this, + if (p->pio_bus) { + pioInterface = newPioInterface(name() + ".pio", p->hier, + p->pio_bus, this, &NSGigE::cacheAccess); + pioLatency = p->pio_latency * p->pio_bus->clockRate; + } - pioLatency = pio_latency * header_bus->clockRatio; - - if (payload_bus) - dmaInterface = new DMAInterface(name + ".dma", - header_bus, payload_bus, 1); + if (p->header_bus) { + if (p->payload_bus) + dmaInterface = new DMAInterface(name() + ".dma", + p->header_bus, + p->payload_bus, 1, + p->dma_no_allocate); else - dmaInterface = new DMAInterface(name + ".dma", - header_bus, header_bus, 1); - } else if (payload_bus) { - pioInterface = newPioInterface(name, hier, payload_bus, this, - &NSGigE::cacheAccess); + dmaInterface = new DMAInterface(name() + ".dma", + p->header_bus, + p->header_bus, 1, + p->dma_no_allocate); + } else if (p->payload_bus) + panic("Must define a header bus if defining a payload bus"); - pioLatency = pio_latency * payload_bus->clockRatio; + pioDelayWrite = p->pio_delay_write && pioInterface; - dmaInterface = new DMAInterface(name + ".dma", payload_bus, - payload_bus, 1); - } - - - intrDelay = US2Ticks(intr_delay); - dmaReadDelay = dma_read_delay; - dmaWriteDelay = dma_write_delay; - dmaReadFactor = dma_read_factor; - dmaWriteFactor = dma_write_factor; + intrDelay = p->intr_delay; + dmaReadDelay = p->dma_read_delay; + dmaWriteDelay = p->dma_write_delay; + dmaReadFactor = p->dma_read_factor; + dmaWriteFactor = p->dma_write_factor; regsReset(); - rom.perfectMatch[0] = eaddr[0]; - rom.perfectMatch[1] = eaddr[1]; - rom.perfectMatch[2] = eaddr[2]; - rom.perfectMatch[3] = eaddr[3]; - rom.perfectMatch[4] = eaddr[4]; - rom.perfectMatch[5] = eaddr[5]; + memcpy(&rom.perfectMatch, p->eaddr.bytes(), ETH_ADDR_LEN); + + memset(&rxDesc32, 0, sizeof(rxDesc32)); + memset(&txDesc32, 0, sizeof(txDesc32)); + memset(&rxDesc64, 0, sizeof(rxDesc64)); + memset(&txDesc64, 0, sizeof(txDesc64)); } NSGigE::~NSGigE() @@ -255,7 +243,6 @@ NSGigE::regStats() .precision(0) ; - txBandwidth .name(name() + ".txBandwidth") .desc("Transmit Bandwidth (bits/s)") @@ -270,6 +257,34 @@ NSGigE::regStats() .prereq(rxBytes) ; + totBandwidth + .name(name() + ".totBandwidth") + .desc("Total Bandwidth (bits/s)") + .precision(0) + .prereq(totBytes) + ; + + totPackets + .name(name() + ".totPackets") + .desc("Total Packets") + .precision(0) + .prereq(totBytes) + ; + + totBytes + .name(name() + ".totBytes") + .desc("Total Bytes") + .precision(0) + .prereq(totBytes) + ; + + totPacketRate + .name(name() + ".totPPS") + .desc("Total Tranmission Rate (packets/s)") + .precision(0) + .prereq(totBytes) + ; + txPacketRate .name(name() + ".txPPS") .desc("Packet Tranmission Rate (packets/s)") @@ -284,8 +299,187 @@ NSGigE::regStats() .prereq(rxBytes) ; + postedSwi + .name(name() + ".postedSwi") + .desc("number of software interrupts posted to CPU") + .precision(0) + ; + + totalSwi + .name(name() + ".totalSwi") + .desc("total number of Swi written to ISR") + .precision(0) + ; + + coalescedSwi + .name(name() + ".coalescedSwi") + .desc("average number of Swi's coalesced into each post") + .precision(0) + ; + + postedRxIdle + .name(name() + ".postedRxIdle") + .desc("number of rxIdle interrupts posted to CPU") + .precision(0) + ; + + totalRxIdle + .name(name() + ".totalRxIdle") + .desc("total number of RxIdle written to ISR") + .precision(0) + ; + + coalescedRxIdle + .name(name() + ".coalescedRxIdle") + .desc("average number of RxIdle's coalesced into each post") + .precision(0) + ; + + postedRxOk + .name(name() + ".postedRxOk") + .desc("number of RxOk interrupts posted to CPU") + .precision(0) + ; + + totalRxOk + .name(name() + ".totalRxOk") + .desc("total number of RxOk written to ISR") + .precision(0) + ; + + coalescedRxOk + .name(name() + ".coalescedRxOk") + .desc("average number of RxOk's coalesced into each post") + .precision(0) + ; + + postedRxDesc + .name(name() + ".postedRxDesc") + .desc("number of RxDesc interrupts posted to CPU") + .precision(0) + ; + + totalRxDesc + .name(name() + ".totalRxDesc") + .desc("total number of RxDesc written to ISR") + .precision(0) + ; + + coalescedRxDesc + .name(name() + ".coalescedRxDesc") + .desc("average number of RxDesc's coalesced into each post") + .precision(0) + ; + + postedTxOk + .name(name() + ".postedTxOk") + .desc("number of TxOk interrupts posted to CPU") + .precision(0) + ; + + totalTxOk + .name(name() + ".totalTxOk") + .desc("total number of TxOk written to ISR") + .precision(0) + ; + + coalescedTxOk + .name(name() + ".coalescedTxOk") + .desc("average number of TxOk's coalesced into each post") + .precision(0) + ; + + postedTxIdle + .name(name() + ".postedTxIdle") + .desc("number of TxIdle interrupts posted to CPU") + .precision(0) + ; + + totalTxIdle + .name(name() + ".totalTxIdle") + .desc("total number of TxIdle written to ISR") + .precision(0) + ; + + coalescedTxIdle + .name(name() + ".coalescedTxIdle") + .desc("average number of TxIdle's coalesced into each post") + .precision(0) + ; + + postedTxDesc + .name(name() + ".postedTxDesc") + .desc("number of TxDesc interrupts posted to CPU") + .precision(0) + ; + + totalTxDesc + .name(name() + ".totalTxDesc") + .desc("total number of TxDesc written to ISR") + .precision(0) + ; + + coalescedTxDesc + .name(name() + ".coalescedTxDesc") + .desc("average number of TxDesc's coalesced into each post") + .precision(0) + ; + + postedRxOrn + .name(name() + ".postedRxOrn") + .desc("number of RxOrn posted to CPU") + .precision(0) + ; + + totalRxOrn + .name(name() + ".totalRxOrn") + .desc("total number of RxOrn written to ISR") + .precision(0) + ; + + coalescedRxOrn + .name(name() + ".coalescedRxOrn") + .desc("average number of RxOrn's coalesced into each post") + .precision(0) + ; + + coalescedTotal + .name(name() + ".coalescedTotal") + .desc("average number of interrupts coalesced into each post") + .precision(0) + ; + + postedInterrupts + .name(name() + ".postedInterrupts") + .desc("number of posts to CPU") + .precision(0) + ; + + droppedPackets + .name(name() + ".droppedPackets") + .desc("number of packets dropped") + .precision(0) + ; + + coalescedSwi = totalSwi / postedInterrupts; + coalescedRxIdle = totalRxIdle / postedInterrupts; + coalescedRxOk = totalRxOk / postedInterrupts; + coalescedRxDesc = totalRxDesc / postedInterrupts; + coalescedTxOk = totalTxOk / postedInterrupts; + coalescedTxIdle = totalTxIdle / postedInterrupts; + coalescedTxDesc = totalTxDesc / postedInterrupts; + coalescedRxOrn = totalRxOrn / postedInterrupts; + + coalescedTotal = (totalSwi + totalRxIdle + totalRxOk + totalRxDesc + + totalTxOk + totalTxIdle + totalTxDesc + + totalRxOrn) / postedInterrupts; + txBandwidth = txBytes * Stats::constant(8) / simSeconds; rxBandwidth = rxBytes * Stats::constant(8) / simSeconds; + totBandwidth = txBandwidth + rxBandwidth; + totBytes = txBytes + rxBytes; + totPackets = txPackets + rxPackets; + txPacketRate = txPackets / simSeconds; rxPacketRate = rxPackets / simSeconds; } @@ -294,10 +488,10 @@ NSGigE::regStats() * This is to read the PCI general configuration registers */ void -NSGigE::ReadConfig(int offset, int size, uint8_t *data) +NSGigE::readConfig(int offset, int size, uint8_t *data) { if (offset < PCI_DEVICE_SPECIFIC) - PciDev::ReadConfig(offset, size, data); + PciDev::readConfig(offset, size, data); else panic("Device specific PCI config space not implemented!\n"); } @@ -306,10 +500,10 @@ NSGigE::ReadConfig(int offset, int size, uint8_t *data) * This is to write to the PCI general configuration registers */ void -NSGigE::WriteConfig(int offset, int size, uint32_t data) +NSGigE::writeConfig(int offset, int size, const uint8_t* data) { if (offset < PCI_DEVICE_SPECIFIC) - PciDev::WriteConfig(offset, size, data); + PciDev::writeConfig(offset, size, data); else panic("Device specific PCI config space not implemented!\n"); @@ -344,19 +538,17 @@ NSGigE::WriteConfig(int offset, int size, uint32_t data) case PCI0_BASE_ADDR0: if (BARAddrs[0] != 0) { if (pioInterface) - pioInterface->addAddrRange(BARAddrs[0], - BARAddrs[0] + BARSize[0] - 1); + pioInterface->addAddrRange(RangeSize(BARAddrs[0], BARSize[0])); - BARAddrs[0] &= PA_UNCACHED_MASK; + BARAddrs[0] &= EV5::PAddrUncachedMask; } break; case PCI0_BASE_ADDR1: if (BARAddrs[1] != 0) { if (pioInterface) - pioInterface->addAddrRange(BARAddrs[1], - BARAddrs[1] + BARSize[1] - 1); + pioInterface->addAddrRange(RangeSize(BARAddrs[1], BARSize[1])); - BARAddrs[1] &= PA_UNCACHED_MASK; + BARAddrs[1] &= EV5::PAddrUncachedMask; } break; } @@ -382,7 +574,7 @@ NSGigE::read(MemReqPtr &req, uint8_t *data) if (daddr > LAST && daddr <= RESERVED) { panic("Accessing reserved register"); } else if (daddr > RESERVED && daddr <= 0x3FC) { - ReadConfig(daddr & 0xff, req->size, data); + readConfig(daddr & 0xff, req->size, data); return No_Fault; } else if (daddr >= MIB_START && daddr <= MIB_END) { // don't implement all the MIB's. hopefully the kernel @@ -398,6 +590,7 @@ NSGigE::read(MemReqPtr &req, uint8_t *data) case sizeof(uint32_t): { uint32_t ® = *(uint32_t *)data; + uint16_t rfaddr; switch (daddr) { case CR: @@ -406,7 +599,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; @@ -443,7 +636,7 @@ NSGigE::read(MemReqPtr &req, uint8_t *data) reg = regs.txdp_hi; break; - case TXCFG: + case TX_CFG: reg = regs.txcfg; break; @@ -459,7 +652,7 @@ NSGigE::read(MemReqPtr &req, uint8_t *data) reg = regs.rxdp_hi; break; - case RXCFG: + case RX_CFG: reg = regs.rxcfg; break; @@ -485,7 +678,9 @@ NSGigE::read(MemReqPtr &req, uint8_t *data) break; case RFDR: - switch (regs.rfcr & RFCR_RFADDR) { + rfaddr = (uint16_t)(regs.rfcr & RFCR_RFADDR); + switch (rfaddr) { + // Read from perfect match ROM octets case 0x000: reg = rom.perfectMatch[1]; reg = reg << 8; @@ -500,9 +695,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; @@ -555,6 +762,14 @@ NSGigE::read(MemReqPtr &req, uint8_t *data) reg = regs.tesr; break; + case M5REG: + reg = 0; + if (params()->rx_thread) + reg |= M5REG_RX_THREAD; + if (params()->tx_thread) + reg |= M5REG_TX_THREAD; + break; + default: panic("reading unimplemented register: addr=%#x", daddr); } @@ -584,13 +799,22 @@ NSGigE::write(MemReqPtr &req, const uint8_t *data) if (daddr > LAST && daddr <= RESERVED) { panic("Accessing reserved register"); } else if (daddr > RESERVED && daddr <= 0x3FC) { - WriteConfig(daddr & 0xff, req->size, *(uint32_t *)data); + writeConfig(daddr & 0xff, req->size, data); return No_Fault; } else if (daddr > 0x3FC) panic("Something is messed up!\n"); + if (pioDelayWrite) { + int cpu = (req->xc->regs.ipr[TheISA::IPR_PALtemp16] >> 8) & 0xff; + if (cpu >= writeQueue.size()) + writeQueue.resize(cpu + 1); + writeQueue[cpu].push_back(RegWriteData(daddr, *(uint32_t *)data)); + } + if (req->size == sizeof(uint32_t)) { uint32_t reg = *(uint32_t *)data; + uint16_t rfaddr; + DPRINTF(EthernetPIO, "write data=%d data=%#x\n", reg, reg); switch (daddr) { @@ -599,20 +823,24 @@ NSGigE::write(MemReqPtr &req, const uint8_t *data) if (reg & CR_TXD) { txEnable = false; } else if (reg & CR_TXE) { - txEnable = true; + if (!pioDelayWrite) { + txEnable = true; - // the kernel is enabling the transmit machine - if (txState == txIdle) - txKick(); + // the kernel is enabling the transmit machine + if (txState == txIdle) + txKick(); + } } if (reg & CR_RXD) { rxEnable = false; } else if (reg & CR_RXE) { - rxEnable = true; + if (!pioDelayWrite) { + rxEnable = true; - if (rxState == rxIdle) - rxKick(); + if (rxState == rxIdle) + rxKick(); + } } if (reg & CR_TXR) @@ -632,82 +860,91 @@ 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) ; -#endif + if (reg & CFGR_TBI_EN) ; + if (reg & CFGR_MODE_1000) ; - 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) ; -#endif + if (reg & CFGR_DATA64_EN) ; + if (reg & CFGR_M64ADDR) ; + if (reg & CFGR_PHY_RST) ; + if (reg & CFGR_PHY_DIS) ; - 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) ; -#endif + 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) ; 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) ; -#endif break; case PTSCR: @@ -749,14 +986,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 @@ -764,12 +1001,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 @@ -780,7 +1017,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; @@ -793,23 +1034,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; @@ -837,14 +1078,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"); @@ -852,10 +1093,41 @@ NSGigE::write(MemReqPtr &req, const uint8_t *data) break; case RFDR: - panic("the driver never writes to RFDR, something is wrong!\n"); + 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"); @@ -876,7 +1148,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 */ @@ -903,12 +1174,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: @@ -940,27 +1215,87 @@ NSGigE::devIntrPost(uint32_t interrupts) if (interrupts & ISR_NOIMPL) warn("interrupt not implemented %#x\n", interrupts); - interrupts &= ~ISR_NOIMPL; + interrupts &= ISR_IMPL; regs.isr |= interrupts; + if (interrupts & regs.imr) { + if (interrupts & ISR_SWI) { + totalSwi++; + } + if (interrupts & ISR_RXIDLE) { + totalRxIdle++; + } + if (interrupts & ISR_RXOK) { + totalRxOk++; + } + if (interrupts & ISR_RXDESC) { + totalRxDesc++; + } + if (interrupts & ISR_TXOK) { + totalTxOk++; + } + if (interrupts & ISR_TXIDLE) { + totalTxIdle++; + } + if (interrupts & ISR_TXDESC) { + totalTxDesc++; + } + if (interrupts & ISR_RXORN) { + totalRxOrn++; + } + } + DPRINTF(EthernetIntr, "interrupt written to ISR: intr=%#x isr=%#x imr=%#x\n", interrupts, regs.isr, regs.imr); if ((regs.isr & regs.imr)) { Tick when = curTick; - if (!(regs.isr & regs.imr & ISR_NODELAY)) + if ((regs.isr & regs.imr & ISR_NODELAY) == 0) when += intrDelay; cpuIntrPost(when); } } +/* writing this interrupt counting stats inside this means that this function + is now limited to being used to clear all interrupts upon the kernel + reading isr and servicing. just telling you in case you were thinking + of expanding use. +*/ void NSGigE::devIntrClear(uint32_t interrupts) { if (interrupts & ISR_RESERVE) panic("Cannot clear a reserved interrupt"); + if (regs.isr & regs.imr & ISR_SWI) { + postedSwi++; + } + if (regs.isr & regs.imr & ISR_RXIDLE) { + postedRxIdle++; + } + if (regs.isr & regs.imr & ISR_RXOK) { + postedRxOk++; + } + if (regs.isr & regs.imr & ISR_RXDESC) { + postedRxDesc++; + } + if (regs.isr & regs.imr & ISR_TXOK) { + postedTxOk++; + } + if (regs.isr & regs.imr & ISR_TXIDLE) { + postedTxIdle++; + } + if (regs.isr & regs.imr & ISR_TXDESC) { + postedTxDesc++; + } + if (regs.isr & regs.imr & ISR_RXORN) { + postedRxOrn++; + } + + if (regs.isr & regs.imr & ISR_IMPL) + postedInterrupts++; + interrupts &= ~ISR_NOIMPL; regs.isr &= ~interrupts; @@ -1037,8 +1372,8 @@ NSGigE::cpuInterrupt() // Send interrupt cpuPendingIntr = true; - DPRINTF(EthernetIntr, "posting cchip interrupt\n"); - tsunami->postPciInt(configData->config.hdr.pci0.interruptLine); + DPRINTF(EthernetIntr, "posting interrupt\n"); + intrPost(); } } @@ -1057,8 +1392,8 @@ NSGigE::cpuIntrClear() cpuPendingIntr = false; - DPRINTF(EthernetIntr, "clearing cchip interrupt\n"); - tsunami->clearPciInt(configData->config.hdr.pci0.interruptLine); + DPRINTF(EthernetIntr, "clearing interrupt\n"); + intrClear(); } bool @@ -1072,7 +1407,6 @@ NSGigE::txReset() DPRINTF(Ethernet, "transmit reset\n"); CTDD = false; - txFifoAvail = maxTxFifoSize; txEnable = false;; txFragPtr = 0; assert(txDescCnt == 0); @@ -1088,7 +1422,6 @@ NSGigE::rxReset() CRDD = false; assert(rxPktBytes == 0); - rxFifoCnt = 0; rxEnable = false; rxFragPtr = 0; assert(rxDescCnt == 0); @@ -1101,8 +1434,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 @@ -1110,6 +1443,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; @@ -1226,16 +1560,29 @@ NSGigE::rxDmaWriteDone() void NSGigE::rxKick() { - DPRINTF(EthernetSM, "receive kick rxState=%s (rxBuf.size=%d)\n", - NsRxStateStrings[rxState], rxFifo.size()); + bool is64bit = (bool)(regs.config & CFGR_M64ADDR); - if (rxKickTick > curTick) { - DPRINTF(EthernetSM, "receive kick exiting, can't run till %d\n", - rxKickTick); - return; - } + DPRINTF(EthernetSM, + "receive kick rxState=%s (rxBuf.size=%d) %d-bit\n", + NsRxStateStrings[rxState], rxFifo.size(), is64bit ? 64 : 32); + + Addr link, bufptr; + uint32_t &cmdsts = is64bit ? rxDesc64.cmdsts : rxDesc32.cmdsts; + uint32_t &extsts = is64bit ? rxDesc64.extsts : rxDesc32.extsts; 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); + } + switch(rxDmaState) { case dmaReadWaiting: if (doRxDmaRead()) @@ -1249,6 +1596,9 @@ NSGigE::rxKick() break; } + link = is64bit ? (Addr)rxDesc64.link : (Addr)rxDesc32.link; + bufptr = is64bit ? (Addr)rxDesc64.bufptr : (Addr)rxDesc32.bufptr; + // see state machine from spec for details // the way this works is, if you finish work on one state and can // go directly to another, you do that through jumping to the @@ -1267,8 +1617,9 @@ NSGigE::rxKick() rxState = rxDescRefr; rxDmaAddr = regs.rxdp & 0x3fffffff; - rxDmaData = &rxDescCache + offsetof(ns_desc, link); - rxDmaLen = sizeof(rxDescCache.link); + rxDmaData = + is64bit ? (void *)&rxDesc64.link : (void *)&rxDesc32.link; + rxDmaLen = is64bit ? sizeof(rxDesc64.link) : sizeof(rxDesc32.link); rxDmaFree = dmaDescFree; descDmaReads++; @@ -1280,8 +1631,8 @@ NSGigE::rxKick() rxState = rxDescRead; rxDmaAddr = regs.rxdp & 0x3fffffff; - rxDmaData = &rxDescCache; - rxDmaLen = sizeof(ns_desc); + rxDmaData = is64bit ? (void *)&rxDesc64 : (void *)&rxDesc32; + rxDmaLen = is64bit ? sizeof(rxDesc64) : sizeof(rxDesc32); rxDmaFree = dmaDescFree; descDmaReads++; @@ -1303,22 +1654,20 @@ NSGigE::rxKick() if (rxDmaState != dmaIdle) goto exit; - DPRINTF(EthernetDesc, - "rxDescCache: addr=%08x read descriptor\n", + DPRINTF(EthernetDesc, "rxDesc: addr=%08x read descriptor\n", regs.rxdp & 0x3fffffff); DPRINTF(EthernetDesc, - "rxDescCache: link=%08x bufptr=%08x cmdsts=%08x extsts=%08x\n", - rxDescCache.link, rxDescCache.bufptr, rxDescCache.cmdsts, - rxDescCache.extsts); + "rxDesc: link=%#x bufptr=%#x cmdsts=%08x extsts=%08x\n", + link, bufptr, cmdsts, extsts); - if (rxDescCache.cmdsts & CMDSTS_OWN) { + if (cmdsts & CMDSTS_OWN) { devIntrPost(ISR_RXIDLE); rxState = rxIdle; goto exit; } else { rxState = rxFifoBlock; - rxFragPtr = rxDescCache.bufptr; - rxDescCnt = rxDescCache.cmdsts & CMDSTS_LEN_MASK; + rxFragPtr = bufptr; + rxDescCnt = cmdsts & CMDSTS_LEN_MASK; } break; @@ -1341,13 +1690,15 @@ NSGigE::rxKick() #if TRACING_ON if (DTRACE(Ethernet)) { - const IpHdr *ip = rxPacket->ip(); + IpPtr ip(rxPacket); if (ip) { DPRINTF(Ethernet, "ID is %d\n", ip->id()); - const TcpHdr *tcp = rxPacket->tcp(); + 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()); } } } @@ -1355,12 +1706,7 @@ NSGigE::rxKick() // sanity check - i think the driver behaves like this assert(rxDescCnt >= rxPktBytes); - - // Must clear the value before popping to decrement the - // reference count - rxFifo.front() = NULL; - rxFifo.pop_front(); - rxFifoCnt -= rxPacket->length; + rxFifo.pop(); } @@ -1387,11 +1733,11 @@ NSGigE::rxKick() assert(rxPktBytes == 0); DPRINTF(EthernetSM, "done with receiving packet\n"); - rxDescCache.cmdsts |= CMDSTS_OWN; - rxDescCache.cmdsts &= ~CMDSTS_MORE; - rxDescCache.cmdsts |= CMDSTS_OK; - rxDescCache.cmdsts &= 0xffff0000; - rxDescCache.cmdsts += rxPacket->length; //i.e. set CMDSTS_SIZE + cmdsts |= CMDSTS_OWN; + cmdsts &= ~CMDSTS_MORE; + cmdsts |= CMDSTS_OK; + cmdsts &= 0xffff0000; + cmdsts += rxPacket->length; //i.e. set CMDSTS_SIZE #if 0 /* @@ -1402,39 +1748,41 @@ NSGigE::rxKick() * functional purposes, just undef */ if (rxFilterEnable) { - rxDescCache.cmdsts &= ~CMDSTS_DEST_MASK; - EthHdr *eth = rxFifoFront()->eth(); - if (eth->unicast()) - rxDescCache.cmdsts |= CMDSTS_DEST_SELF; - if (eth->multicast()) - rxDescCache.cmdsts |= CMDSTS_DEST_MULTI; - if (eth->broadcast()) - rxDescCache.cmdsts |= CMDSTS_DEST_MASK; + cmdsts &= ~CMDSTS_DEST_MASK; + const EthAddr &dst = rxFifoFront()->dst(); + if (dst->unicast()) + cmdsts |= CMDSTS_DEST_SELF; + if (dst->multicast()) + cmdsts |= CMDSTS_DEST_MULTI; + if (dst->broadcast()) + cmdsts |= CMDSTS_DEST_MASK; } #endif - if (extstsEnable && rxPacket->ip()) { - rxDescCache.extsts |= EXTSTS_IPPKT; + IpPtr ip(rxPacket); + if (extstsEnable && ip) { + extsts |= EXTSTS_IPPKT; rxIpChecksums++; - IpHdr *ip = rxPacket->ip(); - if (ip->ip_cksum() != 0) { + if (cksum(ip) != 0) { DPRINTF(EthernetCksum, "Rx IP Checksum Error\n"); - rxDescCache.extsts |= EXTSTS_IPERR; + extsts |= EXTSTS_IPERR; } - if (rxPacket->tcp()) { - rxDescCache.extsts |= EXTSTS_TCPPKT; + TcpPtr tcp(ip); + UdpPtr udp(ip); + if (tcp) { + extsts |= EXTSTS_TCPPKT; rxTcpChecksums++; - if (ip->tu_cksum() != 0) { + if (cksum(tcp) != 0) { DPRINTF(EthernetCksum, "Rx TCP Checksum Error\n"); - rxDescCache.extsts |= EXTSTS_TCPERR; + extsts |= EXTSTS_TCPERR; } - } else if (rxPacket->udp()) { - rxDescCache.extsts |= EXTSTS_UDPPKT; + } else if (udp) { + extsts |= EXTSTS_UDPPKT; rxUdpChecksums++; - if (ip->tu_cksum() != 0) { + if (cksum(udp) != 0) { DPRINTF(EthernetCksum, "Rx UDP Checksum Error\n"); - rxDescCache.extsts |= EXTSTS_UDPERR; + extsts |= EXTSTS_UDPERR; } } } @@ -1448,16 +1796,21 @@ NSGigE::rxKick() */ DPRINTF(EthernetDesc, - "rxDescCache: addr=%08x writeback cmdsts extsts\n", + "rxDesc: addr=%08x writeback cmdsts extsts\n", regs.rxdp & 0x3fffffff); DPRINTF(EthernetDesc, - "rxDescCache: link=%08x bufptr=%08x cmdsts=%08x extsts=%08x\n", - rxDescCache.link, rxDescCache.bufptr, rxDescCache.cmdsts, - rxDescCache.extsts); + "rxDesc: link=%#x bufptr=%#x cmdsts=%08x extsts=%08x\n", + link, bufptr, cmdsts, extsts); - rxDmaAddr = (regs.rxdp + offsetof(ns_desc, cmdsts)) & 0x3fffffff; - rxDmaData = &(rxDescCache.cmdsts); - rxDmaLen = sizeof(rxDescCache.cmdsts) + sizeof(rxDescCache.extsts); + rxDmaAddr = regs.rxdp & 0x3fffffff; + rxDmaData = &cmdsts; + if (is64bit) { + rxDmaAddr += offsetof(ns_desc64, cmdsts); + rxDmaLen = sizeof(rxDesc64.cmdsts) + sizeof(rxDesc64.extsts); + } else { + rxDmaAddr += offsetof(ns_desc32, cmdsts); + rxDmaLen = sizeof(rxDesc32.cmdsts) + sizeof(rxDesc32.extsts); + } rxDmaFree = dmaDescFree; descDmaWrites++; @@ -1483,12 +1836,12 @@ NSGigE::rxKick() if (rxDmaState != dmaIdle) goto exit; - assert(rxDescCache.cmdsts & CMDSTS_OWN); + assert(cmdsts & CMDSTS_OWN); assert(rxPacket == 0); devIntrPost(ISR_RXOK); - if (rxDescCache.cmdsts & CMDSTS_INTR) + if (cmdsts & CMDSTS_INTR) devIntrPost(ISR_RXDESC); if (!rxEnable) { @@ -1500,19 +1853,21 @@ NSGigE::rxKick() break; case rxAdvance: - if (rxDescCache.link == 0) { + if (link == 0) { devIntrPost(ISR_RXIDLE); rxState = rxIdle; CRDD = true; goto exit; } else { + if (rxDmaState != dmaIdle) + goto exit; rxState = rxDescRead; - regs.rxdp = rxDescCache.link; + regs.rxdp = link; CRDD = false; rxDmaAddr = regs.rxdp & 0x3fffffff; - rxDmaData = &rxDescCache; - rxDmaLen = sizeof(ns_desc); + rxDmaData = is64bit ? (void *)&rxDesc64 : (void *)&rxDesc32; + rxDmaLen = is64bit ? sizeof(rxDesc64) : sizeof(rxDesc32); rxDmaFree = dmaDescFree; if (doRxDmaRead()) @@ -1526,7 +1881,6 @@ NSGigE::rxKick() DPRINTF(EthernetSM, "entering next rxState=%s\n", NsRxStateStrings[rxState]); - goto next; exit: @@ -1535,6 +1889,9 @@ NSGigE::rxKick() */ DPRINTF(EthernetSM, "rx state machine exited rxState=%s\n", NsRxStateStrings[rxState]); + + if (clock && !rxKickEvent.scheduled()) + rxKickEvent.schedule(rxKickTick); } void @@ -1546,32 +1903,31 @@ NSGigE::transmit() } DPRINTF(Ethernet, "Attempt Pkt Transmit: txFifo length=%d\n", - maxTxFifoSize - txFifoAvail); + txFifo.size()); if (interface->sendPacket(txFifo.front())) { #if TRACING_ON if (DTRACE(Ethernet)) { - const IpHdr *ip = txFifo.front()->ip(); + IpPtr ip(txFifo.front()); if (ip) { DPRINTF(Ethernet, "ID is %d\n", ip->id()); - const TcpHdr *tcp = txFifo.front()->tcp(); + 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++; - txFifoAvail += txFifo.front()->length; - DPRINTF(Ethernet, "Successful Xmit! now txFifoAvail is %d\n", - txFifoAvail); - txFifo.front() = NULL; - txFifo.pop_front(); + txFifo.avail()); + txFifo.pop(); /* * normally do a writeback of the descriptor here, and ONLY @@ -1581,14 +1937,11 @@ NSGigE::transmit() * besides, it's functionally the same. */ devIntrPost(ISR_TXOK); - } else { - DPRINTF(Ethernet, - "May need to rethink always sending the descriptors back?\n"); } if (!txFifo.empty() && !txEvent.scheduled()) { DPRINTF(Ethernet, "reschedule transmit\n"); - txEvent.schedule(curTick + 1000); + txEvent.schedule(curTick + retryTime); } } @@ -1699,17 +2052,27 @@ NSGigE::txDmaWriteDone() void NSGigE::txKick() { - DPRINTF(EthernetSM, "transmit kick txState=%s\n", - NsTxStateStrings[txState]); + bool is64bit = (bool)(regs.config & CFGR_M64ADDR); - if (txKickTick > curTick) { - DPRINTF(EthernetSM, "transmit kick exiting, can't run till %d\n", - txKickTick); + DPRINTF(EthernetSM, "transmit kick txState=%s %d-bit\n", + NsTxStateStrings[txState], is64bit ? 64 : 32); - return; - } + Addr link, bufptr; + uint32_t &cmdsts = is64bit ? txDesc64.cmdsts : txDesc32.cmdsts; + uint32_t &extsts = is64bit ? txDesc64.extsts : txDesc32.extsts; next: + if (clock) { + if (txKickTick > curTick) { + DPRINTF(EthernetSM, "transmit kick exiting, can't run till %d\n", + txKickTick); + goto exit; + } + + // Go to the next state machine clock tick. + txKickTick = curTick + cycles(1); + } + switch(txDmaState) { case dmaReadWaiting: if (doTxDmaRead()) @@ -1723,6 +2086,8 @@ NSGigE::txKick() break; } + link = is64bit ? (Addr)txDesc64.link : (Addr)txDesc32.link; + bufptr = is64bit ? (Addr)txDesc64.bufptr : (Addr)txDesc32.bufptr; switch (txState) { case txIdle: if (!txEnable) { @@ -1734,8 +2099,9 @@ NSGigE::txKick() txState = txDescRefr; txDmaAddr = regs.txdp & 0x3fffffff; - txDmaData = &txDescCache + offsetof(ns_desc, link); - txDmaLen = sizeof(txDescCache.link); + txDmaData = + is64bit ? (void *)&txDesc64.link : (void *)&txDesc32.link; + txDmaLen = is64bit ? sizeof(txDesc64.link) : sizeof(txDesc32.link); txDmaFree = dmaDescFree; descDmaReads++; @@ -1748,8 +2114,8 @@ NSGigE::txKick() txState = txDescRead; txDmaAddr = regs.txdp & 0x3fffffff; - txDmaData = &txDescCache; - txDmaLen = sizeof(ns_desc); + txDmaData = is64bit ? (void *)&txDesc64 : (void *)&txDesc32; + txDmaLen = is64bit ? sizeof(txDesc64) : sizeof(txDesc32); txDmaFree = dmaDescFree; descDmaReads++; @@ -1771,15 +2137,16 @@ NSGigE::txKick() if (txDmaState != dmaIdle) goto exit; + DPRINTF(EthernetDesc, "txDesc: 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, - txDescCache.extsts); + "txDesc: link=%#x bufptr=%#x cmdsts=%#08x extsts=%#08x\n", + link, bufptr, cmdsts, extsts); - if (txDescCache.cmdsts & CMDSTS_OWN) { + if (cmdsts & CMDSTS_OWN) { txState = txFifoBlock; - txFragPtr = txDescCache.bufptr; - txDescCnt = txDescCache.cmdsts & CMDSTS_LEN_MASK; + txFragPtr = bufptr; + txDescCnt = cmdsts & CMDSTS_LEN_MASK; } else { devIntrPost(ISR_TXIDLE); txState = txIdle; @@ -1790,23 +2157,27 @@ NSGigE::txKick() case txFifoBlock: if (!txPacket) { DPRINTF(EthernetSM, "****starting the tx of a new packet****\n"); - txPacket = new PacketData; - txPacket->data = new uint8_t[16384]; + txPacket = new PacketData(16384); txPacketBufPtr = txPacket->data; } if (txDescCnt == 0) { DPRINTF(EthernetSM, "the txDescCnt == 0, done with descriptor\n"); - if (txDescCache.cmdsts & CMDSTS_MORE) { + if (cmdsts & CMDSTS_MORE) { DPRINTF(EthernetSM, "there are more descriptors to come\n"); txState = txDescWrite; - txDescCache.cmdsts &= ~CMDSTS_OWN; + cmdsts &= ~CMDSTS_OWN; - txDmaAddr = regs.txdp + offsetof(ns_desc, cmdsts); - txDmaAddr &= 0x3fffffff; - txDmaData = &(txDescCache.cmdsts); - txDmaLen = sizeof(txDescCache.cmdsts); + txDmaAddr = regs.txdp & 0x3fffffff; + txDmaData = &cmdsts; + if (is64bit) { + txDmaAddr += offsetof(ns_desc64, cmdsts); + txDmaLen = sizeof(txDesc64.cmdsts); + } else { + txDmaAddr += offsetof(ns_desc32, cmdsts); + txDmaLen = sizeof(txDesc32.cmdsts); + } txDmaFree = dmaDescFree; if (doTxDmaWrite()) @@ -1816,21 +2187,21 @@ NSGigE::txKick() DPRINTF(EthernetSM, "This packet is done, let's wrap it up\n"); /* deal with the the packet that just finished */ if ((regs.vtcr & VTCR_PPCHK) && extstsEnable) { - IpHdr *ip = txPacket->ip(); - if (txDescCache.extsts & EXTSTS_UDPPKT) { - UdpHdr *udp = txPacket->udp(); + IpPtr ip(txPacket); + if (extsts & EXTSTS_UDPPKT) { + UdpPtr udp(ip); udp->sum(0); - udp->sum(ip->tu_cksum()); + udp->sum(cksum(udp)); txUdpChecksums++; - } else if (txDescCache.extsts & EXTSTS_TCPPKT) { - TcpHdr *tcp = txPacket->tcp(); + } else if (extsts & EXTSTS_TCPPKT) { + TcpPtr tcp(ip); tcp->sum(0); - tcp->sum(ip->tu_cksum()); + tcp->sum(cksum(tcp)); txTcpChecksums++; } - if (txDescCache.extsts & EXTSTS_IPPKT) { + if (extsts & EXTSTS_IPPKT) { ip->sum(0); - ip->sum(ip->ip_cksum()); + ip->sum(cksum(ip)); txIpChecksums++; } } @@ -1838,8 +2209,15 @@ NSGigE::txKick() txPacket->length = txPacketBufPtr - txPacket->data; // this is just because the receive can't handle a // packet bigger want to make sure - assert(txPacket->length <= 1514); - txFifo.push_back(txPacket); + if (txPacket->length > 1514) + panic("transmit packet too large, %s > 1514\n", + txPacket->length); + +#ifndef NDEBUG + bool success = +#endif + txFifo.push(txPacket); + assert(success); /* * this following section is not tqo spec, but @@ -1853,19 +2231,25 @@ NSGigE::txKick() * spec would complicate the code, we just do it here */ - txDescCache.cmdsts &= ~CMDSTS_OWN; - txDescCache.cmdsts |= CMDSTS_OK; + cmdsts &= ~CMDSTS_OWN; + cmdsts |= CMDSTS_OK; DPRINTF(EthernetDesc, "txDesc writeback: cmdsts=%08x extsts=%08x\n", - txDescCache.cmdsts, txDescCache.extsts); + cmdsts, extsts); - txDmaAddr = regs.txdp + offsetof(ns_desc, cmdsts); - txDmaAddr &= 0x3fffffff; - txDmaData = &(txDescCache.cmdsts); - txDmaLen = sizeof(txDescCache.cmdsts) + - sizeof(txDescCache.extsts); txDmaFree = dmaDescFree; + txDmaAddr = regs.txdp & 0x3fffffff; + txDmaData = &cmdsts; + if (is64bit) { + txDmaAddr += offsetof(ns_desc64, cmdsts); + txDmaLen = + sizeof(txDesc64.cmdsts) + sizeof(txDesc64.extsts); + } else { + txDmaAddr += offsetof(ns_desc32, cmdsts); + txDmaLen = + sizeof(txDesc32.cmdsts) + sizeof(txDesc32.extsts); + } descDmaWrites++; descDmaWrBytes += txDmaLen; @@ -1885,7 +2269,7 @@ NSGigE::txKick() } } else { DPRINTF(EthernetSM, "this descriptor isn't done yet\n"); - if (txFifoAvail) { + if (!txFifo.full()) { txState = txFragRead; /* @@ -1894,7 +2278,7 @@ NSGigE::txKick() * is not enough room in the fifo, just whatever room * is left in the fifo */ - txXferLen = min(txDescCnt, txFifoAvail); + txXferLen = min(txDescCnt, txFifo.avail()); txDmaAddr = txFragPtr & 0x3fffffff; txDmaData = txPacketBufPtr; @@ -1920,7 +2304,7 @@ NSGigE::txKick() txPacketBufPtr += txXferLen; txFragPtr += txXferLen; txDescCnt -= txXferLen; - txFifoAvail -= txXferLen; + txFifo.reserve(txXferLen); txState = txFifoBlock; break; @@ -1929,25 +2313,32 @@ NSGigE::txKick() if (txDmaState != dmaIdle) goto exit; - if (txDescCache.cmdsts & CMDSTS_INTR) + if (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: - if (txDescCache.link == 0) { + if (link == 0) { devIntrPost(ISR_TXIDLE); txState = txIdle; goto exit; } else { + if (txDmaState != dmaIdle) + goto exit; txState = txDescRead; - regs.txdp = txDescCache.link; + regs.txdp = link; CTDD = false; - txDmaAddr = txDescCache.link & 0x3fffffff; - txDmaData = &txDescCache; - txDmaLen = sizeof(ns_desc); + txDmaAddr = link & 0x3fffffff; + txDmaData = is64bit ? (void *)&txDesc64 : (void *)&txDesc32; + txDmaLen = is64bit ? sizeof(txDesc64) : sizeof(txDesc32); txDmaFree = dmaDescFree; if (doTxDmaRead()) @@ -1961,7 +2352,6 @@ NSGigE::txKick() DPRINTF(EthernetSM, "entering next txState=%s\n", NsTxStateStrings[txState]); - goto next; exit: @@ -1970,6 +2360,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 @@ -1983,41 +2477,44 @@ 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 -NSGigE::rxFilter(PacketPtr packet) +NSGigE::rxFilter(const PacketPtr &packet) { + EthPtr eth = packet; bool drop = true; string type; - EthHdr *eth = packet->eth(); - if (eth->unicast()) { + const EthAddr &dst = eth->dst(); + if (dst.unicast()) { // If we're accepting all unicast addresses if (acceptUnicast) drop = false; // If we make a perfect match - if (acceptPerfect && - memcmp(rom.perfectMatch, packet->data, EADDR_LEN) == 0) + if (acceptPerfect && dst == rom.perfectMatch) drop = false; if (acceptArp && eth->type() == ETH_TYPE_ARP) drop = false; - } else if (eth->broadcast()) { + } else if (dst.broadcast()) { // if we're accepting broadcasts if (acceptBroadcast) drop = false; - } else if (eth->multicast()) { + } else if (dst.multicast()) { // if we're accepting all multicasts if (acceptMulticast) drop = false; + // Multicast hashing faked - all packets accepted + if (multicastHashEnable) + drop = false; } if (drop) { @@ -2035,31 +2532,43 @@ NSGigE::recvPacket(PacketPtr packet) rxPackets++; DPRINTF(Ethernet, "Receiving packet from wire, rxFifoAvail=%d\n", - maxRxFifoSize - rxFifoCnt); + rxFifo.avail()); 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"); + return true; + } + + if (rxFilter(packet)) { DPRINTF(Ethernet, "packet filtered...dropped\n"); - interface->recvDone(); return true; } - if ((rxFifoCnt + packet->length) >= maxRxFifoSize) { - DPRINTF(Ethernet, - "packet will not fit in receive buffer...packet dropped\n"); + if (rxFifo.avail() < packet->length) { +#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; } - rxFifo.push_back(packet); - rxFifoCnt += packet->length; - interface->recvDone(); + rxFifo.push(packet); rxKick(); return true; @@ -2109,6 +2618,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); @@ -2122,30 +2633,16 @@ NSGigE::serialize(ostream &os) SERIALIZE_SCALAR(regs.taner); SERIALIZE_SCALAR(regs.tesr); - SERIALIZE_ARRAY(rom.perfectMatch, EADDR_LEN); + SERIALIZE_ARRAY(rom.perfectMatch, ETH_ADDR_LEN); + SERIALIZE_ARRAY(rom.filterHash, FHASH_SIZE); SERIALIZE_SCALAR(ioEnable); /* * Serialize the data Fifos */ - int txNumPkts = txFifo.size(); - SERIALIZE_SCALAR(txNumPkts); - int i = 0; - pktiter_t end = txFifo.end(); - for (pktiter_t p = txFifo.begin(); p != end; ++p) { - nameOut(os, csprintf("%s.txFifo%d", name(), i++)); - (*p)->serialize(os); - } - - int rxNumPkts = rxFifo.size(); - SERIALIZE_SCALAR(rxNumPkts); - i = 0; - end = rxFifo.end(); - for (pktiter_t p = rxFifo.begin(); p != end; ++p) { - nameOut(os, csprintf("%s.rxFifo%d", name(), i++)); - (*p)->serialize(os); - } + rxFifo.serialize("rxFifo", os); + txFifo.serialize("txFifo", os); /* * Serialize the various helper variables @@ -2153,8 +2650,8 @@ NSGigE::serialize(ostream &os) bool txPacketExists = txPacket; SERIALIZE_SCALAR(txPacketExists); if (txPacketExists) { - nameOut(os, csprintf("%s.txPacket", name())); - txPacket->serialize(os); + txPacket->length = txPacketBufPtr - txPacket->data; + txPacket->serialize("txPacket", os); uint32_t txPktBufPtr = (uint32_t) (txPacketBufPtr - txPacket->data); SERIALIZE_SCALAR(txPktBufPtr); } @@ -2162,8 +2659,7 @@ NSGigE::serialize(ostream &os) bool rxPacketExists = rxPacket; SERIALIZE_SCALAR(rxPacketExists); if (rxPacketExists) { - nameOut(os, csprintf("%s.rxPacket", name())); - rxPacket->serialize(os); + rxPacket->serialize("rxPacket", os); uint32_t rxPktBufPtr = (uint32_t) (rxPacketBufPtr - rxPacket->data); SERIALIZE_SCALAR(rxPktBufPtr); } @@ -2172,16 +2668,25 @@ NSGigE::serialize(ostream &os) SERIALIZE_SCALAR(rxXferLen); /* - * Serialize DescCaches + * Serialize Cached Descriptors */ - SERIALIZE_SCALAR(txDescCache.link); - SERIALIZE_SCALAR(txDescCache.bufptr); - SERIALIZE_SCALAR(txDescCache.cmdsts); - SERIALIZE_SCALAR(txDescCache.extsts); - SERIALIZE_SCALAR(rxDescCache.link); - SERIALIZE_SCALAR(rxDescCache.bufptr); - SERIALIZE_SCALAR(rxDescCache.cmdsts); - SERIALIZE_SCALAR(rxDescCache.extsts); + SERIALIZE_SCALAR(rxDesc64.link); + SERIALIZE_SCALAR(rxDesc64.bufptr); + SERIALIZE_SCALAR(rxDesc64.cmdsts); + SERIALIZE_SCALAR(rxDesc64.extsts); + SERIALIZE_SCALAR(txDesc64.link); + SERIALIZE_SCALAR(txDesc64.bufptr); + SERIALIZE_SCALAR(txDesc64.cmdsts); + SERIALIZE_SCALAR(txDesc64.extsts); + SERIALIZE_SCALAR(rxDesc32.link); + SERIALIZE_SCALAR(rxDesc32.bufptr); + SERIALIZE_SCALAR(rxDesc32.cmdsts); + SERIALIZE_SCALAR(rxDesc32.extsts); + SERIALIZE_SCALAR(txDesc32.link); + SERIALIZE_SCALAR(txDesc32.bufptr); + SERIALIZE_SCALAR(txDesc32.cmdsts); + SERIALIZE_SCALAR(txDesc32.extsts); + SERIALIZE_SCALAR(extstsEnable); /* * Serialize tx state machine @@ -2190,11 +2695,11 @@ NSGigE::serialize(ostream &os) SERIALIZE_SCALAR(txState); SERIALIZE_SCALAR(txEnable); SERIALIZE_SCALAR(CTDD); - SERIALIZE_SCALAR(txFifoAvail); SERIALIZE_SCALAR(txFragPtr); SERIALIZE_SCALAR(txDescCnt); int txDmaState = this->txDmaState; SERIALIZE_SCALAR(txDmaState); + SERIALIZE_SCALAR(txKickTick); /* * Serialize rx state machine @@ -2204,12 +2709,22 @@ NSGigE::serialize(ostream &os) SERIALIZE_SCALAR(rxEnable); SERIALIZE_SCALAR(CRDD); SERIALIZE_SCALAR(rxPktBytes); - SERIALIZE_SCALAR(rxFifoCnt); + SERIALIZE_SCALAR(rxFragPtr); 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 @@ -2227,6 +2742,7 @@ NSGigE::serialize(ostream &os) SERIALIZE_SCALAR(acceptUnicast); SERIALIZE_SCALAR(acceptPerfect); SERIALIZE_SCALAR(acceptArp); + SERIALIZE_SCALAR(multicastHashEnable); /* * Keep track of pending interrupt status. @@ -2266,6 +2782,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); @@ -2279,29 +2797,16 @@ NSGigE::unserialize(Checkpoint *cp, const std::string §ion) UNSERIALIZE_SCALAR(regs.taner); UNSERIALIZE_SCALAR(regs.tesr); - UNSERIALIZE_ARRAY(rom.perfectMatch, EADDR_LEN); + UNSERIALIZE_ARRAY(rom.perfectMatch, ETH_ADDR_LEN); + UNSERIALIZE_ARRAY(rom.filterHash, FHASH_SIZE); UNSERIALIZE_SCALAR(ioEnable); /* * unserialize the data fifos */ - int txNumPkts; - UNSERIALIZE_SCALAR(txNumPkts); - int i; - for (i = 0; i < txNumPkts; ++i) { - PacketPtr p = new PacketData; - p->unserialize(cp, csprintf("%s.rxFifo%d", section, i)); - txFifo.push_back(p); - } - - int rxNumPkts; - UNSERIALIZE_SCALAR(rxNumPkts); - for (i = 0; i < rxNumPkts; ++i) { - PacketPtr p = new PacketData; - p->unserialize(cp, csprintf("%s.rxFifo%d", section, i)); - rxFifo.push_back(p); - } + rxFifo.unserialize("rxFifo", cp, section); + txFifo.unserialize("txFifo", cp, section); /* * unserialize the various helper variables @@ -2309,8 +2814,8 @@ NSGigE::unserialize(Checkpoint *cp, const std::string §ion) bool txPacketExists; UNSERIALIZE_SCALAR(txPacketExists); if (txPacketExists) { - txPacket = new PacketData; - txPacket->unserialize(cp, csprintf("%s.txPacket", section)); + txPacket = new PacketData(16384); + txPacket->unserialize("txPacket", cp, section); uint32_t txPktBufPtr; UNSERIALIZE_SCALAR(txPktBufPtr); txPacketBufPtr = (uint8_t *) txPacket->data + txPktBufPtr; @@ -2321,8 +2826,8 @@ NSGigE::unserialize(Checkpoint *cp, const std::string §ion) UNSERIALIZE_SCALAR(rxPacketExists); rxPacket = 0; if (rxPacketExists) { - rxPacket = new PacketData; - rxPacket->unserialize(cp, csprintf("%s.rxPacket", section)); + rxPacket = new PacketData(16384); + rxPacket->unserialize("rxPacket", cp, section); uint32_t rxPktBufPtr; UNSERIALIZE_SCALAR(rxPktBufPtr); rxPacketBufPtr = (uint8_t *) rxPacket->data + rxPktBufPtr; @@ -2333,16 +2838,25 @@ NSGigE::unserialize(Checkpoint *cp, const std::string §ion) UNSERIALIZE_SCALAR(rxXferLen); /* - * Unserialize DescCaches + * Unserialize Cached Descriptors */ - UNSERIALIZE_SCALAR(txDescCache.link); - UNSERIALIZE_SCALAR(txDescCache.bufptr); - UNSERIALIZE_SCALAR(txDescCache.cmdsts); - UNSERIALIZE_SCALAR(txDescCache.extsts); - UNSERIALIZE_SCALAR(rxDescCache.link); - UNSERIALIZE_SCALAR(rxDescCache.bufptr); - UNSERIALIZE_SCALAR(rxDescCache.cmdsts); - UNSERIALIZE_SCALAR(rxDescCache.extsts); + UNSERIALIZE_SCALAR(rxDesc64.link); + UNSERIALIZE_SCALAR(rxDesc64.bufptr); + UNSERIALIZE_SCALAR(rxDesc64.cmdsts); + UNSERIALIZE_SCALAR(rxDesc64.extsts); + UNSERIALIZE_SCALAR(txDesc64.link); + UNSERIALIZE_SCALAR(txDesc64.bufptr); + UNSERIALIZE_SCALAR(txDesc64.cmdsts); + UNSERIALIZE_SCALAR(txDesc64.extsts); + UNSERIALIZE_SCALAR(rxDesc32.link); + UNSERIALIZE_SCALAR(rxDesc32.bufptr); + UNSERIALIZE_SCALAR(rxDesc32.cmdsts); + UNSERIALIZE_SCALAR(rxDesc32.extsts); + UNSERIALIZE_SCALAR(txDesc32.link); + UNSERIALIZE_SCALAR(txDesc32.bufptr); + UNSERIALIZE_SCALAR(txDesc32.cmdsts); + UNSERIALIZE_SCALAR(txDesc32.extsts); + UNSERIALIZE_SCALAR(extstsEnable); /* * unserialize tx state machine @@ -2352,12 +2866,14 @@ NSGigE::unserialize(Checkpoint *cp, const std::string §ion) this->txState = (TxState) txState; UNSERIALIZE_SCALAR(txEnable); UNSERIALIZE_SCALAR(CTDD); - UNSERIALIZE_SCALAR(txFifoAvail); UNSERIALIZE_SCALAR(txFragPtr); UNSERIALIZE_SCALAR(txDescCnt); int txDmaState; UNSERIALIZE_SCALAR(txDmaState); this->txDmaState = (DmaState) txDmaState; + UNSERIALIZE_SCALAR(txKickTick); + if (txKickTick) + txKickEvent.schedule(txKickTick); /* * unserialize rx state machine @@ -2368,15 +2884,28 @@ NSGigE::unserialize(Checkpoint *cp, const std::string §ion) UNSERIALIZE_SCALAR(rxEnable); UNSERIALIZE_SCALAR(CRDD); UNSERIALIZE_SCALAR(rxPktBytes); - UNSERIALIZE_SCALAR(rxFifoCnt); + UNSERIALIZE_SCALAR(rxFragPtr); UNSERIALIZE_SCALAR(rxDescCnt); 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; @@ -2393,6 +2922,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. @@ -2410,16 +2940,46 @@ NSGigE::unserialize(Checkpoint *cp, const std::string §ion) * re-add addrRanges to bus bridges */ if (pioInterface) { - pioInterface->addAddrRange(BARAddrs[0], BARAddrs[0] + BARSize[0] - 1); - pioInterface->addAddrRange(BARAddrs[1], BARAddrs[1] + BARSize[1] - 1); + pioInterface->addAddrRange(RangeSize(BARAddrs[0], BARSize[0])); + pioInterface->addAddrRange(RangeSize(BARAddrs[1], BARSize[1])); } } Tick NSGigE::cacheAccess(MemReqPtr &req) { + Addr daddr = req->paddr & 0xfff; DPRINTF(EthernetPIO, "timing access to paddr=%#x (daddr=%#x)\n", - req->paddr, req->paddr - addr); + req->paddr, daddr); + + if (!pioDelayWrite || !req->cmd.isWrite()) + return curTick + pioLatency; + + int cpu = (req->xc->regs.ipr[TheISA::IPR_PALtemp16] >> 8) & 0xff; + std::list &wq = writeQueue[cpu]; + if (wq.empty()) + panic("WriteQueue for cpu %d empty timing daddr=%#x", cpu, daddr); + + const RegWriteData &data = wq.front(); + if (data.daddr != daddr) + panic("read mismatch on cpu %d, daddr functional=%#x timing=%#x", + cpu, data.daddr, daddr); + + if (daddr == CR) { + if ((data.value & (CR_TXD | CR_TXE)) == CR_TXE) { + txEnable = true; + if (txState == txIdle) + txKick(); + } + + if ((data.value & (CR_RXD | CR_RXE)) == CR_RXE) { + rxEnable = true; + if (rxState == rxIdle) + rxKick(); + } + } + + wq.pop_front(); return curTick + pioLatency; } @@ -2455,81 +3015,130 @@ REGISTER_SIM_OBJECT("NSGigEInt", NSGigEInt) BEGIN_DECLARE_SIM_OBJECT_PARAMS(NSGigE) - Param tx_delay; - Param rx_delay; - SimObjectParam intr_ctrl; - Param intr_delay; + Param clock; + + Param addr; SimObjectParam mmu; SimObjectParam physmem; - Param rx_filter; - Param hardware_address; - SimObjectParam header_bus; - SimObjectParam payload_bus; + SimObjectParam configspace; + SimObjectParam configdata; + SimObjectParam platform; + Param pci_bus; + Param pci_dev; + Param pci_func; + SimObjectParam hier; - Param pio_latency; + SimObjectParam pio_bus; + SimObjectParam dma_bus; + SimObjectParam payload_bus; Param dma_desc_free; Param dma_data_free; Param dma_read_delay; Param dma_write_delay; Param dma_read_factor; Param dma_write_factor; - SimObjectParam configspace; - SimObjectParam configdata; - SimObjectParam tsunami; - Param pci_bus; - Param pci_dev; - Param pci_func; - Param tx_fifo_size; + Param dma_no_allocate; + Param pio_latency; + Param pio_delay_write; + Param intr_delay; + + Param rx_delay; + Param tx_delay; Param rx_fifo_size; + Param tx_fifo_size; + + Param rx_filter; + Param hardware_address; + Param rx_thread; + Param tx_thread; END_DECLARE_SIM_OBJECT_PARAMS(NSGigE) BEGIN_INIT_SIM_OBJECT_PARAMS(NSGigE) - INIT_PARAM_DFLT(tx_delay, "Transmit Delay", 1000), - INIT_PARAM_DFLT(rx_delay, "Receive Delay", 1000), - INIT_PARAM(intr_ctrl, "Interrupt Controller"), - INIT_PARAM_DFLT(intr_delay, "Interrupt Delay in microseconds", 0), + INIT_PARAM(clock, "State machine processor frequency"), + + INIT_PARAM(addr, "Device Address"), 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_DFLT(header_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), - INIT_PARAM_DFLT(pio_latency, "Programmed IO latency in bus cycles", 1), - INIT_PARAM_DFLT(dma_desc_free, "DMA of Descriptors is free", false), - INIT_PARAM_DFLT(dma_data_free, "DMA of Data is free", false), - INIT_PARAM_DFLT(dma_read_delay, "fixed delay for dma reads", 0), - INIT_PARAM_DFLT(dma_write_delay, "fixed delay for dma writes", 0), - INIT_PARAM_DFLT(dma_read_factor, "multiplier for dma reads", 0), - INIT_PARAM_DFLT(dma_write_factor, "multiplier for dma writes", 0), INIT_PARAM(configspace, "PCI Configspace"), INIT_PARAM(configdata, "PCI Config data"), - INIT_PARAM(tsunami, "Tsunami"), + INIT_PARAM(platform, "Platform"), INIT_PARAM(pci_bus, "PCI bus"), 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(hier, "Hierarchy global variables"), + INIT_PARAM(pio_bus, ""), + INIT_PARAM(dma_bus, ""), + INIT_PARAM(payload_bus, "The IO Bus to attach to for payload"), + INIT_PARAM(dma_desc_free, "DMA of Descriptors is free"), + INIT_PARAM(dma_data_free, "DMA of Data is free"), + INIT_PARAM(dma_read_delay, "fixed delay for dma reads"), + INIT_PARAM(dma_write_delay, "fixed delay for dma writes"), + INIT_PARAM(dma_read_factor, "multiplier for dma reads"), + INIT_PARAM(dma_write_factor, "multiplier for dma writes"), + INIT_PARAM(dma_no_allocate, "Should DMA reads allocate cache lines"), + INIT_PARAM(pio_latency, "Programmed IO latency in bus cycles"), + INIT_PARAM(pio_delay_write, ""), + INIT_PARAM(intr_delay, "Interrupt Delay in microseconds"), + + INIT_PARAM(rx_delay, "Receive Delay"), + INIT_PARAM(tx_delay, "Transmit Delay"), + INIT_PARAM(rx_fifo_size, "max size in bytes of rxFifo"), + INIT_PARAM(tx_fifo_size, "max size in bytes of txFifo"), + + INIT_PARAM(rx_filter, "Enable Receive Filter"), + INIT_PARAM(hardware_address, "Ethernet Hardware Address"), + INIT_PARAM(rx_thread, ""), + INIT_PARAM(tx_thread, "") END_INIT_SIM_OBJECT_PARAMS(NSGigE) CREATE_SIM_OBJECT(NSGigE) { - int eaddr[6]; - sscanf(((string)hardware_address).c_str(), "%x:%x:%x:%x:%x:%x", - &eaddr[0], &eaddr[1], &eaddr[2], &eaddr[3], &eaddr[4], &eaddr[5]); - - return new NSGigE(getInstanceName(), intr_ctrl, intr_delay, - physmem, tx_delay, rx_delay, mmu, hier, header_bus, - payload_bus, pio_latency, dma_desc_free, dma_data_free, - dma_read_delay, dma_write_delay, dma_read_factor, - dma_write_factor, configspace, configdata, - tsunami, pci_bus, pci_dev, pci_func, rx_filter, eaddr, - tx_fifo_size, rx_fifo_size); + NSGigE::Params *params = new NSGigE::Params; + + params->name = getInstanceName(); + + params->clock = clock; + + params->mmu = mmu; + params->pmem = physmem; + params->configSpace = configspace; + params->configData = configdata; + params->plat = platform; + params->busNum = pci_bus; + params->deviceNum = pci_dev; + params->functionNum = pci_func; + + params->hier = hier; + params->pio_bus = pio_bus; + params->header_bus = dma_bus; + params->payload_bus = payload_bus; + params->dma_desc_free = dma_desc_free; + params->dma_data_free = dma_data_free; + params->dma_read_delay = dma_read_delay; + params->dma_write_delay = dma_write_delay; + params->dma_read_factor = dma_read_factor; + params->dma_write_factor = dma_write_factor; + params->dma_no_allocate = dma_no_allocate; + params->pio_latency = pio_latency; + params->pio_delay_write = pio_delay_write; + params->intr_delay = intr_delay; + + params->rx_delay = rx_delay; + params->tx_delay = tx_delay; + params->rx_fifo_size = rx_fifo_size; + params->tx_fifo_size = tx_fifo_size; + + params->rx_filter = rx_filter; + params->eaddr = hardware_address; + params->rx_thread = rx_thread; + params->tx_thread = tx_thread; + + return new NSGigE(params); } REGISTER_SIM_OBJECT("NSGigE", NSGigE)