/*
- * 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
#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"
#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[] =
{
};
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, 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<Bus>(name + ".dma",
- header_bus, payload_bus, 1);
- else
- dmaInterface = new DMAInterface<Bus>(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<Bus>(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<Bus>(name() + ".dma",
+ p->header_bus,
+ p->payload_bus, 1);
+ else
+ dmaInterface = new DMAInterface<Bus>(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<Bus>(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")
.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)")
.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)")
.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;
}
* 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;
+ }
}
/**
* 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) {
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];
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;
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;
}
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);
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)
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) ;
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) ;
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)
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;
case RXDP:
regs.rxdp = reg;
+ CRDD = false;
break;
case RXDP_HI:
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;
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");
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);
}
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",
}
bool
-EtherDev::doRxDmaRead()
+NSGigE::doRxDmaRead()
{
assert(rxDmaState == dmaIdle || rxDmaState == dmaReadWaiting);
rxDmaState = dmaReading;
rxDmaState = dmaReadWaiting;
else
dmaInterface->doDMA(Read, rxDmaAddr, rxDmaLen, curTick,
- &rxDmaReadEvent);
+ &rxDmaReadEvent, true);
return true;
}
}
void
-EtherDev::rxDmaReadDone()
+NSGigE::rxDmaReadDone()
{
assert(rxDmaState == dmaReading);
rxDmaReadCopy();
}
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",
}
bool
-EtherDev::doRxDmaWrite()
+NSGigE::doRxDmaWrite()
{
assert(rxDmaState == dmaIdle || rxDmaState == dmaWriteWaiting);
rxDmaState = dmaWriting;
rxDmaState = dmaWriteWaiting;
else
dmaInterface->doDMA(WriteInvalidate, rxDmaAddr, rxDmaLen, curTick,
- &rxDmaWriteEvent);
+ &rxDmaWriteEvent, true);
return true;
}
}
void
-EtherDev::rxDmaWriteDone()
+NSGigE::rxDmaWriteDone()
{
assert(rxDmaState == dmaWriting);
rxDmaWriteCopy();
}
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;
}
}
// 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;
}
rxDmaLen = sizeof(rxDescCache.link);
rxDmaFree = dmaDescFree;
+ descDmaReads++;
+ descDmaRdBytes += rxDmaLen;
+
if (doRxDmaRead())
goto exit;
} else {
rxDmaLen = sizeof(ns_desc);
rxDmaFree = dmaDescFree;
+ descDmaReads++;
+ descDmaRdBytes += rxDmaLen;
+
if (doRxDmaRead())
goto exit;
}
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;
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;
//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;
}
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;
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");
}
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",
}
bool
-EtherDev::doTxDmaRead()
+NSGigE::doTxDmaRead()
{
assert(txDmaState == dmaIdle || txDmaState == dmaReadWaiting);
txDmaState = dmaReading;
txDmaState = dmaReadWaiting;
else
dmaInterface->doDMA(Read, txDmaAddr, txDmaLen, curTick,
- &txDmaReadEvent);
+ &txDmaReadEvent, true);
return true;
}
}
void
-EtherDev::txDmaReadDone()
+NSGigE::txDmaReadDone()
{
assert(txDmaState == dmaReading);
txDmaReadCopy();
}
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",
}
bool
-EtherDev::doTxDmaWrite()
+NSGigE::doTxDmaWrite()
{
assert(txDmaState == dmaIdle || txDmaState == dmaWriteWaiting);
txDmaState = dmaWriting;
txDmaState = dmaWriteWaiting;
else
dmaInterface->doDMA(WriteInvalidate, txDmaAddr, txDmaLen, curTick,
- &txDmaWriteEvent);
+ &txDmaWriteEvent, true);
return true;
}
}
void
-EtherDev::txDmaWriteDone()
+NSGigE::txDmaWriteDone()
{
assert(txDmaState == dmaWriting);
txDmaWriteCopy();
}
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;
}
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;
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;
}
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;
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<uint32_t>(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<uint32_t>(txDescCnt, txFifoAvail);
-
- txDmaAddr = txFragPtr & 0x3fffffff;
- txDmaData = txPacketBufPtr;
- txDmaLen = txXferLen;
- txDmaFree = dmaDataFree;
-
- if (doTxDmaRead())
- goto exit;
}
break;
txPacketBufPtr += txXferLen;
txFragPtr += txXferLen;
- txFifoCnt += txXferLen;
txDescCnt -= txXferLen;
+ txFifo.reserve(txXferLen);
txState = txFifoBlock;
break;
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;
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);
}
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) {
}
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;
}
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.
*/
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
/*
* 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;
/*
* 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.
*/
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);
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
/*
* 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;
/*
* 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);
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.
*/
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<EtherInt *> peer;
- SimObjectParam<EtherDev *> device;
+ SimObjectParam<NSGigE *> 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) {
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> addr;
Param<Tick> tx_delay;
Param<Tick> rx_delay;
- SimObjectParam<IntrControl *> intr_ctrl;
Param<Tick> intr_delay;
SimObjectParam<MemoryController *> mmu;
SimObjectParam<PhysicalMemory *> physmem;
- Param<Addr> addr;
Param<bool> rx_filter;
Param<string> hardware_address;
- SimObjectParam<Bus*> header_bus;
+ SimObjectParam<Bus*> io_bus;
SimObjectParam<Bus*> payload_bus;
SimObjectParam<HierParams *> hier;
Param<Tick> pio_latency;
Param<Tick> dma_write_factor;
SimObjectParam<PciConfigAll *> configspace;
SimObjectParam<PciConfigData *> configdata;
- SimObjectParam<Tsunami *> tsunami;
+ SimObjectParam<Platform *> platform;
Param<uint32_t> pci_bus;
Param<uint32_t> pci_dev;
Param<uint32_t> pci_func;
+ Param<uint32_t> tx_fifo_size;
+ Param<uint32_t> 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),
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)