summaryrefslogtreecommitdiff
path: root/src/dev/sinic.cc
diff options
context:
space:
mode:
authorAndreas Sandberg <andreas.sandberg@arm.com>2015-12-10 10:35:18 +0000
committerAndreas Sandberg <andreas.sandberg@arm.com>2015-12-10 10:35:18 +0000
commit23c961a0fd97251ee7c760bc2ff2a011a417ad9b (patch)
tree0481b7552303373cd3722156b1cef92d813de215 /src/dev/sinic.cc
parentef097ac4381ad2f14acda640ae198f04d9f7988d (diff)
downloadgem5-23c961a0fd97251ee7c760bc2ff2a011a417ad9b.tar.xz
dev: Move network devices to src/dev/net/
--HG-- rename : src/dev/Ethernet.py => src/dev/net/Ethernet.py rename : src/dev/etherbus.cc => src/dev/net/etherbus.cc rename : src/dev/etherbus.hh => src/dev/net/etherbus.hh rename : src/dev/etherdevice.cc => src/dev/net/etherdevice.cc rename : src/dev/etherdevice.hh => src/dev/net/etherdevice.hh rename : src/dev/etherdump.cc => src/dev/net/etherdump.cc rename : src/dev/etherdump.hh => src/dev/net/etherdump.hh rename : src/dev/etherint.cc => src/dev/net/etherint.cc rename : src/dev/etherint.hh => src/dev/net/etherint.hh rename : src/dev/etherlink.cc => src/dev/net/etherlink.cc rename : src/dev/etherlink.hh => src/dev/net/etherlink.hh rename : src/dev/etherobject.hh => src/dev/net/etherobject.hh rename : src/dev/etherpkt.cc => src/dev/net/etherpkt.cc rename : src/dev/etherpkt.hh => src/dev/net/etherpkt.hh rename : src/dev/ethertap.cc => src/dev/net/ethertap.cc rename : src/dev/ethertap.hh => src/dev/net/ethertap.hh rename : src/dev/i8254xGBe.cc => src/dev/net/i8254xGBe.cc rename : src/dev/i8254xGBe.hh => src/dev/net/i8254xGBe.hh rename : src/dev/i8254xGBe_defs.hh => src/dev/net/i8254xGBe_defs.hh rename : src/dev/multi_etherlink.cc => src/dev/net/multi_etherlink.cc rename : src/dev/multi_etherlink.hh => src/dev/net/multi_etherlink.hh rename : src/dev/multi_iface.cc => src/dev/net/multi_iface.cc rename : src/dev/multi_iface.hh => src/dev/net/multi_iface.hh rename : src/dev/multi_packet.cc => src/dev/net/multi_packet.cc rename : src/dev/multi_packet.hh => src/dev/net/multi_packet.hh rename : src/dev/ns_gige.cc => src/dev/net/ns_gige.cc rename : src/dev/ns_gige.hh => src/dev/net/ns_gige.hh rename : src/dev/ns_gige_reg.h => src/dev/net/ns_gige_reg.h rename : src/dev/pktfifo.cc => src/dev/net/pktfifo.cc rename : src/dev/pktfifo.hh => src/dev/net/pktfifo.hh rename : src/dev/sinic.cc => src/dev/net/sinic.cc rename : src/dev/sinic.hh => src/dev/net/sinic.hh rename : src/dev/sinicreg.hh => src/dev/net/sinicreg.hh rename : src/dev/tcp_iface.cc => src/dev/net/tcp_iface.cc rename : src/dev/tcp_iface.hh => src/dev/net/tcp_iface.hh
Diffstat (limited to 'src/dev/sinic.cc')
-rw-r--r--src/dev/sinic.cc1561
1 files changed, 0 insertions, 1561 deletions
diff --git a/src/dev/sinic.cc b/src/dev/sinic.cc
deleted file mode 100644
index 18642efb7..000000000
--- a/src/dev/sinic.cc
+++ /dev/null
@@ -1,1561 +0,0 @@
-/*
- * Copyright (c) 2004-2005 The Regents of The University of Michigan
- * All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions are
- * met: redistributions of source code must retain the above copyright
- * notice, this list of conditions and the following disclaimer;
- * redistributions in binary form must reproduce the above copyright
- * notice, this list of conditions and the following disclaimer in the
- * documentation and/or other materials provided with the distribution;
- * neither the name of the copyright holders nor the names of its
- * contributors may be used to endorse or promote products derived from
- * this software without specific prior written permission.
- *
- * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
- * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
- * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
- * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
- * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
- * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
- * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
- * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
- * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
- * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
- * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
- *
- * Authors: Nathan Binkert
- */
-
-#include <deque>
-#include <limits>
-#include <string>
-
-#ifdef SINIC_VTOPHYS
-#include "arch/vtophys.hh"
-#endif
-#include "base/compiler.hh"
-#include "base/debug.hh"
-#include "base/inet.hh"
-#include "base/types.hh"
-#include "config/the_isa.hh"
-#include "debug/EthernetAll.hh"
-#include "dev/etherlink.hh"
-#include "dev/sinic.hh"
-#include "mem/packet.hh"
-#include "mem/packet_access.hh"
-#include "sim/eventq.hh"
-#include "sim/stats.hh"
-
-using namespace std;
-using namespace Net;
-using namespace TheISA;
-
-namespace Sinic {
-
-const char *RxStateStrings[] =
-{
- "rxIdle",
- "rxFifoBlock",
- "rxBeginCopy",
- "rxCopy",
- "rxCopyDone"
-};
-
-const char *TxStateStrings[] =
-{
- "txIdle",
- "txFifoBlock",
- "txBeginCopy",
- "txCopy",
- "txCopyDone"
-};
-
-
-///////////////////////////////////////////////////////////////////////
-//
-// Sinic PCI Device
-//
-Base::Base(const Params *p)
- : EtherDevBase(p), rxEnable(false), txEnable(false),
- intrDelay(p->intr_delay), intrTick(0), cpuIntrEnable(false),
- cpuPendingIntr(false), intrEvent(0), interface(NULL)
-{
-}
-
-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),
- rxKickTick(0), txKickTick(0),
- txEvent(this), rxDmaEvent(this), txDmaEvent(this),
- 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();
-
-}
-
-Device::~Device()
-{}
-
-void
-Device::regStats()
-{
- Base::regStats();
-
- _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()
-{
- Base::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(ContextID cpu, int index)
-{
- int size = virtualRegs.size();
- if (index > size)
- panic("Trying to access a vnic that doesn't exist %d > %d\n",
- 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(ContextID 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.RxFifoHigh);
- 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.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
-Device::prepareWrite(ContextID cpu, int index)
-{
- prepareIO(cpu, index);
-}
-
-/**
- * I/O read of device register
- */
-Tick
-Device::read(PacketPtr pkt)
-{
- assert(config.command & PCI_CMD_MSE);
- assert(pkt->getAddr() >= BARAddrs[0] && pkt->getSize() < BARSize[0]);
-
- ContextID cpu = pkt->req->contextId();
- Addr daddr = pkt->getAddr() - BARAddrs[0];
- Addr index = daddr >> Regs::VirtualShift;
- Addr raddr = daddr & Regs::VirtualMask;
-
- if (!regValid(raddr))
- panic("invalid register: cpu=%d vnic=%d da=%#x pa=%#x size=%d",
- cpu, index, daddr, pkt->getAddr(), pkt->getSize());
-
- 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->getAddr(), pkt->getSize());
-
- panic("read %s (invalid size): "
- "cpu=%d vnic=%d da=%#x pa=%#x size=%d",
- info.name, cpu, index, daddr, pkt->getAddr(), pkt->getSize());
-
- prepareRead(cpu, index);
-
- uint64_t value M5_VAR_USED = 0;
- if (pkt->getSize() == 4) {
- uint32_t reg = regData32(raddr);
- pkt->set(reg);
- value = reg;
- }
-
- if (pkt->getSize() == 8) {
- uint64_t reg = regData64(raddr);
- pkt->set(reg);
- value = reg;
- }
-
- DPRINTF(EthernetPIO,
- "read %s: cpu=%d vnic=%d da=%#x pa=%#x size=%d val=%#x\n",
- info.name, cpu, index, daddr, pkt->getAddr(), pkt->getSize(), value);
-
- // reading the interrupt status register has the side effect of
- // clearing it
- if (raddr == Regs::IntrStatus)
- devIntrClear();
-
- return pioDelay;
-}
-
-/**
- * IPR read of device register
-
- Fault
-Device::iprRead(Addr daddr, ContextID cpu, uint64_t &result)
-{
- if (!regValid(daddr))
- panic("invalid address: da=%#x", daddr);
-
- const Regs::Info &info = regInfo(daddr);
- if (!info.read)
- panic("reading %s (write only): cpu=%d da=%#x", info.name, cpu, daddr);
-
- DPRINTF(EthernetPIO, "IPR read %s: cpu=%d da=%#x\n",
- info.name, cpu, daddr);
-
- prepareRead(cpu, 0);
-
- if (info.size == 4)
- result = regData32(daddr);
-
- if (info.size == 8)
- result = regData64(daddr);
-
- DPRINTF(EthernetPIO, "IPR read %s: cpu=%s da=%#x val=%#x\n",
- info.name, cpu, result);
-
- return NoFault;
-}
-*/
-/**
- * I/O write of device register
- */
-Tick
-Device::write(PacketPtr pkt)
-{
- assert(config.command & PCI_CMD_MSE);
- assert(pkt->getAddr() >= BARAddrs[0] && pkt->getSize() < BARSize[0]);
-
- ContextID cpu = pkt->req->contextId();
- Addr daddr = pkt->getAddr() - BARAddrs[0];
- Addr index = daddr >> Regs::VirtualShift;
- Addr raddr = daddr & Regs::VirtualMask;
-
- if (!regValid(raddr))
- panic("invalid register: cpu=%d, da=%#x pa=%#x size=%d",
- cpu, daddr, pkt->getAddr(), pkt->getSize());
-
- 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->getAddr(), pkt->getSize());
-
- if (pkt->getSize() != info.size)
- panic("write %s (invalid size): "
- "cpu=%d vnic=%d da=%#x pa=%#x size=%d",
- info.name, cpu, index, daddr, pkt->getAddr(), pkt->getSize());
-
- VirtualReg &vnic = virtualRegs[index];
-
- 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->getAddr(), pkt->getSize());
-
- prepareWrite(cpu, index);
-
- switch (raddr) {
- case Regs::Config:
- changeConfig(pkt->get<uint32_t>());
- break;
-
- case Regs::Command:
- command(pkt->get<uint32_t>());
- break;
-
- case Regs::IntrStatus:
- devIntrClear(regs.IntrStatus & pkt->get<uint32_t>());
- break;
-
- case Regs::IntrMask:
- devIntrChangeMask(pkt->get<uint32_t>());
- break;
-
- case Regs::RxData:
- 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>();
- rxBusyCount++;
-
- if (Regs::get_RxData_Vaddr(pkt->get<uint64_t>())) {
- panic("vtophys not implemented in newmem");
-#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);
-#endif
- } else {
- DPRINTF(EthernetPIO, "write RxData vnic %d (rxunique %d)\n",
- index, vnic.rxUnique);
- }
-
- if (vnic.rxIndex == 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();
- }
- break;
-
- case Regs::TxData:
- 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");
-#ifdef SINIC_VTOPHYS
- Addr vaddr = Regs::get_TxData_Addr(reg64);
- Addr paddr = vtophys(req->xc, vaddr);
- 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);
-#endif
- } else {
- DPRINTF(EthernetPIO, "write TxData vnic %d (txunique %d)\n",
- index, vnic.txUnique);
- }
-
- if (txList.empty() || txList.front() != index)
- txList.push_back(index);
- if (txEnable && txState == txIdle && txList.front() == index) {
- txState = txFifoBlock;
- txKick();
- }
- break;
- }
-
- return pioDelay;
-}
-
-void
-Device::devIntrPost(uint32_t interrupts)
-{
- if ((interrupts & Regs::Intr_Res))
- panic("Cannot set a reserved interrupt");
-
- regs.IntrStatus |= interrupts;
-
- DPRINTF(EthernetIntr,
- "interrupt written to intStatus: intr=%#x status=%#x mask=%#x\n",
- interrupts, 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 ((interrupts & Regs::Intr_NoDelay) == 0)
- when += intrDelay;
- cpuIntrPost(when);
- }
-}
-
-void
-Device::devIntrClear(uint32_t interrupts)
-{
- if ((interrupts & Regs::Intr_Res))
- panic("Cannot clear a reserved interrupt");
-
- regs.IntrStatus &= ~interrupts;
-
- DPRINTF(EthernetIntr,
- "interrupt cleared from intStatus: intr=%x status=%x mask=%x\n",
- interrupts, regs.IntrStatus, regs.IntrMask);
-
- if (!(regs.IntrStatus & regs.IntrMask))
- cpuIntrClear();
-}
-
-void
-Device::devIntrChangeMask(uint32_t newmask)
-{
- if (regs.IntrMask == newmask)
- return;
-
- regs.IntrMask = newmask;
-
- DPRINTF(EthernetIntr,
- "interrupt mask changed: intStatus=%x intMask=%x masked=%x\n",
- regs.IntrStatus, regs.IntrMask, regs.IntrStatus & regs.IntrMask);
-
- if (regs.IntrStatus & regs.IntrMask)
- cpuIntrPost(curTick());
- else
- cpuIntrClear();
-}
-
-void
-Base::cpuIntrPost(Tick when)
-{
- // If the interrupt you want to post is later than an interrupt
- // already scheduled, just let it post in the coming one and don't
- // schedule another.
- // HOWEVER, must be sure that the scheduled intrTick is in the
- // future (this was formerly the source of a bug)
- /**
- * @todo this warning should be removed and the intrTick code should
- * be fixed.
- */
- assert(when >= curTick());
- assert(intrTick >= curTick() || intrTick == 0);
- if (!cpuIntrEnable) {
- DPRINTF(EthernetIntr, "interrupts not enabled.\n",
- intrTick);
- return;
- }
-
- if (when > intrTick && intrTick != 0) {
- DPRINTF(EthernetIntr, "don't need to schedule event...intrTick=%d\n",
- intrTick);
- return;
- }
-
- intrTick = when;
- if (intrTick < curTick()) {
- Debug::breakpoint();
- intrTick = curTick();
- }
-
- DPRINTF(EthernetIntr, "going to schedule an interrupt for intrTick=%d\n",
- intrTick);
-
- if (intrEvent)
- intrEvent->squash();
- intrEvent = new IntrEvent(this, true);
- schedule(intrEvent, intrTick);
-}
-
-void
-Base::cpuInterrupt()
-{
- assert(intrTick == curTick());
-
- // Whether or not there's a pending interrupt, we don't care about
- // it anymore
- intrEvent = 0;
- intrTick = 0;
-
- // Don't send an interrupt if there's already one
- if (cpuPendingIntr) {
- DPRINTF(EthernetIntr,
- "would send an interrupt now, but there's already pending\n");
- } else {
- // Send interrupt
- cpuPendingIntr = true;
-
- DPRINTF(EthernetIntr, "posting interrupt\n");
- intrPost();
- }
-}
-
-void
-Base::cpuIntrClear()
-{
- if (!cpuPendingIntr)
- return;
-
- if (intrEvent) {
- intrEvent->squash();
- intrEvent = 0;
- }
-
- intrTick = 0;
-
- cpuPendingIntr = false;
-
- DPRINTF(EthernetIntr, "clearing cchip interrupt\n");
- intrClear();
-}
-
-bool
-Base::cpuIntrPending() const
-{ return cpuPendingIntr; }
-
-void
-Device::changeConfig(uint32_t newconf)
-{
- uint32_t changed = regs.Config ^ newconf;
- if (!changed)
- return;
-
- regs.Config = newconf;
-
- if ((changed & Regs::Config_IntEn)) {
- cpuIntrEnable = regs.Config & Regs::Config_IntEn;
- if (cpuIntrEnable) {
- if (regs.IntrStatus & regs.IntrMask)
- cpuIntrPost(curTick());
- } else {
- cpuIntrClear();
- }
- }
-
- if ((changed & Regs::Config_TxEn)) {
- txEnable = regs.Config & Regs::Config_TxEn;
- if (txEnable)
- txKick();
- }
-
- if ((changed & Regs::Config_RxEn)) {
- rxEnable = regs.Config & Regs::Config_RxEn;
- if (rxEnable)
- rxKick();
- }
-}
-
-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(&regs, 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.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.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;
-
- 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].rxIndex = rxFifo.end();
-}
-
-void
-Device::rxDmaDone()
-{
- assert(rxState == rxCopy);
- rxState = rxCopyDone;
- DPRINTF(EthernetDMA, "end rx dma write paddr=%#x len=%d\n",
- rxDmaAddr, rxDmaLen);
- DDUMP(EthernetData, rxDmaData, rxDmaLen);
-
- // If the transmit state machine has a pending DMA, let it go first
- if (txState == txBeginCopy)
- txKick();
-
- rxKick();
-}
-
-void
-Device::rxKick()
-{
- VirtualReg *vnic = NULL;
-
- DPRINTF(EthernetSM, "rxKick: rxState=%s (rxFifo.size=%d)\n",
- RxStateStrings[rxState], rxFifo.size());
-
- if (rxKickTick > curTick()) {
- DPRINTF(EthernetSM, "rxKick: exiting, can't run till %d\n",
- rxKickTick);
- return;
- }
-
- next:
- rxFifo.check();
- 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 (DTRACE(EthernetSM)) {
- PacketFifo::iterator end = rxFifo.end();
- int size = virtualRegs.size();
- for (int i = 0; i < size; ++i) {
- VirtualReg *vn = &virtualRegs[i];
- 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 %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);
- }
- }
- }
-
- if (!rxBusy.empty()) {
- rxActive = rxBusy.front();
- rxBusy.pop_front();
- vnic = &virtualRegs[rxActive];
-
- if (vnic->rxIndex == rxFifo.end())
- panic("continuing vnic without packet\n");
-
- DPRINTF(EthernetSM,
- "continue processing for vnic %d (rxunique %d)\n",
- rxActive, vnic->rxUnique);
-
- 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;
- }
-
- 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.
- vnic->rxIndex = rxFifoPtr++;
- vnic->rxIndex->priv = rxActive;
- vnic->rxPacketOffset = 0;
- vnic->rxPacketBytes = vnic->rxIndex->packet->length;
- assert(vnic->rxPacketBytes);
- rxMappedCount++;
-
- vnic->rxDoneData = 0;
- /* scope for variables */ {
- IpPtr ip(vnic->rxIndex->packet);
- if (ip) {
- 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");
- vnic->rxDoneData |= Regs::RxDone_IpError;
- }
- 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) {
- DPRINTF(EthernetCksum, "Rx TCP Checksum Error\n");
- vnic->rxDoneData |= Regs::RxDone_TcpError;
- }
- } else if (udp) {
- vnic->rxDoneData |= Regs::RxDone_UdpPacket;
- rxUdpChecksums++;
- if (cksum(udp) != 0) {
- DPRINTF(EthernetCksum, "Rx UDP Checksum Error\n");
- vnic->rxDoneData |= Regs::RxDone_UdpError;
- }
- }
- }
- }
- rxState = rxBeginCopy;
- break;
-
- case rxBeginCopy:
- if (dmaPending() || drainState() != DrainState::Running)
- goto exit;
-
- rxDmaAddr = pciToDma(Regs::get_RxData_Addr(vnic->RxData));
- 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;
-
- case rxCopy:
- DPRINTF(EthernetSM, "receive machine still copying\n");
- goto exit;
-
- 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->rxIndex);
- vnic->rxIndex = rxFifo.end();
- rxMappedCount--;
- } else {
- if (!vnic->rxPacketOffset)
- rxDirtyCount++;
-
- 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;
- }
-
- if (rxFifo.size() < regs.RxFifoLow)
- rxLow = true;
-
- if (rxFifo.size() > regs.RxFifoHigh)
- rxLow = false;
-
- devIntrPost(Regs::Intr_RxDMA);
- break;
-
- default:
- panic("Invalid rxState!");
- }
-
- DPRINTF(EthernetSM, "entering next rxState=%s\n",
- RxStateStrings[rxState]);
-
- goto next;
-
- exit:
- /**
- * @todo do we want to schedule a future kick?
- */
- DPRINTF(EthernetSM, "rx state machine exited rxState=%s\n",
- RxStateStrings[rxState]);
-}
-
-void
-Device::txDmaDone()
-{
- assert(txState == txCopy);
- txState = txCopyDone;
- DPRINTF(EthernetDMA, "tx dma read paddr=%#x len=%d\n",
- txDmaAddr, txDmaLen);
- DDUMP(EthernetData, txDmaData, txDmaLen);
-
- // If the receive state machine has a pending DMA, let it go first
- if (rxState == rxBeginCopy)
- rxKick();
-
- txKick();
-}
-
-void
-Device::transmit()
-{
- if (txFifo.empty()) {
- DPRINTF(Ethernet, "nothing to transmit\n");
- return;
- }
-
- uint32_t interrupts;
- EthPacketPtr packet = txFifo.front();
- if (!interface->sendPacket(packet)) {
- DPRINTF(Ethernet, "Packet Transmit: failed txFifo available %d\n",
- txFifo.avail());
- return;
- }
-
- txFifo.pop();
-#if TRACING_ON
- if (DTRACE(Ethernet)) {
- IpPtr ip(packet);
- if (ip) {
- DPRINTF(Ethernet, "ID is %d\n", ip->id());
- TcpPtr tcp(ip);
- if (tcp) {
- DPRINTF(Ethernet,
- "Src Port=%d, Dest Port=%d, Seq=%d, Ack=%d\n",
- tcp->sport(), tcp->dport(), tcp->seq(),
- tcp->ack());
- }
- }
- }
-#endif
-
- DDUMP(EthernetData, packet->data, packet->length);
- txBytes += packet->length;
- txPackets++;
-
- DPRINTF(Ethernet, "Packet Transmit: successful txFifo Available %d\n",
- txFifo.avail());
-
- interrupts = Regs::Intr_TxPacket;
- if (txFifo.size() < regs.TxFifoLow)
- interrupts |= Regs::Intr_TxLow;
- devIntrPost(interrupts);
-}
-
-void
-Device::txKick()
-{
- VirtualReg *vnic;
- DPRINTF(EthernetSM, "txKick: txState=%s (txFifo.size=%d)\n",
- TxStateStrings[txState], txFifo.size());
-
- if (txKickTick > curTick()) {
- DPRINTF(EthernetSM, "txKick: exiting, can't run till %d\n",
- txKickTick);
- return;
- }
-
- next:
- 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 = make_shared<EthPacketData>(16384);
- txPacketOffset = 0;
- }
-
- if (txFifo.avail() - txPacket->length <
- Regs::get_TxData_Len(vnic->TxData)) {
- DPRINTF(EthernetSM, "transmit fifo full. Nothing to do.\n");
- goto exit;
- }
-
- txState = txBeginCopy;
- break;
-
- case txBeginCopy:
- if (dmaPending() || drainState() != DrainState::Running)
- goto exit;
-
- txDmaAddr = pciToDma(Regs::get_TxData_Addr(vnic->TxData));
- txDmaLen = Regs::get_TxData_Len(vnic->TxData);
- txDmaData = txPacket->data + txPacketOffset;
- txState = txCopy;
-
- dmaRead(txDmaAddr, txDmaLen, &txDmaEvent, txDmaData);
- break;
-
- case txCopy:
- DPRINTF(EthernetSM, "transmit machine still copying\n");
- goto exit;
-
- case txCopyDone:
- vnic->TxDone = txDmaLen | Regs::TxDone_Complete;
- txPacket->length += txDmaLen;
- if ((vnic->TxData & Regs::TxData_More)) {
- txPacketOffset += txDmaLen;
- txState = txIdle;
- devIntrPost(Regs::Intr_TxDMA);
- break;
- }
-
- 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++;
- }
-
- UdpPtr udp(ip);
- if (udp) {
- udp->sum(0);
- udp->sum(cksum(udp));
- txUdpChecksums++;
- }
-
- ip->sum(0);
- ip->sum(cksum(ip));
- txIpChecksums++;
- }
- }
-
- 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:
- panic("Invalid txState!");
- }
-
- DPRINTF(EthernetSM, "entering next txState=%s\n",
- TxStateStrings[txState]);
-
- goto next;
-
- exit:
- /**
- * @todo do we want to schedule a future kick?
- */
- DPRINTF(EthernetSM, "tx state machine exited txState=%s\n",
- TxStateStrings[txState]);
-}
-
-void
-Device::transferDone()
-{
- if (txFifo.empty()) {
- DPRINTF(Ethernet, "transfer complete: txFifo empty...nothing to do\n");
- return;
- }
-
- DPRINTF(Ethernet, "transfer complete: data in txFifo...schedule xmit\n");
-
- reschedule(txEvent, clockEdge(Cycles(1)), true);
-}
-
-bool
-Device::rxFilter(const EthPacketPtr &packet)
-{
- if (!Regs::get_Config_Filter(regs.Config))
- return false;
-
- panic("receive filter not implemented\n");
- bool drop = true;
-
-#if 0
- string type;
-
- EthHdr *eth = packet->eth();
- if (eth->unicast()) {
- // If we're accepting all unicast addresses
- if (acceptUnicast)
- drop = false;
-
- // If we make a perfect match
- if (acceptPerfect && params->eaddr == eth.dst())
- drop = false;
-
- if (acceptArp && eth->type() == ETH_TYPE_ARP)
- drop = false;
-
- } else if (eth->broadcast()) {
- // if we're accepting broadcasts
- if (acceptBroadcast)
- drop = false;
-
- } else if (eth->multicast()) {
- // if we're accepting all multicasts
- if (acceptMulticast)
- drop = false;
-
- }
-
- if (drop) {
- DPRINTF(Ethernet, "rxFilter drop\n");
- DDUMP(EthernetData, packet->data, packet->length);
- }
-#endif
- return drop;
-}
-
-bool
-Device::recvPacket(EthPacketPtr packet)
-{
- rxBytes += packet->length;
- rxPackets++;
-
- DPRINTF(Ethernet, "Receiving packet from wire, rxFifo Available is %d\n",
- rxFifo.avail());
-
- if (!rxEnable) {
- DPRINTF(Ethernet, "receive disabled...packet dropped\n");
- return true;
- }
-
- if (rxFilter(packet)) {
- DPRINTF(Ethernet, "packet filtered...dropped\n");
- return true;
- }
-
- if (rxFifo.size() >= regs.RxFifoHigh)
- devIntrPost(Regs::Intr_RxHigh);
-
- if (!rxFifo.push(packet)) {
- DPRINTF(Ethernet,
- "packet will not fit in receive buffer...packet dropped\n");
- return false;
- }
-
- // 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
-Device::drainResume()
-{
- Drainable::drainResume();
-
- // During drain we could have left the state machines in a waiting state and
- // they wouldn't get out until some other event occured to kick them.
- // This way they'll get out immediately
- txKick();
- rxKick();
-}
-
-//=====================================================================
-//
-//
-void
-Base::serialize(CheckpointOut &cp) const
-{
- // Serialize the PciDevice base class
- PciDevice::serialize(cp);
-
- SERIALIZE_SCALAR(rxEnable);
- SERIALIZE_SCALAR(txEnable);
- SERIALIZE_SCALAR(cpuIntrEnable);
-
- /*
- * Keep track of pending interrupt status.
- */
- SERIALIZE_SCALAR(intrTick);
- SERIALIZE_SCALAR(cpuPendingIntr);
- Tick intrEventTick = 0;
- if (intrEvent)
- intrEventTick = intrEvent->when();
- SERIALIZE_SCALAR(intrEventTick);
-}
-
-void
-Base::unserialize(CheckpointIn &cp)
-{
- // Unserialize the PciDevice base class
- PciDevice::unserialize(cp);
-
- UNSERIALIZE_SCALAR(rxEnable);
- UNSERIALIZE_SCALAR(txEnable);
- UNSERIALIZE_SCALAR(cpuIntrEnable);
-
- /*
- * Keep track of pending interrupt status.
- */
- UNSERIALIZE_SCALAR(intrTick);
- UNSERIALIZE_SCALAR(cpuPendingIntr);
- Tick intrEventTick;
- UNSERIALIZE_SCALAR(intrEventTick);
- if (intrEventTick) {
- intrEvent = new IntrEvent(this, true);
- schedule(intrEvent, intrEventTick);
- }
-}
-
-void
-Device::serialize(CheckpointOut &cp) const
-{
- int count;
-
- // Serialize the PciDevice base class
- Base::serialize(cp);
-
- if (rxState == rxCopy)
- panic("can't serialize with an in flight dma request rxState=%s",
- RxStateStrings[rxState]);
-
- if (txState == txCopy)
- panic("can't serialize with an in flight dma request txState=%s",
- TxStateStrings[txState]);
-
- /*
- * 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.RxData);
- SERIALIZE_SCALAR(regs.TxData);
-
- /*
- * Serialize the virtual nic state
- */
- int virtualRegsSize = virtualRegs.size();
- SERIALIZE_SCALAR(virtualRegsSize);
- for (int i = 0; i < virtualRegsSize; ++i) {
- const VirtualReg *vnic = &virtualRegs[i];
-
- std::string reg = csprintf("vnic%d", i);
- paramOut(cp, reg + ".RxData", vnic->RxData);
- paramOut(cp, reg + ".RxDone", vnic->RxDone);
- paramOut(cp, reg + ".TxData", vnic->TxData);
- paramOut(cp, reg + ".TxDone", vnic->TxDone);
-
- bool rxPacketExists = vnic->rxIndex != rxFifo.end();
- paramOut(cp, reg + ".rxPacketExists", rxPacketExists);
- if (rxPacketExists) {
- int rxPacket = 0;
- auto i = rxFifo.begin();
- while (i != vnic->rxIndex) {
- assert(i != rxFifo.end());
- ++i;
- ++rxPacket;
- }
-
- paramOut(cp, reg + ".rxPacket", rxPacket);
- paramOut(cp, reg + ".rxPacketOffset", vnic->rxPacketOffset);
- paramOut(cp, reg + ".rxPacketBytes", vnic->rxPacketBytes);
- }
- paramOut(cp, reg + ".rxDoneData", vnic->rxDoneData);
- }
-
- 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::const_iterator i, end;
- for (count = 0, i = rxList.begin(), end = rxList.end(); i != end; ++i)
- paramOut(cp, csprintf("rxList%d", count++), *i);
- int rxListSize = count;
- SERIALIZE_SCALAR(rxListSize);
-
- for (count = 0, i = rxBusy.begin(), end = rxBusy.end(); i != end; ++i)
- paramOut(cp, csprintf("rxBusy%d", count++), *i);
- int rxBusySize = count;
- SERIALIZE_SCALAR(rxBusySize);
-
- for (count = 0, i = txList.begin(), end = txList.end(); i != end; ++i)
- paramOut(cp, 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", cp);
-
- /*
- * Serialize tx state machine
- */
- int txState = this->txState;
- SERIALIZE_SCALAR(txState);
- SERIALIZE_SCALAR(txFull);
- txFifo.serialize("txFifo", cp);
- bool txPacketExists = txPacket != nullptr;
- SERIALIZE_SCALAR(txPacketExists);
- if (txPacketExists) {
- txPacket->serialize("txPacket", cp);
- SERIALIZE_SCALAR(txPacketOffset);
- SERIALIZE_SCALAR(txPacketBytes);
- }
-
- /*
- * If there's a pending transmit, store the time so we can
- * reschedule it later
- */
- Tick transmitTick = txEvent.scheduled() ? txEvent.when() - curTick() : 0;
- SERIALIZE_SCALAR(transmitTick);
-}
-
-void
-Device::unserialize(CheckpointIn &cp)
-{
- // Unserialize the PciDevice base class
- Base::unserialize(cp);
-
- /*
- * 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.RxData);
- UNSERIALIZE_SCALAR(regs.TxData);
-
- UNSERIALIZE_SCALAR(rxActive);
- UNSERIALIZE_SCALAR(rxBusyCount);
- UNSERIALIZE_SCALAR(rxDirtyCount);
- UNSERIALIZE_SCALAR(rxMappedCount);
-
- int rxListSize;
- UNSERIALIZE_SCALAR(rxListSize);
- rxList.clear();
- for (int i = 0; i < rxListSize; ++i) {
- int value;
- paramIn(cp, 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, 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, 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);
-
- int rxFifoPtr;
- UNSERIALIZE_SCALAR(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
- */
- int txState;
- UNSERIALIZE_SCALAR(txState);
- UNSERIALIZE_SCALAR(txFull);
- this->txState = (TxState) txState;
- txFifo.unserialize("txFifo", cp);
- bool txPacketExists;
- UNSERIALIZE_SCALAR(txPacketExists);
- txPacket = 0;
- if (txPacketExists) {
- txPacket = make_shared<EthPacketData>(16384);
- txPacket->unserialize("txPacket", cp);
- 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, reg + ".RxData", vnic->RxData);
- paramIn(cp, reg + ".RxDone", vnic->RxDone);
- paramIn(cp, reg + ".TxData", vnic->TxData);
- paramIn(cp, reg + ".TxDone", vnic->TxDone);
-
- vnic->rxUnique = rxUnique++;
- vnic->txUnique = txUnique++;
-
- bool rxPacketExists;
- paramIn(cp, reg + ".rxPacketExists", rxPacketExists);
- if (rxPacketExists) {
- int rxPacket;
- paramIn(cp, reg + ".rxPacket", rxPacket);
- vnic->rxIndex = rxFifo.begin();
- while (rxPacket--)
- ++vnic->rxIndex;
-
- paramIn(cp, reg + ".rxPacketOffset",
- vnic->rxPacketOffset);
- paramIn(cp, reg + ".rxPacketBytes", vnic->rxPacketBytes);
- } else {
- vnic->rxIndex = rxFifo.end();
- }
- paramIn(cp, reg + ".rxDoneData", vnic->rxDoneData);
- }
-
- /*
- * If there's a pending transmit, reschedule it now
- */
- Tick transmitTick;
- UNSERIALIZE_SCALAR(transmitTick);
- if (transmitTick)
- schedule(txEvent, curTick() + transmitTick);
-
- pioPort.sendRangeChange();
-
-}
-
-} // namespace Sinic
-
-Sinic::Device *
-SinicParams::create()
-{
- return new Sinic::Device(this);
-}