MEM: Move port creation to the memory object(s) construction
[gem5.git] / src / dev / sinic.cc
index e13fdb0bc84dff22d380e6a41df5981acf43cd9c..1030e1a9c21d135a9c945325a83ed35df43f8f4e 100644 (file)
 #include <limits>
 #include <string>
 
+#include "arch/vtophys.hh"
+#include "base/compiler.hh"
+#include "base/debug.hh"
 #include "base/inet.hh"
-#include "cpu/thread_context.hh"
+#include "base/types.hh"
+#include "config/the_isa.hh"
 #include "cpu/intr_control.hh"
+#include "cpu/thread_context.hh"
+#include "debug/EthernetAll.hh"
 #include "dev/etherlink.hh"
 #include "dev/sinic.hh"
 #include "mem/packet.hh"
 #include "mem/packet_access.hh"
-#include "sim/builder.hh"
-#include "sim/debug.hh"
 #include "sim/eventq.hh"
-#include "sim/host.hh"
 #include "sim/stats.hh"
-#include "arch/vtophys.hh"
 
+using namespace std;
 using namespace Net;
 using namespace TheISA;
 
@@ -74,14 +77,14 @@ const char *TxStateStrings[] =
 //
 // Sinic PCI Device
 //
-Base::Base(Params *p)
+Base::Base(const Params *p)
     : 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)
+Device::Device(const Params *p)
     : Base(p), rxUnique(0), txUnique(0),
       virtualRegs(p->virtual_count < 1 ? 1 : p->virtual_count),
       rxFifo(p->rx_fifo_size), txFifo(p->tx_fifo_size),
@@ -90,6 +93,7 @@ Device::Device(Params *p)
       dmaReadDelay(p->dma_read_delay), dmaReadFactor(p->dma_read_factor),
       dmaWriteDelay(p->dma_write_delay), dmaWriteFactor(p->dma_write_factor)
 {
+    interface = new Interface(name() + ".int0", this);
     reset();
 
 }
@@ -265,8 +269,50 @@ Device::regStats()
     totPackets = txPackets + rxPackets;
     txPacketRate = txPackets / simSeconds;
     rxPacketRate = rxPackets / simSeconds;
+
+    _maxVnicDistance = 0;
+
+    maxVnicDistance
+        .name(name() + ".maxVnicDistance")
+        .desc("maximum vnic distance")
+        ;
+
+    totalVnicDistance
+        .name(name() + ".totalVnicDistance")
+        .desc("total vnic distance")
+        ;
+    numVnicDistance
+        .name(name() + ".numVnicDistance")
+        .desc("number of vnic distance measurements")
+        ;
+
+    avgVnicDistance
+        .name(name() + ".avgVnicDistance")
+        .desc("average vnic distance")
+        ;
+
+    avgVnicDistance = totalVnicDistance / numVnicDistance;
+}
+
+void
+Device::resetStats()
+{
+    _maxVnicDistance = 0;
+}
+
+EtherInt*
+Device::getEthPort(const std::string &if_name, int idx)
+{
+    if (if_name == "interface") {
+        if (interface->getPeer())
+            panic("interface already connected to\n");
+
+        return interface;
+    }
+    return NULL;
 }
 
+
 void
 Device::prepareIO(int cpu, int index)
 {
@@ -276,6 +322,10 @@ Device::prepareIO(int cpu, int index)
               index, size);
 }
 
+//add stats for head of line blocking
+//add stats for average fifo length
+//add stats for average number of vnics busy
+
 void
 Device::prepareRead(int cpu, int index)
 {
@@ -288,7 +338,7 @@ Device::prepareRead(int cpu, int index)
     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_High(rxdone, rxFifo.size() > regs.RxFifoHigh);
     rxdone = set_RxDone_NotHigh(rxdone, rxLow);
     regs.RxData = vnic.RxData;
     regs.RxDone = rxdone;
@@ -298,10 +348,23 @@ Device::prepareRead(int cpu, int index)
     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);
+    txdone = set_TxDone_Low(txdone, txFifo.size() < regs.TxFifoLow);
     regs.TxData = vnic.TxData;
     regs.TxDone = txdone;
     regs.TxWait = txdone;
+
+    int head = 0xffff;
+
+    if (!rxFifo.empty()) {
+        int vnic = rxFifo.begin()->priv;
+        if (vnic != -1 && virtualRegs[vnic].rxPacketOffset > 0)
+            head = vnic;
+    }
+
+    regs.RxStatus = set_RxStatus_Head(regs.RxStatus, head);
+    regs.RxStatus = set_RxStatus_Busy(regs.RxStatus, rxBusyCount);
+    regs.RxStatus = set_RxStatus_Mapped(regs.RxStatus, rxMappedCount);
+    regs.RxStatus = set_RxStatus_Dirty(regs.RxStatus, rxDirtyCount);
 }
 
 void
@@ -319,7 +382,7 @@ Device::read(PacketPtr pkt)
     assert(config.command & PCI_CMD_MSE);
     assert(pkt->getAddr() >= BARAddrs[0] && pkt->getSize() < BARSize[0]);
 
-    int cpu = pkt->req->getCpuNum();
+    int cpu = pkt->req->contextId();
     Addr daddr = pkt->getAddr() - BARAddrs[0];
     Addr index = daddr >> Regs::VirtualShift;
     Addr raddr = daddr & Regs::VirtualMask;
@@ -342,7 +405,7 @@ Device::read(PacketPtr pkt)
 
     prepareRead(cpu, index);
 
-    uint64_t value = 0;
+    uint64_t value M5_VAR_USED = 0;
     if (pkt->getSize() == 4) {
         uint32_t reg = regData32(raddr);
         pkt->set(reg);
@@ -406,7 +469,7 @@ Device::write(PacketPtr pkt)
     assert(config.command & PCI_CMD_MSE);
     assert(pkt->getAddr() >= BARAddrs[0] && pkt->getSize() < BARSize[0]);
 
-    int cpu = pkt->req->getCpuNum();
+    int cpu = pkt->req->contextId();
     Addr daddr = pkt->getAddr() - BARAddrs[0];
     Addr index = daddr >> Regs::VirtualShift;
     Addr raddr = daddr & Regs::VirtualMask;
@@ -460,22 +523,25 @@ Device::write(PacketPtr pkt)
         vnic.rxUnique = rxUnique++;
         vnic.RxDone = Regs::RxDone_Busy;
         vnic.RxData = pkt->get<uint64_t>();
+        rxBusyCount++;
 
         if (Regs::get_RxData_Vaddr(pkt->get<uint64_t>())) {
             panic("vtophys not implemented in newmem");
-/*            Addr vaddr = Regs::get_RxData_Addr(reg64);
+#ifdef SINIC_VTOPHYS
+            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);*/
+            vnic.RxData = Regs::set_RxData_Addr(vnic.RxData, paddr);
+#endif
         } else {
             DPRINTF(EthernetPIO, "write RxData vnic %d (rxunique %d)\n",
                     index, vnic.rxUnique);
         }
 
-        if (vnic.rxPacket == rxFifo.end()) {
+        if (vnic.rxIndex == rxFifo.end()) {
             DPRINTF(EthernetPIO, "request new packet...appending to rxList\n");
             rxList.push_back(index);
         } else {
@@ -499,15 +565,17 @@ Device::write(PacketPtr pkt)
 
         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);
+#ifdef SINIC_VTOPHYS
+            Addr vaddr = Regs::get_TxData_Addr(reg64);
             Addr paddr = vtophys(req->xc, vaddr);
-            DPRINTF(EthernetPIO, "write TxData vnic %d (rxunique %d): "
+            DPRINTF(EthernetPIO, "write TxData vnic %d (txunique %d): "
                     "vaddr=%#x, paddr=%#x\n",
                     index, vnic.txUnique, vaddr, paddr);
 
-            vnic.TxData = Regs::set_TxData_Addr(vnic.TxData, paddr);*/
+            vnic.TxData = Regs::set_TxData_Addr(vnic.TxData, paddr);
+#endif
         } else {
-            DPRINTF(EthernetPIO, "write TxData vnic %d (rxunique %d)\n",
+            DPRINTF(EthernetPIO, "write TxData vnic %d (txunique %d)\n",
                     index, vnic.txUnique);
         }
 
@@ -552,7 +620,7 @@ Device::devIntrPost(uint32_t interrupts)
         interrupts &= ~Regs::Intr_TxLow;
 
     if (interrupts) {
-        Tick when = curTick;
+        Tick when = curTick();
         if ((interrupts & Regs::Intr_NoDelay) == 0)
             when += intrDelay;
         cpuIntrPost(when);
@@ -588,7 +656,7 @@ Device::devIntrChangeMask(uint32_t newmask)
             regs.IntrStatus, regs.IntrMask, regs.IntrStatus & regs.IntrMask);
 
     if (regs.IntrStatus & regs.IntrMask)
-        cpuIntrPost(curTick);
+        cpuIntrPost(curTick());
     else
         cpuIntrClear();
 }
@@ -605,8 +673,8 @@ Base::cpuIntrPost(Tick when)
      * @todo this warning should be removed and the intrTick code should
      * be fixed.
      */
-    assert(when >= curTick);
-    assert(intrTick >= curTick || intrTick == 0);
+    assert(when >= curTick());
+    assert(intrTick >= curTick() || intrTick == 0);
     if (!cpuIntrEnable) {
         DPRINTF(EthernetIntr, "interrupts not enabled.\n",
                 intrTick);
@@ -620,9 +688,9 @@ Base::cpuIntrPost(Tick when)
     }
 
     intrTick = when;
-    if (intrTick < curTick) {
-        debug_break();
-        intrTick = curTick;
+    if (intrTick < curTick()) {
+        Debug::breakpoint();
+        intrTick = curTick();
     }
 
     DPRINTF(EthernetIntr, "going to schedule an interrupt for intrTick=%d\n",
@@ -630,13 +698,14 @@ Base::cpuIntrPost(Tick when)
 
     if (intrEvent)
         intrEvent->squash();
-    intrEvent = new IntrEvent(this, intrTick, true);
+    intrEvent = new IntrEvent(this, true);
+    schedule(intrEvent, intrTick);
 }
 
 void
 Base::cpuInterrupt()
 {
-    assert(intrTick == curTick);
+    assert(intrTick == curTick());
 
     // Whether or not there's a pending interrupt, we don't care about
     // it anymore
@@ -692,7 +761,7 @@ Device::changeConfig(uint32_t newconf)
         cpuIntrEnable = regs.Config & Regs::Config_IntEn;
         if (cpuIntrEnable) {
             if (regs.IntrStatus & regs.IntrMask)
-                cpuIntrPost(curTick);
+                cpuIntrPost(curTick());
         } else {
             cpuIntrClear();
         }
@@ -748,18 +817,31 @@ Device::reset()
     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.ZeroCopySize = params()->zero_copy_size;
+    regs.ZeroCopyMark = params()->zero_copy_threshold;
     regs.VirtualCount = params()->virtual_count;
+    regs.RxMaxIntr = params()->rx_max_intr;
     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;
+    regs.RxFifoLow = params()->rx_fifo_low_mark;
+    regs.TxFifoLow = params()->tx_fifo_threshold;
+    regs.RxFifoHigh = params()->rx_fifo_threshold;
+    regs.TxFifoHigh = params()->tx_fifo_high_mark;
+    regs.HwAddr = params()->hardware_address;
+
+    if (regs.RxMaxCopy < regs.ZeroCopyMark)
+        panic("Must be able to copy at least as many bytes as the threshold");
+
+    if (regs.ZeroCopySize >= regs.ZeroCopyMark)
+        panic("The number of bytes to copy must be less than the threshold");
 
     rxList.clear();
     rxBusy.clear();
     rxActive = -1;
     txList.clear();
+    rxBusyCount = 0;
+    rxDirtyCount = 0;
+    rxMappedCount = 0;
 
     rxState = rxIdle;
     txState = txIdle;
@@ -775,7 +857,7 @@ Device::reset()
     virtualRegs.clear();
     virtualRegs.resize(size);
     for (int i = 0; i < size; ++i)
-        virtualRegs[i].rxPacket = rxFifo.end();
+        virtualRegs[i].rxIndex = rxFifo.end();
 }
 
 void
@@ -802,13 +884,14 @@ Device::rxKick()
     DPRINTF(EthernetSM, "rxKick: rxState=%s (rxFifo.size=%d)\n",
             RxStateStrings[rxState], rxFifo.size());
 
-    if (rxKickTick > curTick) {
+    if (rxKickTick > curTick()) {
         DPRINTF(EthernetSM, "rxKick: exiting, can't run till %d\n",
                 rxKickTick);
         return;
     }
 
   next:
+    rxFifo.check();
     if (rxState == rxIdle)
         goto exit;
 
@@ -832,12 +915,30 @@ Device::rxKick()
             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)) {
+                bool busy = Regs::get_RxDone_Busy(vn->RxDone);
+                if (vn->rxIndex != end) {
+#ifndef NDEBUG
+                    bool dirty = vn->rxPacketOffset > 0;
+                    const char *status;
+
+                    if (busy && dirty)
+                        status = "busy,dirty";
+                    else if (busy)
+                        status = "busy";
+                    else if (dirty)
+                        status = "dirty";
+                    else
+                        status = "mapped";
+
                     DPRINTF(EthernetSM,
-                            "vnic %d (rxunique %d), has outstanding packet %d\n",
-                            i, vn->rxUnique,
-                            rxFifo.countPacketsBefore(vn->rxPacket));
+                            "vnic %d %s (rxunique %d), packet %d, slack %d\n",
+                            i, status, vn->rxUnique,
+                            rxFifo.countPacketsBefore(vn->rxIndex),
+                            vn->rxIndex->slack);
+#endif
+                } else if (busy) {
+                    DPRINTF(EthernetSM, "vnic %d unmapped (rxunique %d)\n",
+                            i, vn->rxUnique);
                 }
             }
         }
@@ -847,7 +948,7 @@ Device::rxKick()
             rxBusy.pop_front();
             vnic = &virtualRegs[rxActive];
 
-            if (vnic->rxPacket == rxFifo.end())
+            if (vnic->rxIndex == rxFifo.end())
                 panic("continuing vnic without packet\n");
 
             DPRINTF(EthernetSM,
@@ -856,6 +957,14 @@ Device::rxKick()
 
             rxState = rxBeginCopy;
 
+            int vnic_distance = rxFifo.countPacketsBefore(vnic->rxIndex);
+            totalVnicDistance += vnic_distance;
+            numVnicDistance += 1;
+            if (vnic_distance > _maxVnicDistance) {
+                maxVnicDistance = vnic_distance;
+                _maxVnicDistance = vnic_distance;
+            }
+
             break;
         }
 
@@ -878,14 +987,16 @@ Device::rxKick()
                 rxActive, vnic->rxUnique);
 
         // Grab a new packet from the fifo.
-        vnic->rxPacket = rxFifoPtr++;
+        vnic->rxIndex = rxFifoPtr++;
+        vnic->rxIndex->priv = rxActive;
         vnic->rxPacketOffset = 0;
-        vnic->rxPacketBytes = (*vnic->rxPacket)->length;
+        vnic->rxPacketBytes = vnic->rxIndex->packet->length;
         assert(vnic->rxPacketBytes);
+        rxMappedCount++;
 
         vnic->rxDoneData = 0;
         /* scope for variables */ {
-            IpPtr ip(*vnic->rxPacket);
+            IpPtr ip(vnic->rxIndex->packet);
             if (ip) {
                 DPRINTF(Ethernet, "ID is %d\n", ip->id());
                 vnic->rxDoneData |= Regs::RxDone_IpPacket;
@@ -926,16 +1037,26 @@ Device::rxKick()
 
         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;
+        rxDmaLen = min<unsigned>(Regs::get_RxData_Len(vnic->RxData),
+                                 vnic->rxPacketBytes);
+
+        /*
+         * if we're doing zero/delay copy and we're below the fifo
+         * threshold, see if we should try to do the zero/defer copy
+         */
+        if ((Regs::get_Config_ZeroCopy(regs.Config) ||
+             Regs::get_Config_DelayCopy(regs.Config)) &&
+            !Regs::get_RxData_NoDelay(vnic->RxData) && rxLow) {
+            if (rxDmaLen > regs.ZeroCopyMark)
+                rxDmaLen = regs.ZeroCopySize;
+        }
+        rxDmaData = vnic->rxIndex->packet->data + vnic->rxPacketOffset;
         rxState = rxCopy;
         if (rxDmaAddr == 1LL) {
             rxState = rxCopyDone;
             break;
         }
 
-
         dmaWrite(rxDmaAddr, rxDmaLen, &rxDmaEvent, rxDmaData);
         break;
 
@@ -946,17 +1067,25 @@ Device::rxKick()
       case rxCopyDone:
         vnic->RxDone = vnic->rxDoneData;
         vnic->RxDone |= Regs::RxDone_Complete;
+        rxBusyCount--;
 
         if (vnic->rxPacketBytes == rxDmaLen) {
+            if (vnic->rxPacketOffset)
+                rxDirtyCount--;
+
             // 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();
+            rxFifo.remove(vnic->rxIndex);
+            vnic->rxIndex = rxFifo.end();
+            rxMappedCount--;
         } else {
+            if (!vnic->rxPacketOffset)
+                rxDirtyCount++;
+
             vnic->rxPacketBytes -= rxDmaLen;
             vnic->rxPacketOffset += rxDmaLen;
             vnic->RxDone |= Regs::RxDone_More;
@@ -976,10 +1105,10 @@ Device::rxKick()
             rxEmpty = true;
         }
 
-        if (rxFifo.size() < params()->rx_fifo_low_mark)
+        if (rxFifo.size() < regs.RxFifoLow)
             rxLow = true;
 
-        if (rxFifo.size() > params()->rx_fifo_threshold)
+        if (rxFifo.size() > regs.RxFifoHigh)
             rxLow = false;
 
         devIntrPost(Regs::Intr_RxDMA);
@@ -1031,7 +1160,7 @@ Device::transmit()
     if (!interface->sendPacket(packet)) {
         DPRINTF(Ethernet, "Packet Transmit: failed txFifo available %d\n",
                 txFifo.avail());
-        goto reschedule;
+        return;
     }
 
     txFifo.pop();
@@ -1059,15 +1188,9 @@ Device::transmit()
             txFifo.avail());
 
     interrupts = Regs::Intr_TxPacket;
-    if (txFifo.size() < regs.TxFifoMark)
+    if (txFifo.size() < regs.TxFifoLow)
         interrupts |= Regs::Intr_TxLow;
     devIntrPost(interrupts);
-
-  reschedule:
-   if (!txFifo.empty() && !txEvent.scheduled()) {
-       DPRINTF(Ethernet, "reschedule transmit\n");
-       txEvent.schedule(curTick + retryTime);
-   }
 }
 
 void
@@ -1077,7 +1200,7 @@ Device::txKick()
     DPRINTF(EthernetSM, "txKick: txState=%s (txFifo.size=%d)\n",
             TxStateStrings[txState], txFifo.size());
 
-    if (txKickTick > curTick) {
+    if (txKickTick > curTick()) {
         DPRINTF(EthernetSM, "txKick: exiting, can't run till %d\n",
                 txKickTick);
         return;
@@ -1198,7 +1321,7 @@ Device::transferDone()
 
     DPRINTF(Ethernet, "transfer complete: data in txFifo...schedule xmit\n");
 
-    txEvent.reschedule(curTick + cycles(1), true);
+    reschedule(txEvent, curTick() + ticks(1), true);
 }
 
 bool
@@ -1265,7 +1388,7 @@ Device::recvPacket(EthPacketPtr packet)
         return true;
     }
 
-    if (rxFifo.size() >= regs.RxFifoMark)
+    if (rxFifo.size() >= regs.RxFifoHigh)
         devIntrPost(Regs::Intr_RxHigh);
 
     if (!rxFifo.push(packet)) {
@@ -1338,7 +1461,8 @@ Base::unserialize(Checkpoint *cp, const std::string &section)
     Tick intrEventTick;
     UNSERIALIZE_SCALAR(intrEventTick);
     if (intrEventTick) {
-        intrEvent = new IntrEvent(this, intrEventTick, true);
+        intrEvent = new IntrEvent(this, true);
+        schedule(intrEvent, intrEventTick);
     }
 }
 
@@ -1359,19 +1483,13 @@ Device::serialize(std::ostream &os)
               TxStateStrings[txState]);
 
     /*
-     * Serialize the device registers
+     * Serialize the device registers that could be modified by the OS.
      */
     SERIALIZE_SCALAR(regs.Config);
     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
@@ -1387,12 +1505,12 @@ Device::serialize(std::ostream &os)
         paramOut(os, reg + ".TxData", vnic->TxData);
         paramOut(os, reg + ".TxDone", vnic->TxDone);
 
-        bool rxPacketExists = vnic->rxPacket != rxFifo.end();
+        bool rxPacketExists = vnic->rxIndex != rxFifo.end();
         paramOut(os, reg + ".rxPacketExists", rxPacketExists);
         if (rxPacketExists) {
             int rxPacket = 0;
             PacketFifo::iterator i = rxFifo.begin();
-            while (i != vnic->rxPacket) {
+            while (i != vnic->rxIndex) {
                 assert(i != rxFifo.end());
                 ++i;
                 ++rxPacket;
@@ -1405,10 +1523,15 @@ Device::serialize(std::ostream &os)
         paramOut(os, reg + ".rxDoneData", vnic->rxDoneData);
     }
 
-    int rxFifoPtr = rxFifo.countPacketsBefore(this->rxFifoPtr);
+    int rxFifoPtr = -1;
+    if (this->rxFifoPtr != rxFifo.end())
+        rxFifoPtr = rxFifo.countPacketsBefore(this->rxFifoPtr);
     SERIALIZE_SCALAR(rxFifoPtr);
 
     SERIALIZE_SCALAR(rxActive);
+    SERIALIZE_SCALAR(rxBusyCount);
+    SERIALIZE_SCALAR(rxDirtyCount);
+    SERIALIZE_SCALAR(rxMappedCount);
 
     VirtualList::iterator i, end;
     for (count = 0, i = rxList.begin(), end = rxList.end(); i != end; ++i)
@@ -1454,7 +1577,7 @@ Device::serialize(std::ostream &os)
      * If there's a pending transmit, store the time so we can
      * reschedule it later
      */
-    Tick transmitTick = txEvent.scheduled() ? txEvent.when() - curTick : 0;
+    Tick transmitTick = txEvent.scheduled() ? txEvent.when() - curTick() : 0;
     SERIALIZE_SCALAR(transmitTick);
 }
 
@@ -1465,21 +1588,18 @@ Device::unserialize(Checkpoint *cp, const std::string &section)
     Base::unserialize(cp, section);
 
     /*
-     * Unserialize the device registers
+     * Unserialize the device registers that may have been written by the OS.
      */
     UNSERIALIZE_SCALAR(regs.Config);
     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);
+    UNSERIALIZE_SCALAR(rxBusyCount);
+    UNSERIALIZE_SCALAR(rxDirtyCount);
+    UNSERIALIZE_SCALAR(rxMappedCount);
 
     int rxListSize;
     UNSERIALIZE_SCALAR(rxListSize);
@@ -1520,9 +1640,13 @@ Device::unserialize(Checkpoint *cp, const std::string &section)
 
     int rxFifoPtr;
     UNSERIALIZE_SCALAR(rxFifoPtr);
-    this->rxFifoPtr = rxFifo.begin();
-    for (int i = 0; i < rxFifoPtr; ++i)
-        ++this->rxFifoPtr;
+    if (rxFifoPtr >= 0) {
+        this->rxFifoPtr = rxFifo.begin();
+        for (int i = 0; i < rxFifoPtr; ++i)
+            ++this->rxFifoPtr;
+    } else {
+        this->rxFifoPtr = rxFifo.end();
+    }
 
     /*
      * Unserialize tx state machine
@@ -1569,15 +1693,15 @@ Device::unserialize(Checkpoint *cp, const std::string &section)
         if (rxPacketExists) {
             int rxPacket;
             paramIn(cp, section, reg + ".rxPacket", rxPacket);
-            vnic->rxPacket = rxFifo.begin();
+            vnic->rxIndex = rxFifo.begin();
             while (rxPacket--)
-                ++vnic->rxPacket;
+                ++vnic->rxIndex;
 
             paramIn(cp, section, reg + ".rxPacketOffset",
                     vnic->rxPacketOffset);
             paramIn(cp, section, reg + ".rxPacketBytes", vnic->rxPacketBytes);
         } else {
-            vnic->rxPacket = rxFifo.end();
+            vnic->rxIndex = rxFifo.end();
         }
         paramIn(cp, section, reg + ".rxDoneData", vnic->rxDoneData);
     }
@@ -1588,180 +1712,16 @@ Device::unserialize(Checkpoint *cp, const std::string &section)
     Tick transmitTick;
     UNSERIALIZE_SCALAR(transmitTick);
     if (transmitTick)
-        txEvent.schedule(curTick + transmitTick);
+        schedule(txEvent, curTick() + transmitTick);
 
-    pioPort->sendStatusChange(Port::RangeChange);
+    pioPort.sendRangeChange();
 
 }
 
-/* namespace Sinic */ }
-
-BEGIN_DECLARE_SIM_OBJECT_PARAMS_WNS(Sinic, SinicInterface)
-
-    SimObjectParam<EtherInt *> peer;
-    SimObjectParam<Sinic::Device *> device;
-END_DECLARE_SIM_OBJECT_PARAMS_WNS(Sinic, SinicInterface)
-
-BEGIN_INIT_SIM_OBJECT_PARAMS_WNS(Sinic, SinicInterface)
-
-    INIT_PARAM_DFLT(peer, "peer interface", NULL),
-    INIT_PARAM(device, "Ethernet device of this interface")
-
-END_INIT_SIM_OBJECT_PARAMS_WNS(Sinic, SinicInterface)
-
-CREATE_SIM_OBJECT_WNS(Sinic, SinicInterface)
-{
-    Sinic::Interface *dev_int = new Sinic::Interface(getInstanceName(), device);
-
-    EtherInt *p = (EtherInt *)peer;
-    if (p) {
-        dev_int->setPeer(p);
-        p->setPeer(dev_int);
-    }
+} // namespace Sinic
 
-    return dev_int;
-}
-
-REGISTER_SIM_OBJECT_WNS(Sinic, "SinicInt", SinicInterface)
-
-
-BEGIN_DECLARE_SIM_OBJECT_PARAMS_WNS(Sinic, SinicDevice)
-
-
-    SimObjectParam<System *> system;
-    SimObjectParam<Platform *> platform;
-    Param<Tick> min_backoff_delay;
-    Param<Tick> max_backoff_delay;
-    SimObjectParam<PciConfigData *> configdata;
-    Param<uint32_t> pci_bus;
-    Param<uint32_t> pci_dev;
-    Param<uint32_t> pci_func;
-    Param<Tick> pio_latency;
-    Param<Tick> config_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<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_WNS(Sinic, SinicDevice)
-
-BEGIN_INIT_SIM_OBJECT_PARAMS_WNS(Sinic, SinicDevice)
-
-
-    INIT_PARAM(system, "System pointer"),
-    INIT_PARAM(platform, "Platform pointer"),
-    INIT_PARAM(min_backoff_delay, "Minimum delay after receving a nack packed"),
-    INIT_PARAM(max_backoff_delay, "Maximum delay after receving a nack packed"),
-    INIT_PARAM(configdata, "PCI Config data"),
-    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(config_latency, "Number of cycles for a config read or write"),
-    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_WNS(Sinic, SinicDevice)
-
-
-CREATE_SIM_OBJECT_WNS(Sinic, SinicDevice)
+Sinic::Device *
+SinicParams::create()
 {
-    Sinic::Sinic::Device::Params *params = new Device::Params;
-    params->name = getInstanceName();
-    params->platform = platform;
-    params->system = system;
-    params->min_backoff_delay = min_backoff_delay;
-    params->max_backoff_delay = max_backoff_delay;
-    params->configData = configdata;
-    params->busNum = pci_bus;
-    params->deviceNum = pci_dev;
-    params->functionNum = pci_func;
-    params->pio_delay = pio_latency;
-    params->config_delay = config_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->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 Sinic::Device(params);
+    return new Sinic::Device(this);
 }
-
-REGISTER_SIM_OBJECT_WNS(Sinic, "Sinic", SinicDevice)
-