summaryrefslogtreecommitdiff
path: root/dev/ns_gige.cc
diff options
context:
space:
mode:
Diffstat (limited to 'dev/ns_gige.cc')
-rw-r--r--dev/ns_gige.cc1865
1 files changed, 1147 insertions, 718 deletions
diff --git a/dev/ns_gige.cc b/dev/ns_gige.cc
index e3c31597e..2277ececc 100644
--- a/dev/ns_gige.cc
+++ b/dev/ns_gige.cc
@@ -40,12 +40,49 @@
#include "dev/dma.hh"
#include "dev/ns_gige.hh"
#include "dev/etherlink.hh"
+#include "mem/bus/bus.hh"
+#include "mem/bus/dma_interface.hh"
+#include "mem/bus/pio_interface.hh"
+#include "mem/bus/pio_interface_impl.hh"
#include "mem/functional_mem/memory_control.hh"
#include "mem/functional_mem/physical_memory.hh"
#include "sim/builder.hh"
#include "sim/host.hh"
#include "sim/sim_stats.hh"
#include "targetarch/vtophys.hh"
+#include "dev/pciconfigall.hh"
+#include "dev/tsunami_cchip.hh"
+
+const char *NsRxStateStrings[] =
+{
+ "rxIdle",
+ "rxDescRefr",
+ "rxDescRead",
+ "rxFifoBlock",
+ "rxFragWrite",
+ "rxDescWrite",
+ "rxAdvance"
+};
+
+const char *NsTxStateStrings[] =
+{
+ "txIdle",
+ "txDescRefr",
+ "txDescRead",
+ "txFifoBlock",
+ "txFragRead",
+ "txDescWrite",
+ "txAdvance"
+};
+
+const char *NsDmaState[] =
+{
+ "dmaIdle",
+ "dmaReading",
+ "dmaWriting",
+ "dmaReadWaiting",
+ "dmaWriteWaiting"
+};
using namespace std;
@@ -53,40 +90,68 @@ using namespace std;
//
// EtherDev PCI Device
//
-EtherDev::EtherDev(const string &_name, DmaEngine *de, bool use_interface,
- IntrControl *i, MemoryController *mmu, PhysicalMemory *pmem,
- PCIConfigAll *cf, PciConfigData *cd, Tsunami *t, uint32_t bus,
- uint32_t dev, uint32_t func, bool rx_filter,
- const int eaddr[6], Tick tx_delay, Tick rx_delay, Addr addr,
- Addr mask)
- : PciDev(_name, mmu, cf, cd, bus, dev, func), tsunami(t),
- addr(addr), mask(mask), txPacketLen(0),
- txPacketBufPtr(NULL), rxPacketBufPtr(NULL), rxDescBufPtr(NULL),
- fragLen(0), rxCopied(0), txState(txIdle), CTDD(false), txFifoCnt(0),
- txFifoAvail(MAX_TX_FIFO_SIZE), txHalt(false), txPacketFlag(false),
- txFragPtr(0), txDescCnt(0), rxState(rxIdle), CRDD(false),
- rxPktBytes(0), rxFifoCnt(0), rxHalt(false), rxPacketFlag(false),
- rxFragPtr(0), rxDescCnt(0), extstsEnable(false), maxTxBurst(0),
- maxRxBurst(0), physmem(pmem),
- rxDescDoneCB(this), rxDoneCB(this), txDescDoneCB(this), txDoneCB(this),
- dma(de), readRequest(use_interface), writeRequest(use_interface),
- readDescRequest(use_interface), writeDescRequest(use_interface),
- interface(NULL), intctrl(i), txDelay(tx_delay), rxDelay(rx_delay),
- txEvent(this), cpuPendingIntr(false), rxFilterEnable(rx_filter),
- acceptBroadcast(false), acceptMulticast(false), acceptUnicast(false),
- acceptPerfect(false), acceptArp(false)
+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),
+ txFragPtr(0), txDescCnt(0), txDmaState(dmaIdle), rxState(rxIdle),
+ CRDD(false), rxPktBytes(0), rxFifoCnt(0), rxHalt(false),
+ 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),
+ acceptMulticast(false), acceptUnicast(false),
+ acceptPerfect(false), acceptArp(false),
+ physmem(pmem), intctrl(i), intrTick(0),
+ cpuPendingIntr(false), intrEvent(0), interface(0), pioLatency(pio_latency)
{
+ 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);
+
+ }
+
+
+ intrDelay = US2Ticks(intr_delay);
+ dmaReadDelay = dma_read_delay;
+ dmaWriteDelay = dma_write_delay;
+ dmaReadFactor = dma_read_factor;
+ dmaWriteFactor = dma_write_factor;
+
memset(&regs, 0, sizeof(regs));
regsReset();
- regs.perfectMatch[0] = eaddr[0];
- regs.perfectMatch[1] = eaddr[1];
- regs.perfectMatch[2] = eaddr[2];
- regs.perfectMatch[3] = eaddr[3];
- regs.perfectMatch[4] = eaddr[4];
- regs.perfectMatch[5] = eaddr[5];
-
+ 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];
}
EtherDev::~EtherDev()
@@ -173,14 +238,25 @@ EtherDev::WriteConfig(int offset, int size, uint32_t data)
}
Fault
-EtherDev::read(MemReqPtr req, uint8_t *data)
+EtherDev::read(MemReqPtr &req, uint8_t *data)
{
- DPRINTF(Ethernet, "read va=%#x size=%d\n", req->vaddr, req->size);
+ Addr daddr = req->paddr & 0xfff;
+ DPRINTF(EthernetPIO, "read da=%#x pa=%#x va=%#x size=%d\n",
+ daddr, req->paddr, req->vaddr, req->size);
- Addr daddr = req->paddr - addr;
-
- if (daddr > LAST)
+ if (daddr > LAST && daddr <= RESERVED) {
panic("Accessing reserved register");
+ } else if (daddr > RESERVED && daddr <= 0x3FC) {
+ ReadConfig(daddr & 0xff, req->size, data);
+ return No_Fault;
+ } else if (daddr >= MIB_START && daddr <= MIB_END) {
+ // don't implement all the MIB's. hopefully the kernel
+ // doesn't actually DEPEND upon their values
+ uint32_t &reg = *(uint32_t *) data;
+ reg = 0;
+ return No_Fault;
+ } else if (daddr > 0x3FC)
+ panic("Something is messed up!\n");
switch (req->size) {
case sizeof(uint32_t):
@@ -267,19 +343,20 @@ EtherDev::read(MemReqPtr req, uint8_t *data)
break;
case RFDR:
-
+ DPRINTF(Ethernet, "reading from RFDR\n");
switch (regs.rfcr & RFCR_RFADDR) {
case 0x000:
- reg = regs.perfectMatch[1] << 8;
- reg += regs.perfectMatch[0];
+ reg = rom.perfectMatch[1];
+ reg = reg << 8;
+ reg += rom.perfectMatch[0];
break;
case 0x002:
- reg = regs.perfectMatch[3] << 8;
- reg += regs.perfectMatch[2];
+ reg = rom.perfectMatch[3] << 8;
+ reg += rom.perfectMatch[2];
break;
case 0x004:
- reg = regs.perfectMatch[5] << 8;
- reg += regs.perfectMatch[4];
+ reg = rom.perfectMatch[5] << 8;
+ reg += rom.perfectMatch[4];
break;
default:
panic("reading from RFDR for something for other than PMATCH!\n");
@@ -340,7 +417,7 @@ EtherDev::read(MemReqPtr req, uint8_t *data)
panic("reading unimplemented register: addr = %#x", daddr);
}
- DPRINTF(Ethernet, "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;
@@ -353,21 +430,23 @@ EtherDev::read(MemReqPtr req, uint8_t *data)
}
Fault
-EtherDev::write(MemReqPtr req, const uint8_t *data)
+EtherDev::write(MemReqPtr &req, const uint8_t *data)
{
- DPRINTF(Ethernet, "write va=%#x size=%d\n", req->vaddr, req->size);
-
- Addr daddr = req->paddr - addr;
+ Addr daddr = req->paddr & 0xfff;
+ DPRINTF(EthernetPIO, "write da=%#x pa=%#x va=%#x size=%d\n",
+ daddr, req->paddr, req->vaddr, req->size);
- if (daddr > LAST && daddr <= RESERVED)
+ if (daddr > LAST && daddr <= RESERVED) {
panic("Accessing reserved register");
-
- if (daddr > RESERVED)
- panic("higher memory accesses not implemented!\n");
+ } else if (daddr > RESERVED && daddr <= 0x3FC) {
+ WriteConfig(daddr & 0xff, req->size, *(uint32_t *)data);
+ return No_Fault;
+ } else if (daddr > 0x3FC)
+ panic("Something is messed up!\n");
if (req->size == sizeof(uint32_t)) {
uint32_t reg = *(uint32_t *)data;
- DPRINTF(Ethernet, "write data=%d data=%#x\n", reg, reg);
+ DPRINTF(EthernetPIO, "write data=%d data=%#x\n", reg, reg);
switch (daddr) {
case CR:
@@ -403,17 +482,20 @@ EtherDev::write(MemReqPtr req, const uint8_t *data)
if (reg & CR_RST) {
txReset();
rxReset();
+
regsReset();
}
break;
case CFG:
- regs.config = reg;
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);
+
#if 0
if (reg & CFG_TBI_EN) ;
if (reg & CFG_MODE_1000) ;
@@ -427,7 +509,6 @@ EtherDev::write(MemReqPtr req, const uint8_t *data)
if (reg & CFG_TMRTEST) ;
if (reg & CFG_MRM_DIS) ;
if (reg & CFG_MWI_DIS) ;
-#endif
if (reg & CFG_T64ADDR)
panic("CFG_T64ADDR is read only register!\n");
@@ -435,11 +516,10 @@ EtherDev::write(MemReqPtr req, const uint8_t *data)
if (reg & CFG_PCI64_DET)
panic("CFG_PCI64_DET is read only register!\n");
-#if 0
- if (reg & CFG_DATA64_EN) ;
- if (reg & CFG_M64ADDR) ;
- if (reg & CFG_PHY_RST) ;
- if (reg & CFG_PHY_DIS) ;
+ if (reg & CFG_DATA64_EN) ;
+ if (reg & CFG_M64ADDR) ;
+ if (reg & CFG_PHY_RST) ;
+ if (reg & CFG_PHY_DIS) ;
#endif
if (reg & CFG_EXTSTS_EN)
@@ -475,8 +555,15 @@ EtherDev::write(MemReqPtr req, const uint8_t *data)
break;
case PTSCR:
- regs.ptscr = reg;
- /* these control BISTs for various parts of chip - we don't care or do */
+ 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 */
+ if (reg & PTSCR_RBIST_EN)
+ regs.ptscr |= PTSCR_RBIST_DONE;
+ if (reg & PTSCR_EEBIST_EN)
+ regs.ptscr &= ~PTSCR_EEBIST_EN;
+ if (reg & PTSCR_EELOAD_EN)
+ regs.ptscr &= ~PTSCR_EELOAD_EN;
break;
case ISR: /* writing to the ISR has no effect */
@@ -520,31 +607,9 @@ EtherDev::write(MemReqPtr req, const uint8_t *data)
if (reg & TXCFG_BRST_DIS) ;
#endif
-#if 0 /* current 2.6 driver doesn't use these. if we upgrade, may need these */
- if (reg & TXCFG_MXDMA1024)
- maxTxBurst = 1024;
-
- if (reg & TXCFG_MXDMA8)
- maxTxBurst = 8;
-
- if (reg & TXCFG_MXDMA16)
- maxTxBurst = 16;
-
- if (reg & TXCFG_MXDMA32)
- maxTxBurst = 32;
-
- if (reg & TXCFG_MXDMA64)
- maxTxBurst = 64;
-
- if (reg & TXCFG_MXDMA128)
- maxTxBurst = 128;
-
- if (reg & TXCFG_MXDMA256)
- maxTxBurst = 256;
-#endif
- if (reg & TXCFG_MXDMA512)
- maxTxBurst = 512;
+ /* we handle our own DMA, ignore the kernel's exhortations */
+ if (reg & TXCFG_MXDMA) ;
break;
@@ -553,6 +618,14 @@ EtherDev::write(MemReqPtr req, const uint8_t *data)
/* these just control general purpose i/o pins, don't matter */
break;
+ case RXDP:
+ regs.rxdp = reg;
+ break;
+
+ case RXDP_HI:
+ regs.rxdp_hi = reg;
+ break;
+
case RXCFG:
regs.rxcfg = reg;
#if 0
@@ -564,8 +637,8 @@ EtherDev::write(MemReqPtr req, const uint8_t *data)
if (reg & RXCFG_AIRL) ;
#endif
- if (reg & RXCFG_MXDMA512)
- maxRxBurst = 512;
+ /* we handle our own DMA, ignore what kernel says about it */
+ if (reg & RXCFG_MXDMA) ;
#if 0
if (reg & (RXCFG_DRTH | RXCFG_DRTH0)) ;
@@ -589,6 +662,8 @@ 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;
@@ -601,8 +676,8 @@ EtherDev::write(MemReqPtr req, const uint8_t *data)
acceptArp = (reg & RFCR_AARP) ? true : false;
- if (reg & RFCR_APAT)
- panic("RFCR_APAT not implemented!\n");
+ if (reg & RFCR_APAT) ;
+// panic("RFCR_APAT not implemented!\n");
if (reg & RFCR_MHEN || reg & RFCR_UHEN)
panic("hash filtering not implemented!\n");
@@ -695,17 +770,19 @@ EtherDev::write(MemReqPtr req, const uint8_t *data)
void
EtherDev::devIntrPost(uint32_t interrupts)
{
-DPRINTF(Ethernet, "interrupt posted intr=%x isr=%x imr=%x\n",
- interrupts, regs.isr, regs.imr);
+ DPRINTF(Ethernet, "interrupt posted intr=%#x isr=%#x imr=%#x\n",
+ interrupts, regs.isr, regs.imr);
-if (interrupts & ISR_RESERVE)
- panic("Cannot set a reserved interrupt");
+ bool delay = false;
-if (interrupts & ISR_TXRCMP)
- regs.isr |= ISR_TXRCMP;
+ if (interrupts & ISR_RESERVE)
+ panic("Cannot set a reserved interrupt");
-if (interrupts & ISR_RXRCMP)
- regs.isr |= ISR_RXRCMP;
+ if (interrupts & ISR_TXRCMP)
+ regs.isr |= ISR_TXRCMP;
+
+ if (interrupts & ISR_RXRCMP)
+ regs.isr |= ISR_RXRCMP;
//ISR_DPERR not implemented
//ISR_SSERR not implemented
@@ -715,40 +792,48 @@ if (interrupts & ISR_RXRCMP)
//ISR_PHY not implemented
//ISR_PME not implemented
-if (interrupts & ISR_SWI)
- regs.isr |= ISR_SWI;
+ 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_TXIDLE)
+ regs.isr |= ISR_TXIDLE;
- if (interrupts & ISR_TXERR)
- regs.isr |= ISR_TXERR;
+ if (interrupts & ISR_TXERR)
+ regs.isr |= ISR_TXERR;
- if (interrupts & ISR_TXDESC)
- regs.isr |= ISR_TXDESC;
+ if (interrupts & ISR_TXDESC)
+ regs.isr |= ISR_TXDESC;
- if (interrupts & ISR_TXOK)
- regs.isr |= ISR_TXOK;
+ if (interrupts & ISR_TXOK) {
+ regs.isr |= ISR_TXOK;
+ delay = true;
+ }
- if (interrupts & ISR_RXORN)
- regs.isr |= ISR_RXORN;
+ if (interrupts & ISR_RXORN)
+ regs.isr |= ISR_RXORN;
- if (interrupts & ISR_RXIDLE)
- regs.isr |= ISR_RXIDLE;
+ if (interrupts & ISR_RXIDLE)
+ regs.isr |= ISR_RXIDLE;
//ISR_RXEARLY not implemented
- if (interrupts & ISR_RXERR)
- regs.isr |= ISR_RXERR;
+ if (interrupts & ISR_RXERR)
+ regs.isr |= ISR_RXERR;
- if (interrupts & ISR_RXOK)
- regs.isr |= ISR_RXOK;
+ if (interrupts & ISR_RXOK) {
+ delay = true;
+ regs.isr |= ISR_RXOK;
+ }
- if ((regs.isr & regs.imr))
- cpuIntrPost();
+ if ((regs.isr & regs.imr)) {
+ Tick when = curTick;
+ if (delay)
+ when += intrDelay;
+ cpuIntrPost(when);
+ }
}
void
@@ -806,9 +891,6 @@ EtherDev::devIntrClear(uint32_t interrupts)
if (interrupts & ISR_RXOK)
regs.isr &= ~ISR_RXOK;
- if ((regs.isr & regs.imr))
- cpuIntrPost();
-
if (!(regs.isr & regs.imr))
cpuIntrClear();
}
@@ -816,31 +898,66 @@ EtherDev::devIntrClear(uint32_t interrupts)
void
EtherDev::devIntrChangeMask()
{
- DPRINTF(Ethernet, "iterrupt mask changed\n");
+ DPRINTF(Ethernet, "interrupt mask changed\n");
if (regs.isr & regs.imr)
- cpuIntrPost();
+ cpuIntrPost(curTick);
else
cpuIntrClear();
}
void
-EtherDev::cpuIntrPost()
+EtherDev::cpuIntrPost(Tick when)
{
- if (!cpuPendingIntr) {
- if (regs.ier) {
- cpuPendingIntr = true;
- intctrl->post(TheISA::INTLEVEL_IRQ1, TheISA::INTINDEX_ETHERNET);
- }
+ if (when > intrTick && intrTick != 0)
+ return;
+
+ intrTick = when;
+
+ if (intrEvent) {
+ intrEvent->squash();
+ intrEvent = 0;
+ }
+
+ if (when < curTick) {
+ cpuInterrupt();
+ } else {
+ intrEvent = new IntrEvent(this, true);
+ intrEvent->schedule(intrTick);
}
}
void
+EtherDev::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;
+
+ // 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);
+}
+
+void
EtherDev::cpuIntrClear()
{
if (cpuPendingIntr) {
cpuPendingIntr = false;
- intctrl->clear(TheISA::INTLEVEL_IRQ1, TheISA::INTINDEX_ETHERNET);
+ /** @todo rework the intctrl to be tsunami ok */
+ //intctrl->clear(TheISA::INTLEVEL_IRQ1, TheISA::INTINDEX_ETHERNET);
+ tsunami->cchip->clearDRIR(configData->config.hdr.pci0.interruptLine);
}
}
@@ -854,15 +971,16 @@ EtherDev::txReset()
DPRINTF(Ethernet, "transmit reset\n");
- txPacketFlag = false;
CTDD = false;
txFifoCnt = 0;
- txFifoAvail = 0;
+ txFifoAvail = MAX_TX_FIFO_SIZE;
txHalt = false;
+ txFragPtr = 0;
+ assert(txDescCnt == 0);
txFifo.clear();
- descAddrFifo.clear();
regs.command &= ~CR_TXE;
txState = txIdle;
+ assert(txDmaState == dmaIdle);
}
void
@@ -870,171 +988,257 @@ EtherDev::rxReset()
{
DPRINTF(Ethernet, "receive reset\n");
- rxPacketFlag = false;
CRDD = false;
- fragLen = 0;
+ assert(rxPktBytes == 0);
rxFifoCnt = 0;
rxHalt = false;
+ rxFragPtr = 0;
+ assert(rxDescCnt == 0);
+ assert(rxDmaState == dmaIdle);
rxFifo.clear();
regs.command &= ~CR_RXE;
rxState = rxIdle;
}
-/**
- * This sets up a DMA transfer to read one data segment from the rxFifo into
- * the buffer indicated by rxDescCache.bufptr. Assumes the value of rxFragPtr
- * is already correctly set.
- */
void
-EtherDev::writeOneFrag()
+EtherDev::rxDmaReadCopy()
{
- /* i think there is no need for an "in use" warning here like in old */
- fragLen = rxFifo.front()->length; //length of whole packet
- fragLen = (fragLen < rxDescCnt) ? fragLen : rxDescCnt;
+ assert(rxDmaState == dmaReading);
- writePhys.addr = rxFragPtr;
- writePhys.length = fragLen;
+ memcpy(rxDmaData, physmem->dma_addr(rxDmaAddr, rxDmaLen), rxDmaLen);
+ rxDmaState = dmaIdle;
- // Set up DMA request area
- writeRequest.init(&rxDoneCB, 0, false, &writePhys, 1, fragLen,
- rxDescBufPtr, fragLen, curTick);
+ DPRINTF(EthernetDMA, "rx dma read paddr=%#x len=%d\n",
+ rxDmaAddr, rxDmaLen);
+ DDUMP(EthernetDMA, rxDmaData, rxDmaLen);
+}
+
+bool
+EtherDev::doRxDmaRead()
+{
+ assert(rxDmaState == dmaIdle || rxDmaState == dmaReadWaiting);
+ rxDmaState = dmaReading;
+
+ if (dmaInterface && !rxDmaFree) {
+ if (dmaInterface->busy())
+ rxDmaState = dmaReadWaiting;
+ else
+ dmaInterface->doDMA(Read, rxDmaAddr, rxDmaLen, curTick,
+ &rxDmaReadEvent);
+ return true;
+ }
- dma->doTransfer(&readRequest);
+ if (dmaReadDelay == 0 && dmaReadFactor == 0) {
+ rxDmaReadCopy();
+ return false;
+ }
+
+ Tick factor = ((rxDmaLen + ULL(63)) >> ULL(6)) * dmaReadFactor;
+ Tick start = curTick + dmaReadDelay + factor;
+ rxDmaReadEvent.schedule(start);
+ return true;
}
void
-EtherDev::rxKick()
+EtherDev::rxDmaReadDone()
{
- DPRINTF(Ethernet, "receive state machine activated!\n");
+ assert(rxDmaState == dmaReading);
+ rxDmaReadCopy();
- if (CRDD) {
- rxState = rxDescRefr;
- readOneDesc(rx, LINK_LEN);
- } else {
- rxState = rxDescRead;
- readOneDesc(rx);
- }
+ // If the transmit state machine has a pending DMA, let it go first
+ if (txDmaState == dmaReadWaiting || txDmaState == dmaWriteWaiting)
+ txKick();
+
+ rxKick();
}
-EtherDev::RxDescDone::RxDescDone(EtherDev *e)
- : ethernet(e)
+void
+EtherDev::rxDmaWriteCopy()
{
+ assert(rxDmaState == dmaWriting);
+
+ memcpy(physmem->dma_addr(rxDmaAddr, rxDmaLen), rxDmaData, rxDmaLen);
+ rxDmaState = dmaIdle;
+
+ DPRINTF(EthernetDMA, "rx dma write paddr=%#x len=%d\n",
+ rxDmaAddr, rxDmaLen);
+ DDUMP(EthernetDMA, rxDmaData, rxDmaLen);
}
-std::string
-EtherDev::RxDescDone::name() const
+bool
+EtherDev::doRxDmaWrite()
{
- return ethernet->name() + ".rxDescDoneCB";
+ assert(rxDmaState == dmaIdle || rxDmaState == dmaWriteWaiting);
+ rxDmaState = dmaWriting;
+
+ if (dmaInterface && !rxDmaFree) {
+ if (dmaInterface->busy())
+ rxDmaState = dmaWriteWaiting;
+ else
+ dmaInterface->doDMA(WriteInvalidate, rxDmaAddr, rxDmaLen, curTick,
+ &rxDmaWriteEvent);
+ return true;
+ }
+
+ if (dmaWriteDelay == 0 && dmaWriteFactor == 0) {
+ rxDmaWriteCopy();
+ return false;
+ }
+
+ Tick factor = ((rxDmaLen + ULL(63)) >> ULL(6)) * dmaWriteFactor;
+ Tick start = curTick + dmaWriteDelay + factor;
+ rxDmaWriteEvent.schedule(start);
+ return true;
}
void
-EtherDev::RxDescDone::process()
+EtherDev::rxDmaWriteDone()
{
- DPRINTF(Ethernet, "receive descriptor done callback\n");
- ethernet->rxDescDone();
+ assert(rxDmaState == dmaWriting);
+ rxDmaWriteCopy();
+
+ // If the transmit state machine has a pending DMA, let it go first
+ if (txDmaState == dmaReadWaiting || txDmaState == dmaWriteWaiting)
+ txKick();
+
+ rxKick();
}
void
-EtherDev::rxDescDone()
+EtherDev::rxKick()
{
- if (rxState == rxDescRefr) {
- if (rxDescCache.link == 0) {
- rxState = rxIdle;
- regs.command &= ~CR_RXE;
- devIntrPost(ISR_RXIDLE);
- return;
+ DPRINTF(Ethernet, "receive kick state=%s (rxBuf.size=%d)\n",
+ NsRxStateStrings[rxState], rxFifo.size());
+
+ if (rxKickTick > curTick) {
+ DPRINTF(Ethernet, "receive kick exiting, can't run till %d\n",
+ rxKickTick);
+ return;
+ }
+
+ next:
+ switch(rxDmaState) {
+ case dmaReadWaiting:
+ if (doRxDmaRead())
+ goto exit;
+ break;
+ case dmaWriteWaiting:
+ if (doRxDmaWrite())
+ goto exit;
+ break;
+ default:
+ break;
+ }
+
+ switch (rxState) {
+ case rxIdle:
+ if (!regs.command & CR_RXE) {
+ DPRINTF(Ethernet, "Receive Disabled! Nothing to do.\n");
+ goto exit;
+ }
+
+ if (CRDD) {
+ rxState = rxDescRefr;
+
+ rxDmaAddr = regs.rxdp & 0x3fffffff;
+ rxDmaData = &rxDescCache + offsetof(ns_desc, link);
+ rxDmaLen = sizeof(rxDescCache.link);
+ rxDmaFree = dmaDescFree;
+
+ if (doRxDmaRead())
+ goto exit;
} else {
rxState = rxDescRead;
- regs.rxdp = rxDescCache.link;
- CRDD = false;
- readOneDesc(rx);
+
+ rxDmaAddr = regs.rxdp & 0x3fffffff;
+ rxDmaData = &rxDescCache;
+ rxDmaLen = sizeof(ns_desc);
+ rxDmaFree = dmaDescFree;
+
+ if (doRxDmaRead())
+ goto exit;
}
- } else if (rxState == rxDescRead) {
+ break;
+
+ case rxDescRefr:
+ if (rxDmaState != dmaIdle)
+ goto exit;
+
+ rxState = rxAdvance;
+ break;
+
+ case rxDescRead:
+ if (rxDmaState != dmaIdle)
+ goto exit;
+
if (rxDescCache.cmdsts & CMDSTS_OWN) {
rxState = rxIdle;
- regs.command &= ~CR_RXE;
- devIntrPost(ISR_RXIDLE);
} else {
rxState = rxFifoBlock;
rxFragPtr = rxDescCache.bufptr;
rxDescCnt = rxDescCache.cmdsts & CMDSTS_LEN_MASK;
-
- if (!rxFifo.empty()) {
- rxState = rxFragWrite;
- if (!rxPacketFlag) { // reading a new packet
- rxPacketBufPtr = rxFifo.front()->data;
- rxPacketBufPtr -= rxDescCnt;
- rxDescBufPtr = rxPacketBufPtr;
- rxCopied = 0;
- } else {
- rxDescBufPtr = rxPacketBufPtr - rxDescCnt;
- }
- writeOneFrag();
- }
}
- } else if (rxState == rxDescWrite) {
- devIntrPost(ISR_RXOK);
-
- if (rxDescCache.cmdsts & CMDSTS_INTR)
- devIntrPost(ISR_RXDESC);
+ break;
- if (rxDescCache.link == 0 || ((rxPktBytes != 0) && rxHalt)) {
- rxState = rxIdle;
- regs.command &= ~CR_RXE;
- devIntrPost(ISR_RXIDLE);
- rxHalt = false;
- } else {
- rxState = rxDescRead;
- regs.rxdp = rxDescCache.link;
- CRDD = false;
- readOneDesc(rx);
+ case rxFifoBlock:
+ if (!rxPacket) {
+ /**
+ * @todo in reality, we should be able to start processing
+ * the packet as it arrives, and not have to wait for the
+ * full packet ot be in the receive fifo.
+ */
+ if (rxFifo.empty())
+ goto exit;
+
+ // If we don't have a packet, grab a new one from the fifo.
+ rxPacket = rxFifo.front();
+ rxPktBytes = rxPacket->length;
+ rxPacketBufPtr = rxPacket->data;
+
+ // 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();
}
- }
-}
-EtherDev::RxDone::RxDone(EtherDev *e)
- : ethernet(e)
-{
-}
-std::string
-EtherDev::RxDone::name() const
-{
- return ethernet->name() + ".rxDoneCB";
-}
+ // 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
+ rxXferLen = rxPktBytes;
-void
-EtherDev::RxDone::process()
-{
- DPRINTF(Ethernet, "receive done callback\n");
- ethernet->rxDone();
-}
+ rxDmaAddr = rxFragPtr & 0x3fffffff;
+ rxDmaData = rxPacketBufPtr;
+ rxDmaLen = rxXferLen;
+ rxDmaFree = dmaDataFree;
-void
-EtherDev::rxDone()
-{
- DPRINTF(Ethernet, "packet received to host memory\n");
+ if (doRxDmaWrite())
+ goto exit;
- if (!rxDescCache.cmdsts & CMDSTS_OWN)
- panic("This descriptor is already owned by the driver!\n");
+ } else {
+ rxState = rxDescWrite;
- rxState = rxFifoBlock;
- rxCopied += fragLen;
- rxFifoCnt -= fragLen;
+ //if (rxPktBytes == 0) { /* packet is done */
+ assert(rxPktBytes == 0);
+
+ rxFifoCnt -= rxPacket->length;
+ rxPacket = 0;
- if (rxDescCnt) { /* there is still data left in the descriptor */
- rxState = rxFragWrite;
- rxDescBufPtr += fragLen;
- writeOneFrag();
- } else {
- rxState = rxDescWrite;
- if (rxPktBytes == 0) { /* packet is done */
rxDescCache.cmdsts |= CMDSTS_OWN;
rxDescCache.cmdsts &= ~CMDSTS_MORE;
rxDescCache.cmdsts |= CMDSTS_OK;
- rxDescCache.cmdsts += rxCopied; //i.e. set CMDSTS_SIZE
+ rxDescCache.cmdsts += rxPacket->length; //i.e. set CMDSTS_SIZE
- rxPacketFlag = false;
+#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
+ */
if (rxFilterEnable) {
rxDescCache.cmdsts &= ~CMDSTS_DEST_MASK;
if (rxFifo.front()->IsUnicast())
@@ -1044,76 +1248,113 @@ EtherDev::rxDone()
if (rxFifo.front()->IsBroadcast())
rxDescCache.cmdsts |= CMDSTS_DEST_MASK;
}
+#endif
- PacketPtr &pkt = rxFifo.front();
- eth_header *eth = (eth_header *) pkt->data;
+ eth_header *eth = (eth_header *) rxPacket->data;
if (eth->type == 0x800 && extstsEnable) {
rxDescCache.extsts |= EXTSTS_IPPKT;
- if (!ipChecksum(pkt, false))
+ if (!ipChecksum(rxPacket, false))
rxDescCache.extsts |= EXTSTS_IPERR;
ip_header *ip = rxFifo.front()->getIpHdr();
if (ip->protocol == 6) {
rxDescCache.extsts |= EXTSTS_TCPPKT;
- if (!tcpChecksum(pkt, false))
+ if (!tcpChecksum(rxPacket, false))
rxDescCache.extsts |= EXTSTS_TCPERR;
} else if (ip->protocol == 17) {
rxDescCache.extsts |= EXTSTS_UDPPKT;
- if (!udpChecksum(pkt, false))
+ if (!udpChecksum(rxPacket, false))
rxDescCache.extsts |= EXTSTS_UDPERR;
}
}
- rxFifo.front() = NULL;
- rxFifo.pop_front();
- } else { /* just the descriptor is done */
- rxDescCache.cmdsts |= CMDSTS_OWN;
- rxDescCache.cmdsts |= CMDSTS_MORE;
+ /* 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.
+ */
+
+ rxDmaAddr = (regs.rxdp + offsetof(ns_desc, cmdsts)) & 0x3fffffff;
+ rxDmaData = &(rxDescCache.cmdsts);
+ rxDmaLen = sizeof(rxDescCache.cmdsts) + sizeof(rxDescCache.extsts);
+ rxDmaFree = dmaDescFree;
+
+ if (doRxDmaWrite())
+ goto exit;
}
- writeDescPhys.addr = regs.rxdp + LINK_LEN + BUFPTR_LEN;
- writeDescPhys.length = CMDSTS_LEN;
+ break;
- writeDescRequest.init(&rxDescDoneCB, 0, true, &writeDescPhys, 1,
- CMDSTS_LEN, (uint8_t *) &rxDescCache.cmdsts,
- CMDSTS_LEN, curTick);
- }
-}
+ case rxFragWrite:
+ if (rxDmaState != dmaIdle)
+ goto exit;
-/**
- * This sets up a DMA transfer to read one descriptor into the network device.
- */
-void
-EtherDev::readOneDesc(dir_t dir, uint32_t len) {
- readDescPhys.addr = (dir == tx) ? regs.txdp : regs.rxdp;
- readDescPhys.length = len;
+ rxPacketBufPtr += rxXferLen;
+ rxFragPtr += rxXferLen;
+ rxPktBytes -= rxXferLen;
- ns_desc *cache = (dir == tx) ? &txDescCache : &rxDescCache;
+ rxState = rxFifoBlock;
+ break;
- /* THIS ASSUMES THAT DESC_LEN < regs.txcfg's maxdma value,
- which is 512 bytes in the driver, so i'll just hard code it here */
- readDescRequest.init(&txDescDoneCB, 0, false, &readDescPhys, 1,
- len, (uint8_t *) cache , len, curTick);
+ case rxDescWrite:
+ if (rxDmaState != dmaIdle)
+ goto exit;
- dma->doTransfer(&readDescRequest);
-}
+ assert(rxDescCache.cmdsts & CMDSTS_OWN);
-/**
- * This sets up a DMA transfer to read one data segment of the descriptor in
- * txDescCache. Assumes the value of txFragPtr is already correctly set
- */
-void
-EtherDev::readOneFrag()
-{
- /* i think there is no need for an "in use" warning here like in old */
- fragLen = (txDescCnt < txFifoAvail) ? txDescCnt : txFifoAvail;
- readPhys.addr = txFragPtr;
- readPhys.length = fragLen;
+ assert(rxPacket == 0);
+ devIntrPost(ISR_RXOK);
+
+ if (rxDescCache.cmdsts & CMDSTS_INTR)
+ devIntrPost(ISR_RXDESC);
+
+ if (rxHalt) {
+ rxState = rxIdle;
+ rxHalt = false;
+ } else
+ rxState = rxAdvance;
+ break;
+
+ case rxAdvance:
+ if (rxDescCache.link == 0) {
+ rxState = rxIdle;
+ return;
+ } else {
+ rxState = rxDescRead;
+ regs.rxdp = rxDescCache.link;
+ CRDD = false;
+
+ rxDmaAddr = regs.rxdp & 0x3fffffff;
+ rxDmaData = &rxDescCache;
+ rxDmaLen = sizeof(ns_desc);
+ rxDmaFree = dmaDescFree;
+
+ if (doRxDmaRead())
+ goto exit;
+ }
+ break;
+
+ default:
+ panic("Invalid rxState!");
+ }
- // Set up DMA request area
- readRequest.init(&txDoneCB, 0, false, &readPhys, 1, fragLen,
- txPacketBufPtr, fragLen, curTick);
- dma->doTransfer(&readRequest);
+ DPRINTF(Ethernet, "entering next rx state = %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",
+ NsRxStateStrings[rxState]);
}
void
@@ -1126,226 +1367,383 @@ EtherDev::transmit()
if (interface->sendPacket(txFifo.front())) {
DPRINTF(Ethernet, "transmit packet\n");
+ DDUMP(Ethernet, txFifo.front()->data, txFifo.front()->length);
txBytes += txFifo.front()->length;
txPackets++;
- txFifoCnt -= txFifo.front()->length;
-
+ txFifoCnt -= (txFifo.front()->length - txPktXmitted);
+ txPktXmitted = 0;
txFifo.front() = NULL;
txFifo.pop_front();
- txDescCache.cmdsts &= ~CMDSTS_OK;
- } else {
- txDescCache.cmdsts &= ~CMDSTS_ERR;
- }
+ /* 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");
+ txEvent.schedule(curTick + 1000);
+ }
+}
- txDescCache.cmdsts &= ~CMDSTS_OWN;
+void
+EtherDev::txDmaReadCopy()
+{
+ assert(txDmaState == dmaReading);
- writeDescPhys.addr = descAddrFifo.front() + LINK_LEN + BUFPTR_LEN;
- writeDescPhys.length = CMDSTS_LEN;
+ memcpy(txDmaData, physmem->dma_addr(txDmaAddr, txDmaLen), txDmaLen);
+ txDmaState = dmaIdle;
- descAddrFifo.front() = 0;
- descAddrFifo.pop_front();
+ DPRINTF(EthernetDMA, "tx dma read paddr=%#x len=%d\n",
+ txDmaAddr, txDmaLen);
+ DDUMP(EthernetDMA, txDmaData, txDmaLen);
+}
- writeDescRequest.init(&txDescDoneCB, 0, true, &writeDescPhys, 1,
- writeDescPhys.length,
- (uint8_t *) &(txDescCache.cmdsts),
- writeDescPhys.length, curTick);
+bool
+EtherDev::doTxDmaRead()
+{
+ assert(txDmaState == dmaIdle || txDmaState == dmaReadWaiting);
+ txDmaState = dmaReading;
+
+ if (dmaInterface && !txDmaFree) {
+ if (dmaInterface->busy())
+ txDmaState = dmaReadWaiting;
+ else
+ dmaInterface->doDMA(Read, txDmaAddr, txDmaLen, curTick,
+ &txDmaReadEvent);
+ return true;
+ }
- dma->doTransfer(&writeDescRequest);
+ if (dmaReadDelay == 0 && dmaReadFactor == 0.0) {
+ txDmaReadCopy();
+ return false;
+ }
- transmit();
+ Tick factor = ((txDmaLen + ULL(63)) >> ULL(6)) * dmaReadFactor;
+ Tick start = curTick + dmaReadDelay + factor;
+ txDmaReadEvent.schedule(start);
+ return true;
}
void
-EtherDev::txKick()
+EtherDev::txDmaReadDone()
{
- DPRINTF(Ethernet, "transmit state machine activated\n");
-#if 0
- if (DTRACE(Ethernet))
- txDump();
-#endif
+ assert(txDmaState == dmaReading);
+ txDmaReadCopy();
- if (CTDD) {
- txState = txDescRefr;
- readOneDesc(tx, LINK_LEN);
- } else {
- txState = txDescRead;
- readOneDesc(tx);
- }
+ // If the receive state machine has a pending DMA, let it go first
+ if (rxDmaState == dmaReadWaiting || rxDmaState == dmaWriteWaiting)
+ rxKick();
+
+ txKick();
}
-EtherDev::TxDescDone::TxDescDone(EtherDev *e)
- : ethernet(e)
+void
+EtherDev::txDmaWriteCopy()
{
+ assert(txDmaState == dmaWriting);
+
+ memcpy(physmem->dma_addr(txDmaAddr, txDmaLen), txDmaData, txDmaLen);
+ txDmaState = dmaIdle;
+
+ DPRINTF(EthernetDMA, "tx dma write paddr=%#x len=%d\n",
+ txDmaAddr, txDmaLen);
+ DDUMP(EthernetDMA, txDmaData, txDmaLen);
}
-std::string
-EtherDev::TxDescDone::name() const
+bool
+EtherDev::doTxDmaWrite()
{
- return ethernet->name() + ".txDescDoneCB";
+ assert(txDmaState == dmaIdle || txDmaState == dmaWriteWaiting);
+ txDmaState = dmaWriting;
+
+ if (dmaInterface && !txDmaFree) {
+ if (dmaInterface->busy())
+ txDmaState = dmaWriteWaiting;
+ else
+ dmaInterface->doDMA(WriteInvalidate, txDmaAddr, txDmaLen, curTick,
+ &txDmaWriteEvent);
+ return true;
+ }
+
+ if (dmaWriteDelay == 0 && dmaWriteFactor == 0.0) {
+ txDmaWriteCopy();
+ return false;
+ }
+
+ Tick factor = ((txDmaLen + ULL(63)) >> ULL(6)) * dmaWriteFactor;
+ Tick start = curTick + dmaWriteDelay + factor;
+ txDmaWriteEvent.schedule(start);
+ return true;
}
void
-EtherDev::TxDescDone::process()
+EtherDev::txDmaWriteDone()
{
- DPRINTF(Ethernet, "transmit descriptor done callback\n");
- ethernet->txDescDone();
+ assert(txDmaState == dmaWriting);
+ txDmaWriteCopy();
+ // If the receive state machine has a pending DMA, let it go first
+ if (rxDmaState == dmaReadWaiting || rxDmaState == dmaWriteWaiting)
+ rxKick();
+
+ txKick();
}
void
-EtherDev::txDescDone()
+EtherDev::txKick()
{
- if (txState == txFifoBlock) {
- if (txDescCache.cmdsts & CMDSTS_OK) {
- devIntrPost(ISR_TXOK);
- } else if (txDescCache.cmdsts & CMDSTS_ERR) {
- devIntrPost(ISR_TXERR);
- }
- } else if (txState == txDescRefr || txState == txDescWrite) {
+ DPRINTF(Ethernet, "transmit kick state=%s\n", NsTxStateStrings[txState]);
- if (txState == txDescWrite) {
- if (txDescCache.cmdsts & CMDSTS_INTR) {
- devIntrPost(ISR_TXDESC);
- }
+ if (rxKickTick > curTick) {
+ DPRINTF(Ethernet, "receive kick exiting, can't run till %d\n",
+ rxKickTick);
+
+ return;
+ }
+
+ next:
+ switch(txDmaState) {
+ case dmaReadWaiting:
+ if (doTxDmaRead())
+ goto exit;
+ break;
+ case dmaWriteWaiting:
+ if (doTxDmaWrite())
+ goto exit;
+ break;
+ default:
+ break;
+ }
+
+ switch (txState) {
+ case txIdle:
+ if (!regs.command & CR_TXE) {
+ DPRINTF(Ethernet, "Transmit disabled. Nothing to do.\n");
+ goto exit;
}
- if (txDescCache.link == 0) {
- txState = txIdle;
- regs.command &= ~CR_TXE;
- devIntrPost(ISR_TXIDLE);
- return;
+ if (CTDD) {
+ txState = txDescRefr;
+
+ txDmaAddr = txDescCache.link & 0x3fffffff;
+ txDmaData = &txDescCache;
+ txDmaLen = sizeof(txDescCache.link);
+ txDmaFree = dmaDescFree;
+
+ if (doTxDmaRead())
+ goto exit;
+
} else {
txState = txDescRead;
- regs.txdp = txDescCache.link;
- CTDD = false;
- readOneDesc(tx);
+
+ txDmaAddr = regs.txdp & 0x3fffffff;
+ txDmaData = &txDescCache + offsetof(ns_desc, link);
+ txDmaLen = sizeof(ns_desc);
+ txDmaFree = dmaDescFree;
+
+ if (doTxDmaRead())
+ goto exit;
}
- } else if (txState == txDescRead) {
+ break;
+
+ case txDescRefr:
+ if (txDmaState != dmaIdle)
+ goto exit;
+
+ txState = txAdvance;
+ break;
+
+ case txDescRead:
+ if (txDmaState != dmaIdle)
+ goto exit;
+
if (txDescCache.cmdsts & CMDSTS_OWN) {
txState = txFifoBlock;
txFragPtr = txDescCache.bufptr;
txDescCnt = txDescCache.cmdsts & CMDSTS_LEN_MASK;
+ } else {
+ txState = txIdle;
+ }
+ break;
+
+ case txFifoBlock:
+ if (!txPacket) {
+ DPRINTF(Ethernet, "starting the tx of a new packet\n");
+ txPacket = new EtherPacket;
+ txPacket->data = new uint8_t[16384];
+ txPacketBufPtr = txPacket->data;
+ }
- if (txFifoAvail >= ((regs.txcfg & TXCFG_FLTH_MASK) >> 8)) {
- txState = txFragRead;
- if (!txPacketFlag) {
- txPacketFlag = true;
- /* find the total length of this packet */
- txPacketLen = txDescCnt;
- bool more = txDescCache.cmdsts & CMDSTS_MORE;
- uint8_t *addr = (uint8_t *) regs.txdp;
- while (more) {
- addr = physmem->dma_addr(((ns_desc *) addr)->link, sizeof(ns_desc));
- /* !!!!!!mask needed? */
- txPacketLen += ((ns_desc *)addr)->cmdsts & CMDSTS_LEN_MASK;
- more = ((ns_desc *) addr)->cmdsts & CMDSTS_MORE;
+ if (txDescCnt == 0) {
+ DPRINTF(Ethernet, "the txDescCnt == 0, done with descriptor\n");
+ if (txDescCache.cmdsts & CMDSTS_MORE) {
+ DPRINTF(Ethernet, "there are more descriptors to come\n");
+ txState = txDescWrite;
+
+ txDescCache.cmdsts &= ~CMDSTS_OWN;
+
+ txDmaAddr = (regs.txdp + offsetof(ns_desc, cmdsts)) & 0x3fffffff;
+ txDmaData = &(txDescCache.cmdsts);
+ txDmaLen = sizeof(txDescCache.cmdsts);
+ txDmaFree = dmaDescFree;
+
+ if (doTxDmaWrite())
+ goto exit;
+
+ } else { /* this packet is totally done */
+ DPRINTF(Ethernet, "This packet is done, let's wrap it up\n");
+ /* deal with the the packet that just finished */
+ if ((regs.vtcr & VTCR_PPCHK) && extstsEnable) {
+ if (txDescCache.extsts & EXTSTS_UDPPKT) {
+ udpChecksum(txPacket, true);
+ } else if (txDescCache.extsts & EXTSTS_TCPPKT) {
+ tcpChecksum(txPacket, true);
+ } else if (txDescCache.extsts & EXTSTS_IPPKT) {
+ ipChecksum(txPacket, true);
}
- PacketPtr &packet = txDoneCB.packet;
- packet = new EtherPacket;
- packet->length = txPacketLen;
- packet->data = new uint8_t[txPacketLen];
- txPacketBufPtr = packet->data;
}
- readOneFrag();
+
+ txPacket->length = txPacketBufPtr - txPacket->data;
+ /* this is just because the receive can't handle a packet bigger
+ want to make sure */
+ assert(txPacket->length <= 1514);
+ txFifo.push_back(txPacket);
+
+
+ /* 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;
+
+
+ if (doTxDmaWrite())
+ goto exit;
+
+ txPacket = 0;
+ transmit();
+
+ if (txHalt) {
+ txState = txIdle;
+ txHalt = false;
+ } else
+ txState = txAdvance;
}
} else {
- txState = txIdle;
- regs.command &= ~CR_TXE;
- devIntrPost(ISR_TXIDLE);
- }
- }
-}
+ 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);
+ goto exit;
+ }
-EtherDev::TxDone::TxDone(EtherDev *e)
- : ethernet(e)
-{
-}
+ txState = txFragRead;
-std::string
-EtherDev::TxDone::name() const
-{
- return ethernet->name() + ".txDoneCB";
-}
+ /* 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;
-void
-EtherDev::TxDone::process()
-{
- DPRINTF(Ethernet, "transmit done callback\n");
- ethernet->txDone(packet);
-}
+ if (doTxDmaRead())
+ goto exit;
+ }
+ break;
-void
-EtherDev::txDone(PacketPtr packet)
-{
- DPRINTF(Ethernet, "transmit done\n");
+ case txFragRead:
+ if (txDmaState != dmaIdle)
+ goto exit;
- if (!txDescCache.cmdsts & CMDSTS_OWN)
- panic("This descriptor is already owned by the driver!\n");
+ txPacketBufPtr += txXferLen;
+ txFragPtr += txXferLen;
+ txFifoCnt += txXferLen;
+ txDescCnt -= txXferLen;
- txState = txFifoBlock;
+ txState = txFifoBlock;
+ break;
- txPacketBufPtr += fragLen; /* hope this ptr manipulation is right! */
- txDescCnt -= fragLen;
- txFifoCnt += fragLen;
+ case txDescWrite:
+ 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 (txFifoCnt >= (regs.txcfg & TXCFG_DRTH_MASK)) {
- if (txFifo.empty()) {
- txFifoCnt -= (uint32_t) (txPacketBufPtr - packet->data);
+ if (txDescCache.cmdsts & CMDSTS_INTR) {
+ devIntrPost(ISR_TXDESC);
+ }
+
+ txState = txAdvance;
+ break;
+
+ case txAdvance:
+ if (txDescCache.link == 0) {
+ txState = txIdle;
} else {
- transmit();
+ txState = txDescRead;
+ regs.txdp = txDescCache.link;
+ CTDD = false;
+
+ txDmaAddr = txDescCache.link & 0x3fffffff;
+ txDmaData = &txDescCache;
+ txDmaLen = sizeof(ns_desc);
+ txDmaFree = dmaDescFree;
+
+ if (doTxDmaRead())
+ goto exit;
}
+ break;
+
+ default:
+ panic("invalid state");
}
- if (txDescCnt) { /* if there is still more data to go in this desc */
- if (txFifoAvail >= regs.txcfg & TXCFG_FLTH_MASK) {
- txState = txFragRead;
- readOneFrag();
- }
- } else { /* this descriptor is done */
- /* but there is more descriptors for this packet */
- if (txDescCache.cmdsts & CMDSTS_MORE) {
- txState = txDescWrite;
- txDescCache.cmdsts &= ~CMDSTS_OWN;
- writeDescPhys.addr = regs.txdp + LINK_LEN + BUFPTR_LEN;
- writeDescPhys.length = CMDSTS_LEN;
-
- writeDescRequest.init(&txDescDoneCB, 0, true, &writeDescPhys, 1,
- writeDescPhys.length,
- (uint8_t*) &txDescCache.cmdsts,
- writeDescPhys.length, curTick);
- } else { /* this packet is totally done */
- /* deal with the the packet that just finished */
- if (regs.vtcr & VTCR_PPCHK && extstsEnable) {
- if (txDescCache.extsts & EXTSTS_UDPPKT) {
- udpChecksum(packet, true);
- } else if (txDescCache.extsts & EXTSTS_TCPPKT) {
- tcpChecksum(packet, true);
- } else if (txDescCache.extsts & EXTSTS_IPPKT) {
- ipChecksum(packet, true);
- }
- }
+ DPRINTF(Ethernet, "entering next tx state=%s\n",
+ NsTxStateStrings[txState]);
- txFifo.push_back(packet);
- transmit();
- txPacketFlag = false;
- descAddrFifo.push_back(regs.txdp);
-
- /* if there is not another descriptor ready for reading, go idle */
- if (txDescCache.link == 0 || txHalt) {
- txState = txIdle;
- devIntrPost(ISR_TXIDLE);
- txHalt = false;
- } else { /* else go read next descriptor */
- txState = txDescRead;
- regs.txdp = txDescCache.link;
- CTDD = false;
- readOneDesc(tx);
- }
- }
+ 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",
+ NsTxStateStrings[txState]);
}
void
@@ -1362,42 +1760,6 @@ EtherDev::transferDone()
txEvent.schedule(curTick + 1);
}
-void
-EtherDev::txDump() const
-{
-#if 0
- int i = tx_ptr;
- for (int loop = 0; loop < tx_ring_len; loop++) {
- es_desc *desc = &tx_ring[i];
-
- if (desc->addr)
- cprintf("desc[%d]: addr=%#x, len=%d, flags=%#x\n",
- i, desc->addr, desc->length, desc->flags);
-
- if (++i >= tx_ring_len)
- i = 0;
- }
-#endif
-}
-
-void
-EtherDev::rxDump() const
-{
-#if 0
- int i = rx_ptr;
- for (int loop = 0; loop < rx_ring_len; loop++) {
- es_desc *desc = &rx_ring[i];
-
- if (desc->addr)
- cprintf("desc[%d]: addr=%#x, len=%d, flags=%#x\n",
- i, desc->addr, desc->length, desc->flags);
-
- if (++i >= rx_ring_len)
- i = 0;
- }
-#endif
-}
-
bool
EtherDev::rxFilter(PacketPtr packet)
{
@@ -1413,7 +1775,7 @@ EtherDev::rxFilter(PacketPtr packet)
// If we make a perfect match
if ((acceptPerfect)
- && (memcmp(regs.perfectMatch, packet->data, sizeof(regs.perfectMatch)) == 0))
+ && (memcmp(rom.perfectMatch, packet->data, sizeof(rom.perfectMatch)) == 0))
drop = false;
eth_header *eth = (eth_header *) packet->data;
@@ -1474,10 +1836,10 @@ EtherDev::recvPacket(PacketPtr packet)
}
rxFifo.push_back(packet);
- rxPktBytes = packet->length;
rxFifoCnt += packet->length;
interface->recvDone();
+ rxKick();
return true;
}
@@ -1582,263 +1944,311 @@ EtherDev::checksumCalc(uint16_t *pseudo, uint16_t *buf, uint32_t len)
//
//
void
-dp_regs::serialize(ostream &os)
-{
- SERIALIZE_SCALAR(command);
- SERIALIZE_SCALAR(config);
- SERIALIZE_SCALAR(isr);
- SERIALIZE_SCALAR(imr);
-}
-
-void
-dp_regs::unserialize(Checkpoint *cp, const std::string &section)
-{
- UNSERIALIZE_SCALAR(command);
- UNSERIALIZE_SCALAR(config);
- UNSERIALIZE_SCALAR(isr);
- UNSERIALIZE_SCALAR(imr);
-#if 0
- UNSERIALIZE_SCALAR(tx_ring);
- UNSERIALIZE_SCALAR(rx_ring);
- UNSERIALIZE_SCALAR(tx_ring_len);
- UNSERIALIZE_SCALAR(rx_ring_len);
- UNSERIALIZE_SCALAR(rom_addr);
- UNSERIALIZE_SCALAR(rom_data);
- UNSERIALIZE_SCALAR(rxfilt_ctl);
- UNSERIALIZE_SCALAR(rxfilt_data);
-
- UNSERIALIZE_ARRAY(perfect,EADDR_LEN);
- UNSERIALIZE_ARRAY(hash_table,ES_HASH_SIZE);
-
- UNSERIALIZE_SCALAR(tx_ring_ptr);
- UNSERIALIZE_SCALAR(rx_ring_ptr);
-#endif
-}
-
-//---------------------------------------
-
-void
-EtherPacket::serialize(ostream &os)
-{
- SERIALIZE_SCALAR(length);
- SERIALIZE_ARRAY(data, length);
-}
-
-void
-EtherPacket::unserialize(Checkpoint *cp, const std::string &section)
-{
- UNSERIALIZE_SCALAR(length);
- data = new uint8_t[length];
- UNSERIALIZE_ARRAY(data, length);
-}
-
-//---------------------------------------
-
-void
EtherDev::serialize(ostream &os)
{
-
-#if 0
- regs.serialize(os);
-
- // tx_ring & rx_ring are contained in the physmem...
- SERIALIZE_SCALAR(cpuPendingIntr);
- SERIALIZE_SCALAR(tx_ptr);
- SERIALIZE_SCALAR(rx_ptr);
-
- SERIALIZE_SCALAR(rxDoneCB.ptr);
- SERIALIZE_SCALAR(rxDoneCB.ignore);
-
- SERIALIZE_SCALAR(txDoneCB.ptr);
- SERIALIZE_SCALAR(txDoneCB.ignore);
-
- for (int i=0; i<ES_MAX_DMA_SEGS; ++i) {
- paramOut(os, csprintf("readPhys%d.addr",i), readPhys[i].addr);
- paramOut(os, csprintf("readPhys%d.length",i), readPhys[i].length);
- paramOut(os, csprintf("writePhys%d.addr",i), writePhys[i].addr);
- paramOut(os, csprintf("writePhys%d.length",i), writePhys[i].length);
- }
-
- SERIALIZE_SCALAR(txEnable);
- SERIALIZE_SCALAR(rxEnable);
- SERIALIZE_SCALAR(txDelay);
- SERIALIZE_SCALAR(rxDelay);
-
- SERIALIZE_SCALAR(txbuf_len);
-
- //Calculate the number here, actually dump them at end
- int numTxPkts=0;
- for (pktiter_t p=txbuf.begin(); p!=txbuf.end(); ++p) {
- numTxPkts++;
- }
- SERIALIZE_SCALAR(numTxPkts);
-
- SERIALIZE_SCALAR(rxbuf_len);
- int numRxPkts=0;
- for (pktiter_t p=rxbuf.begin(); p!=rxbuf.end(); ++p) {
- numRxPkts++;
- }
- SERIALIZE_SCALAR(numRxPkts);
-
- // output whether the tx and rx packets exist
- bool txPacketExists = false;
- if (txDoneCB.packet)
- txPacketExists = true;
+ /*
+ * Finalize any DMA events now.
+ */
+ if (rxDmaReadEvent.scheduled())
+ rxDmaReadCopy();
+ if (rxDmaWriteEvent.scheduled())
+ rxDmaWriteCopy();
+ if (txDmaReadEvent.scheduled())
+ txDmaReadCopy();
+ if (txDmaWriteEvent.scheduled())
+ txDmaWriteCopy();
+
+ /*
+ * Serialize the device registers
+ */
+ SERIALIZE_SCALAR(regs.command);
+ SERIALIZE_SCALAR(regs.config);
+ SERIALIZE_SCALAR(regs.mear);
+ SERIALIZE_SCALAR(regs.ptscr);
+ SERIALIZE_SCALAR(regs.isr);
+ SERIALIZE_SCALAR(regs.imr);
+ SERIALIZE_SCALAR(regs.ier);
+ SERIALIZE_SCALAR(regs.ihr);
+ SERIALIZE_SCALAR(regs.txdp);
+ SERIALIZE_SCALAR(regs.txdp_hi);
+ SERIALIZE_SCALAR(regs.txcfg);
+ SERIALIZE_SCALAR(regs.gpior);
+ SERIALIZE_SCALAR(regs.rxdp);
+ SERIALIZE_SCALAR(regs.rxdp_hi);
+ SERIALIZE_SCALAR(regs.rxcfg);
+ SERIALIZE_SCALAR(regs.pqcr);
+ SERIALIZE_SCALAR(regs.wcsr);
+ SERIALIZE_SCALAR(regs.pcr);
+ SERIALIZE_SCALAR(regs.rfcr);
+ SERIALIZE_SCALAR(regs.rfdr);
+ SERIALIZE_SCALAR(regs.srr);
+ SERIALIZE_SCALAR(regs.mibc);
+ SERIALIZE_SCALAR(regs.vrcr);
+ SERIALIZE_SCALAR(regs.vtcr);
+ SERIALIZE_SCALAR(regs.vdr);
+ SERIALIZE_SCALAR(regs.ccsr);
+ SERIALIZE_SCALAR(regs.tbicr);
+ SERIALIZE_SCALAR(regs.tbisr);
+ SERIALIZE_SCALAR(regs.tanar);
+ SERIALIZE_SCALAR(regs.tanlpar);
+ SERIALIZE_SCALAR(regs.taner);
+ SERIALIZE_SCALAR(regs.tesr);
+
+ SERIALIZE_ARRAY(rom.perfectMatch, EADDR_LEN);
+
+ /*
+ * Serialize the various helper variables
+ */
+ 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);
+
+ bool txPacketExists = txPacket;
SERIALIZE_SCALAR(txPacketExists);
-
- bool rxPacketExists = false;
- if (rxPacket)
- rxPacketExists = true;
+ bool rxPacketExists = rxPacket;
SERIALIZE_SCALAR(rxPacketExists);
- // output the names (unique by pointer) of the read and write requests
- paramOut(os, csprintf("readReqName"), readRequest.name());
- paramOut(os, csprintf("writeReqName"), writeRequest.name());
-
- // Serialize txPacket, because its data is needed for readRequest
- if (txPacketExists) {
- nameOut(os, csprintf("%s.txPacket", name()));
- txDoneCB.packet->serialize(os);
+ /*
+ * Serialize DescCaches
+ */
+ SERIALIZE_SCALAR(txDescCache.link);
+ SERIALIZE_SCALAR(txDescCache.bufptr);
+ SERIALIZE_SCALAR(txDescCache.cmdsts);
+ SERIALIZE_SCALAR(txDescCache.extsts);
+ SERIALIZE_SCALAR(rxDescCache.link);
+ SERIALIZE_SCALAR(rxDescCache.bufptr);
+ SERIALIZE_SCALAR(rxDescCache.cmdsts);
+ SERIALIZE_SCALAR(rxDescCache.extsts);
+
+ /*
+ * Serialize tx state machine
+ */
+ int txNumPkts = txFifo.size();
+ SERIALIZE_SCALAR(txNumPkts);
+ int txState = this->txState;
+ SERIALIZE_SCALAR(txState);
+ SERIALIZE_SCALAR(CTDD);
+ SERIALIZE_SCALAR(txFifoCnt);
+ SERIALIZE_SCALAR(txFifoAvail);
+ SERIALIZE_SCALAR(txHalt);
+ SERIALIZE_SCALAR(txFragPtr);
+ SERIALIZE_SCALAR(txDescCnt);
+ int txDmaState = this->txDmaState;
+ SERIALIZE_SCALAR(txDmaState);
+
+ /*
+ * Serialize rx state machine
+ */
+ int rxNumPkts = rxFifo.size();
+ SERIALIZE_SCALAR(rxNumPkts);
+ int rxState = this->rxState;
+ SERIALIZE_SCALAR(rxState);
+ SERIALIZE_SCALAR(CRDD);
+ SERIALIZE_SCALAR(rxPktBytes);
+ SERIALIZE_SCALAR(rxFifoCnt);
+ SERIALIZE_SCALAR(rxHalt);
+ 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);
+
+ /*
+ * Keep track of pending interrupt status.
+ */
+ SERIALIZE_SCALAR(intrTick);
+ SERIALIZE_SCALAR(cpuPendingIntr);
+ Tick intrEventTick = 0;
+ if (intrEvent)
+ 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);
}
-
- // Serialize rxPacket, because its data is needed for writeRequest
if (rxPacketExists) {
nameOut(os, csprintf("%s.rxPacket", name()));
rxPacket->serialize(os);
}
-
- // create a section for the readRequest
- nameOut(os, readRequest.name());
- paramOut(os, csprintf("parent"), name());
- paramOut(os, csprintf("id"), 0);
- readRequest.serialize(os);
-
- // create a section for the writeRequest
- nameOut(os, writeRequest.name());
- paramOut(os, csprintf("parent"), name());
- paramOut(os, csprintf("id"), 1);
- writeRequest.serialize(os);
-
- //Redo the buffers, this time outputing them to the file
- numTxPkts = 0;
- for (pktiter_t p=txbuf.begin(); p!=txbuf.end(); ++p) {
- nameOut(os, csprintf("%s.txbuf%d", name(),numTxPkts++));
+ i = 0;
+ for (pktiter_t p = txFifo.begin(); p != txFifo.end(); ++p) {
+ nameOut(os, csprintf("%s.txFifo%d", name(), i++));
(*p)->serialize(os);
}
-
- numRxPkts = 0;
- for (pktiter_t p=rxbuf.begin(); p!=rxbuf.end(); ++p) {
- nameOut(os, csprintf("%s.rxbuf%d", name(),numRxPkts++));
- (*p)->serialize(os);
+ if (txPacketExists) {
+ nameOut(os, csprintf("%s.txPacket", name()));
+ txPacket->serialize(os);
}
-#endif
}
void
EtherDev::unserialize(Checkpoint *cp, const std::string &section)
{
-#if 0
- regs.unserialize(cp, section);
-
- UNSERIALIZE_SCALAR(cpuPendingIntr);
-
- // initialize the tx_ring
- txReset();
+ UNSERIALIZE_SCALAR(regs.command);
+ UNSERIALIZE_SCALAR(regs.config);
+ UNSERIALIZE_SCALAR(regs.mear);
+ UNSERIALIZE_SCALAR(regs.ptscr);
+ UNSERIALIZE_SCALAR(regs.isr);
+ UNSERIALIZE_SCALAR(regs.imr);
+ UNSERIALIZE_SCALAR(regs.ier);
+ UNSERIALIZE_SCALAR(regs.ihr);
+ UNSERIALIZE_SCALAR(regs.txdp);
+ UNSERIALIZE_SCALAR(regs.txdp_hi);
+ UNSERIALIZE_SCALAR(regs.txcfg);
+ UNSERIALIZE_SCALAR(regs.gpior);
+ UNSERIALIZE_SCALAR(regs.rxdp);
+ UNSERIALIZE_SCALAR(regs.rxdp_hi);
+ UNSERIALIZE_SCALAR(regs.rxcfg);
+ UNSERIALIZE_SCALAR(regs.pqcr);
+ UNSERIALIZE_SCALAR(regs.wcsr);
+ UNSERIALIZE_SCALAR(regs.pcr);
+ UNSERIALIZE_SCALAR(regs.rfcr);
+ UNSERIALIZE_SCALAR(regs.rfdr);
+ UNSERIALIZE_SCALAR(regs.srr);
+ UNSERIALIZE_SCALAR(regs.mibc);
+ UNSERIALIZE_SCALAR(regs.vrcr);
+ UNSERIALIZE_SCALAR(regs.vtcr);
+ UNSERIALIZE_SCALAR(regs.vdr);
+ UNSERIALIZE_SCALAR(regs.ccsr);
+ UNSERIALIZE_SCALAR(regs.tbicr);
+ UNSERIALIZE_SCALAR(regs.tbisr);
+ UNSERIALIZE_SCALAR(regs.tanar);
+ UNSERIALIZE_SCALAR(regs.tanlpar);
+ UNSERIALIZE_SCALAR(regs.taner);
+ UNSERIALIZE_SCALAR(regs.tesr);
+
+ UNSERIALIZE_ARRAY(rom.perfectMatch, EADDR_LEN);
+
+ /*
+ * unserialize the various helper variables
+ */
+ 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);
- // initialize the rx_ring
- rxReset();
-
- UNSERIALIZE_SCALAR(tx_ptr);
- UNSERIALIZE_SCALAR(rx_ptr);
-
- PacketPtr p;
- UNSERIALIZE_SCALAR(txbuf_len);
- int numTxPkts;
- UNSERIALIZE_SCALAR(numTxPkts);
- for (int i=0; i<numTxPkts; ++i) {
- p = new EtherPacket;
- p->unserialize(cp, csprintf("%s.txbuf%d", section, i));
- txbuf.push_back(p);
- }
-
- UNSERIALIZE_SCALAR(rxbuf_len);
- int numRxPkts;
- UNSERIALIZE_SCALAR(numRxPkts);
- for (int i=0; i<numRxPkts; ++i) {
- p = new EtherPacket;
- p->unserialize(cp, csprintf("%s.rxbuf%d", section, i));
- rxbuf.push_back(p);
- }
-
- UNSERIALIZE_SCALAR(rxDoneCB.ptr);
- UNSERIALIZE_SCALAR(rxDoneCB.ignore);
-
- UNSERIALIZE_SCALAR(txDoneCB.ptr);
- UNSERIALIZE_SCALAR(txDoneCB.ignore);
-
- for (int i=0; i<ES_MAX_DMA_SEGS; ++i) {
- paramIn(cp, section, csprintf("readPhys%d.addr",i),
- readPhys[i].addr);
- paramIn(cp, section, csprintf("readPhys%d.length",i),
- readPhys[i].length);
- paramIn(cp, section, csprintf("writePhys%d.addr",i),
- writePhys[i].addr);
- paramIn(cp, section, csprintf("writePhys%d.length",i),
- writePhys[i].length);
- }
-
- UNSERIALIZE_SCALAR(txEnable);
- UNSERIALIZE_SCALAR(rxEnable);
- UNSERIALIZE_SCALAR(txDelay);
- UNSERIALIZE_SCALAR(rxDelay);
-
- // Unserialize the current txPacket
bool txPacketExists;
UNSERIALIZE_SCALAR(txPacketExists);
-
- txDoneCB.packet = NULL;
- if (txPacketExists) {
- txDoneCB.packet = new EtherPacket;
- txDoneCB.packet->unserialize(cp, csprintf("%s.txPacket", section));
- }
-
- // Unserialize the current rxPacket
bool rxPacketExists;
UNSERIALIZE_SCALAR(rxPacketExists);
+ /*
+ * Unserialize DescCaches
+ */
+ UNSERIALIZE_SCALAR(txDescCache.link);
+ UNSERIALIZE_SCALAR(txDescCache.bufptr);
+ UNSERIALIZE_SCALAR(txDescCache.cmdsts);
+ UNSERIALIZE_SCALAR(txDescCache.extsts);
+ UNSERIALIZE_SCALAR(rxDescCache.link);
+ UNSERIALIZE_SCALAR(rxDescCache.bufptr);
+ UNSERIALIZE_SCALAR(rxDescCache.cmdsts);
+ UNSERIALIZE_SCALAR(rxDescCache.extsts);
+
+ /*
+ * unserialize tx state machine
+ */
+ int txNumPkts;
+ UNSERIALIZE_SCALAR(txNumPkts);
+ int txState;
+ UNSERIALIZE_SCALAR(txState);
+ this->txState = (TxState) txState;
+ UNSERIALIZE_SCALAR(CTDD);
+ UNSERIALIZE_SCALAR(txFifoCnt);
+ UNSERIALIZE_SCALAR(txFifoAvail);
+ UNSERIALIZE_SCALAR(txHalt);
+ UNSERIALIZE_SCALAR(txFragPtr);
+ UNSERIALIZE_SCALAR(txDescCnt);
+ int txDmaState;
+ UNSERIALIZE_SCALAR(txDmaState);
+ this->txDmaState = (DmaState) txDmaState;
+
+ /*
+ * unserialize rx state machine
+ */
+ int rxNumPkts;
+ UNSERIALIZE_SCALAR(rxNumPkts);
+ int rxState;
+ UNSERIALIZE_SCALAR(rxState);
+ this->rxState = (RxState) rxState;
+ UNSERIALIZE_SCALAR(CRDD);
+ UNSERIALIZE_SCALAR(rxPktBytes);
+ UNSERIALIZE_SCALAR(rxFifoCnt);
+ UNSERIALIZE_SCALAR(rxHalt);
+ UNSERIALIZE_SCALAR(rxDescCnt);
+ int rxDmaState;
+ UNSERIALIZE_SCALAR(rxDmaState);
+ this->rxDmaState = (DmaState) rxDmaState;
+
+ UNSERIALIZE_SCALAR(extstsEnable);
+
+ /*
+ * If there's a pending transmit, store the time so we can
+ * reschedule it later
+ */
+ Tick transmitTick;
+ UNSERIALIZE_SCALAR(transmitTick);
+ if (transmitTick)
+ txEvent.schedule(curTick + transmitTick);
+
+ /*
+ * Keep track of pending interrupt status.
+ */
+ UNSERIALIZE_SCALAR(intrTick);
+ UNSERIALIZE_SCALAR(cpuPendingIntr);
+ Tick intrEventTick;
+ UNSERIALIZE_SCALAR(intrEventTick);
+ if (intrEventTick) {
+ intrEvent = new IntrEvent(this, true);
+ 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));
}
-
- std::string readReqName, writeReqName;
- UNSERIALIZE_SCALAR(readReqName);
- UNSERIALIZE_SCALAR(writeReqName);
-
- // Unserialize and fixup the readRequest
- readRequest.unserialize(cp, readReqName);
- readRequest.phys = readPhys;
- readRequest.bufferCB = 0;
- readRequest.dmaDoneCB = &txDoneCB;
- readRequest.data = NULL;
-
- if (txDoneCB.packet)
- readRequest.data = txDoneCB.packet->data;
-
- // Unserialize and fixup the writeRequest
- writeRequest.unserialize(cp, writeReqName);
- writeRequest.phys = writePhys;
- writeRequest.bufferCB = 0;
- writeRequest.dmaDoneCB = &rxDoneCB;
- writeRequest.data = NULL;
-
- if (rxPacket)
- writeRequest.data = rxPacket->data;
-#endif
+ 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));
+ }
}
+Tick
+EtherDev::cacheAccess(MemReqPtr &req)
+{
+ DPRINTF(EthernetPIO, "timing access to paddr=%#x (daddr=%#x)\n",
+ req->paddr, req->paddr - addr);
+ return curTick + pioLatency;
+}
//=====================================================================
@@ -1876,16 +2286,24 @@ BEGIN_DECLARE_SIM_OBJECT_PARAMS(EtherDev)
Param<Tick> tx_delay;
Param<Tick> rx_delay;
- SimObjectParam<DmaEngine *> engine;
- Param<bool> use_interface;
SimObjectParam<IntrControl *> intr_ctrl;
+ Param<Tick> intr_delay;
SimObjectParam<MemoryController *> mmu;
SimObjectParam<PhysicalMemory *> physmem;
Param<Addr> addr;
- Param<Addr> mask;
Param<bool> rx_filter;
Param<string> hardware_address;
- SimObjectParam<PCIConfigAll *> configspace;
+ SimObjectParam<Bus*> header_bus;
+ SimObjectParam<Bus*> payload_bus;
+ SimObjectParam<HierParams *> hier;
+ Param<Tick> pio_latency;
+ Param<bool> dma_desc_free;
+ Param<bool> dma_data_free;
+ Param<Tick> dma_read_delay;
+ Param<Tick> dma_write_delay;
+ Param<Tick> dma_read_factor;
+ Param<Tick> dma_write_factor;
+ SimObjectParam<PciConfigAll *> configspace;
SimObjectParam<PciConfigData *> configdata;
SimObjectParam<Tsunami *> tsunami;
Param<uint32_t> pci_bus;
@@ -1898,16 +2316,24 @@ BEGIN_INIT_SIM_OBJECT_PARAMS(EtherDev)
INIT_PARAM_DFLT(tx_delay, "Transmit Delay", 1000),
INIT_PARAM_DFLT(rx_delay, "Receive Delay", 1000),
- INIT_PARAM(engine, "DMA Engine"),
- INIT_PARAM_DFLT(use_interface, "Use DMA Interface", true),
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(mask, "Address Mask"),
INIT_PARAM_DFLT(rx_filter, "Enable Receive Filter", true),
INIT_PARAM_DFLT(hardware_address, "Ethernet Hardware Address",
"00:99:00:00:00:01"),
+ INIT_PARAM_DFLT(header_bus, "The IO Bus to attach to for headers", NULL),
+ INIT_PARAM_DFLT(payload_bus, "The IO Bus to attach to for payload", NULL),
+ INIT_PARAM_DFLT(hier, "Hierarchy global variables", &defaultHierParams),
+ INIT_PARAM_DFLT(pio_latency, "Programmed IO latency", 1000),
+ INIT_PARAM_DFLT(dma_desc_free, "DMA of Descriptors is free", false),
+ INIT_PARAM_DFLT(dma_data_free, "DMA of Data is free", false),
+ INIT_PARAM_DFLT(dma_read_delay, "fixed delay for dma reads", 0),
+ INIT_PARAM_DFLT(dma_write_delay, "fixed delay for dma writes", 0),
+ INIT_PARAM_DFLT(dma_read_factor, "multiplier for dma reads", 0),
+ INIT_PARAM_DFLT(dma_write_factor, "multiplier for dma writes", 0),
INIT_PARAM(configspace, "PCI Configspace"),
INIT_PARAM(configdata, "PCI Config data"),
INIT_PARAM(tsunami, "Tsunami"),
@@ -1924,10 +2350,13 @@ CREATE_SIM_OBJECT(EtherDev)
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(), engine, use_interface,
- intr_ctrl, mmu, physmem, configspace, configdata,
+ 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,
- tx_delay, rx_delay, addr, mask);
+ addr);
}
REGISTER_SIM_OBJECT("EtherDev", EtherDev)