Many files:
[gem5.git] / dev / sinic.cc
index e79f80678dab0d3b52358b1c0cdf46cd440cb60a..7f4a7f8f03cee93b5629c7afa56a6724cadfb65c 100644 (file)
@@ -26,8 +26,8 @@
  * 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 {
 
@@ -84,8 +80,8 @@ Base::Base(Params *p)
 }
 
 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),
@@ -93,27 +89,6 @@ Device::Device(Params *p)
 {
     reset();
 
-    if (p->pio_bus) {
-        pioInterface = newPioInterface(p->name + ".pio", p->hier, p->pio_bus,
-                                       this, &Device::cacheAccess);
-        pioLatency = p->pio_latency * p->pio_bus->clockRate;
-    }
-
-    if (p->header_bus) {
-        if (p->payload_bus)
-            dmaInterface = new DMAInterface<Bus>(p->name + ".dma",
-                                                 p->header_bus,
-                                                 p->payload_bus, 1,
-                                                 p->dma_no_allocate);
-        else
-            dmaInterface = new DMAInterface<Bus>(p->name + ".dma",
-                                                 p->header_bus,
-                                                 p->header_bus, 1,
-                                                 p->dma_no_allocate);
-    } else if (p->payload_bus)
-        panic("must define a header bus if defining a payload bus");
-
-    pioDelayWrite = p->pio_delay_write && pioInterface;
 }
 
 Device::~Device()
@@ -289,39 +264,13 @@ Device::regStats()
     rxPacketRate = rxPackets / simSeconds;
 }
 
-/**
- * This is to write to the PCI general configuration registers
- */
-void
-Device::writeConfig(int offset, int size, const uint8_t *data)
-{
-    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;
-
-      default:
-        PciDev::writeConfig(offset, size, data);
-    }
-}
-
 void
 Device::prepareIO(int cpu, int index)
 {
     int size = virtualRegs.size();
-    if (index < size)
-        return;
-
-    virtualRegs.resize(index + 1);
-    for (int i = size; i <= index; ++i)
-        virtualRegs[i].rxPacket = rxFifo.end();
+    if (index > size)
+        panic("Trying to access a vnic that doesn't exist %d > %d\n",
+              index, size);
 }
 
 void
@@ -334,7 +283,10 @@ Device::prepareRead(int cpu, int index)
 
     // update rx registers
     uint64_t rxdone = vnic.RxDone;
-    rxdone = set_RxDone_Packets(rxdone, rxFifo.packets());
+    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;
@@ -352,82 +304,71 @@ Device::prepareRead(int cpu, int index)
 void
 Device::prepareWrite(int cpu, int index)
 {
-    if (cpu >= writeQueue.size())
-        writeQueue.resize(cpu + 1);
-
     prepareIO(cpu, index);
 }
 
 /**
  * I/O read of device register
  */
-Fault *
-Device::read(MemReqPtr &req, uint8_t *data)
+Tick
+Device::read(Packet &pkt)
 {
     assert(config.command & PCI_CMD_MSE);
-    Fault * fault = readBar(req, data);
-
-    if (fault == MachineCheckFault) {
-        panic("address does not map to a BAR pa=%#x va=%#x size=%d",
-              req->paddr, req->vaddr, req->size);
-
-        return MachineCheckFault;
-    }
-
-    return fault;
-}
+    assert(pkt.addr >= BARAddrs[0] && pkt.size < BARSize[0]);
 
-Fault *
-Device::readBar0(MemReqPtr &req, Addr daddr, uint8_t *data)
-{
-    int cpu = (req->xc->regs.ipr[TheISA::IPR_PALtemp16] >> 8) & 0xff;
+    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, da=%#x pa=%#x va=%#x size=%d",
-              cpu, daddr, req->paddr, req->vaddr, req->size);
+        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("reading %s (write only): cpu=%d da=%#x pa=%#x va=%#x size=%d",
-              info.name, cpu, daddr, req->paddr, req->vaddr, req->size);
+        panic("read %s (write only): "
+              "cpu=%d vnic=%d da=%#x pa=%#x size=%d",
+              info.name, cpu, index, daddr, pkt.addr, pkt.size);
 
-    if (req->size != info.size)
-        panic("invalid size for reg %s: cpu=%d da=%#x pa=%#x va=%#x size=%d",
-              info.name, cpu, daddr, req->paddr, req->vaddr, req->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 (req->size == 4) {
-        uint32_t &reg = *(uint32_t *)data;
-        reg = regData32(raddr);
+    if (pkt.size == 4) {
+        uint32_t reg = regData32(raddr);
+        pkt.set(reg);
         value = reg;
     }
 
-    if (req->size == 8) {
-        uint64_t &reg = *(uint64_t *)data;
-        reg = regData64(raddr);
+    if (pkt.size == 8) {
+        uint64_t reg = regData64(raddr);
+        pkt.set(reg);
         value = reg;
     }
 
     DPRINTF(EthernetPIO,
-            "read %s cpu=%d da=%#x pa=%#x va=%#x size=%d val=%#x\n",
-            info.name, cpu, daddr, req->paddr, req->vaddr, req->size, value);
+            "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);
 
     // reading the interrupt status register has the side effect of
     // clearing it
     if (raddr == Regs::IntrStatus)
         devIntrClear();
 
-    return NoFault;
+    return pioDelay;
 }
 
 /**
  * IPR read of device register
- */
-Fault *
+
+    Fault
 Device::iprRead(Addr daddr, int cpu, uint64_t &result)
 {
     if (!regValid(daddr))
@@ -453,89 +394,62 @@ Device::iprRead(Addr daddr, int cpu, uint64_t &result)
 
     return NoFault;
 }
-
+*/
 /**
  * I/O write of device register
  */
-Fault *
-Device::write(MemReqPtr &req, const uint8_t *data)
+Tick
+Device::write(Packet &pkt)
 {
     assert(config.command & PCI_CMD_MSE);
-    Fault * fault = writeBar(req, data);
+    assert(pkt.addr >= BARAddrs[0] && pkt.size < BARSize[0]);
 
-    if (fault == MachineCheckFault) {
-        panic("address does not map to a BAR pa=%#x va=%#x size=%d",
-              req->paddr, req->vaddr, req->size);
-
-        return MachineCheckFault;
-    }
-
-    return fault;
-}
-
-Fault *
-Device::writeBar0(MemReqPtr &req, Addr daddr, const uint8_t *data)
-{
-    int cpu = (req->xc->regs.ipr[TheISA::IPR_PALtemp16] >> 8) & 0xff;
+    int cpu = pkt.req->getCpuNum();
+    Addr daddr = pkt.addr - BARAddrs[0];
     Addr index = daddr >> Regs::VirtualShift;
     Addr raddr = daddr & Regs::VirtualMask;
 
+    pkt.time += pioDelay;
+
     if (!regValid(raddr))
-        panic("invalid address: cpu=%d da=%#x pa=%#x va=%#x size=%d",
-              cpu, daddr, req->paddr, req->vaddr, req->size);
+        panic("invalid register: cpu=%d, da=%#x pa=%#x size=%d",
+                cpu, daddr, pkt.addr, pkt.size);
 
     const Regs::Info &info = regInfo(raddr);
     if (!info.write)
-        panic("writing %s (read only): cpu=%d da=%#x",
-              info.name, cpu, daddr);
+        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 != info.size)
-        panic("invalid size for %s: cpu=%d da=%#x pa=%#x va=%#x size=%d",
-              info.name, cpu, 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);
+
+    VirtualReg &vnic = virtualRegs[index];
 
-    uint32_t reg32 = *(uint32_t *)data;
-    uint64_t reg64 = *(uint64_t *)data;
     DPRINTF(EthernetPIO,
-            "write %s: cpu=%d val=%#x da=%#x pa=%#x va=%#x size=%d\n",
-            info.name, cpu, info.size == 4 ? reg32 : reg64, daddr,
-            req->paddr, req->vaddr, req->size);
+            "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);
 
-    if (pioDelayWrite)
-        writeQueue[cpu].push_back(RegWriteData(daddr, reg64));
-
-    if (!pioDelayWrite || !info.delay_write)
-        regWrite(daddr, cpu, data);
-
-    return NoFault;
-}
-
-void
-Device::regWrite(Addr daddr, int cpu, const uint8_t *data)
-{
-    Addr index = daddr >> Regs::VirtualShift;
-    Addr raddr = daddr & Regs::VirtualMask;
-
-    uint32_t reg32 = *(uint32_t *)data;
-    uint64_t reg64 = *(uint64_t *)data;
-    VirtualReg &vnic = virtualRegs[index];
-
     switch (raddr) {
       case Regs::Config:
-        changeConfig(reg32);
+        changeConfig(pkt.get<uint32_t>());
         break;
 
       case Regs::Command:
-        command(reg32);
+        command(pkt.get<uint32_t>());
         break;
 
       case Regs::IntrStatus:
-        devIntrClear(regs.IntrStatus & reg32);
+        devIntrClear(regs.IntrStatus & pkt.get<uint32_t>());
         break;
 
       case Regs::IntrMask:
-        devIntrChangeMask(reg32);
+        devIntrChangeMask(pkt.get<uint32_t>());
         break;
 
       case Regs::RxData:
@@ -543,10 +457,32 @@ Device::regWrite(Addr daddr, int cpu, const uint8_t *data)
             panic("receive machine busy with another request! rxState=%s",
                   RxStateStrings[rxState]);
 
+        vnic.rxUnique = rxUnique++;
         vnic.RxDone = Regs::RxDone_Busy;
-        vnic.RxData = reg64;
-        rxList.push_back(index);
-        if (rxEnable && rxState == rxIdle) {
+        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);
+        }
+
+        if (rxEnable && (rxState == rxIdle || rxState == rxFifoBlock)) {
             rxState = rxFifoBlock;
             rxKick();
         }
@@ -557,8 +493,23 @@ Device::regWrite(Addr daddr, int cpu, const uint8_t *data)
             panic("transmit machine busy with another request! txState=%s",
                   TxStateStrings[txState]);
 
+        vnic.txUnique = txUnique++;
         vnic.TxDone = Regs::TxDone_Busy;
-        vnic.TxData = reg64;
+
+        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);
+        }
+
         if (txList.empty() || txList.front() != index)
             txList.push_back(index);
         if (txEnable && txState == txIdle && txList.front() == index) {
@@ -567,6 +518,8 @@ Device::regWrite(Addr daddr, int cpu, const uint8_t *data)
         }
         break;
     }
+
+    return pioDelay;
 }
 
 void
@@ -780,10 +733,23 @@ Device::reset()
         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.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;
@@ -791,6 +757,8 @@ Device::reset()
     regs.HwAddr = params()->eaddr;
 
     rxList.clear();
+    rxBusy.clear();
+    rxActive = -1;
     txList.clear();
 
     rxState = rxIdle;
@@ -800,6 +768,7 @@ Device::reset()
     rxFifoPtr = rxFifo.end();
     txFifo.clear();
     rxEmpty = false;
+    rxLow = true;
     txFull = false;
 
     int size = virtualRegs.size();
@@ -810,20 +779,13 @@ Device::reset()
 }
 
 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(EthernetData, rxDmaData, rxDmaLen);
-}
-
-void
-Device::rxDmaDone()
-{
-    rxDmaCopy();
 
     // If the transmit state machine  has a pending DMA, let it go first
     if (txState == txBeginCopy)
@@ -835,13 +797,13 @@ Device::rxDmaDone()
 void
 Device::rxKick()
 {
-    VirtualReg *vnic;
+    VirtualReg *vnic = NULL;
 
-    DPRINTF(EthernetSM, "receive kick rxState=%s (rxFifo.size=%d)\n",
+    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;
     }
@@ -850,16 +812,50 @@ Device::rxKick()
     if (rxState == rxIdle)
         goto exit;
 
-    assert(!rxList.empty());
-    vnic = &virtualRegs[rxList.front()];
+    if (rxActive == -1) {
+        if (rxState != rxFifoBlock)
+            panic("no active vnic while in state %s", RxStateStrings[rxState]);
 
-    DPRINTF(EthernetSM, "processing rxState=%s for virtual nic %d\n",
-            RxStateStrings[rxState], rxList.front());
+        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 (vnic->rxPacket != rxFifo.end()) {
+        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;
         }
 
@@ -868,8 +864,19 @@ Device::rxKick()
             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.
         vnic->rxPacket = rxFifoPtr++;
         vnic->rxPacketOffset = 0;
@@ -880,6 +887,7 @@ Device::rxKick()
         /* scope for variables */ {
             IpPtr ip(*vnic->rxPacket);
             if (ip) {
+                DPRINTF(Ethernet, "ID is %d\n", ip->id());
                 vnic->rxDoneData |= Regs::RxDone_IpPacket;
                 rxIpChecksums++;
                 if (cksum(ip) != 0) {
@@ -889,6 +897,10 @@ Device::rxKick()
                 TcpPtr tcp(ip);
                 UdpPtr udp(ip);
                 if (tcp) {
+                    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) {
@@ -909,29 +921,22 @@ Device::rxKick()
         break;
 
       case rxBeginCopy:
-        if (dmaInterface && dmaInterface->busy())
+        if (dmaPending())
             goto exit;
 
-        rxDmaAddr = plat->pciToDma(Regs::get_RxData_Addr(vnic->RxData));
-        rxDmaLen = min<int>(Regs::get_RxData_Len(vnic->RxData),
+        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 (dmaInterface) {
-            dmaInterface->doDMA(WriteInvalidate, rxDmaAddr, rxDmaLen,
-                                curTick, &rxDmaEvent, true);
-            goto exit;
+        if (rxDmaAddr == 1LL) {
+            rxState = rxCopyDone;
+            break;
         }
 
-        if (dmaWriteDelay != 0 || dmaWriteFactor != 0) {
-            Tick factor = ((rxDmaLen + ULL(63)) >> ULL(6)) * dmaWriteFactor;
-            Tick start = curTick + dmaWriteDelay + factor;
-            rxDmaEvent.schedule(start);
-            goto exit;
-        }
 
-        rxDmaCopy();
+        dmaWrite(rxDmaAddr, rxDmaLen, &rxDmaEvent, rxDmaData);
         break;
 
       case rxCopy:
@@ -939,31 +944,44 @@ Device::rxKick()
         goto exit;
 
       case rxCopyDone:
-        vnic->RxDone = vnic->rxDoneData | rxDmaLen;
+        vnic->RxDone = vnic->rxDoneData;
         vnic->RxDone |= Regs::RxDone_Complete;
 
         if (vnic->rxPacketBytes == rxDmaLen) {
-            DPRINTF(EthernetSM, "rxKick: packet complete on vnic %d\n",
-                    rxList.front());
+            // 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 {
-            vnic->RxDone |= Regs::RxDone_More;
             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: %d bytes left\n",
-                    rxList.front(), vnic->rxPacketBytes);
+                    "rxKick: packet not complete on vnic %d (rxunique %d): "
+                    "%d bytes left\n",
+                    rxActive, vnic->rxUnique, vnic->rxPacketBytes);
         }
 
-        rxList.pop_front();
-        rxState = rxList.empty() ? rxIdle : rxFifoBlock;
+        rxActive = -1;
+        rxState = rxBusy.empty() && rxList.empty() ? rxIdle : rxFifoBlock;
 
         if (rxFifo.empty()) {
             devIntrPost(Regs::Intr_RxEmpty);
             rxEmpty = true;
         }
 
+        if (rxFifo.size() < params()->rx_fifo_low_mark)
+            rxLow = true;
+
+        if (rxFifo.size() > params()->rx_fifo_threshold)
+            rxLow = false;
+
         devIntrPost(Regs::Intr_RxDMA);
         break;
 
@@ -985,20 +1003,13 @@ Device::rxKick()
 }
 
 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(EthernetData, txDmaData, txDmaLen);
-}
-
-void
-Device::txDmaDone()
-{
-    txDmaCopy();
 
     // If the receive state machine  has a pending DMA, let it go first
     if (rxState == rxBeginCopy)
@@ -1016,7 +1027,7 @@ Device::transmit()
     }
 
     uint32_t interrupts;
-    PacketPtr packet = txFifo.front();
+    EthPacketPtr packet = txFifo.front();
     if (!interface->sendPacket(packet)) {
         DPRINTF(Ethernet, "Packet Transmit: failed txFifo available %d\n",
                 txFifo.avail());
@@ -1031,8 +1042,10 @@ Device::transmit()
             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());
             }
         }
     }
@@ -1061,11 +1074,11 @@ void
 Device::txKick()
 {
     VirtualReg *vnic;
-    DPRINTF(EthernetSM, "transmit kick txState=%s (txFifo.size=%d)\n",
+    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;
     }
@@ -1079,10 +1092,10 @@ Device::txKick()
 
     switch (txState) {
       case txFifoBlock:
-        assert(Regs::get_TxDone_Busy(vnic->TxData));
+        assert(Regs::get_TxDone_Busy(vnic->TxDone));
         if (!txPacket) {
             // Grab a new packet from the fifo.
-            txPacket = new PacketData(16384);
+            txPacket = new EthPacketData(16384);
             txPacketOffset = 0;
         }
 
@@ -1096,28 +1109,16 @@ Device::txKick()
         break;
 
       case txBeginCopy:
-        if (dmaInterface && dmaInterface->busy())
+        if (dmaPending())
             goto exit;
 
-        txDmaAddr = plat->pciToDma(Regs::get_TxData_Addr(vnic->TxData));
+        txDmaAddr = params()->platform->pciToDma(
+                Regs::get_TxData_Addr(vnic->TxData));
         txDmaLen = Regs::get_TxData_Len(vnic->TxData);
         txDmaData = txPacket->data + txPacketOffset;
         txState = txCopy;
 
-        if (dmaInterface) {
-            dmaInterface->doDMA(Read, txDmaAddr, txDmaLen,
-                                curTick, &txDmaEvent, true);
-            goto exit;
-        }
-
-        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:
@@ -1204,7 +1205,7 @@ Device::transferDone()
 }
 
 bool
-Device::rxFilter(const PacketPtr &packet)
+Device::rxFilter(const EthPacketPtr &packet)
 {
     if (!Regs::get_Config_Filter(regs.Config))
         return false;
@@ -1249,7 +1250,7 @@ Device::rxFilter(const PacketPtr &packet)
 }
 
 bool
-Device::recvPacket(PacketPtr packet)
+Device::recvPacket(EthPacketPtr packet)
 {
     rxBytes += packet->length;
     rxPackets++;
@@ -1290,7 +1291,7 @@ Device::recvPacket(PacketPtr packet)
 //
 //
 void
-Base::serialize(ostream &os)
+Base::serialize(std::ostream &os)
 {
     // Serialize the PciDev base class
     PciDev::serialize(os);
@@ -1334,8 +1335,10 @@ Base::unserialize(Checkpoint *cp, const std::string &section)
 }
 
 void
-Device::serialize(ostream &os)
+Device::serialize(std::ostream &os)
 {
+    int count;
+
     // Serialize the PciDev base class
     Base::serialize(os);
 
@@ -1356,6 +1359,7 @@ Device::serialize(ostream &os)
     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);
@@ -1369,14 +1373,12 @@ Device::serialize(ostream &os)
     for (int i = 0; i < virtualRegsSize; ++i) {
         VirtualReg *vnic = &virtualRegs[i];
 
-        string reg = csprintf("vnic%d", 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);
 
-        PacketFifo::iterator rxFifoPtr;
-
         bool rxPacketExists = vnic->rxPacket != rxFifo.end();
         paramOut(os, reg + ".rxPacketExists", rxPacketExists);
         if (rxPacketExists) {
@@ -1395,18 +1397,26 @@ Device::serialize(ostream &os)
         paramOut(os, reg + ".rxDoneData", vnic->rxDoneData);
     }
 
-    VirtualList::iterator i, end;
-    int count;
+    int rxFifoPtr = rxFifo.countPacketsBefore(this->rxFifoPtr);
+    SERIALIZE_SCALAR(rxFifoPtr);
 
-    int rxListSize = rxList.size();
-    SERIALIZE_SCALAR(rxListSize);
+    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);
 
-    int txListSize = txList.size();
-    SERIALIZE_SCALAR(txListSize);
     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
@@ -1414,6 +1424,7 @@ Device::serialize(ostream &os)
     int rxState = this->rxState;
     SERIALIZE_SCALAR(rxState);
     SERIALIZE_SCALAR(rxEmpty);
+    SERIALIZE_SCALAR(rxLow);
     rxFifo.serialize("rxFifo", os);
 
     /*
@@ -1454,11 +1465,14 @@ Device::unserialize(Checkpoint *cp, const std::string &section)
     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();
@@ -1468,6 +1482,15 @@ Device::unserialize(Checkpoint *cp, const std::string &section)
         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();
@@ -1483,9 +1506,16 @@ Device::unserialize(Checkpoint *cp, const std::string &section)
     int rxState;
     UNSERIALIZE_SCALAR(rxState);
     UNSERIALIZE_SCALAR(rxEmpty);
+    UNSERIALIZE_SCALAR(rxLow);
     this->rxState = (RxState) rxState;
     rxFifo.unserialize("rxFifo", cp, section);
 
+    int rxFifoPtr;
+    UNSERIALIZE_SCALAR(rxFifoPtr);
+    this->rxFifoPtr = rxFifo.begin();
+    for (int i = 0; i < rxFifoPtr; ++i)
+        ++this->rxFifoPtr;
+
     /*
      * Unserialize tx state machine
      */
@@ -1498,7 +1528,7 @@ Device::unserialize(Checkpoint *cp, const std::string &section)
     UNSERIALIZE_SCALAR(txPacketExists);
     txPacket = 0;
     if (txPacketExists) {
-        txPacket = new PacketData(16384);
+        txPacket = new EthPacketData(16384);
         txPacket->unserialize("txPacket", cp, section);
         UNSERIALIZE_SCALAR(txPacketOffset);
         UNSERIALIZE_SCALAR(txPacketBytes);
@@ -1516,13 +1546,16 @@ Device::unserialize(Checkpoint *cp, const std::string &section)
     virtualRegs.resize(virtualRegsSize);
     for (int i = 0; i < virtualRegsSize; ++i) {
         VirtualReg *vnic = &virtualRegs[i];
-        string reg = csprintf("vnic%d", 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) {
@@ -1549,51 +1582,11 @@ Device::unserialize(Checkpoint *cp, const std::string &section)
     if (transmitTick)
         txEvent.schedule(curTick + transmitTick);
 
-    /*
-     * re-add addrRanges to bus bridges
-     */
-    if (pioInterface) {
-        pioInterface->addAddrRange(RangeSize(BARAddrs[0], BARSize[0]));
-        pioInterface->addAddrRange(RangeSize(BARAddrs[1], BARSize[1]));
-    }
-}
-
-Tick
-Device::cacheAccess(MemReqPtr &req)
-{
-    Addr daddr;
-    int bar;
-    if (!getBAR(req->paddr, daddr, bar))
-        panic("address does not map to a BAR pa=%#x va=%#x size=%d",
-              req->paddr, req->vaddr, req->size);
-
-    DPRINTF(EthernetPIO, "timing %s to paddr=%#x bar=%d daddr=%#x\n",
-            req->cmd.toString(), req->paddr, bar, daddr);
-
-    if (!pioDelayWrite || !req->cmd.isWrite())
-        return curTick + pioLatency;
-
-    if (bar == 0) {
-        int cpu = (req->xc->regs.ipr[TheISA::IPR_PALtemp16] >> 8) & 0xff;
-        std::list<RegWriteData> &wq = writeQueue[cpu];
-        if (wq.empty())
-            panic("WriteQueue for cpu %d empty timing daddr=%#x", cpu, daddr);
-
-        const RegWriteData &data = wq.front();
-        if (data.daddr != daddr)
-            panic("read mismatch on cpu %d, daddr functional=%#x timing=%#x",
-                  cpu, data.daddr, daddr);
-
-        const Regs::Info &info = regInfo(data.daddr);
-        if (info.delay_write)
-            regWrite(daddr, cpu, (uint8_t *)&data.value);
-
-        wq.pop_front();
-    }
+    pioPort->sendStatusChange(Port::RangeChange);
 
-    return curTick + pioLatency;
 }
 
+
 BEGIN_DECLARE_SIM_OBJECT_PARAMS(Interface)
 
     SimObjectParam<EtherInt *> peer;
@@ -1626,30 +1619,22 @@ REGISTER_SIM_OBJECT("SinicInt", Interface)
 
 BEGIN_DECLARE_SIM_OBJECT_PARAMS(Device)
 
-    Param<Tick> clock;
 
-    Param<Addr> addr;
-    SimObjectParam<MemoryController *> mmu;
-    SimObjectParam<PhysicalMemory *> physmem;
+    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;
 
-    SimObjectParam<HierParams *> hier;
-    SimObjectParam<Bus*> pio_bus;
-    SimObjectParam<Bus*> dma_bus;
-    SimObjectParam<Bus*> payload_bus;
+    Param<Tick> clock;
     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<Tick> pio_latency;
-    Param<bool> pio_delay_write;
-    Param<Tick> intr_delay;
 
     Param<Tick> rx_delay;
     Param<Tick> tx_delay;
@@ -1659,41 +1644,40 @@ BEGIN_DECLARE_SIM_OBJECT_PARAMS(Device)
     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<bool> rx_filter;
-    Param<string> hardware_address;
+    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(clock, "State machine cycle time"),
 
-    INIT_PARAM(addr, "Device Address"),
-    INIT_PARAM(mmu, "Memory Controller"),
-    INIT_PARAM(physmem, "Physical Memory"),
+    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(pio_latency, "Programmed IO latency in bus cycles", 1),
+    INIT_PARAM(intr_delay, "Interrupt Delay"),
+    INIT_PARAM(clock, "State machine cycle time"),
 
-    INIT_PARAM(hier, "Hierarchy global variables"),
-    INIT_PARAM(pio_bus, ""),
-    INIT_PARAM(dma_bus, ""),
-    INIT_PARAM(payload_bus, "The IO Bus to attach to for payload"),
     INIT_PARAM(dma_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(dma_no_allocate, "Should we allocat on read in cache"),
-    INIT_PARAM(pio_latency, "Programmed IO latency in bus cycles"),
-    INIT_PARAM(pio_delay_write, ""),
-    INIT_PARAM(intr_delay, "Interrupt Delay"),
 
     INIT_PARAM(rx_delay, "Receive Delay"),
     INIT_PARAM(tx_delay, "Transmit Delay"),
@@ -1703,12 +1687,19 @@ BEGIN_INIT_SIM_OBJECT_PARAMS(Device)
     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(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)
 
@@ -1716,32 +1707,22 @@ END_INIT_SIM_OBJECT_PARAMS(Device)
 CREATE_SIM_OBJECT(Device)
 {
     Device::Params *params = new Device::Params;
-
     params->name = getInstanceName();
-
-    params->clock = clock;
-
-    params->mmu = mmu;
-    params->physmem = physmem;
+    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->pio_delay = pio_latency;
+    params->intr_delay = intr_delay;
+    params->clock = clock;
 
-    params->hier = hier;
-    params->pio_bus = pio_bus;
-    params->header_bus = dma_bus;
-    params->payload_bus = payload_bus;
     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->pio_latency = pio_latency;
-    params->pio_delay_write = pio_delay_write;
-    params->intr_delay = intr_delay;
 
     params->tx_delay = tx_delay;
     params->rx_delay = rx_delay;
@@ -1751,12 +1732,19 @@ CREATE_SIM_OBJECT(Device)
     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->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);
 }