diff options
author | Andreas Sandberg <andreas.sandberg@arm.com> | 2015-12-10 10:35:18 +0000 |
---|---|---|
committer | Andreas Sandberg <andreas.sandberg@arm.com> | 2015-12-10 10:35:18 +0000 |
commit | 23c961a0fd97251ee7c760bc2ff2a011a417ad9b (patch) | |
tree | 0481b7552303373cd3722156b1cef92d813de215 /src/dev/sinic.cc | |
parent | ef097ac4381ad2f14acda640ae198f04d9f7988d (diff) | |
download | gem5-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.cc | 1561 |
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(®s, 0, sizeof(regs)); - - regs.Config = 0; - if (params()->rx_thread) - regs.Config |= Config_RxThread; - if (params()->tx_thread) - regs.Config |= Config_TxThread; - if (params()->rss) - regs.Config |= Config_RSS; - if (params()->zero_copy) - regs.Config |= Config_ZeroCopy; - if (params()->delay_copy) - regs.Config |= Config_DelayCopy; - if (params()->virtual_addr) - regs.Config |= Config_Vaddr; - - if (params()->delay_copy && params()->zero_copy) - panic("Can't delay copy and zero copy"); - - regs.IntrMask = Intr_Soft | Intr_RxHigh | Intr_RxPacket | Intr_TxLow; - regs.RxMaxCopy = params()->rx_max_copy; - regs.TxMaxCopy = params()->tx_max_copy; - regs.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); -} |