* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
-#include <cstdio>
#include <deque>
+#include <limits>
#include <string>
#include "base/inet.hh"
#include "dev/etherlink.hh"
#include "dev/sinic.hh"
#include "dev/pciconfigall.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/memory_control.hh"
-#include "mem/functional/physical.hh"
+#include "mem/packet.hh"
#include "sim/builder.hh"
#include "sim/debug.hh"
#include "sim/eventq.hh"
#include "sim/host.hh"
#include "sim/stats.hh"
-#include "targetarch/vtophys.hh"
+#include "arch/vtophys.hh"
using namespace Net;
+using namespace TheISA;
namespace Sinic {
// Sinic PCI Device
//
Base::Base(Params *p)
- : PciDev(p), rxEnable(false), txEnable(false), cycleTime(p->cycle_time),
+ : PciDev(p), rxEnable(false), txEnable(false), clock(p->clock),
intrDelay(p->intr_delay), intrTick(0), cpuIntrEnable(false),
cpuPendingIntr(false), intrEvent(0), interface(NULL)
{
}
Device::Device(Params *p)
- : Base(p), plat(p->plat), physmem(p->physmem),
- rxFifo(p->rx_fifo_size), txFifo(p->tx_fifo_size),
+ : Base(p), plat(p->plat), physmem(p->physmem), rxUnique(0), txUnique(0),
+ virtualRegs(p->virtual_count < 1 ? 1 : p->virtual_count),
rxKickTick(0), txKickTick(0),
txEvent(this), rxDmaEvent(this), txDmaEvent(this),
dmaReadDelay(p->dma_read_delay), dmaReadFactor(p->dma_read_factor),
{
reset();
- if (p->io_bus) {
- pioInterface = newPioInterface(p->name, p->hier, p->io_bus, this,
- &Device::cacheAccess);
-
- pioLatency = p->pio_latency * p->io_bus->clockRate;
-
- if (p->payload_bus)
- dmaInterface = new DMAInterface<Bus>(p->name + ".dma", p->io_bus,
- p->payload_bus, 1,
- p->dma_no_allocate);
- else
- dmaInterface = new DMAInterface<Bus>(p->name + ".dma", p->io_bus,
- p->io_bus, 1,
- p->dma_no_allocate);
- } else if (p->payload_bus) {
- pioInterface = newPioInterface(p->name, p->hier, p->payload_bus, this,
- &Device::cacheAccess);
-
- pioLatency = p->pio_latency * p->payload_bus->clockRate;
-
- dmaInterface = new DMAInterface<Bus>(p->name + ".dma", p->payload_bus,
- p->payload_bus, 1,
- p->dma_no_allocate);
- }
}
Device::~Device()
rxPacketRate = rxPackets / simSeconds;
}
-/**
- * This is to write to the PCI general configuration registers
- */
void
-Device::WriteConfig(int offset, int size, uint32_t data)
+Device::prepareIO(int cpu, int index)
{
- switch (offset) {
- case PCI0_BASE_ADDR0:
- // Need to catch writes to BARs to update the PIO interface
- PciDev::WriteConfig(offset, size, data);
- if (BARAddrs[0] != 0) {
- if (pioInterface)
- pioInterface->addAddrRange(RangeSize(BARAddrs[0], BARSize[0]));
-
- BARAddrs[0] &= EV5::PAddrUncachedMask;
- }
- break;
+ int size = virtualRegs.size();
+ if (index > size)
+ panic("Trying to access a vnic that doesn't exist %d > %d\n",
+ index, size);
+}
- default:
- PciDev::WriteConfig(offset, size, data);
- }
+void
+Device::prepareRead(int cpu, int index)
+{
+ using namespace Regs;
+ prepareIO(cpu, index);
+
+ VirtualReg &vnic = virtualRegs[index];
+
+ // update rx registers
+ uint64_t rxdone = vnic.RxDone;
+ rxdone = set_RxDone_Packets(rxdone, rxFifo.countPacketsAfter(rxFifoPtr));
+ rxdone = set_RxDone_Empty(rxdone, rxFifo.empty());
+ rxdone = set_RxDone_High(rxdone, rxFifo.size() > regs.RxFifoMark);
+ rxdone = set_RxDone_NotHigh(rxdone, rxLow);
+ regs.RxData = vnic.RxData;
+ regs.RxDone = rxdone;
+ regs.RxWait = rxdone;
+
+ // update tx regsiters
+ uint64_t txdone = vnic.TxDone;
+ txdone = set_TxDone_Packets(txdone, txFifo.packets());
+ txdone = set_TxDone_Full(txdone, txFifo.avail() < regs.TxMaxCopy);
+ txdone = set_TxDone_Low(txdone, txFifo.size() < regs.TxFifoMark);
+ regs.TxData = vnic.TxData;
+ regs.TxDone = txdone;
+ regs.TxWait = txdone;
+}
+
+void
+Device::prepareWrite(int cpu, int index)
+{
+ prepareIO(cpu, index);
}
/**
- * This reads the device registers, which are detailed in the NS83820
- * spec sheet
+ * I/O read of device register
*/
-Fault
-Device::read(MemReqPtr &req, uint8_t *data)
+Tick
+Device::read(Packet &pkt)
{
- assert(config.hdr.command & PCI_CMD_MSE);
-
- //The mask is to give you only the offset into the device register file
- Addr daddr = req->paddr & 0xfff;
-
- if (Regs::regSize(daddr) == 0)
- panic("invalid address: da=%#x pa=%#x va=%#x size=%d",
- daddr, req->paddr, req->vaddr, req->size);
-
- if (req->size != Regs::regSize(daddr))
- panic("invalid size for reg %s: da=%#x pa=%#x va=%#x size=%d",
- Regs::regName(daddr), daddr, req->paddr, req->vaddr, req->size);
-
- DPRINTF(EthernetPIO, "read reg=%s da=%#x pa=%#x va=%#x size=%d\n",
- Regs::regName(daddr), daddr, req->paddr, req->vaddr, req->size);
-
- uint32_t ®32 = *(uint32_t *)data;
- uint64_t ®64 = *(uint64_t *)data;
+ assert(config.command & PCI_CMD_MSE);
+ assert(pkt.addr >= BARAddrs[0] && pkt.size < BARSize[0]);
+
+ int cpu = pkt.req->getCpuNum();
+ Addr daddr = pkt.addr - BARAddrs[0];
+ Addr index = daddr >> Regs::VirtualShift;
+ Addr raddr = daddr & Regs::VirtualMask;
+
+ pkt.time += pioDelay;
+ pkt.allocate();
+
+ if (!regValid(raddr))
+ panic("invalid register: cpu=%d vnic=%d da=%#x pa=%#x size=%d",
+ cpu, index, daddr, pkt.addr, pkt.size);
+
+ const Regs::Info &info = regInfo(raddr);
+ if (!info.read)
+ panic("read %s (write only): "
+ "cpu=%d vnic=%d da=%#x pa=%#x size=%d",
+ info.name, cpu, index, daddr, pkt.addr, pkt.size);
+
+ panic("read %s (invalid size): "
+ "cpu=%d vnic=%d da=%#x pa=%#x size=%d",
+ info.name, cpu, index, daddr, pkt.addr, pkt.size);
+
+ prepareRead(cpu, index);
+
+ uint64_t value = 0;
+ if (pkt.size == 4) {
+ uint32_t reg = regData32(raddr);
+ pkt.set(reg);
+ value = reg;
+ }
- switch (daddr) {
- case Regs::Config:
- reg32 = regs.Config;
- break;
+ if (pkt.size == 8) {
+ uint64_t reg = regData64(raddr);
+ pkt.set(reg);
+ value = reg;
+ }
- case Regs::RxMaxCopy:
- reg32 = regs.RxMaxCopy;
- break;
+ DPRINTF(EthernetPIO,
+ "read %s: cpu=%d vnic=%d da=%#x pa=%#x size=%d val=%#x\n",
+ info.name, cpu, index, daddr, pkt.addr, pkt.size, value);
- case Regs::TxMaxCopy:
- reg32 = regs.TxMaxCopy;
- break;
+ // reading the interrupt status register has the side effect of
+ // clearing it
+ if (raddr == Regs::IntrStatus)
+ devIntrClear();
- case Regs::RxThreshold:
- reg32 = regs.RxThreshold;
- break;
+ return pioDelay;
+}
- case Regs::TxThreshold:
- reg32 = regs.TxThreshold;
- break;
+/**
+ * IPR read of device register
- case Regs::IntrStatus:
- reg32 = regs.IntrStatus;
- devIntrClear();
- break;
+ Fault
+Device::iprRead(Addr daddr, int cpu, uint64_t &result)
+{
+ if (!regValid(daddr))
+ panic("invalid address: da=%#x", daddr);
- case Regs::IntrMask:
- reg32 = regs.IntrMask;
- break;
+ const Regs::Info &info = regInfo(daddr);
+ if (!info.read)
+ panic("reading %s (write only): cpu=%d da=%#x", info.name, cpu, daddr);
- case Regs::RxData:
- reg64 = regs.RxData;
- break;
+ DPRINTF(EthernetPIO, "IPR read %s: cpu=%d da=%#x\n",
+ info.name, cpu, daddr);
- case Regs::RxDone:
- case Regs::RxWait:
- reg64 = Regs::set_RxDone_FifoLen(regs.RxDone,
- min(rxFifo.packets(), 255));
- break;
+ prepareRead(cpu, 0);
- case Regs::TxData:
- reg64 = regs.TxData;
- break;
+ if (info.size == 4)
+ result = regData32(daddr);
- case Regs::TxDone:
- case Regs::TxWait:
- reg64 = Regs::set_TxDone_FifoLen(regs.TxDone,
- min(txFifo.packets(), 255));
- break;
+ if (info.size == 8)
+ result = regData64(daddr);
- case Regs::HwAddr:
- reg64 = params()->eaddr;
- break;
+ DPRINTF(EthernetPIO, "IPR read %s: cpu=%s da=%#x val=%#x\n",
+ info.name, cpu, result);
- default:
- panic("reading write only register %s: da=%#x pa=%#x va=%#x size=%d",
- Regs::regName(daddr), daddr, req->paddr, req->vaddr, req->size);
- }
+ return NoFault;
+}
+*/
+/**
+ * I/O write of device register
+ */
+Tick
+Device::write(Packet &pkt)
+{
+ assert(config.command & PCI_CMD_MSE);
+ assert(pkt.addr >= BARAddrs[0] && pkt.size < BARSize[0]);
- DPRINTF(EthernetPIO, "read reg=%s done val=%#x\n", Regs::regName(daddr),
- Regs::regSize(daddr) == 4 ? reg32 : reg64);
+ int cpu = pkt.req->getCpuNum();
+ Addr daddr = pkt.addr - BARAddrs[0];
+ Addr index = daddr >> Regs::VirtualShift;
+ Addr raddr = daddr & Regs::VirtualMask;
- return No_Fault;
-}
+ pkt.time += pioDelay;
-Fault
-Device::write(MemReqPtr &req, const uint8_t *data)
-{
- assert(config.hdr.command & PCI_CMD_MSE);
- Addr daddr = req->paddr & 0xfff;
+ if (!regValid(raddr))
+ panic("invalid register: cpu=%d, da=%#x pa=%#x size=%d",
+ cpu, daddr, pkt.addr, pkt.size);
- if (Regs::regSize(daddr) == 0)
- panic("invalid address: da=%#x pa=%#x va=%#x size=%d",
- daddr, req->paddr, req->vaddr, req->size);
+ const Regs::Info &info = regInfo(raddr);
+ if (!info.write)
+ panic("write %s (read only): "
+ "cpu=%d vnic=%d da=%#x pa=%#x size=%d",
+ info.name, cpu, index, daddr, pkt.addr, pkt.size);
- if (req->size != Regs::regSize(daddr))
- panic("invalid size: reg=%s da=%#x pa=%#x va=%#x size=%d",
- Regs::regName(daddr), daddr, req->paddr, req->vaddr, req->size);
+ if (pkt.size != info.size)
+ panic("write %s (invalid size): "
+ "cpu=%d vnic=%d da=%#x pa=%#x size=%d",
+ info.name, cpu, index, daddr, pkt.addr, pkt.size);
- uint32_t reg32 = *(uint32_t *)data;
- uint64_t reg64 = *(uint64_t *)data;
+ VirtualReg &vnic = virtualRegs[index];
- DPRINTF(EthernetPIO, "write reg=%s val=%#x da=%#x pa=%#x va=%#x size=%d\n",
- Regs::regName(daddr), Regs::regSize(daddr) == 4 ? reg32 : reg64,
- daddr, req->paddr, req->vaddr, req->size);
+ DPRINTF(EthernetPIO,
+ "write %s vnic %d: cpu=%d val=%#x da=%#x pa=%#x size=%d\n",
+ info.name, index, cpu, info.size == 4 ? pkt.get<uint32_t>() :
+ pkt.get<uint64_t>(), daddr, pkt.addr, pkt.size);
+ prepareWrite(cpu, index);
- switch (daddr) {
+ switch (raddr) {
case Regs::Config:
- changeConfig(reg32);
+ changeConfig(pkt.get<uint32_t>());
break;
- case Regs::RxThreshold:
- regs.RxThreshold = reg32;
+ case Regs::Command:
+ command(pkt.get<uint32_t>());
break;
- case Regs::TxThreshold:
- regs.TxThreshold = reg32;
+ case Regs::IntrStatus:
+ devIntrClear(regs.IntrStatus & pkt.get<uint32_t>());
break;
case Regs::IntrMask:
- devIntrChangeMask(reg32);
+ devIntrChangeMask(pkt.get<uint32_t>());
break;
case Regs::RxData:
- if (rxState != rxIdle)
- panic("receive machine busy with another request!");
+ if (Regs::get_RxDone_Busy(vnic.RxDone))
+ panic("receive machine busy with another request! rxState=%s",
+ RxStateStrings[rxState]);
+
+ vnic.rxUnique = rxUnique++;
+ vnic.RxDone = Regs::RxDone_Busy;
+ vnic.RxData = pkt.get<uint64_t>();
+
+ if (Regs::get_RxData_Vaddr(reg64)) {
+ Addr vaddr = Regs::get_RxData_Addr(reg64);
+ Addr paddr = vtophys(req->xc, vaddr);
+ DPRINTF(EthernetPIO, "write RxData vnic %d (rxunique %d): "
+ "vaddr=%#x, paddr=%#x\n",
+ index, vnic.rxUnique, vaddr, paddr);
+
+ vnic.RxData = Regs::set_RxData_Addr(vnic.RxData, paddr);
+ } else {
+ DPRINTF(EthernetPIO, "write RxData vnic %d (rxunique %d)\n",
+ index, vnic.rxUnique);
+ }
+
+ if (vnic.rxPacket == rxFifo.end()) {
+ DPRINTF(EthernetPIO, "request new packet...appending to rxList\n");
+ rxList.push_back(index);
+ } else {
+ DPRINTF(EthernetPIO, "packet exists...appending to rxBusy\n");
+ rxBusy.push_back(index);
+ }
- regs.RxDone = 0;
- regs.RxData = reg64;
- if (rxEnable) {
+ if (rxEnable && (rxState == rxIdle || rxState == rxFifoBlock)) {
rxState = rxFifoBlock;
rxKick();
}
break;
case Regs::TxData:
- if (txState != txIdle)
- panic("transmit machine busy with another request!");
+ if (Regs::get_TxDone_Busy(vnic.TxDone))
+ panic("transmit machine busy with another request! txState=%s",
+ TxStateStrings[txState]);
+
+ vnic.txUnique = txUnique++;
+ vnic.TxDone = Regs::TxDone_Busy;
+
+ if (Regs::get_TxData_Vaddr(pkt.get<uint64_t>())) {
+ panic("vtophys won't work here in newmem.\n");
+ /*Addr vaddr = Regs::get_TxData_Addr(reg64);
+ Addr paddr = vtophys(req->xc, vaddr);
+ DPRINTF(EthernetPIO, "write TxData vnic %d (rxunique %d): "
+ "vaddr=%#x, paddr=%#x\n",
+ index, vnic.txUnique, vaddr, paddr);
+
+ vnic.TxData = Regs::set_TxData_Addr(vnic.TxData, paddr);*/
+ } else {
+ DPRINTF(EthernetPIO, "write TxData vnic %d (rxunique %d)\n",
+ index, vnic.txUnique);
+ }
- regs.TxDone = 0;
- regs.TxData = reg64;
- if (txEnable) {
+ if (txList.empty() || txList.front() != index)
+ txList.push_back(index);
+ if (txEnable && txState == txIdle && txList.front() == index) {
txState = txFifoBlock;
txKick();
}
break;
-
- default:
- panic("writing read only register %s: da=%#x pa=%#x va=%#x size=%d",
- Regs::regName(daddr), daddr, req->paddr, req->vaddr, req->size);
}
- return No_Fault;
+ return pioDelay;
}
void
"interrupt written to intStatus: intr=%#x status=%#x mask=%#x\n",
interrupts, regs.IntrStatus, regs.IntrMask);
- if ((regs.IntrStatus & regs.IntrMask)) {
+ interrupts = regs.IntrStatus & regs.IntrMask;
+
+ // Intr_RxHigh is special, we only signal it if we've emptied the fifo
+ // and then filled it above the high watermark
+ if (rxEmpty)
+ rxEmpty = false;
+ else
+ interrupts &= ~Regs::Intr_RxHigh;
+
+ // Intr_TxLow is special, we only signal it if we've filled up the fifo
+ // and then dropped below the low watermark
+ if (txFull)
+ txFull = false;
+ else
+ interrupts &= ~Regs::Intr_TxLow;
+
+ if (interrupts) {
Tick when = curTick;
- if ((regs.IntrStatus & regs.IntrMask & Regs::Intr_NoDelay) == 0)
+ if ((interrupts & Regs::Intr_NoDelay) == 0)
when += intrDelay;
cpuIntrPost(when);
}
regs.Config = newconf;
- if ((changed & Regs::Config_Reset)) {
- assert(regs.Config & Regs::Config_Reset);
- reset();
- regs.Config &= ~Regs::Config_Reset;
- }
-
if ((changed & Regs::Config_IntEn)) {
cpuIntrEnable = regs.Config & Regs::Config_IntEn;
if (cpuIntrEnable) {
}
}
+void
+Device::command(uint32_t command)
+{
+ if (command & Regs::Command_Intr)
+ devIntrPost(Regs::Intr_Soft);
+
+ if (command & Regs::Command_Reset)
+ reset();
+}
+
void
Device::reset()
{
using namespace Regs;
+
memset(®s, 0, sizeof(regs));
+
+ regs.Config = 0;
+ if (params()->rx_thread)
+ regs.Config |= Config_RxThread;
+ if (params()->tx_thread)
+ regs.Config |= Config_TxThread;
+ if (params()->rss)
+ regs.Config |= Config_RSS;
+ if (params()->zero_copy)
+ regs.Config |= Config_ZeroCopy;
+ if (params()->delay_copy)
+ regs.Config |= Config_DelayCopy;
+ if (params()->virtual_addr)
+ regs.Config |= Config_Vaddr;
+
+ if (params()->delay_copy && params()->zero_copy)
+ panic("Can't delay copy and zero copy");
+
+ regs.IntrMask = Intr_Soft | Intr_RxHigh | Intr_RxPacket | Intr_TxLow;
regs.RxMaxCopy = params()->rx_max_copy;
regs.TxMaxCopy = params()->tx_max_copy;
- regs.IntrMask = Intr_TxFifo | Intr_RxFifo | Intr_RxData;
+ regs.RxMaxIntr = params()->rx_max_intr;
+ regs.VirtualCount = params()->virtual_count;
+ regs.RxFifoSize = params()->rx_fifo_size;
+ regs.TxFifoSize = params()->tx_fifo_size;
+ regs.RxFifoMark = params()->rx_fifo_threshold;
+ regs.TxFifoMark = params()->tx_fifo_threshold;
+ regs.HwAddr = params()->eaddr;
+
+ rxList.clear();
+ rxBusy.clear();
+ rxActive = -1;
+ txList.clear();
rxState = rxIdle;
txState = txIdle;
rxFifo.clear();
+ rxFifoPtr = rxFifo.end();
txFifo.clear();
+ rxEmpty = false;
+ rxLow = true;
+ txFull = false;
+
+ int size = virtualRegs.size();
+ virtualRegs.clear();
+ virtualRegs.resize(size);
+ for (int i = 0; i < size; ++i)
+ virtualRegs[i].rxPacket = rxFifo.end();
}
void
-Device::rxDmaCopy()
+Device::rxDmaDone()
{
assert(rxState == rxCopy);
rxState = rxCopyDone;
- physmem->dma_write(rxDmaAddr, (uint8_t *)rxDmaData, rxDmaLen);
- DPRINTF(EthernetDMA, "rx dma write paddr=%#x len=%d\n",
+ DPRINTF(EthernetDMA, "end rx dma write paddr=%#x len=%d\n",
rxDmaAddr, rxDmaLen);
- DDUMP(EthernetDMA, rxDmaData, rxDmaLen);
-}
+ DDUMP(EthernetData, rxDmaData, rxDmaLen);
+
+ // If the transmit state machine has a pending DMA, let it go first
+ if (txState == txBeginCopy)
+ txKick();
-void
-Device::rxDmaDone()
-{
- rxDmaCopy();
rxKick();
}
void
Device::rxKick()
{
- DPRINTF(EthernetSM, "receive kick rxState=%s (rxFifo.size=%d)\n",
+ VirtualReg *vnic = NULL;
+
+ DPRINTF(EthernetSM, "rxKick: rxState=%s (rxFifo.size=%d)\n",
RxStateStrings[rxState], rxFifo.size());
if (rxKickTick > curTick) {
- DPRINTF(EthernetSM, "receive kick exiting, can't run till %d\n",
+ DPRINTF(EthernetSM, "rxKick: exiting, can't run till %d\n",
rxKickTick);
return;
}
next:
- switch (rxState) {
- case rxIdle:
- if (rxPioRequest) {
- pioInterface->respond(rxPioRequest, curTick);
- rxPioRequest = 0;
- }
+ if (rxState == rxIdle)
goto exit;
+ if (rxActive == -1) {
+ if (rxState != rxFifoBlock)
+ panic("no active vnic while in state %s", RxStateStrings[rxState]);
+
+ DPRINTF(EthernetSM, "processing rxState=%s\n",
+ RxStateStrings[rxState]);
+ } else {
+ vnic = &virtualRegs[rxActive];
+ DPRINTF(EthernetSM,
+ "processing rxState=%s for vnic %d (rxunique %d)\n",
+ RxStateStrings[rxState], rxActive, vnic->rxUnique);
+ }
+
+ switch (rxState) {
case rxFifoBlock:
- if (rxPacket) {
+ if (DTRACE(EthernetSM)) {
+ PacketFifo::iterator end = rxFifo.end();
+ int size = virtualRegs.size();
+ for (int i = 0; i < size; ++i) {
+ VirtualReg *vn = &virtualRegs[i];
+ if (vn->rxPacket != end &&
+ !Regs::get_RxDone_Busy(vn->RxDone)) {
+ DPRINTF(EthernetSM,
+ "vnic %d (rxunique %d), has outstanding packet %d\n",
+ i, vn->rxUnique,
+ rxFifo.countPacketsBefore(vn->rxPacket));
+ }
+ }
+ }
+
+ if (!rxBusy.empty()) {
+ rxActive = rxBusy.front();
+ rxBusy.pop_front();
+ vnic = &virtualRegs[rxActive];
+
+ if (vnic->rxPacket == rxFifo.end())
+ panic("continuing vnic without packet\n");
+
+ DPRINTF(EthernetSM,
+ "continue processing for vnic %d (rxunique %d)\n",
+ rxActive, vnic->rxUnique);
+
rxState = rxBeginCopy;
+
break;
}
- if (rxFifo.empty()) {
+ if (rxFifoPtr == rxFifo.end()) {
DPRINTF(EthernetSM, "receive waiting for data. Nothing to do.\n");
goto exit;
}
+ if (rxList.empty())
+ panic("Not idle, but nothing to do!");
+
+ assert(!rxFifo.empty());
+
+ rxActive = rxList.front();
+ rxList.pop_front();
+ vnic = &virtualRegs[rxActive];
+
+ DPRINTF(EthernetSM,
+ "processing new packet for vnic %d (rxunique %d)\n",
+ rxActive, vnic->rxUnique);
+
// Grab a new packet from the fifo.
- rxPacket = rxFifo.front();
- rxPacketBufPtr = rxPacket->data;
- rxPktBytes = rxPacket->length;
- assert(rxPktBytes);
+ vnic->rxPacket = rxFifoPtr++;
+ vnic->rxPacketOffset = 0;
+ vnic->rxPacketBytes = (*vnic->rxPacket)->length;
+ assert(vnic->rxPacketBytes);
- rxDoneData = 0;
+ vnic->rxDoneData = 0;
/* scope for variables */ {
- IpPtr ip(rxPacket);
+ IpPtr ip(*vnic->rxPacket);
if (ip) {
- rxDoneData |= Regs::RxDone_IpPacket;
+ DPRINTF(Ethernet, "ID is %d\n", ip->id());
+ vnic->rxDoneData |= Regs::RxDone_IpPacket;
rxIpChecksums++;
if (cksum(ip) != 0) {
DPRINTF(EthernetCksum, "Rx IP Checksum Error\n");
- rxDoneData |= Regs::RxDone_IpError;
+ vnic->rxDoneData |= Regs::RxDone_IpError;
}
TcpPtr tcp(ip);
UdpPtr udp(ip);
if (tcp) {
- rxDoneData |= Regs::RxDone_TcpPacket;
+ DPRINTF(Ethernet,
+ "Src Port=%d, Dest Port=%d, Seq=%d, Ack=%d\n",
+ tcp->sport(), tcp->dport(), tcp->seq(),
+ tcp->ack());
+ vnic->rxDoneData |= Regs::RxDone_TcpPacket;
rxTcpChecksums++;
if (cksum(tcp) != 0) {
DPRINTF(EthernetCksum, "Rx TCP Checksum Error\n");
- rxDoneData |= Regs::RxDone_TcpError;
+ vnic->rxDoneData |= Regs::RxDone_TcpError;
}
} else if (udp) {
- rxDoneData |= Regs::RxDone_UdpPacket;
+ vnic->rxDoneData |= Regs::RxDone_UdpPacket;
rxUdpChecksums++;
if (cksum(udp) != 0) {
DPRINTF(EthernetCksum, "Rx UDP Checksum Error\n");
- rxDoneData |= Regs::RxDone_UdpError;
+ vnic->rxDoneData |= Regs::RxDone_UdpError;
}
}
}
break;
case rxBeginCopy:
- rxDmaAddr = plat->pciToDma(Regs::get_RxData_Addr(regs.RxData));
- rxDmaLen = min<int>(Regs::get_RxData_Len(regs.RxData), rxPktBytes);
- rxDmaData = rxPacketBufPtr;
-
- if (dmaInterface) {
- if (!dmaInterface->busy()) {
- dmaInterface->doDMA(WriteInvalidate, rxDmaAddr, rxDmaLen,
- curTick, &rxDmaEvent, true);
- rxState = rxCopy;
- }
+ if (dmaPending())
goto exit;
- }
+ rxDmaAddr = params()->platform->pciToDma(
+ Regs::get_RxData_Addr(vnic->RxData));
+ rxDmaLen = std::min<int>(Regs::get_RxData_Len(vnic->RxData),
+ vnic->rxPacketBytes);
+ rxDmaData = (*vnic->rxPacket)->data + vnic->rxPacketOffset;
rxState = rxCopy;
- if (dmaWriteDelay != 0 || dmaWriteFactor != 0) {
- Tick factor = ((rxDmaLen + ULL(63)) >> ULL(6)) * dmaWriteFactor;
- Tick start = curTick + dmaWriteDelay + factor;
- rxDmaEvent.schedule(start);
- goto exit;
+ if (rxDmaAddr == 1LL) {
+ rxState = rxCopyDone;
+ break;
}
- rxDmaCopy();
+
+ dmaWrite(rxDmaAddr, rxDmaLen, &rxDmaEvent, rxDmaData);
break;
case rxCopy:
goto exit;
case rxCopyDone:
- regs.RxDone = rxDoneData | rxDmaLen;
-
- if (rxPktBytes == rxDmaLen) {
- rxPacket = NULL;
- rxFifo.pop();
+ vnic->RxDone = vnic->rxDoneData;
+ vnic->RxDone |= Regs::RxDone_Complete;
+
+ if (vnic->rxPacketBytes == rxDmaLen) {
+ // Packet is complete. Indicate how many bytes were copied
+ vnic->RxDone = Regs::set_RxDone_CopyLen(vnic->RxDone, rxDmaLen);
+
+ DPRINTF(EthernetSM,
+ "rxKick: packet complete on vnic %d (rxunique %d)\n",
+ rxActive, vnic->rxUnique);
+ rxFifo.remove(vnic->rxPacket);
+ vnic->rxPacket = rxFifo.end();
} else {
- regs.RxDone |= Regs::RxDone_More;
- rxPktBytes -= rxDmaLen;
- rxPacketBufPtr += rxDmaLen;
+ vnic->rxPacketBytes -= rxDmaLen;
+ vnic->rxPacketOffset += rxDmaLen;
+ vnic->RxDone |= Regs::RxDone_More;
+ vnic->RxDone = Regs::set_RxDone_CopyLen(vnic->RxDone,
+ vnic->rxPacketBytes);
+ DPRINTF(EthernetSM,
+ "rxKick: packet not complete on vnic %d (rxunique %d): "
+ "%d bytes left\n",
+ rxActive, vnic->rxUnique, vnic->rxPacketBytes);
+ }
+
+ rxActive = -1;
+ rxState = rxBusy.empty() && rxList.empty() ? rxIdle : rxFifoBlock;
+
+ if (rxFifo.empty()) {
+ devIntrPost(Regs::Intr_RxEmpty);
+ rxEmpty = true;
}
- regs.RxDone |= Regs::RxDone_Complete;
- devIntrPost(Regs::Intr_RxData);
- rxState = rxIdle;
+ if (rxFifo.size() < params()->rx_fifo_low_mark)
+ rxLow = true;
+
+ if (rxFifo.size() > params()->rx_fifo_threshold)
+ rxLow = false;
+
+ devIntrPost(Regs::Intr_RxDMA);
break;
default:
}
void
-Device::txDmaCopy()
+Device::txDmaDone()
{
assert(txState == txCopy);
txState = txCopyDone;
- physmem->dma_read((uint8_t *)txDmaData, txDmaAddr, txDmaLen);
DPRINTF(EthernetDMA, "tx dma read paddr=%#x len=%d\n",
txDmaAddr, txDmaLen);
- DDUMP(EthernetDMA, txDmaData, txDmaLen);
-}
+ DDUMP(EthernetData, txDmaData, txDmaLen);
+
+ // If the receive state machine has a pending DMA, let it go first
+ if (rxState == rxBeginCopy)
+ rxKick();
-void
-Device::txDmaDone()
-{
- txDmaCopy();
txKick();
}
return;
}
- PacketPtr packet = txFifo.front();
+ uint32_t interrupts;
+ EthPacketPtr packet = txFifo.front();
if (!interface->sendPacket(packet)) {
DPRINTF(Ethernet, "Packet Transmit: failed txFifo available %d\n",
txFifo.avail());
}
txFifo.pop();
-
#if TRACING_ON
if (DTRACE(Ethernet)) {
IpPtr ip(packet);
DPRINTF(Ethernet, "ID is %d\n", ip->id());
TcpPtr tcp(ip);
if (tcp) {
- DPRINTF(Ethernet, "Src Port=%d, Dest Port=%d\n",
- tcp->sport(), tcp->dport());
+ DPRINTF(Ethernet,
+ "Src Port=%d, Dest Port=%d, Seq=%d, Ack=%d\n",
+ tcp->sport(), tcp->dport(), tcp->seq(),
+ tcp->ack());
}
}
}
#endif
- DDUMP(Ethernet, packet->data, packet->length);
+ DDUMP(EthernetData, packet->data, packet->length);
txBytes += packet->length;
txPackets++;
DPRINTF(Ethernet, "Packet Transmit: successful txFifo Available %d\n",
txFifo.avail());
- if (txFifo.size() <= params()->tx_fifo_threshold)
- devIntrPost(Regs::Intr_TxFifo);
-
- devIntrPost(Regs::Intr_TxDone);
+ interrupts = Regs::Intr_TxPacket;
+ if (txFifo.size() < regs.TxFifoMark)
+ interrupts |= Regs::Intr_TxLow;
+ devIntrPost(interrupts);
reschedule:
if (!txFifo.empty() && !txEvent.scheduled()) {
void
Device::txKick()
{
- DPRINTF(EthernetSM, "transmit kick txState=%s (txFifo.size=%d)\n",
+ VirtualReg *vnic;
+ DPRINTF(EthernetSM, "txKick: txState=%s (txFifo.size=%d)\n",
TxStateStrings[txState], txFifo.size());
if (txKickTick > curTick) {
- DPRINTF(EthernetSM, "transmit kick exiting, can't run till %d\n",
+ DPRINTF(EthernetSM, "txKick: exiting, can't run till %d\n",
txKickTick);
return;
}
next:
- switch (txState) {
- case txIdle:
- if (txPioRequest) {
- pioInterface->respond(txPioRequest, curTick + pioLatency);
- txPioRequest = 0;
- }
+ if (txState == txIdle)
goto exit;
+ assert(!txList.empty());
+ vnic = &virtualRegs[txList.front()];
+
+ switch (txState) {
case txFifoBlock:
+ assert(Regs::get_TxDone_Busy(vnic->TxDone));
if (!txPacket) {
// Grab a new packet from the fifo.
- txPacket = new PacketData(16384);
- txPacketBufPtr = txPacket->data;
+ txPacket = new EthPacketData(16384);
+ txPacketOffset = 0;
}
if (txFifo.avail() - txPacket->length <
- Regs::get_TxData_Len(regs.TxData)) {
+ Regs::get_TxData_Len(vnic->TxData)) {
DPRINTF(EthernetSM, "transmit fifo full. Nothing to do.\n");
goto exit;
}
break;
case txBeginCopy:
- txDmaAddr = plat->pciToDma(Regs::get_TxData_Addr(regs.TxData));
- txDmaLen = Regs::get_TxData_Len(regs.TxData);
- txDmaData = txPacketBufPtr;
-
- if (dmaInterface) {
- if (!dmaInterface->busy()) {
- dmaInterface->doDMA(Read, txDmaAddr, txDmaLen,
- curTick, &txDmaEvent, true);
- txState = txCopy;
- }
-
+ if (dmaPending())
goto exit;
- }
+ txDmaAddr = params()->platform->pciToDma(
+ Regs::get_TxData_Addr(vnic->TxData));
+ txDmaLen = Regs::get_TxData_Len(vnic->TxData);
+ txDmaData = txPacket->data + txPacketOffset;
txState = txCopy;
- if (dmaReadDelay != 0 || dmaReadFactor != 0) {
- Tick factor = ((txDmaLen + ULL(63)) >> ULL(6)) * dmaReadFactor;
- Tick start = curTick + dmaReadDelay + factor;
- txDmaEvent.schedule(start);
- goto exit;
- }
- txDmaCopy();
+ dmaRead(txDmaAddr, txDmaLen, &txDmaEvent, txDmaData);
break;
case txCopy:
goto exit;
case txCopyDone:
+ vnic->TxDone = txDmaLen | Regs::TxDone_Complete;
txPacket->length += txDmaLen;
- if ((regs.TxData & Regs::TxData_More)) {
- txPacketBufPtr += txDmaLen;
- } else {
- assert(txPacket->length <= txFifo.avail());
- if ((regs.TxData & Regs::TxData_Checksum)) {
- IpPtr ip(txPacket);
- if (ip) {
- TcpPtr tcp(ip);
- if (tcp) {
- tcp->sum(0);
- tcp->sum(cksum(tcp));
- txTcpChecksums++;
- }
+ if ((vnic->TxData & Regs::TxData_More)) {
+ txPacketOffset += txDmaLen;
+ txState = txIdle;
+ devIntrPost(Regs::Intr_TxDMA);
+ break;
+ }
- UdpPtr udp(ip);
- if (udp) {
- udp->sum(0);
- udp->sum(cksum(udp));
- txUdpChecksums++;
- }
+ assert(txPacket->length <= txFifo.avail());
+ if ((vnic->TxData & Regs::TxData_Checksum)) {
+ IpPtr ip(txPacket);
+ if (ip) {
+ TcpPtr tcp(ip);
+ if (tcp) {
+ tcp->sum(0);
+ tcp->sum(cksum(tcp));
+ txTcpChecksums++;
+ }
- ip->sum(0);
- ip->sum(cksum(ip));
- txIpChecksums++;
+ UdpPtr udp(ip);
+ if (udp) {
+ udp->sum(0);
+ udp->sum(cksum(udp));
+ txUdpChecksums++;
}
+
+ ip->sum(0);
+ ip->sum(cksum(ip));
+ txIpChecksums++;
}
- txFifo.push(txPacket);
- txPacket = 0;
- transmit();
}
- regs.TxDone = txDmaLen | Regs::TxDone_Complete;
- devIntrPost(Regs::Intr_TxData);
- txState = txIdle;
+ txFifo.push(txPacket);
+ if (txFifo.avail() < regs.TxMaxCopy) {
+ devIntrPost(Regs::Intr_TxFull);
+ txFull = true;
+ }
+ txPacket = 0;
+ transmit();
+ txList.pop_front();
+ txState = txList.empty() ? txIdle : txFifoBlock;
+ devIntrPost(Regs::Intr_TxDMA);
break;
default:
}
bool
-Device::rxFilter(const PacketPtr &packet)
+Device::rxFilter(const EthPacketPtr &packet)
{
if (!Regs::get_Config_Filter(regs.Config))
return false;
}
bool
-Device::recvPacket(PacketPtr packet)
+Device::recvPacket(EthPacketPtr packet)
{
rxBytes += packet->length;
rxPackets++;
if (!rxEnable) {
DPRINTF(Ethernet, "receive disabled...packet dropped\n");
- interface->recvDone();
return true;
}
if (rxFilter(packet)) {
DPRINTF(Ethernet, "packet filtered...dropped\n");
- interface->recvDone();
return true;
}
- if (rxFifo.size() >= params()->rx_fifo_threshold)
- devIntrPost(Regs::Intr_RxFifo);
+ if (rxFifo.size() >= regs.RxFifoMark)
+ devIntrPost(Regs::Intr_RxHigh);
if (!rxFifo.push(packet)) {
DPRINTF(Ethernet,
return false;
}
- interface->recvDone();
- devIntrPost(Regs::Intr_RxDone);
+ // If we were at the last element, back up one ot go to the new
+ // last element of the list.
+ if (rxFifoPtr == rxFifo.end())
+ --rxFifoPtr;
+
+ devIntrPost(Regs::Intr_RxPacket);
rxKick();
return true;
}
//
//
void
-Base::serialize(ostream &os)
+Base::serialize(std::ostream &os)
{
// Serialize the PciDev base class
PciDev::serialize(os);
}
void
-Device::serialize(ostream &os)
+Device::serialize(std::ostream &os)
{
+ int count;
+
// Serialize the PciDev base class
Base::serialize(os);
- if (rxDmaEvent.scheduled())
- rxDmaCopy();
+ if (rxState == rxCopy)
+ panic("can't serialize with an in flight dma request rxState=%s",
+ RxStateStrings[rxState]);
- if (txDmaEvent.scheduled())
- txDmaCopy();
+ if (txState == txCopy)
+ panic("can't serialize with an in flight dma request txState=%s",
+ TxStateStrings[txState]);
/*
* Serialize the device registers
*/
SERIALIZE_SCALAR(regs.Config);
- SERIALIZE_SCALAR(regs.RxMaxCopy);
- SERIALIZE_SCALAR(regs.TxMaxCopy);
- SERIALIZE_SCALAR(regs.RxThreshold);
- SERIALIZE_SCALAR(regs.TxThreshold);
SERIALIZE_SCALAR(regs.IntrStatus);
SERIALIZE_SCALAR(regs.IntrMask);
+ SERIALIZE_SCALAR(regs.RxMaxCopy);
+ SERIALIZE_SCALAR(regs.TxMaxCopy);
+ SERIALIZE_SCALAR(regs.RxMaxIntr);
+ SERIALIZE_SCALAR(regs.VirtualCount);
SERIALIZE_SCALAR(regs.RxData);
SERIALIZE_SCALAR(regs.RxDone);
SERIALIZE_SCALAR(regs.TxData);
SERIALIZE_SCALAR(regs.TxDone);
+ /*
+ * Serialize the virtual nic state
+ */
+ int virtualRegsSize = virtualRegs.size();
+ SERIALIZE_SCALAR(virtualRegsSize);
+ for (int i = 0; i < virtualRegsSize; ++i) {
+ VirtualReg *vnic = &virtualRegs[i];
+
+ std::string reg = csprintf("vnic%d", i);
+ paramOut(os, reg + ".RxData", vnic->RxData);
+ paramOut(os, reg + ".RxDone", vnic->RxDone);
+ paramOut(os, reg + ".TxData", vnic->TxData);
+ paramOut(os, reg + ".TxDone", vnic->TxDone);
+
+ bool rxPacketExists = vnic->rxPacket != rxFifo.end();
+ paramOut(os, reg + ".rxPacketExists", rxPacketExists);
+ if (rxPacketExists) {
+ int rxPacket = 0;
+ PacketFifo::iterator i = rxFifo.begin();
+ while (i != vnic->rxPacket) {
+ assert(i != rxFifo.end());
+ ++i;
+ ++rxPacket;
+ }
+
+ paramOut(os, reg + ".rxPacket", rxPacket);
+ paramOut(os, reg + ".rxPacketOffset", vnic->rxPacketOffset);
+ paramOut(os, reg + ".rxPacketBytes", vnic->rxPacketBytes);
+ }
+ paramOut(os, reg + ".rxDoneData", vnic->rxDoneData);
+ }
+
+ int rxFifoPtr = rxFifo.countPacketsBefore(this->rxFifoPtr);
+ SERIALIZE_SCALAR(rxFifoPtr);
+
+ SERIALIZE_SCALAR(rxActive);
+
+ VirtualList::iterator i, end;
+ for (count = 0, i = rxList.begin(), end = rxList.end(); i != end; ++i)
+ paramOut(os, csprintf("rxList%d", count++), *i);
+ int rxListSize = count;
+ SERIALIZE_SCALAR(rxListSize);
+
+ for (count = 0, i = rxBusy.begin(), end = rxBusy.end(); i != end; ++i)
+ paramOut(os, csprintf("rxBusy%d", count++), *i);
+ int rxBusySize = count;
+ SERIALIZE_SCALAR(rxBusySize);
+
+ for (count = 0, i = txList.begin(), end = txList.end(); i != end; ++i)
+ paramOut(os, csprintf("txList%d", count++), *i);
+ int txListSize = count;
+ SERIALIZE_SCALAR(txListSize);
+
/*
* Serialize rx state machine
*/
int rxState = this->rxState;
SERIALIZE_SCALAR(rxState);
+ SERIALIZE_SCALAR(rxEmpty);
+ SERIALIZE_SCALAR(rxLow);
rxFifo.serialize("rxFifo", os);
- 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(rxPktBytes);
- }
- SERIALIZE_SCALAR(rxDoneData);
/*
* Serialize tx state machine
*/
int txState = this->txState;
SERIALIZE_SCALAR(txState);
+ SERIALIZE_SCALAR(txFull);
txFifo.serialize("txFifo", os);
bool txPacketExists = txPacket;
SERIALIZE_SCALAR(txPacketExists);
if (txPacketExists) {
txPacket->serialize("txPacket", os);
- uint32_t txPktBufPtr = (uint32_t) (txPacketBufPtr - txPacket->data);
- SERIALIZE_SCALAR(txPktBufPtr);
- SERIALIZE_SCALAR(txPktBytes);
+ SERIALIZE_SCALAR(txPacketOffset);
+ SERIALIZE_SCALAR(txPacketBytes);
}
/*
* Unserialize the device registers
*/
UNSERIALIZE_SCALAR(regs.Config);
- UNSERIALIZE_SCALAR(regs.RxMaxCopy);
- UNSERIALIZE_SCALAR(regs.TxMaxCopy);
- UNSERIALIZE_SCALAR(regs.RxThreshold);
- UNSERIALIZE_SCALAR(regs.TxThreshold);
UNSERIALIZE_SCALAR(regs.IntrStatus);
UNSERIALIZE_SCALAR(regs.IntrMask);
+ UNSERIALIZE_SCALAR(regs.RxMaxCopy);
+ UNSERIALIZE_SCALAR(regs.TxMaxCopy);
+ UNSERIALIZE_SCALAR(regs.RxMaxIntr);
+ UNSERIALIZE_SCALAR(regs.VirtualCount);
UNSERIALIZE_SCALAR(regs.RxData);
UNSERIALIZE_SCALAR(regs.RxDone);
UNSERIALIZE_SCALAR(regs.TxData);
UNSERIALIZE_SCALAR(regs.TxDone);
+ UNSERIALIZE_SCALAR(rxActive);
+
+ int rxListSize;
+ UNSERIALIZE_SCALAR(rxListSize);
+ rxList.clear();
+ for (int i = 0; i < rxListSize; ++i) {
+ int value;
+ paramIn(cp, section, csprintf("rxList%d", i), value);
+ rxList.push_back(value);
+ }
+
+ int rxBusySize;
+ UNSERIALIZE_SCALAR(rxBusySize);
+ rxBusy.clear();
+ for (int i = 0; i < rxBusySize; ++i) {
+ int value;
+ paramIn(cp, section, csprintf("rxBusy%d", i), value);
+ rxBusy.push_back(value);
+ }
+
+ int txListSize;
+ UNSERIALIZE_SCALAR(txListSize);
+ txList.clear();
+ for (int i = 0; i < txListSize; ++i) {
+ int value;
+ paramIn(cp, section, csprintf("txList%d", i), value);
+ txList.push_back(value);
+ }
+
/*
* Unserialize rx state machine
*/
int rxState;
UNSERIALIZE_SCALAR(rxState);
+ UNSERIALIZE_SCALAR(rxEmpty);
+ UNSERIALIZE_SCALAR(rxLow);
this->rxState = (RxState) rxState;
rxFifo.unserialize("rxFifo", cp, section);
- bool rxPacketExists;
- UNSERIALIZE_SCALAR(rxPacketExists);
- rxPacket = 0;
- if (rxPacketExists) {
- rxPacket = new PacketData(16384);
- rxPacket->unserialize("rxPacket", cp, section);
- uint32_t rxPktBufPtr;
- UNSERIALIZE_SCALAR(rxPktBufPtr);
- this->rxPacketBufPtr = (uint8_t *) rxPacket->data + rxPktBufPtr;
- UNSERIALIZE_SCALAR(rxPktBytes);
- }
- UNSERIALIZE_SCALAR(rxDoneData);
+
+ int rxFifoPtr;
+ UNSERIALIZE_SCALAR(rxFifoPtr);
+ this->rxFifoPtr = rxFifo.begin();
+ for (int i = 0; i < rxFifoPtr; ++i)
+ ++this->rxFifoPtr;
/*
* Unserialize tx state machine
*/
int txState;
UNSERIALIZE_SCALAR(txState);
+ UNSERIALIZE_SCALAR(txFull);
this->txState = (TxState) txState;
txFifo.unserialize("txFifo", cp, section);
bool txPacketExists;
UNSERIALIZE_SCALAR(txPacketExists);
txPacket = 0;
if (txPacketExists) {
- txPacket = new PacketData(16384);
+ txPacket = new EthPacketData(16384);
txPacket->unserialize("txPacket", cp, section);
- uint32_t txPktBufPtr;
- UNSERIALIZE_SCALAR(txPktBufPtr);
- this->txPacketBufPtr = (uint8_t *) txPacket->data + txPktBufPtr;
- UNSERIALIZE_SCALAR(txPktBytes);
+ UNSERIALIZE_SCALAR(txPacketOffset);
+ UNSERIALIZE_SCALAR(txPacketBytes);
+ }
+
+ /*
+ * unserialize the virtual nic registers/state
+ *
+ * this must be done after the unserialization of the rxFifo
+ * because the packet iterators depend on the fifo being populated
+ */
+ int virtualRegsSize;
+ UNSERIALIZE_SCALAR(virtualRegsSize);
+ virtualRegs.clear();
+ virtualRegs.resize(virtualRegsSize);
+ for (int i = 0; i < virtualRegsSize; ++i) {
+ VirtualReg *vnic = &virtualRegs[i];
+ std::string reg = csprintf("vnic%d", i);
+
+ paramIn(cp, section, reg + ".RxData", vnic->RxData);
+ paramIn(cp, section, reg + ".RxDone", vnic->RxDone);
+ paramIn(cp, section, reg + ".TxData", vnic->TxData);
+ paramIn(cp, section, reg + ".TxDone", vnic->TxDone);
+
+ vnic->rxUnique = rxUnique++;
+ vnic->txUnique = txUnique++;
+
+ bool rxPacketExists;
+ paramIn(cp, section, reg + ".rxPacketExists", rxPacketExists);
+ if (rxPacketExists) {
+ int rxPacket;
+ paramIn(cp, section, reg + ".rxPacket", rxPacket);
+ vnic->rxPacket = rxFifo.begin();
+ while (rxPacket--)
+ ++vnic->rxPacket;
+
+ paramIn(cp, section, reg + ".rxPacketOffset",
+ vnic->rxPacketOffset);
+ paramIn(cp, section, reg + ".rxPacketBytes", vnic->rxPacketBytes);
+ } else {
+ vnic->rxPacket = rxFifo.end();
+ }
+ paramIn(cp, section, reg + ".rxDoneData", vnic->rxDoneData);
}
/*
if (transmitTick)
txEvent.schedule(curTick + transmitTick);
- /*
- * re-add addrRanges to bus bridges
- */
- if (pioInterface)
- pioInterface->addAddrRange(RangeSize(BARAddrs[0], BARSize[0]));
-}
+ pioPort->sendStatusChange(Port::RangeChange);
-Tick
-Device::cacheAccess(MemReqPtr &req)
-{
- //The mask is to give you only the offset into the device register file
- Addr daddr = req->paddr - addr;
-
- DPRINTF(EthernetPIO, "timing access to paddr=%#x (daddr=%#x)\n",
- req->paddr, daddr);
-
- Tick when = curTick + pioLatency;
-
- switch (daddr) {
- case Regs::RxDone:
- if (rxState != rxIdle) {
- rxPioRequest = req;
- when = 0;
- }
- break;
-
- case Regs::TxDone:
- if (txState != txIdle) {
- txPioRequest = req;
- when = 0;
- }
- break;
- }
-
- return when;
}
+
BEGIN_DECLARE_SIM_OBJECT_PARAMS(Interface)
SimObjectParam<EtherInt *> peer;
BEGIN_DECLARE_SIM_OBJECT_PARAMS(Device)
- Param<Addr> addr;
- Param<Tick> cycle_time;
- Param<Tick> tx_delay;
- Param<Tick> rx_delay;
- Param<Tick> intr_delay;
- SimObjectParam<MemoryController *> mmu;
- SimObjectParam<PhysicalMemory *> physmem;
- Param<bool> rx_filter;
- Param<string> hardware_address;
- SimObjectParam<Bus*> io_bus;
- SimObjectParam<Bus*> payload_bus;
- SimObjectParam<HierParams *> hier;
- Param<Tick> pio_latency;
+
+ SimObjectParam<System *> system;
+ SimObjectParam<Platform *> platform;
SimObjectParam<PciConfigAll *> configspace;
SimObjectParam<PciConfigData *> configdata;
- SimObjectParam<Platform *> platform;
Param<uint32_t> pci_bus;
Param<uint32_t> pci_dev;
Param<uint32_t> pci_func;
+ Param<Tick> pio_latency;
+ Param<Tick> intr_delay;
+
+ Param<Tick> clock;
+ Param<Tick> dma_read_delay;
+ Param<Tick> dma_read_factor;
+ Param<Tick> dma_write_delay;
+ Param<Tick> dma_write_factor;
+
+ Param<Tick> rx_delay;
+ Param<Tick> tx_delay;
Param<uint32_t> rx_max_copy;
Param<uint32_t> tx_max_copy;
+ Param<uint32_t> rx_max_intr;
Param<uint32_t> rx_fifo_size;
Param<uint32_t> tx_fifo_size;
Param<uint32_t> rx_fifo_threshold;
+ Param<uint32_t> rx_fifo_low_mark;
+ Param<uint32_t> tx_fifo_high_mark;
Param<uint32_t> tx_fifo_threshold;
- Param<Tick> dma_read_delay;
- Param<Tick> dma_read_factor;
- Param<Tick> dma_write_delay;
- Param<Tick> dma_write_factor;
- Param<bool> dma_no_allocate;
+
+ Param<bool> rx_filter;
+ Param<std::string> hardware_address;
+ Param<bool> rx_thread;
+ Param<bool> tx_thread;
+ Param<bool> rss;
+ Param<uint32_t> virtual_count;
+ Param<bool> zero_copy;
+ Param<bool> delay_copy;
+ Param<bool> virtual_addr;
END_DECLARE_SIM_OBJECT_PARAMS(Device)
BEGIN_INIT_SIM_OBJECT_PARAMS(Device)
- INIT_PARAM(addr, "Device Address"),
- INIT_PARAM(cycle_time, "State machine cycle time"),
- INIT_PARAM_DFLT(tx_delay, "Transmit Delay", 1000),
- INIT_PARAM_DFLT(rx_delay, "Receive Delay", 1000),
- INIT_PARAM_DFLT(intr_delay, "Interrupt Delay in microseconds", 0),
- INIT_PARAM(mmu, "Memory Controller"),
- INIT_PARAM(physmem, "Physical Memory"),
- INIT_PARAM_DFLT(rx_filter, "Enable Receive Filter", true),
- INIT_PARAM_DFLT(hardware_address, "Ethernet Hardware Address",
- "00:99:00:00:00:01"),
- INIT_PARAM_DFLT(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 in bus cycles", 1),
+
+ INIT_PARAM(system, "System pointer"),
+ INIT_PARAM(platform, "Platform pointer"),
INIT_PARAM(configspace, "PCI Configspace"),
INIT_PARAM(configdata, "PCI Config data"),
- INIT_PARAM(platform, "Platform"),
- INIT_PARAM(pci_bus, "PCI bus"),
+ INIT_PARAM(pci_bus, "PCI bus ID"),
INIT_PARAM(pci_dev, "PCI device number"),
INIT_PARAM(pci_func, "PCI function code"),
- INIT_PARAM_DFLT(rx_max_copy, "rx max copy", 16*1024),
- INIT_PARAM_DFLT(tx_max_copy, "rx max copy", 16*1024),
- INIT_PARAM_DFLT(rx_fifo_size, "max size in bytes of rxFifo", 64*1024),
- INIT_PARAM_DFLT(tx_fifo_size, "max size in bytes of txFifo", 64*1024),
- INIT_PARAM_DFLT(rx_fifo_threshold, "max size in bytes of rxFifo", 48*1024),
- INIT_PARAM_DFLT(tx_fifo_threshold, "max size in bytes of txFifo", 16*1024),
- INIT_PARAM_DFLT(dma_read_delay, "fixed delay for dma reads", 0),
- INIT_PARAM_DFLT(dma_read_factor, "multiplier for dma reads", 0),
- INIT_PARAM_DFLT(dma_write_delay, "fixed delay for dma writes", 0),
- INIT_PARAM_DFLT(dma_write_factor, "multiplier for dma writes", 0),
- INIT_PARAM_DFLT(dma_no_allocate, "Should we allocat on read in cache", true)
+ INIT_PARAM_DFLT(pio_latency, "Programmed IO latency in bus cycles", 1),
+ INIT_PARAM(intr_delay, "Interrupt Delay"),
+ INIT_PARAM(clock, "State machine cycle time"),
+
+ INIT_PARAM(dma_read_delay, "fixed delay for dma reads"),
+ INIT_PARAM(dma_read_factor, "multiplier for dma reads"),
+ INIT_PARAM(dma_write_delay, "fixed delay for dma writes"),
+ INIT_PARAM(dma_write_factor, "multiplier for dma writes"),
+
+ INIT_PARAM(rx_delay, "Receive Delay"),
+ INIT_PARAM(tx_delay, "Transmit Delay"),
+ INIT_PARAM(rx_max_copy, "rx max copy"),
+ INIT_PARAM(tx_max_copy, "rx max copy"),
+ INIT_PARAM(rx_max_intr, "rx max intr"),
+ INIT_PARAM(rx_fifo_size, "max size in bytes of rxFifo"),
+ INIT_PARAM(tx_fifo_size, "max size in bytes of txFifo"),
+ INIT_PARAM(rx_fifo_threshold, "max size in bytes of rxFifo"),
+ INIT_PARAM(rx_fifo_low_mark, "max size in bytes of rxFifo"),
+ INIT_PARAM(tx_fifo_high_mark, "max size in bytes of txFifo"),
+ INIT_PARAM(tx_fifo_threshold, "max size in bytes of txFifo"),
+
+ INIT_PARAM(rx_filter, "Enable Receive Filter"),
+ INIT_PARAM(hardware_address, "Ethernet Hardware Address"),
+ INIT_PARAM(rx_thread, ""),
+ INIT_PARAM(tx_thread, ""),
+ INIT_PARAM(rss, ""),
+ INIT_PARAM(virtual_count, ""),
+ INIT_PARAM(zero_copy, ""),
+ INIT_PARAM(delay_copy, ""),
+ INIT_PARAM(virtual_addr, "")
END_INIT_SIM_OBJECT_PARAMS(Device)
{
Device::Params *params = new Device::Params;
params->name = getInstanceName();
- params->intr_delay = intr_delay;
- params->physmem = physmem;
- params->cycle_time = cycle_time;
- params->tx_delay = tx_delay;
- params->rx_delay = rx_delay;
- params->mmu = mmu;
- params->hier = hier;
- params->io_bus = io_bus;
- params->payload_bus = payload_bus;
- params->pio_latency = pio_latency;
+ params->platform = platform;
+ params->system = system;
params->configSpace = configspace;
params->configData = configdata;
- params->plat = platform;
params->busNum = pci_bus;
params->deviceNum = pci_dev;
params->functionNum = pci_func;
- params->rx_filter = rx_filter;
- params->eaddr = hardware_address;
+ params->pio_delay = pio_latency;
+ params->intr_delay = intr_delay;
+ params->clock = clock;
+
+ params->dma_read_delay = dma_read_delay;
+ params->dma_read_factor = dma_read_factor;
+ params->dma_write_delay = dma_write_delay;
+ params->dma_write_factor = dma_write_factor;
+
+ params->tx_delay = tx_delay;
+ params->rx_delay = rx_delay;
params->rx_max_copy = rx_max_copy;
params->tx_max_copy = tx_max_copy;
+ params->rx_max_intr = rx_max_intr;
params->rx_fifo_size = rx_fifo_size;
params->tx_fifo_size = tx_fifo_size;
params->rx_fifo_threshold = rx_fifo_threshold;
+ params->rx_fifo_low_mark = rx_fifo_low_mark;
+ params->tx_fifo_high_mark = tx_fifo_high_mark;
params->tx_fifo_threshold = tx_fifo_threshold;
- params->dma_read_delay = dma_read_delay;
- params->dma_read_factor = dma_read_factor;
- params->dma_write_delay = dma_write_delay;
- params->dma_write_factor = dma_write_factor;
- params->dma_no_allocate = dma_no_allocate;
+
+ params->rx_filter = rx_filter;
+ params->eaddr = hardware_address;
+ params->rx_thread = rx_thread;
+ params->tx_thread = tx_thread;
+ params->rss = rss;
+ params->virtual_count = virtual_count;
+ params->zero_copy = zero_copy;
+ params->delay_copy = delay_copy;
+ params->virtual_addr = virtual_addr;
+
return new Device(params);
}