X-Git-Url: https://git.libre-soc.org/?a=blobdiff_plain;f=dev%2Fns_gige.cc;h=53a881ef704dbf41f8dbfc57897070657fa052d8;hb=40bab977bc09d6126177ee34c51076ee1fff37f7;hp=f5cbdbb9a1154c147923f6fcef827133637b964c;hpb=ba0e69172f57550a0f7c48bc9d31df4feb90d814;p=gem5.git diff --git a/dev/ns_gige.cc b/dev/ns_gige.cc index f5cbdbb9a..53a881ef7 100644 --- a/dev/ns_gige.cc +++ b/dev/ns_gige.cc @@ -1,5 +1,5 @@ /* - * Copyright (c) 2003 The Regents of The University of Michigan + * Copyright (c) 2004 The Regents of The University of Michigan * All rights reserved. * * Redistribution and use in source and binary forms, with or without @@ -36,10 +36,10 @@ #include "base/inet.hh" #include "cpu/exec_context.hh" -#include "cpu/intr_control.hh" #include "dev/dma.hh" -#include "dev/ns_gige.hh" #include "dev/etherlink.hh" +#include "dev/ns_gige.hh" +#include "dev/pciconfigall.hh" #include "mem/bus/bus.hh" #include "mem/bus/dma_interface.hh" #include "mem/bus/pio_interface.hh" @@ -47,11 +47,10 @@ #include "mem/functional_mem/memory_control.hh" #include "mem/functional_mem/physical_memory.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" -#include "dev/pciconfigall.hh" -#include "dev/tsunami_cchip.hh" const char *NsRxStateStrings[] = { @@ -85,80 +84,75 @@ const char *NsDmaState[] = }; using namespace std; +using namespace Net; /////////////////////////////////////////////////////////////////////// // -// EtherDev PCI Device +// NSGigE PCI Device // -EtherDev::EtherDev(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], Addr addr) - : PciDev(name, mmu, cf, cd, bus, dev, func), tsunami(t), - addr(addr), txPacketBufPtr(NULL), rxPacketBufPtr(NULL), - txXferLen(0), rxXferLen(0), txPktXmitted(0), txState(txIdle), CTDD(false), - txFifoCnt(0), txFifoAvail(MAX_TX_FIFO_SIZE), txHalt(false), +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), txFragPtr(0), txDescCnt(0), txDmaState(dmaIdle), rxState(rxIdle), - CRDD(false), rxPktBytes(0), rxFifoCnt(0), rxHalt(false), + rxEnable(false), CRDD(false), rxPktBytes(0), rxFragPtr(0), rxDescCnt(0), rxDmaState(dmaIdle), extstsEnable(false), 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), txKickTick(0), + txEvent(this), rxFilterEnable(p->rx_filter), acceptBroadcast(false), acceptMulticast(false), acceptUnicast(false), acceptPerfect(false), acceptArp(false), - physmem(pmem), intctrl(i), intrTick(0), - cpuPendingIntr(false), intrEvent(0), interface(0), pioLatency(pio_latency) + physmem(p->pmem), intrTick(0), cpuPendingIntr(false), + intrEvent(0), interface(0) { - mmu->add_child(this, Range(addr, addr + size)); - tsunami->ethernet = this; - - if (header_bus) { - pioInterface = newPioInterface(name, hier, header_bus, this, - &EtherDev::cacheAccess); - pioInterface->addAddrRange(addr, addr + size - 1); - if (payload_bus) - dmaInterface = new DMAInterface(name + ".dma", - header_bus, payload_bus, 1); - else - dmaInterface = new DMAInterface(name + ".dma", - header_bus, header_bus, 1); - } else if (payload_bus) { - pioInterface = newPioInterface(name, hier, payload_bus, this, - &EtherDev::cacheAccess); - pioInterface->addAddrRange(addr, addr + size - 1); - dmaInterface = new DMAInterface(name + ".dma", - payload_bus, payload_bus, 1); + if (p->header_bus) { + pioInterface = newPioInterface(name(), p->hier, + p->header_bus, this, + &NSGigE::cacheAccess); + + pioLatency = p->pio_latency * p->header_bus->clockRatio; + if (p->payload_bus) + dmaInterface = new DMAInterface(name() + ".dma", + p->header_bus, + p->payload_bus, 1); + else + dmaInterface = new DMAInterface(name() + ".dma", + p->header_bus, + p->header_bus, 1); + } else if (p->payload_bus) { + pioInterface = newPioInterface(name(), p->hier, + p->payload_bus, this, + &NSGigE::cacheAccess); + + pioLatency = p->pio_latency * p->payload_bus->clockRatio; + + dmaInterface = new DMAInterface(name() + ".dma", + p->payload_bus, + p->payload_bus, 1); } - intrDelay = US2Ticks(intr_delay); - dmaReadDelay = dma_read_delay; - dmaWriteDelay = dma_write_delay; - dmaReadFactor = dma_read_factor; - dmaWriteFactor = dma_write_factor; + intrDelay = US2Ticks(p->intr_delay); + dmaReadDelay = p->dma_read_delay; + dmaWriteDelay = p->dma_write_delay; + dmaReadFactor = p->dma_read_factor; + dmaWriteFactor = p->dma_write_factor; - memset(®s, 0, sizeof(regs)); 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); } -EtherDev::~EtherDev() +NSGigE::~NSGigE() {} void -EtherDev::regStats() +NSGigE::regStats() { txBytes .name(name() + ".txBytes") @@ -184,6 +178,72 @@ EtherDev::regStats() .prereq(rxBytes) ; + txIpChecksums + .name(name() + ".txIpChecksums") + .desc("Number of tx IP Checksums done by device") + .precision(0) + .prereq(txBytes) + ; + + rxIpChecksums + .name(name() + ".rxIpChecksums") + .desc("Number of rx IP Checksums done by device") + .precision(0) + .prereq(rxBytes) + ; + + txTcpChecksums + .name(name() + ".txTcpChecksums") + .desc("Number of tx TCP Checksums done by device") + .precision(0) + .prereq(txBytes) + ; + + rxTcpChecksums + .name(name() + ".rxTcpChecksums") + .desc("Number of rx TCP Checksums done by device") + .precision(0) + .prereq(rxBytes) + ; + + txUdpChecksums + .name(name() + ".txUdpChecksums") + .desc("Number of tx UDP Checksums done by device") + .precision(0) + .prereq(txBytes) + ; + + rxUdpChecksums + .name(name() + ".rxUdpChecksums") + .desc("Number of rx UDP Checksums done by device") + .precision(0) + .prereq(rxBytes) + ; + + descDmaReads + .name(name() + ".descDMAReads") + .desc("Number of descriptors the device read w/ DMA") + .precision(0) + ; + + descDmaWrites + .name(name() + ".descDMAWrites") + .desc("Number of descriptors the device wrote w/ DMA") + .precision(0) + ; + + descDmaRdBytes + .name(name() + ".descDmaReadBytes") + .desc("number of descriptor bytes read w/ DMA") + .precision(0) + ; + + descDmaWrBytes + .name(name() + ".descDmaWriteBytes") + .desc("number of descriptor bytes write w/ DMA") + .precision(0) + ; + txBandwidth .name(name() + ".txBandwidth") .desc("Transmit Bandwidth (bits/s)") @@ -198,6 +258,34 @@ EtherDev::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)") @@ -212,8 +300,186 @@ EtherDev::regStats() .prereq(rxBytes) ; + postedSwi + .name(name() + ".postedSwi") + .desc("number of software interrupts posted to CPU") + .precision(0) + ; + + totalSwi + .name(name() + ".totalSwi") + .desc("number of total 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("number of total 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("number of total 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("number of total 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("number of total 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("number of total 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("number of total 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("number of total 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; } @@ -222,25 +488,70 @@ EtherDev::regStats() * This is to read the PCI general configuration registers */ void -EtherDev::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); - else { - panic("need to do this\n"); - } + else + panic("Device specific PCI config space not implemented!\n"); } /** * This is to write to the PCI general configuration registers */ void -EtherDev::WriteConfig(int offset, int size, uint32_t data) +NSGigE::WriteConfig(int offset, int size, uint32_t data) { if (offset < PCI_DEVICE_SPECIFIC) PciDev::WriteConfig(offset, size, data); else - panic("Need to do that\n"); + panic("Device specific PCI config space not implemented!\n"); + + // Need to catch writes to BARs to update the PIO interface + switch (offset) { + // seems to work fine without all these PCI settings, but i + // put in the IO to double check, an assertion will fail if we + // need to properly implement it + case PCI_COMMAND: + if (config.data[offset] & PCI_CMD_IOSE) + ioEnable = true; + else + ioEnable = false; + +#if 0 + if (config.data[offset] & PCI_CMD_BME) { + bmEnabled = true; + } + else { + bmEnabled = false; + } + + if (config.data[offset] & PCI_CMD_MSE) { + memEnable = true; + } + else { + memEnable = false; + } +#endif + break; + + case PCI0_BASE_ADDR0: + if (BARAddrs[0] != 0) { + if (pioInterface) + pioInterface->addAddrRange(RangeSize(BARAddrs[0], BARSize[0])); + + BARAddrs[0] &= EV5::PAddrUncachedMask; + } + break; + case PCI0_BASE_ADDR1: + if (BARAddrs[1] != 0) { + if (pioInterface) + pioInterface->addAddrRange(RangeSize(BARAddrs[1], BARSize[1])); + + BARAddrs[1] &= EV5::PAddrUncachedMask; + } + break; + } } /** @@ -248,16 +559,18 @@ EtherDev::WriteConfig(int offset, int size, uint32_t data) * spec sheet */ Fault -EtherDev::read(MemReqPtr &req, uint8_t *data) +NSGigE::read(MemReqPtr &req, uint8_t *data) { + assert(ioEnable); + //The mask is to give you only the offset into the device register file Addr daddr = req->paddr & 0xfff; DPRINTF(EthernetPIO, "read da=%#x pa=%#x va=%#x size=%d\n", daddr, req->paddr, req->vaddr, req->size); - //there are some reserved registers, you can see ns_gige_reg.h and - //the spec sheet for details + // there are some reserved registers, you can see ns_gige_reg.h and + // the spec sheet for details if (daddr > LAST && daddr <= RESERVED) { panic("Accessing reserved register"); } else if (daddr > RESERVED && daddr <= 0x3FC) { @@ -354,16 +667,16 @@ EtherDev::read(MemReqPtr &req, uint8_t *data) reg = regs.pcr; break; - //see the spec sheet for how RFCR and RFDR work - //basically, you write to RFCR to tell the machine what you want to do next - //then you act upon RFDR, and the device will be prepared b/c - //of what you wrote to RFCR + // see the spec sheet for how RFCR and RFDR work + // basically, you write to RFCR to tell the machine + // what you want to do next, then you act upon RFDR, + // and the device will be prepared b/c of what you + // wrote to RFCR case RFCR: reg = regs.rfcr; break; case RFDR: - DPRINTF(Ethernet, "reading from RFDR\n"); switch (regs.rfcr & RFCR_RFADDR) { case 0x000: reg = rom.perfectMatch[1]; @@ -379,8 +692,9 @@ EtherDev::read(MemReqPtr &req, uint8_t *data) reg += rom.perfectMatch[4]; break; default: - panic("reading from RFDR for something for other than PMATCH!\n"); - //didn't implement other RFDR functionality b/c driver didn't use + panic("reading RFDR for something other than PMATCH!\n"); + // didn't implement other RFDR functionality b/c + // driver didn't use it } break; @@ -434,10 +748,11 @@ EtherDev::read(MemReqPtr &req, uint8_t *data) break; default: - panic("reading unimplemented register: addr = %#x", daddr); + panic("reading unimplemented register: addr=%#x", daddr); } - DPRINTF(EthernetPIO, "read from %#x: data=%d data=%#x\n", daddr, reg, reg); + DPRINTF(EthernetPIO, "read from %#x: data=%d data=%#x\n", + daddr, reg, reg); } break; @@ -450,8 +765,10 @@ EtherDev::read(MemReqPtr &req, uint8_t *data) } Fault -EtherDev::write(MemReqPtr &req, const uint8_t *data) +NSGigE::write(MemReqPtr &req, const uint8_t *data) { + assert(ioEnable); + Addr daddr = req->paddr & 0xfff; DPRINTF(EthernetPIO, "write da=%#x pa=%#x va=%#x size=%d\n", daddr, req->paddr, req->vaddr, req->size); @@ -471,24 +788,23 @@ EtherDev::write(MemReqPtr &req, const uint8_t *data) switch (daddr) { case CR: regs.command = reg; - if ((reg & (CR_TXE | CR_TXD)) == (CR_TXE | CR_TXD)) { - txHalt = true; + if (reg & CR_TXD) { + txEnable = false; } else if (reg & CR_TXE) { - //the kernel is enabling the transmit machine + txEnable = true; + + // the kernel is enabling the transmit machine if (txState == txIdle) txKick(); - } else if (reg & CR_TXD) { - txHalt = true; } - if ((reg & (CR_RXE | CR_RXD)) == (CR_RXE | CR_RXD)) { - rxHalt = true; + if (reg & CR_RXD) { + rxEnable = false; } else if (reg & CR_RXE) { - if (rxState == rxIdle) { + rxEnable = true; + + if (rxState == rxIdle) rxKick(); - } - } else if (reg & CR_RXD) { - rxHalt = true; } if (reg & CR_TXR) @@ -509,26 +825,34 @@ EtherDev::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) + 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); + regs.config |= reg & ~(CFG_LNKSTS | CFG_SPDSTS | CFG_DUPSTS | + CFG_RESERVED | CFG_T64ADDR | CFG_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 +// 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 & CFG_TBI_EN) ; + if (reg & CFG_MODE_1000) ; #endif if (reg & CFG_AUTO_1000) panic("CFG_AUTO_1000 not implemented!\n"); #if 0 - if (reg & CFG_PINT_DUPSTS || reg & CFG_PINT_LNKSTS || reg & CFG_PINT_SPDSTS) ; + if (reg & CFG_PINT_DUPSTS || + reg & CFG_PINT_LNKSTS || + reg & CFG_PINT_SPDSTS) + ; + if (reg & CFG_TMRTEST) ; if (reg & CFG_MRM_DIS) ; if (reg & CFG_MWI_DIS) ; @@ -564,11 +888,12 @@ EtherDev::write(MemReqPtr &req, const uint8_t *data) case MEAR: regs.mear = reg; - /* since phy is completely faked, MEAR_MD* don't matter - and since the driver never uses MEAR_EE*, they don't matter */ + // 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_EEDO) ; // this one is read only if (reg & MEAR_EECLK) ; if (reg & MEAR_EESEL) ; if (reg & MEAR_MDIO) ; @@ -579,8 +904,8 @@ EtherDev::write(MemReqPtr &req, const uint8_t *data) case PTSCR: regs.ptscr = reg & ~(PTSCR_RBIST_RDONLY); - /* these control BISTs for various parts of chip - we don't care or do - just fake that the BIST is done */ + // these control BISTs for various parts of chip - we + // don't care or do just fake that the BIST is done if (reg & PTSCR_RBIST_EN) regs.ptscr |= PTSCR_RBIST_DONE; if (reg & PTSCR_EEBIST_EN) @@ -623,16 +948,26 @@ EtherDev::write(MemReqPtr &req, const uint8_t *data) if (reg & TXCFG_HBI) ; if (reg & TXCFG_MLB) ; if (reg & TXCFG_ATP) ; - if (reg & TXCFG_ECRETRY) ; /* this could easily be implemented, but - considering the network is just a fake - pipe, wouldn't make sense to do this */ + if (reg & TXCFG_ECRETRY) { + /* + * this could easily be implemented, but considering + * the network is just a fake pipe, wouldn't make + * sense to do this + */ + } if (reg & TXCFG_BRST_DIS) ; #endif - +#if 0 /* we handle our own DMA, ignore the kernel's exhortations */ if (reg & TXCFG_MXDMA) ; +#endif + + // 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 break; @@ -643,6 +978,7 @@ EtherDev::write(MemReqPtr &req, const uint8_t *data) case RXDP: regs.rxdp = reg; + CRDD = false; break; case RXDP_HI: @@ -658,12 +994,13 @@ EtherDev::write(MemReqPtr &req, const uint8_t *data) if (reg & RXCFG_RX_RD) ; if (reg & RXCFG_ALP) ; if (reg & RXCFG_AIRL) ; -#endif /* we handle our own DMA, ignore what kernel says about it */ if (reg & RXCFG_MXDMA) ; -#if 0 + //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)) ; #endif break; @@ -685,22 +1022,18 @@ EtherDev::write(MemReqPtr &req, const uint8_t *data) case RFCR: regs.rfcr = reg; - DPRINTF(Ethernet, "Writing to RFCR, RFADDR is %#x\n", reg & RFCR_RFADDR); rxFilterEnable = (reg & RFCR_RFEN) ? true : false; - acceptBroadcast = (reg & RFCR_AAB) ? true : false; - acceptMulticast = (reg & RFCR_AAM) ? true : false; - acceptUnicast = (reg & RFCR_AAU) ? true : false; - acceptPerfect = (reg & RFCR_APM) ? true : false; - acceptArp = (reg & RFCR_AARP) ? true : false; - if (reg & RFCR_APAT) ; -// panic("RFCR_APAT not implemented!\n"); +#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"); @@ -781,147 +1114,122 @@ EtherDev::write(MemReqPtr &req, const uint8_t *data) break; default: - panic("thought i covered all the register, what is this? addr=%#x", - daddr); + panic("invalid register access daddr=%#x", daddr); } - } else + } else { panic("Invalid Request Size"); + } return No_Fault; } void -EtherDev::devIntrPost(uint32_t interrupts) +NSGigE::devIntrPost(uint32_t interrupts) { - DPRINTF(Ethernet, "interrupt posted intr=%#x isr=%#x imr=%#x\n", - interrupts, regs.isr, regs.imr); - - bool delay = false; - if (interrupts & ISR_RESERVE) panic("Cannot set a reserved interrupt"); - if (interrupts & ISR_TXRCMP) - regs.isr |= ISR_TXRCMP; - - if (interrupts & ISR_RXRCMP) - regs.isr |= ISR_RXRCMP; - -//ISR_DPERR not implemented -//ISR_SSERR not implemented -//ISR_RMABT not implemented -//ISR_RXSOVR not implemented -//ISR_HIBINT not implemented -//ISR_PHY not implemented -//ISR_PME not implemented - - if (interrupts & ISR_SWI) - regs.isr |= ISR_SWI; + if (interrupts & ISR_NOIMPL) + warn("interrupt not implemented %#x\n", interrupts); -//ISR_MIB not implemented -//ISR_TXURN not implemented + interrupts &= ~ISR_NOIMPL; + regs.isr |= interrupts; - if (interrupts & ISR_TXIDLE) - regs.isr |= ISR_TXIDLE; - - if (interrupts & ISR_TXERR) - regs.isr |= ISR_TXERR; - - if (interrupts & ISR_TXDESC) - regs.isr |= ISR_TXDESC; - - if (interrupts & ISR_TXOK) { - regs.isr |= ISR_TXOK; - delay = true; + 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++; + } } - if (interrupts & ISR_RXORN) - regs.isr |= ISR_RXORN; - - if (interrupts & ISR_RXIDLE) - regs.isr |= ISR_RXIDLE; - -//ISR_RXEARLY not implemented - - if (interrupts & ISR_RXERR) - regs.isr |= ISR_RXERR; - - if (interrupts & ISR_RXOK) { - delay = true; - regs.isr |= ISR_RXOK; - } + 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 (delay) + if (!(regs.isr & regs.imr & ISR_NODELAY)) 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 -EtherDev::devIntrClear(uint32_t interrupts) +NSGigE::devIntrClear(uint32_t interrupts) { - DPRINTF(Ethernet, "interrupt cleared intr=%x isr=%x imr=%x\n", - interrupts, regs.isr, regs.imr); - if (interrupts & ISR_RESERVE) panic("Cannot clear a reserved interrupt"); - if (interrupts & ISR_TXRCMP) - regs.isr &= ~ISR_TXRCMP; - - if (interrupts & ISR_RXRCMP) - regs.isr &= ~ISR_RXRCMP; - -//ISR_DPERR not implemented -//ISR_SSERR not implemented -//ISR_RMABT not implemented -//ISR_RXSOVR not implemented -//ISR_HIBINT not implemented -//ISR_PHY not implemented -//ISR_PME not implemented - - if (interrupts & ISR_SWI) - regs.isr &= ~ISR_SWI; - -//ISR_MIB not implemented -//ISR_TXURN not implemented - - if (interrupts & ISR_TXIDLE) - regs.isr &= ~ISR_TXIDLE; - - if (interrupts & ISR_TXERR) - regs.isr &= ~ISR_TXERR; - - if (interrupts & ISR_TXDESC) - regs.isr &= ~ISR_TXDESC; - - if (interrupts & ISR_TXOK) - regs.isr &= ~ISR_TXOK; - - if (interrupts & ISR_RXORN) - regs.isr &= ~ISR_RXORN; - - if (interrupts & ISR_RXIDLE) - regs.isr &= ~ISR_RXIDLE; + 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++; + } -//ISR_RXEARLY not implemented + if (regs.isr & regs.imr & (ISR_SWI | ISR_RXIDLE | ISR_RXOK | ISR_RXDESC | + ISR_TXOK | ISR_TXIDLE | ISR_TXDESC | ISR_RXORN) ) + postedInterrupts++; - if (interrupts & ISR_RXERR) - regs.isr &= ~ISR_RXERR; + interrupts &= ~ISR_NOIMPL; + regs.isr &= ~interrupts; - if (interrupts & ISR_RXOK) - regs.isr &= ~ISR_RXOK; + DPRINTF(EthernetIntr, + "interrupt cleared from ISR: intr=%x isr=%x imr=%x\n", + interrupts, regs.isr, regs.imr); if (!(regs.isr & regs.imr)) cpuIntrClear(); } void -EtherDev::devIntrChangeMask() +NSGigE::devIntrChangeMask() { - DPRINTF(Ethernet, "interrupt mask changed\n"); + DPRINTF(EthernetIntr, "interrupt mask changed: isr=%x imr=%x masked=%x\n", + regs.isr, regs.imr, regs.isr & regs.imr); if (regs.isr & regs.imr) cpuIntrPost(curTick); @@ -930,105 +1238,144 @@ EtherDev::devIntrChangeMask() } void -EtherDev::cpuIntrPost(Tick when) +NSGigE::cpuIntrPost(Tick when) { - if (when > intrTick && intrTick != 0) + // If the interrupt you want to post is later than an interrupt + // already scheduled, just let it post in the coming one and don't + // schedule another. + // HOWEVER, must be sure that the scheduled intrTick is in the + // future (this was formerly the source of a bug) + /** + * @todo this warning should be removed and the intrTick code should + * be fixed. + */ + assert(when >= curTick); + assert(intrTick >= curTick || intrTick == 0); + if (when > intrTick && intrTick != 0) { + DPRINTF(EthernetIntr, "don't need to schedule event...intrTick=%d\n", + intrTick); return; + } intrTick = when; - - if (intrEvent) { - intrEvent->squash(); - intrEvent = 0; + if (intrTick < curTick) { + debug_break(); + intrTick = curTick; } - if (when < curTick) { - cpuInterrupt(); - } else { - intrEvent = new IntrEvent(this, true); - intrEvent->schedule(intrTick); - } + DPRINTF(EthernetIntr, "going to schedule an interrupt for intrTick=%d\n", + intrTick); + + if (intrEvent) + intrEvent->squash(); + intrEvent = new IntrEvent(this, true); + intrEvent->schedule(intrTick); } void -EtherDev::cpuInterrupt() +NSGigE::cpuInterrupt() { - // Don't send an interrupt if there's already one - if (cpuPendingIntr) - return; - - // Don't send an interrupt if it's supposed to be delayed - if (intrTick > curTick) - return; + assert(intrTick == curTick); // Whether or not there's a pending interrupt, we don't care about // it anymore intrEvent = 0; intrTick = 0; - // Send interrupt - cpuPendingIntr = true; - /** @todo rework the intctrl to be tsunami ok */ - //intctrl->post(TheISA::INTLEVEL_IRQ1, TheISA::INTINDEX_ETHERNET); - tsunami->cchip->postDRIR(configData->config.hdr.pci0.interruptLine); + // Don't send an interrupt if there's already one + if (cpuPendingIntr) { + DPRINTF(EthernetIntr, + "would send an interrupt now, but there's already pending\n"); + } else { + // Send interrupt + cpuPendingIntr = true; + + DPRINTF(EthernetIntr, "posting interrupt\n"); + intrPost(); + } } void -EtherDev::cpuIntrClear() +NSGigE::cpuIntrClear() { - if (cpuPendingIntr) { - cpuPendingIntr = false; - /** @todo rework the intctrl to be tsunami ok */ - //intctrl->clear(TheISA::INTLEVEL_IRQ1, TheISA::INTINDEX_ETHERNET); - tsunami->cchip->clearDRIR(configData->config.hdr.pci0.interruptLine); + if (!cpuPendingIntr) + return; + + if (intrEvent) { + intrEvent->squash(); + intrEvent = 0; } + + intrTick = 0; + + cpuPendingIntr = false; + + DPRINTF(EthernetIntr, "clearing interrupt\n"); + intrClear(); } bool -EtherDev::cpuIntrPending() const +NSGigE::cpuIntrPending() const { return cpuPendingIntr; } void -EtherDev::txReset() +NSGigE::txReset() { DPRINTF(Ethernet, "transmit reset\n"); CTDD = false; - txFifoCnt = 0; - txFifoAvail = MAX_TX_FIFO_SIZE; - txHalt = false; + txEnable = false;; txFragPtr = 0; assert(txDescCnt == 0); txFifo.clear(); - regs.command &= ~CR_TXE; txState = txIdle; assert(txDmaState == dmaIdle); } void -EtherDev::rxReset() +NSGigE::rxReset() { DPRINTF(Ethernet, "receive reset\n"); CRDD = false; assert(rxPktBytes == 0); - rxFifoCnt = 0; - rxHalt = false; + rxEnable = false; rxFragPtr = 0; assert(rxDescCnt == 0); assert(rxDmaState == dmaIdle); rxFifo.clear(); - regs.command &= ~CR_RXE; rxState = rxIdle; } void -EtherDev::rxDmaReadCopy() +NSGigE::regsReset() +{ + memset(®s, 0, sizeof(regs)); + regs.config = CFG_LNKSTS; + regs.mear = MEAR_MDDIR | MEAR_EEDO; + regs.txcfg = 0x120; // set drain threshold to 1024 bytes and + // fill threshold to 32 bytes + regs.rxcfg = 0x4; // set drain threshold to 16 bytes + regs.srr = 0x0103; // set the silicon revision to rev B or 0x103 + 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 + + extstsEnable = false; + acceptBroadcast = false; + acceptMulticast = false; + acceptUnicast = false; + acceptPerfect = false; + acceptArp = false; +} + +void +NSGigE::rxDmaReadCopy() { assert(rxDmaState == dmaReading); - memcpy(rxDmaData, physmem->dma_addr(rxDmaAddr, rxDmaLen), rxDmaLen); + physmem->dma_read((uint8_t *)rxDmaData, rxDmaAddr, rxDmaLen); rxDmaState = dmaIdle; DPRINTF(EthernetDMA, "rx dma read paddr=%#x len=%d\n", @@ -1037,7 +1384,7 @@ EtherDev::rxDmaReadCopy() } bool -EtherDev::doRxDmaRead() +NSGigE::doRxDmaRead() { assert(rxDmaState == dmaIdle || rxDmaState == dmaReadWaiting); rxDmaState = dmaReading; @@ -1047,7 +1394,7 @@ EtherDev::doRxDmaRead() rxDmaState = dmaReadWaiting; else dmaInterface->doDMA(Read, rxDmaAddr, rxDmaLen, curTick, - &rxDmaReadEvent); + &rxDmaReadEvent, true); return true; } @@ -1063,7 +1410,7 @@ EtherDev::doRxDmaRead() } void -EtherDev::rxDmaReadDone() +NSGigE::rxDmaReadDone() { assert(rxDmaState == dmaReading); rxDmaReadCopy(); @@ -1076,11 +1423,11 @@ EtherDev::rxDmaReadDone() } void -EtherDev::rxDmaWriteCopy() +NSGigE::rxDmaWriteCopy() { assert(rxDmaState == dmaWriting); - memcpy(physmem->dma_addr(rxDmaAddr, rxDmaLen), rxDmaData, rxDmaLen); + physmem->dma_write(rxDmaAddr, (uint8_t *)rxDmaData, rxDmaLen); rxDmaState = dmaIdle; DPRINTF(EthernetDMA, "rx dma write paddr=%#x len=%d\n", @@ -1089,7 +1436,7 @@ EtherDev::rxDmaWriteCopy() } bool -EtherDev::doRxDmaWrite() +NSGigE::doRxDmaWrite() { assert(rxDmaState == dmaIdle || rxDmaState == dmaWriteWaiting); rxDmaState = dmaWriting; @@ -1099,7 +1446,7 @@ EtherDev::doRxDmaWrite() rxDmaState = dmaWriteWaiting; else dmaInterface->doDMA(WriteInvalidate, rxDmaAddr, rxDmaLen, curTick, - &rxDmaWriteEvent); + &rxDmaWriteEvent, true); return true; } @@ -1115,7 +1462,7 @@ EtherDev::doRxDmaWrite() } void -EtherDev::rxDmaWriteDone() +NSGigE::rxDmaWriteDone() { assert(rxDmaState == dmaWriting); rxDmaWriteCopy(); @@ -1128,13 +1475,13 @@ EtherDev::rxDmaWriteDone() } void -EtherDev::rxKick() +NSGigE::rxKick() { - DPRINTF(Ethernet, "receive kick state=%s (rxBuf.size=%d)\n", + DPRINTF(EthernetSM, "receive kick rxState=%s (rxBuf.size=%d)\n", NsRxStateStrings[rxState], rxFifo.size()); if (rxKickTick > curTick) { - DPRINTF(Ethernet, "receive kick exiting, can't run till %d\n", + DPRINTF(EthernetSM, "receive kick exiting, can't run till %d\n", rxKickTick); return; } @@ -1154,15 +1501,16 @@ EtherDev::rxKick() } // 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 label "next". however, if you have - // intermediate work, like DMA so that you can't go to the next state yet, you go to - // exit and exit the loop. however, when the DMA is done it will trigger an - // event and come back to this loop. + // 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 + // label "next". however, if you have intermediate work, like DMA + // so that you can't go to the next state yet, you go to exit and + // exit the loop. however, when the DMA is done it will trigger + // an event and come back to this loop. switch (rxState) { case rxIdle: - if (!regs.command & CR_RXE) { - DPRINTF(Ethernet, "Receive Disabled! Nothing to do.\n"); + if (!rxEnable) { + DPRINTF(EthernetSM, "Receive Disabled! Nothing to do.\n"); goto exit; } @@ -1174,6 +1522,9 @@ EtherDev::rxKick() rxDmaLen = sizeof(rxDescCache.link); rxDmaFree = dmaDescFree; + descDmaReads++; + descDmaRdBytes += rxDmaLen; + if (doRxDmaRead()) goto exit; } else { @@ -1184,6 +1535,9 @@ EtherDev::rxKick() rxDmaLen = sizeof(ns_desc); rxDmaFree = dmaDescFree; + descDmaReads++; + descDmaRdBytes += rxDmaLen; + if (doRxDmaRead()) goto exit; } @@ -1200,8 +1554,18 @@ EtherDev::rxKick() if (rxDmaState != dmaIdle) goto exit; + DPRINTF(EthernetDesc, + "rxDescCache: 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); + if (rxDescCache.cmdsts & CMDSTS_OWN) { + devIntrPost(ISR_RXIDLE); rxState = rxIdle; + goto exit; } else { rxState = rxFifoBlock; rxFragPtr = rxDescCache.bufptr; @@ -1219,25 +1583,41 @@ EtherDev::rxKick() if (rxFifo.empty()) goto exit; + DPRINTF(EthernetSM, "****processing receive of new packet****\n"); + // If we don't have a packet, grab a new one from the fifo. rxPacket = rxFifo.front(); rxPktBytes = rxPacket->length; rxPacketBufPtr = rxPacket->data; +#if TRACING_ON + if (DTRACE(Ethernet)) { + IpPtr ip(rxPacket); + if (ip) { + DPRINTF(Ethernet, "ID is %d\n", ip->id()); + TcpPtr tcp(ip); + if (tcp) { + DPRINTF(Ethernet, + "Src Port=%d, Dest Port=%d, Seq=%d, Ack=%d\n", + tcp->sport(), tcp->dport(), tcp->seq(), + tcp->ack()); + } + } + } +#endif + // 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(); + rxFifo.pop(); } - // dont' need the && rxDescCnt > 0 if driver sanity check above holds + // dont' need the && rxDescCnt > 0 if driver sanity check + // above holds if (rxPktBytes > 0) { rxState = rxFragWrite; - // don't need min<>(rxPktBytes,rxDescCnt) if above sanity check holds + // don't need min<>(rxPktBytes,rxDescCnt) if above sanity + // check holds rxXferLen = rxPktBytes; rxDmaAddr = rxFragPtr & 0x3fffffff; @@ -1253,62 +1633,86 @@ EtherDev::rxKick() //if (rxPktBytes == 0) { /* packet is done */ assert(rxPktBytes == 0); - - rxFifoCnt -= rxPacket->length; - rxPacket = 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 #if 0 - /* all the driver uses these are for its own stats keeping - which we don't care about, aren't necessary for functionality - and doing this would just slow us down. if they end up using - this in a later version for functional purposes, just undef - */ + /* + * all the driver uses these are for its own stats keeping + * which we don't care about, aren't necessary for + * functionality and doing this would just slow us down. + * if they end up using this in a later version for + * functional purposes, just undef + */ if (rxFilterEnable) { rxDescCache.cmdsts &= ~CMDSTS_DEST_MASK; - if (rxFifo.front()->IsUnicast()) + const EthAddr &dst = rxFifoFront()->dst(); + if (dst->unicast()) rxDescCache.cmdsts |= CMDSTS_DEST_SELF; - if (rxFifo.front()->IsMulticast()) + if (dst->multicast()) rxDescCache.cmdsts |= CMDSTS_DEST_MULTI; - if (rxFifo.front()->IsBroadcast()) + if (dst->broadcast()) rxDescCache.cmdsts |= CMDSTS_DEST_MASK; } #endif - eth_header *eth = (eth_header *) rxPacket->data; - // eth->type 0x800 indicated that it's an ip packet. - if (eth->type == 0x800 && extstsEnable) { + IpPtr ip(rxPacket); + if (extstsEnable && ip) { rxDescCache.extsts |= EXTSTS_IPPKT; - if (!ipChecksum(rxPacket, false)) + rxIpChecksums++; + if (cksum(ip) != 0) { + DPRINTF(EthernetCksum, "Rx IP Checksum Error\n"); rxDescCache.extsts |= EXTSTS_IPERR; - ip_header *ip = rxFifo.front()->getIpHdr(); - - if (ip->protocol == 6) { + } + TcpPtr tcp(ip); + UdpPtr udp(ip); + if (tcp) { rxDescCache.extsts |= EXTSTS_TCPPKT; - if (!tcpChecksum(rxPacket, false)) + rxTcpChecksums++; + if (cksum(tcp) != 0) { + DPRINTF(EthernetCksum, "Rx TCP Checksum Error\n"); rxDescCache.extsts |= EXTSTS_TCPERR; - } else if (ip->protocol == 17) { + + } + } else if (udp) { rxDescCache.extsts |= EXTSTS_UDPPKT; - if (!udpChecksum(rxPacket, false)) + rxUdpChecksums++; + if (cksum(udp) != 0) { + DPRINTF(EthernetCksum, "Rx UDP Checksum Error\n"); rxDescCache.extsts |= EXTSTS_UDPERR; + } } } + rxPacket = 0; - /* the driver seems to always receive into desc buffers - of size 1514, so you never have a pkt that is split - into multiple descriptors on the receive side, so - i don't implement that case, hence the assert above. - */ + /* + * the driver seems to always receive into desc buffers + * of size 1514, so you never have a pkt that is split + * into multiple descriptors on the receive side, so + * i don't implement that case, hence the assert above. + */ + + DPRINTF(EthernetDesc, + "rxDescCache: 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); rxDmaAddr = (regs.rxdp + offsetof(ns_desc, cmdsts)) & 0x3fffffff; rxDmaData = &(rxDescCache.cmdsts); rxDmaLen = sizeof(rxDescCache.cmdsts) + sizeof(rxDescCache.extsts); rxDmaFree = dmaDescFree; + descDmaWrites++; + descDmaWrBytes += rxDmaLen; + if (doRxDmaWrite()) goto exit; } @@ -1337,17 +1741,20 @@ EtherDev::rxKick() if (rxDescCache.cmdsts & CMDSTS_INTR) devIntrPost(ISR_RXDESC); - if (rxHalt) { + if (!rxEnable) { + DPRINTF(EthernetSM, "Halting the RX state machine\n"); rxState = rxIdle; - rxHalt = false; + goto exit; } else rxState = rxAdvance; break; case rxAdvance: if (rxDescCache.link == 0) { + devIntrPost(ISR_RXIDLE); rxState = rxIdle; - return; + CRDD = true; + goto exit; } else { rxState = rxDescRead; regs.rxdp = rxDescCache.link; @@ -1367,52 +1774,62 @@ EtherDev::rxKick() panic("Invalid rxState!"); } - - DPRINTF(Ethernet, "entering next rx state = %s\n", + DPRINTF(EthernetSM, "entering next rxState=%s\n", NsRxStateStrings[rxState]); - if (rxState == rxIdle) { - regs.command &= ~CR_RXE; - devIntrPost(ISR_RXIDLE); - return; - } - goto next; exit: /** * @todo do we want to schedule a future kick? */ - DPRINTF(Ethernet, "rx state machine exited state=%s\n", + DPRINTF(EthernetSM, "rx state machine exited rxState=%s\n", NsRxStateStrings[rxState]); } void -EtherDev::transmit() +NSGigE::transmit() { if (txFifo.empty()) { DPRINTF(Ethernet, "nothing to transmit\n"); return; } - if (interface->sendPacket(txFifo.front())) { - DPRINTF(Ethernet, "transmit packet\n"); - DDUMP(Ethernet, txFifo.front()->data, txFifo.front()->length); + DPRINTF(Ethernet, "Attempt Pkt Transmit: txFifo length=%d\n", + txFifo.size()); + if (interface->sendPacket(txFifo.front())) { +#if TRACING_ON + if (DTRACE(Ethernet)) { + IpPtr ip(txFifo.front()); + if (ip) { + DPRINTF(Ethernet, "ID is %d\n", ip->id()); + TcpPtr tcp(ip); + if (tcp) { + DPRINTF(Ethernet, + "Src Port=%d, Dest Port=%d, Seq=%d, Ack=%d\n", + tcp->sport(), tcp->dport(), tcp->seq(), tcp->ack()); + } + } + } +#endif + + DDUMP(EthernetData, txFifo.front()->data, txFifo.front()->length); txBytes += txFifo.front()->length; txPackets++; - txFifoCnt -= (txFifo.front()->length - txPktXmitted); - txPktXmitted = 0; - txFifo.front() = NULL; - txFifo.pop_front(); - - /* normally do a writeback of the descriptor here, and ONLY after that is - done, send this interrupt. but since our stuff never actually fails, - just do this interrupt here, otherwise the code has to stray from this - nice format. besides, it's functionally the same. - */ + DPRINTF(Ethernet, "Successful Xmit! now txFifoAvail is %d\n", + txFifo.avail()); + txFifo.pop(); + + /* + * normally do a writeback of the descriptor here, and ONLY + * after that is done, send this interrupt. but since our + * stuff never actually fails, just do this interrupt here, + * otherwise the code has to stray from this nice format. + * besides, it's functionally the same. + */ devIntrPost(ISR_TXOK); - } + } if (!txFifo.empty() && !txEvent.scheduled()) { DPRINTF(Ethernet, "reschedule transmit\n"); @@ -1421,11 +1838,11 @@ EtherDev::transmit() } void -EtherDev::txDmaReadCopy() +NSGigE::txDmaReadCopy() { assert(txDmaState == dmaReading); - memcpy(txDmaData, physmem->dma_addr(txDmaAddr, txDmaLen), txDmaLen); + physmem->dma_read((uint8_t *)txDmaData, txDmaAddr, txDmaLen); txDmaState = dmaIdle; DPRINTF(EthernetDMA, "tx dma read paddr=%#x len=%d\n", @@ -1434,7 +1851,7 @@ EtherDev::txDmaReadCopy() } bool -EtherDev::doTxDmaRead() +NSGigE::doTxDmaRead() { assert(txDmaState == dmaIdle || txDmaState == dmaReadWaiting); txDmaState = dmaReading; @@ -1444,7 +1861,7 @@ EtherDev::doTxDmaRead() txDmaState = dmaReadWaiting; else dmaInterface->doDMA(Read, txDmaAddr, txDmaLen, curTick, - &txDmaReadEvent); + &txDmaReadEvent, true); return true; } @@ -1460,7 +1877,7 @@ EtherDev::doTxDmaRead() } void -EtherDev::txDmaReadDone() +NSGigE::txDmaReadDone() { assert(txDmaState == dmaReading); txDmaReadCopy(); @@ -1473,11 +1890,11 @@ EtherDev::txDmaReadDone() } void -EtherDev::txDmaWriteCopy() +NSGigE::txDmaWriteCopy() { assert(txDmaState == dmaWriting); - memcpy(physmem->dma_addr(txDmaAddr, txDmaLen), txDmaData, txDmaLen); + physmem->dma_write(txDmaAddr, (uint8_t *)txDmaData, txDmaLen); txDmaState = dmaIdle; DPRINTF(EthernetDMA, "tx dma write paddr=%#x len=%d\n", @@ -1486,7 +1903,7 @@ EtherDev::txDmaWriteCopy() } bool -EtherDev::doTxDmaWrite() +NSGigE::doTxDmaWrite() { assert(txDmaState == dmaIdle || txDmaState == dmaWriteWaiting); txDmaState = dmaWriting; @@ -1496,7 +1913,7 @@ EtherDev::doTxDmaWrite() txDmaState = dmaWriteWaiting; else dmaInterface->doDMA(WriteInvalidate, txDmaAddr, txDmaLen, curTick, - &txDmaWriteEvent); + &txDmaWriteEvent, true); return true; } @@ -1512,7 +1929,7 @@ EtherDev::doTxDmaWrite() } void -EtherDev::txDmaWriteDone() +NSGigE::txDmaWriteDone() { assert(txDmaState == dmaWriting); txDmaWriteCopy(); @@ -1525,13 +1942,14 @@ EtherDev::txDmaWriteDone() } void -EtherDev::txKick() +NSGigE::txKick() { - DPRINTF(Ethernet, "transmit kick state=%s\n", NsTxStateStrings[txState]); + DPRINTF(EthernetSM, "transmit kick txState=%s\n", + NsTxStateStrings[txState]); - if (rxKickTick > curTick) { - DPRINTF(Ethernet, "receive kick exiting, can't run till %d\n", - rxKickTick); + if (txKickTick > curTick) { + DPRINTF(EthernetSM, "transmit kick exiting, can't run till %d\n", + txKickTick); return; } @@ -1552,19 +1970,22 @@ EtherDev::txKick() switch (txState) { case txIdle: - if (!regs.command & CR_TXE) { - DPRINTF(Ethernet, "Transmit disabled. Nothing to do.\n"); + if (!txEnable) { + DPRINTF(EthernetSM, "Transmit disabled. Nothing to do.\n"); goto exit; } if (CTDD) { txState = txDescRefr; - txDmaAddr = txDescCache.link & 0x3fffffff; - txDmaData = &txDescCache; + txDmaAddr = regs.txdp & 0x3fffffff; + txDmaData = &txDescCache + offsetof(ns_desc, link); txDmaLen = sizeof(txDescCache.link); txDmaFree = dmaDescFree; + descDmaReads++; + descDmaRdBytes += txDmaLen; + if (doTxDmaRead()) goto exit; @@ -1572,10 +1993,13 @@ EtherDev::txKick() txState = txDescRead; txDmaAddr = regs.txdp & 0x3fffffff; - txDmaData = &txDescCache + offsetof(ns_desc, link); + txDmaData = &txDescCache; txDmaLen = sizeof(ns_desc); txDmaFree = dmaDescFree; + descDmaReads++; + descDmaRdBytes += txDmaLen; + if (doTxDmaRead()) goto exit; } @@ -1592,32 +2016,39 @@ EtherDev::txKick() if (txDmaState != dmaIdle) goto exit; + DPRINTF(EthernetDesc, + "txDescCache: link=%08x bufptr=%08x cmdsts=%08x extsts=%08x\n", + txDescCache.link, txDescCache.bufptr, txDescCache.cmdsts, + txDescCache.extsts); + if (txDescCache.cmdsts & CMDSTS_OWN) { txState = txFifoBlock; txFragPtr = txDescCache.bufptr; txDescCnt = txDescCache.cmdsts & CMDSTS_LEN_MASK; } else { + devIntrPost(ISR_TXIDLE); txState = txIdle; + goto exit; } break; case txFifoBlock: if (!txPacket) { - DPRINTF(Ethernet, "starting the tx of a new packet\n"); - txPacket = new EtherPacket; - txPacket->data = new uint8_t[16384]; + DPRINTF(EthernetSM, "****starting the tx of a new packet****\n"); + txPacket = new PacketData(16384); txPacketBufPtr = txPacket->data; } if (txDescCnt == 0) { - DPRINTF(Ethernet, "the txDescCnt == 0, done with descriptor\n"); + DPRINTF(EthernetSM, "the txDescCnt == 0, done with descriptor\n"); if (txDescCache.cmdsts & CMDSTS_MORE) { - DPRINTF(Ethernet, "there are more descriptors to come\n"); + DPRINTF(EthernetSM, "there are more descriptors to come\n"); txState = txDescWrite; txDescCache.cmdsts &= ~CMDSTS_OWN; - txDmaAddr = (regs.txdp + offsetof(ns_desc, cmdsts)) & 0x3fffffff; + txDmaAddr = regs.txdp + offsetof(ns_desc, cmdsts); + txDmaAddr &= 0x3fffffff; txDmaData = &(txDescCache.cmdsts); txDmaLen = sizeof(txDescCache.cmdsts); txDmaFree = dmaDescFree; @@ -1626,79 +2057,107 @@ EtherDev::txKick() goto exit; } else { /* this packet is totally done */ - DPRINTF(Ethernet, "This packet is done, let's wrap it up\n"); + 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) { + IpPtr ip(txPacket); if (txDescCache.extsts & EXTSTS_UDPPKT) { - udpChecksum(txPacket, true); + UdpPtr udp(ip); + udp->sum(0); + udp->sum(cksum(udp)); + txUdpChecksums++; } else if (txDescCache.extsts & EXTSTS_TCPPKT) { - tcpChecksum(txPacket, true); - } else if (txDescCache.extsts & EXTSTS_IPPKT) { - ipChecksum(txPacket, true); + TcpPtr tcp(ip); + tcp->sum(0); + tcp->sum(cksum(tcp)); + txTcpChecksums++; + } + if (txDescCache.extsts & EXTSTS_IPPKT) { + ip->sum(0); + ip->sum(cksum(ip)); + txIpChecksums++; } } txPacket->length = txPacketBufPtr - txPacket->data; - /* this is just because the receive can't handle a packet bigger - want to make sure */ + // this is just because the receive can't handle a + // packet bigger want to make sure assert(txPacket->length <= 1514); - txFifo.push_back(txPacket); - +#ifndef NDEBUG + bool success = +#endif + txFifo.push(txPacket); + assert(success); + + /* + * this following section is not tqo spec, but + * functionally shouldn't be any different. normally, + * the chip will wait til the transmit has occurred + * before writing back the descriptor because it has + * to wait to see that it was successfully transmitted + * to decide whether to set CMDSTS_OK or not. + * however, in the simulator since it is always + * successfully transmitted, and writing it exactly to + * spec would complicate the code, we just do it here + */ - /* this following section is not to spec, but functionally shouldn't - be any different. normally, the chip will wait til the transmit has - occurred before writing back the descriptor because it has to wait - to see that it was successfully transmitted to decide whether to set - CMDSTS_OK or not. however, in the simulator since it is always - successfully transmitted, and writing it exactly to spec would - complicate the code, we just do it here - */ txDescCache.cmdsts &= ~CMDSTS_OWN; txDescCache.cmdsts |= CMDSTS_OK; - txDmaAddr = regs.txdp & 0x3fffffff; - txDmaData = &txDescCache + offsetof(ns_desc, cmdsts); - txDmaLen = sizeof(txDescCache.cmdsts) + sizeof(txDescCache.extsts); - txDmaFree = dmaDescFree; + DPRINTF(EthernetDesc, + "txDesc writeback: cmdsts=%08x extsts=%08x\n", + txDescCache.cmdsts, txDescCache.extsts); + txDmaAddr = regs.txdp + offsetof(ns_desc, cmdsts); + txDmaAddr &= 0x3fffffff; + txDmaData = &(txDescCache.cmdsts); + txDmaLen = sizeof(txDescCache.cmdsts) + + sizeof(txDescCache.extsts); + txDmaFree = dmaDescFree; - if (doTxDmaWrite()) - goto exit; + descDmaWrites++; + descDmaWrBytes += txDmaLen; - txPacket = 0; transmit(); + txPacket = 0; - if (txHalt) { + if (!txEnable) { + DPRINTF(EthernetSM, "halting TX state machine\n"); txState = txIdle; - txHalt = false; + goto exit; } else txState = txAdvance; + + if (doTxDmaWrite()) + goto exit; } } else { - DPRINTF(Ethernet, "this descriptor isn't done yet\n"); - /* the fill thresh is in units of 32 bytes, shift right by 8 to get the - value, shift left by 5 to get the real number of bytes */ - if (txFifoAvail < ((regs.txcfg & TXCFG_FLTH_MASK) >> 3)) { - DPRINTF(Ethernet, "txFifoAvail=%d, regs.txcfg & TXCFG_FLTH_MASK = %#x\n", - txFifoAvail, regs.txcfg & TXCFG_FLTH_MASK); + DPRINTF(EthernetSM, "this descriptor isn't done yet\n"); + if (!txFifo.full()) { + txState = txFragRead; + + /* + * The number of bytes transferred is either whatever + * is left in the descriptor (txDescCnt), or if there + * is not enough room in the fifo, just whatever room + * is left in the fifo + */ + txXferLen = min(txDescCnt, txFifo.avail()); + + txDmaAddr = txFragPtr & 0x3fffffff; + txDmaData = txPacketBufPtr; + txDmaLen = txXferLen; + txDmaFree = dmaDataFree; + + if (doTxDmaRead()) + goto exit; + } else { + txState = txFifoBlock; + transmit(); + goto exit; } - txState = txFragRead; - - /* The number of bytes transferred is either whatever is left - in the descriptor (txDescCnt), or if there is not enough - room in the fifo, just whatever room is left in the fifo - */ - txXferLen = min(txDescCnt, txFifoAvail); - - txDmaAddr = txFragPtr & 0x3fffffff; - txDmaData = txPacketBufPtr; - txDmaLen = txXferLen; - txDmaFree = dmaDataFree; - - if (doTxDmaRead()) - goto exit; } break; @@ -1708,8 +2167,8 @@ EtherDev::txKick() txPacketBufPtr += txXferLen; txFragPtr += txXferLen; - txFifoCnt += txXferLen; txDescCnt -= txXferLen; + txFifo.reserve(txXferLen); txState = txFifoBlock; break; @@ -1718,26 +2177,17 @@ EtherDev::txKick() if (txDmaState != dmaIdle) goto exit; - if (txFifoCnt >= ((regs.txcfg & TXCFG_DRTH_MASK) << 5)) { - if (txFifo.empty()) { - uint32_t xmitted = (uint32_t) (txPacketBufPtr - txPacket->data - txPktXmitted); - txFifoCnt -= xmitted; - txPktXmitted += xmitted; - } else { - transmit(); - } - } - - if (txDescCache.cmdsts & CMDSTS_INTR) { + if (txDescCache.cmdsts & CMDSTS_INTR) devIntrPost(ISR_TXDESC); - } txState = txAdvance; break; case txAdvance: if (txDescCache.link == 0) { + devIntrPost(ISR_TXIDLE); txState = txIdle; + goto exit; } else { txState = txDescRead; regs.txdp = txDescCache.link; @@ -1757,32 +2207,28 @@ EtherDev::txKick() panic("invalid state"); } - DPRINTF(Ethernet, "entering next tx state=%s\n", + DPRINTF(EthernetSM, "entering next txState=%s\n", NsTxStateStrings[txState]); - if (txState == txIdle) { - regs.command &= ~CR_TXE; - devIntrPost(ISR_TXIDLE); - return; - } - goto next; exit: /** * @todo do we want to schedule a future kick? */ - DPRINTF(Ethernet, "tx state machine exited state=%s\n", + DPRINTF(EthernetSM, "tx state machine exited txState=%s\n", NsTxStateStrings[txState]); } void -EtherDev::transferDone() +NSGigE::transferDone() { - if (txFifo.empty()) + if (txFifo.empty()) { + DPRINTF(Ethernet, "transfer complete: txFifo empty...nothing to do\n"); return; + } - DPRINTF(Ethernet, "schedule transmit\n"); + DPRINTF(Ethernet, "transfer complete: data in txFifo...schedule xmit\n"); if (txEvent.scheduled()) txEvent.reschedule(curTick + 1); @@ -1791,45 +2237,35 @@ EtherDev::transferDone() } bool -EtherDev::rxFilter(PacketPtr packet) +NSGigE::rxFilter(const PacketPtr &packet) { + EthPtr eth = packet; bool drop = true; string type; - if (packet->IsUnicast()) { - type = "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, sizeof(rom.perfectMatch)) == 0)) + if (acceptPerfect && dst == rom.perfectMatch) drop = false; - eth_header *eth = (eth_header *) packet->data; - if ((acceptArp) && (eth->type == 0x806)) + if (acceptArp && eth->type() == ETH_TYPE_ARP) drop = false; - } else if (packet->IsBroadcast()) { - type = "broadcast"; - + } else if (dst.broadcast()) { // if we're accepting broadcasts if (acceptBroadcast) drop = false; - } else if (packet->IsMulticast()) { - type = "multicast"; - + } else if (dst.multicast()) { // if we're accepting all multicasts if (acceptMulticast) drop = false; - } else { - type = "unknown"; - - // oh well, punt on this one } if (drop) { @@ -1841,13 +2277,17 @@ EtherDev::rxFilter(PacketPtr packet) } bool -EtherDev::recvPacket(PacketPtr packet) +NSGigE::recvPacket(PacketPtr packet) { rxBytes += packet->length; rxPackets++; - if (rxState == rxIdle) { + DPRINTF(Ethernet, "Receiving packet from wire, rxFifoAvail=%d\n", + rxFifo.avail()); + + if (!rxEnable) { DPRINTF(Ethernet, "receive disabled...packet dropped\n"); + debug_break(); interface->recvDone(); return true; } @@ -1858,128 +2298,40 @@ EtherDev::recvPacket(PacketPtr packet) return true; } - if (rxFifoCnt + packet->length >= MAX_RX_FIFO_SIZE) { - 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; + rxFifo.push(packet); interface->recvDone(); rxKick(); return true; } -/** - * does a udp checksum. if gen is true, then it generates it and puts it in the right place - * else, it just checks what it calculates against the value in the header in packet - */ -bool -EtherDev::udpChecksum(PacketPtr packet, bool gen) -{ - udp_header *hdr = (udp_header *) packet->getTransportHdr(); - - ip_header *ip = packet->getIpHdr(); - - pseudo_header *pseudo = new pseudo_header; - - pseudo->src_ip_addr = ip->src_ip_addr; - pseudo->dest_ip_addr = ip->dest_ip_addr; - pseudo->protocol = ip->protocol; - pseudo->len = hdr->len; - - uint16_t cksum = checksumCalc((uint16_t *) pseudo, (uint16_t *) hdr, - (uint32_t) hdr->len); - - delete pseudo; - if (gen) - hdr->chksum = cksum; - else - if (cksum != 0) - return false; - - return true; -} - -bool -EtherDev::tcpChecksum(PacketPtr packet, bool gen) -{ - tcp_header *hdr = (tcp_header *) packet->getTransportHdr(); - - ip_header *ip = packet->getIpHdr(); - - pseudo_header *pseudo = new pseudo_header; - - pseudo->src_ip_addr = ip->src_ip_addr; - pseudo->dest_ip_addr = ip->dest_ip_addr; - pseudo->protocol = ip->protocol; - pseudo->len = ip->dgram_len - (ip->vers_len & 0xf); - - uint16_t cksum = checksumCalc((uint16_t *) pseudo, (uint16_t *) hdr, - (uint32_t) pseudo->len); - - delete pseudo; - if (gen) - hdr->chksum = cksum; - else - if (cksum != 0) - return false; - - return true; -} - -bool -EtherDev::ipChecksum(PacketPtr packet, bool gen) -{ - ip_header *hdr = packet->getIpHdr(); - - uint16_t cksum = checksumCalc(NULL, (uint16_t *) hdr, (hdr->vers_len & 0xf)); - - if (gen) - hdr->hdr_chksum = cksum; - else - if (cksum != 0) - return false; - - return true; -} - -uint16_t -EtherDev::checksumCalc(uint16_t *pseudo, uint16_t *buf, uint32_t len) -{ - uint32_t sum = 0; - - uint16_t last_pad = 0; - if (len & 1) { - last_pad = buf[len/2] & 0xff; - len--; - sum += last_pad; - } - - if (pseudo) { - sum = pseudo[0] + pseudo[1] + pseudo[2] + - pseudo[3] + pseudo[4] + pseudo[5]; - } - - for (int i=0; i < (len/2); ++i) { - sum += buf[i]; - } - - while (sum >> 16) - sum = (sum >> 16) + (sum & 0xffff); - - return ~sum; -} - //===================================================================== // // void -EtherDev::serialize(ostream &os) +NSGigE::serialize(ostream &os) { + // Serialize the PciDev base class + PciDev::serialize(os); + /* * Finalize any DMA events now. */ @@ -2028,23 +2380,38 @@ EtherDev::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_SCALAR(ioEnable); /* - * Serialize the various helper variables + * Serialize the data Fifos */ - uint32_t txPktBufPtr = (uint32_t) txPacketBufPtr; - SERIALIZE_SCALAR(txPktBufPtr); - uint32_t rxPktBufPtr = (uint32_t) rxPktBufPtr; - SERIALIZE_SCALAR(rxPktBufPtr); - SERIALIZE_SCALAR(txXferLen); - SERIALIZE_SCALAR(rxXferLen); - SERIALIZE_SCALAR(txPktXmitted); + rxFifo.serialize("rxFifo", os); + txFifo.serialize("txFifo", os); + /* + * Serialize the various helper variables + */ 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); + } + bool rxPacketExists = rxPacket; SERIALIZE_SCALAR(rxPacketExists); + if (rxPacketExists) { + rxPacket->serialize("rxPacket", os); + uint32_t rxPktBufPtr = (uint32_t) (rxPacketBufPtr - rxPacket->data); + SERIALIZE_SCALAR(rxPktBufPtr); + } + + SERIALIZE_SCALAR(txXferLen); + SERIALIZE_SCALAR(rxXferLen); /* * Serialize DescCaches @@ -2061,14 +2428,10 @@ EtherDev::serialize(ostream &os) /* * Serialize tx state machine */ - int txNumPkts = txFifo.size(); - SERIALIZE_SCALAR(txNumPkts); int txState = this->txState; SERIALIZE_SCALAR(txState); + SERIALIZE_SCALAR(txEnable); SERIALIZE_SCALAR(CTDD); - SERIALIZE_SCALAR(txFifoCnt); - SERIALIZE_SCALAR(txFifoAvail); - SERIALIZE_SCALAR(txHalt); SERIALIZE_SCALAR(txFragPtr); SERIALIZE_SCALAR(txDescCnt); int txDmaState = this->txDmaState; @@ -2077,27 +2440,35 @@ EtherDev::serialize(ostream &os) /* * Serialize rx state machine */ - int rxNumPkts = rxFifo.size(); - SERIALIZE_SCALAR(rxNumPkts); int rxState = this->rxState; SERIALIZE_SCALAR(rxState); + SERIALIZE_SCALAR(rxEnable); SERIALIZE_SCALAR(CRDD); SERIALIZE_SCALAR(rxPktBytes); - SERIALIZE_SCALAR(rxFifoCnt); - SERIALIZE_SCALAR(rxHalt); + SERIALIZE_SCALAR(rxFragPtr); SERIALIZE_SCALAR(rxDescCnt); int rxDmaState = this->rxDmaState; SERIALIZE_SCALAR(rxDmaState); SERIALIZE_SCALAR(extstsEnable); - /* + /* * If there's a pending transmit, store the time so we can * reschedule it later */ Tick transmitTick = txEvent.scheduled() ? txEvent.when() - curTick : 0; SERIALIZE_SCALAR(transmitTick); + /* + * receive address filter settings + */ + SERIALIZE_SCALAR(rxFilterEnable); + SERIALIZE_SCALAR(acceptBroadcast); + SERIALIZE_SCALAR(acceptMulticast); + SERIALIZE_SCALAR(acceptUnicast); + SERIALIZE_SCALAR(acceptPerfect); + SERIALIZE_SCALAR(acceptArp); + /* * Keep track of pending interrupt status. */ @@ -2108,29 +2479,14 @@ EtherDev::serialize(ostream &os) intrEventTick = intrEvent->when(); SERIALIZE_SCALAR(intrEventTick); - int i = 0; - for (pktiter_t p = rxFifo.begin(); p != rxFifo.end(); ++p) { - nameOut(os, csprintf("%s.rxFifo%d", name(), i++)); - (*p)->serialize(os); - } - if (rxPacketExists) { - nameOut(os, csprintf("%s.rxPacket", name())); - rxPacket->serialize(os); - } - i = 0; - for (pktiter_t p = txFifo.begin(); p != txFifo.end(); ++p) { - nameOut(os, csprintf("%s.txFifo%d", name(), i++)); - (*p)->serialize(os); - } - if (txPacketExists) { - nameOut(os, csprintf("%s.txPacket", name())); - txPacket->serialize(os); - } } void -EtherDev::unserialize(Checkpoint *cp, const std::string §ion) +NSGigE::unserialize(Checkpoint *cp, const std::string §ion) { + // Unserialize the PciDev base class + PciDev::unserialize(cp, section); + UNSERIALIZE_SCALAR(regs.command); UNSERIALIZE_SCALAR(regs.config); UNSERIALIZE_SCALAR(regs.mear); @@ -2164,25 +2520,44 @@ EtherDev::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_SCALAR(ioEnable); /* - * unserialize the various helper variables + * unserialize the data fifos */ - uint32_t txPktBufPtr; - UNSERIALIZE_SCALAR(txPktBufPtr); - txPacketBufPtr = (uint8_t *) txPktBufPtr; - uint32_t rxPktBufPtr; - UNSERIALIZE_SCALAR(rxPktBufPtr); - rxPacketBufPtr = (uint8_t *) rxPktBufPtr; - UNSERIALIZE_SCALAR(txXferLen); - UNSERIALIZE_SCALAR(rxXferLen); - UNSERIALIZE_SCALAR(txPktXmitted); + rxFifo.unserialize("rxFifo", cp, section); + txFifo.unserialize("txFifo", cp, section); + /* + * unserialize the various helper variables + */ bool txPacketExists; UNSERIALIZE_SCALAR(txPacketExists); + if (txPacketExists) { + txPacket = new PacketData(16384); + txPacket->unserialize("txPacket", cp, section); + uint32_t txPktBufPtr; + UNSERIALIZE_SCALAR(txPktBufPtr); + txPacketBufPtr = (uint8_t *) txPacket->data + txPktBufPtr; + } else + txPacket = 0; + bool rxPacketExists; UNSERIALIZE_SCALAR(rxPacketExists); + rxPacket = 0; + if (rxPacketExists) { + rxPacket = new PacketData(16384); + rxPacket->unserialize("rxPacket", cp, section); + uint32_t rxPktBufPtr; + UNSERIALIZE_SCALAR(rxPktBufPtr); + rxPacketBufPtr = (uint8_t *) rxPacket->data + rxPktBufPtr; + } else + rxPacket = 0; + + UNSERIALIZE_SCALAR(txXferLen); + UNSERIALIZE_SCALAR(rxXferLen); /* * Unserialize DescCaches @@ -2199,15 +2574,11 @@ EtherDev::unserialize(Checkpoint *cp, const std::string §ion) /* * unserialize tx state machine */ - int txNumPkts; - UNSERIALIZE_SCALAR(txNumPkts); int txState; UNSERIALIZE_SCALAR(txState); this->txState = (TxState) txState; + UNSERIALIZE_SCALAR(txEnable); UNSERIALIZE_SCALAR(CTDD); - UNSERIALIZE_SCALAR(txFifoCnt); - UNSERIALIZE_SCALAR(txFifoAvail); - UNSERIALIZE_SCALAR(txHalt); UNSERIALIZE_SCALAR(txFragPtr); UNSERIALIZE_SCALAR(txDescCnt); int txDmaState; @@ -2217,15 +2588,13 @@ EtherDev::unserialize(Checkpoint *cp, const std::string §ion) /* * unserialize rx state machine */ - int rxNumPkts; - UNSERIALIZE_SCALAR(rxNumPkts); int rxState; UNSERIALIZE_SCALAR(rxState); this->rxState = (RxState) rxState; + UNSERIALIZE_SCALAR(rxEnable); UNSERIALIZE_SCALAR(CRDD); UNSERIALIZE_SCALAR(rxPktBytes); - UNSERIALIZE_SCALAR(rxFifoCnt); - UNSERIALIZE_SCALAR(rxHalt); + UNSERIALIZE_SCALAR(rxFragPtr); UNSERIALIZE_SCALAR(rxDescCnt); int rxDmaState; UNSERIALIZE_SCALAR(rxDmaState); @@ -2234,14 +2603,23 @@ EtherDev::unserialize(Checkpoint *cp, const std::string §ion) UNSERIALIZE_SCALAR(extstsEnable); /* - * If there's a pending transmit, store the time so we can - * reschedule it later + * If there's a pending transmit, reschedule it now */ Tick transmitTick; UNSERIALIZE_SCALAR(transmitTick); if (transmitTick) txEvent.schedule(curTick + transmitTick); + /* + * unserialize receive address filter settings + */ + UNSERIALIZE_SCALAR(rxFilterEnable); + UNSERIALIZE_SCALAR(acceptBroadcast); + UNSERIALIZE_SCALAR(acceptMulticast); + UNSERIALIZE_SCALAR(acceptUnicast); + UNSERIALIZE_SCALAR(acceptPerfect); + UNSERIALIZE_SCALAR(acceptArp); + /* * Keep track of pending interrupt status. */ @@ -2254,55 +2632,40 @@ EtherDev::unserialize(Checkpoint *cp, const std::string §ion) intrEvent->schedule(intrEventTick); } - for (int i = 0; i < rxNumPkts; ++i) { - PacketPtr p = new EtherPacket; - p->unserialize(cp, csprintf("%s.rxFifo%d", section, i)); - rxFifo.push_back(p); - } - rxPacket = NULL; - if (rxPacketExists) { - rxPacket = new EtherPacket; - rxPacket->unserialize(cp, csprintf("%s.rxPacket", section)); - } - for (int i = 0; i < txNumPkts; ++i) { - PacketPtr p = new EtherPacket; - p->unserialize(cp, csprintf("%s.rxFifo%d", section, i)); - txFifo.push_back(p); - } - if (txPacketExists) { - txPacket = new EtherPacket; - txPacket->unserialize(cp, csprintf("%s.txPacket", section)); + /* + * re-add addrRanges to bus bridges + */ + if (pioInterface) { + pioInterface->addAddrRange(RangeSize(BARAddrs[0], BARSize[0])); + pioInterface->addAddrRange(RangeSize(BARAddrs[1], BARSize[1])); } } - Tick -EtherDev::cacheAccess(MemReqPtr &req) +NSGigE::cacheAccess(MemReqPtr &req) { DPRINTF(EthernetPIO, "timing access to paddr=%#x (daddr=%#x)\n", req->paddr, req->paddr - addr); return curTick + pioLatency; } -//===================================================================== - -BEGIN_DECLARE_SIM_OBJECT_PARAMS(EtherDevInt) +BEGIN_DECLARE_SIM_OBJECT_PARAMS(NSGigEInt) SimObjectParam peer; - SimObjectParam device; + SimObjectParam device; -END_DECLARE_SIM_OBJECT_PARAMS(EtherDevInt) +END_DECLARE_SIM_OBJECT_PARAMS(NSGigEInt) -BEGIN_INIT_SIM_OBJECT_PARAMS(EtherDevInt) +BEGIN_INIT_SIM_OBJECT_PARAMS(NSGigEInt) INIT_PARAM_DFLT(peer, "peer interface", NULL), INIT_PARAM(device, "Ethernet device of this interface") -END_INIT_SIM_OBJECT_PARAMS(EtherDevInt) +END_INIT_SIM_OBJECT_PARAMS(NSGigEInt) -CREATE_SIM_OBJECT(EtherDevInt) +CREATE_SIM_OBJECT(NSGigEInt) { - EtherDevInt *dev_int = new EtherDevInt(getInstanceName(), device); + NSGigEInt *dev_int = new NSGigEInt(getInstanceName(), device); EtherInt *p = (EtherInt *)peer; if (p) { @@ -2313,21 +2676,20 @@ CREATE_SIM_OBJECT(EtherDevInt) return dev_int; } -REGISTER_SIM_OBJECT("EtherDevInt", EtherDevInt) +REGISTER_SIM_OBJECT("NSGigEInt", NSGigEInt) -BEGIN_DECLARE_SIM_OBJECT_PARAMS(EtherDev) +BEGIN_DECLARE_SIM_OBJECT_PARAMS(NSGigE) + Param addr; Param tx_delay; Param rx_delay; - SimObjectParam intr_ctrl; Param intr_delay; SimObjectParam mmu; SimObjectParam physmem; - Param addr; Param rx_filter; Param hardware_address; - SimObjectParam header_bus; + SimObjectParam io_bus; SimObjectParam payload_bus; SimObjectParam hier; Param pio_latency; @@ -2339,29 +2701,30 @@ BEGIN_DECLARE_SIM_OBJECT_PARAMS(EtherDev) Param dma_write_factor; SimObjectParam configspace; SimObjectParam configdata; - SimObjectParam tsunami; + SimObjectParam platform; Param pci_bus; Param pci_dev; Param pci_func; + Param tx_fifo_size; + Param rx_fifo_size; -END_DECLARE_SIM_OBJECT_PARAMS(EtherDev) +END_DECLARE_SIM_OBJECT_PARAMS(NSGigE) -BEGIN_INIT_SIM_OBJECT_PARAMS(EtherDev) +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(intr_ctrl, "Interrupt Controller"), INIT_PARAM_DFLT(intr_delay, "Interrupt Delay in microseconds", 0), INIT_PARAM(mmu, "Memory Controller"), INIT_PARAM(physmem, "Physical Memory"), - INIT_PARAM(addr, "Device Address"), 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(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), - INIT_PARAM_DFLT(pio_latency, "Programmed IO latency", 1000), + 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), @@ -2370,27 +2733,48 @@ BEGIN_INIT_SIM_OBJECT_PARAMS(EtherDev) 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(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) -END_INIT_SIM_OBJECT_PARAMS(EtherDev) +END_INIT_SIM_OBJECT_PARAMS(NSGigE) -CREATE_SIM_OBJECT(EtherDev) +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 EtherDev(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, - addr); + NSGigE::Params *params = new NSGigE::Params; + + params->name = getInstanceName(); + params->mmu = mmu; + params->configSpace = configspace; + params->configData = configdata; + params->plat = platform; + params->busNum = pci_bus; + params->deviceNum = pci_dev; + params->functionNum = pci_func; + + params->intr_delay = intr_delay; + params->pmem = physmem; + params->tx_delay = tx_delay; + params->rx_delay = rx_delay; + params->hier = hier; + params->header_bus = io_bus; + params->payload_bus = payload_bus; + params->pio_latency = pio_latency; + 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->rx_filter = rx_filter; + params->eaddr = hardware_address; + params->tx_fifo_size = tx_fifo_size; + params->rx_fifo_size = rx_fifo_size; + return new NSGigE(params); } -REGISTER_SIM_OBJECT("EtherDev", EtherDev) +REGISTER_SIM_OBJECT("NSGigE", NSGigE)