sinic.cc revision 11006
17119Sgblack@eecs.umich.edu/*
27119Sgblack@eecs.umich.edu * Copyright (c) 2004-2005 The Regents of The University of Michigan
37120Sgblack@eecs.umich.edu * All rights reserved.
47120Sgblack@eecs.umich.edu *
57120Sgblack@eecs.umich.edu * Redistribution and use in source and binary forms, with or without
67120Sgblack@eecs.umich.edu * modification, are permitted provided that the following conditions are
77120Sgblack@eecs.umich.edu * met: redistributions of source code must retain the above copyright
87120Sgblack@eecs.umich.edu * notice, this list of conditions and the following disclaimer;
97120Sgblack@eecs.umich.edu * redistributions in binary form must reproduce the above copyright
107120Sgblack@eecs.umich.edu * notice, this list of conditions and the following disclaimer in the
117120Sgblack@eecs.umich.edu * documentation and/or other materials provided with the distribution;
127120Sgblack@eecs.umich.edu * neither the name of the copyright holders nor the names of its
137120Sgblack@eecs.umich.edu * contributors may be used to endorse or promote products derived from
147120Sgblack@eecs.umich.edu * this software without specific prior written permission.
157119Sgblack@eecs.umich.edu *
167119Sgblack@eecs.umich.edu * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
177119Sgblack@eecs.umich.edu * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
187119Sgblack@eecs.umich.edu * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
197119Sgblack@eecs.umich.edu * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
207119Sgblack@eecs.umich.edu * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
217119Sgblack@eecs.umich.edu * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
227119Sgblack@eecs.umich.edu * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
237119Sgblack@eecs.umich.edu * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
247119Sgblack@eecs.umich.edu * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
257119Sgblack@eecs.umich.edu * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
267119Sgblack@eecs.umich.edu * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
277119Sgblack@eecs.umich.edu *
287119Sgblack@eecs.umich.edu * Authors: Nathan Binkert
297119Sgblack@eecs.umich.edu */
307119Sgblack@eecs.umich.edu
317119Sgblack@eecs.umich.edu#include <deque>
327119Sgblack@eecs.umich.edu#include <limits>
337119Sgblack@eecs.umich.edu#include <string>
347119Sgblack@eecs.umich.edu
357119Sgblack@eecs.umich.edu#ifdef SINIC_VTOPHYS
367119Sgblack@eecs.umich.edu#include "arch/vtophys.hh"
377119Sgblack@eecs.umich.edu#endif
387119Sgblack@eecs.umich.edu#include "base/compiler.hh"
397119Sgblack@eecs.umich.edu#include "base/debug.hh"
407119Sgblack@eecs.umich.edu#include "base/inet.hh"
417119Sgblack@eecs.umich.edu#include "base/types.hh"
427119Sgblack@eecs.umich.edu#include "config/the_isa.hh"
437119Sgblack@eecs.umich.edu#include "debug/EthernetAll.hh"
447646Sgene.wu@arm.com#include "dev/etherlink.hh"
457646Sgene.wu@arm.com#include "dev/sinic.hh"
467646Sgene.wu@arm.com#include "mem/packet.hh"
477646Sgene.wu@arm.com#include "mem/packet_access.hh"
487646Sgene.wu@arm.com#include "sim/eventq.hh"
497646Sgene.wu@arm.com#include "sim/stats.hh"
507646Sgene.wu@arm.com
517646Sgene.wu@arm.comusing namespace std;
527646Sgene.wu@arm.comusing namespace Net;
537646Sgene.wu@arm.comusing namespace TheISA;
547646Sgene.wu@arm.com
557646Sgene.wu@arm.comnamespace Sinic {
567646Sgene.wu@arm.com
577646Sgene.wu@arm.comconst char *RxStateStrings[] =
587646Sgene.wu@arm.com{
597646Sgene.wu@arm.com    "rxIdle",
607646Sgene.wu@arm.com    "rxFifoBlock",
617646Sgene.wu@arm.com    "rxBeginCopy",
627646Sgene.wu@arm.com    "rxCopy",
637646Sgene.wu@arm.com    "rxCopyDone"
647646Sgene.wu@arm.com};
657646Sgene.wu@arm.com
667646Sgene.wu@arm.comconst char *TxStateStrings[] =
677646Sgene.wu@arm.com{
687646Sgene.wu@arm.com    "txIdle",
697646Sgene.wu@arm.com    "txFifoBlock",
707646Sgene.wu@arm.com    "txBeginCopy",
717646Sgene.wu@arm.com    "txCopy",
727646Sgene.wu@arm.com    "txCopyDone"
737205Sgblack@eecs.umich.edu};
747205Sgblack@eecs.umich.edu
757205Sgblack@eecs.umich.edu
767205Sgblack@eecs.umich.edu///////////////////////////////////////////////////////////////////////
777205Sgblack@eecs.umich.edu//
787205Sgblack@eecs.umich.edu// Sinic PCI Device
797205Sgblack@eecs.umich.edu//
807205Sgblack@eecs.umich.eduBase::Base(const Params *p)
817205Sgblack@eecs.umich.edu    : EtherDevBase(p), rxEnable(false), txEnable(false),
827205Sgblack@eecs.umich.edu      intrDelay(p->intr_delay), intrTick(0), cpuIntrEnable(false),
837205Sgblack@eecs.umich.edu      cpuPendingIntr(false), intrEvent(0), interface(NULL)
847205Sgblack@eecs.umich.edu{
857205Sgblack@eecs.umich.edu}
867205Sgblack@eecs.umich.edu
877205Sgblack@eecs.umich.eduDevice::Device(const Params *p)
887205Sgblack@eecs.umich.edu    : Base(p), rxUnique(0), txUnique(0),
897205Sgblack@eecs.umich.edu      virtualRegs(p->virtual_count < 1 ? 1 : p->virtual_count),
907205Sgblack@eecs.umich.edu      rxFifo(p->rx_fifo_size), txFifo(p->tx_fifo_size),
917205Sgblack@eecs.umich.edu      rxKickTick(0), txKickTick(0),
927205Sgblack@eecs.umich.edu      txEvent(this), rxDmaEvent(this), txDmaEvent(this),
937205Sgblack@eecs.umich.edu      dmaReadDelay(p->dma_read_delay), dmaReadFactor(p->dma_read_factor),
947205Sgblack@eecs.umich.edu      dmaWriteDelay(p->dma_write_delay), dmaWriteFactor(p->dma_write_factor)
957205Sgblack@eecs.umich.edu{
967205Sgblack@eecs.umich.edu    interface = new Interface(name() + ".int0", this);
977205Sgblack@eecs.umich.edu    reset();
987205Sgblack@eecs.umich.edu
997205Sgblack@eecs.umich.edu}
1007205Sgblack@eecs.umich.edu
1017597Sminkyu.jeong@arm.comDevice::~Device()
1027597Sminkyu.jeong@arm.com{}
1037205Sgblack@eecs.umich.edu
1047205Sgblack@eecs.umich.eduvoid
1057646Sgene.wu@arm.comDevice::regStats()
1067646Sgene.wu@arm.com{
1077408Sgblack@eecs.umich.edu    Base::regStats();
1087408Sgblack@eecs.umich.edu
1097408Sgblack@eecs.umich.edu    _maxVnicDistance = 0;
1107205Sgblack@eecs.umich.edu
1117205Sgblack@eecs.umich.edu    maxVnicDistance
1127205Sgblack@eecs.umich.edu        .name(name() + ".maxVnicDistance")
1137205Sgblack@eecs.umich.edu        .desc("maximum vnic distance")
1147205Sgblack@eecs.umich.edu        ;
1157205Sgblack@eecs.umich.edu
1167205Sgblack@eecs.umich.edu    totalVnicDistance
1177205Sgblack@eecs.umich.edu        .name(name() + ".totalVnicDistance")
1187205Sgblack@eecs.umich.edu        .desc("total vnic distance")
1197205Sgblack@eecs.umich.edu        ;
1207205Sgblack@eecs.umich.edu    numVnicDistance
1217205Sgblack@eecs.umich.edu        .name(name() + ".numVnicDistance")
1227205Sgblack@eecs.umich.edu        .desc("number of vnic distance measurements")
1237205Sgblack@eecs.umich.edu        ;
1247205Sgblack@eecs.umich.edu
1257205Sgblack@eecs.umich.edu    avgVnicDistance
1267205Sgblack@eecs.umich.edu        .name(name() + ".avgVnicDistance")
1277205Sgblack@eecs.umich.edu        .desc("average vnic distance")
1287205Sgblack@eecs.umich.edu        ;
1297205Sgblack@eecs.umich.edu
1307205Sgblack@eecs.umich.edu    avgVnicDistance = totalVnicDistance / numVnicDistance;
1317205Sgblack@eecs.umich.edu}
1327205Sgblack@eecs.umich.edu
1337205Sgblack@eecs.umich.eduvoid
1347597Sminkyu.jeong@arm.comDevice::resetStats()
1357597Sminkyu.jeong@arm.com{
1367205Sgblack@eecs.umich.edu    Base::resetStats();
1377205Sgblack@eecs.umich.edu
1387646Sgene.wu@arm.com    _maxVnicDistance = 0;
1397646Sgene.wu@arm.com}
1407408Sgblack@eecs.umich.edu
1417408Sgblack@eecs.umich.eduEtherInt*
1427408Sgblack@eecs.umich.eduDevice::getEthPort(const std::string &if_name, int idx)
1437205Sgblack@eecs.umich.edu{
1447205Sgblack@eecs.umich.edu    if (if_name == "interface") {
1457205Sgblack@eecs.umich.edu        if (interface->getPeer())
1467205Sgblack@eecs.umich.edu            panic("interface already connected to\n");
1477205Sgblack@eecs.umich.edu
1487205Sgblack@eecs.umich.edu        return interface;
1497205Sgblack@eecs.umich.edu    }
1507205Sgblack@eecs.umich.edu    return NULL;
1517205Sgblack@eecs.umich.edu}
1527205Sgblack@eecs.umich.edu
1537205Sgblack@eecs.umich.edu
1547205Sgblack@eecs.umich.eduvoid
1557205Sgblack@eecs.umich.eduDevice::prepareIO(ContextID cpu, int index)
1567205Sgblack@eecs.umich.edu{
1577205Sgblack@eecs.umich.edu    int size = virtualRegs.size();
1587205Sgblack@eecs.umich.edu    if (index > size)
1597205Sgblack@eecs.umich.edu        panic("Trying to access a vnic that doesn't exist %d > %d\n",
1607205Sgblack@eecs.umich.edu              index, size);
1617205Sgblack@eecs.umich.edu}
1627205Sgblack@eecs.umich.edu
1637205Sgblack@eecs.umich.edu//add stats for head of line blocking
1647205Sgblack@eecs.umich.edu//add stats for average fifo length
1657205Sgblack@eecs.umich.edu//add stats for average number of vnics busy
1667205Sgblack@eecs.umich.edu
1677205Sgblack@eecs.umich.eduvoid
1687205Sgblack@eecs.umich.eduDevice::prepareRead(ContextID cpu, int index)
1697408Sgblack@eecs.umich.edu{
1707408Sgblack@eecs.umich.edu    using namespace Regs;
1717408Sgblack@eecs.umich.edu    prepareIO(cpu, index);
1727408Sgblack@eecs.umich.edu
1737205Sgblack@eecs.umich.edu    VirtualReg &vnic = virtualRegs[index];
1747205Sgblack@eecs.umich.edu
1757205Sgblack@eecs.umich.edu    // update rx registers
1767205Sgblack@eecs.umich.edu    uint64_t rxdone = vnic.RxDone;
1777119Sgblack@eecs.umich.edu    rxdone = set_RxDone_Packets(rxdone, rxFifo.countPacketsAfter(rxFifoPtr));
1787119Sgblack@eecs.umich.edu    rxdone = set_RxDone_Empty(rxdone, rxFifo.empty());
1797119Sgblack@eecs.umich.edu    rxdone = set_RxDone_High(rxdone, rxFifo.size() > regs.RxFifoHigh);
1807119Sgblack@eecs.umich.edu    rxdone = set_RxDone_NotHigh(rxdone, rxLow);
1817119Sgblack@eecs.umich.edu    regs.RxData = vnic.RxData;
1827119Sgblack@eecs.umich.edu    regs.RxDone = rxdone;
1837119Sgblack@eecs.umich.edu    regs.RxWait = rxdone;
1847119Sgblack@eecs.umich.edu
1857119Sgblack@eecs.umich.edu    // update tx regsiters
1867119Sgblack@eecs.umich.edu    uint64_t txdone = vnic.TxDone;
1877119Sgblack@eecs.umich.edu    txdone = set_TxDone_Packets(txdone, txFifo.packets());
1887119Sgblack@eecs.umich.edu    txdone = set_TxDone_Full(txdone, txFifo.avail() < regs.TxMaxCopy);
1897119Sgblack@eecs.umich.edu    txdone = set_TxDone_Low(txdone, txFifo.size() < regs.TxFifoLow);
1907119Sgblack@eecs.umich.edu    regs.TxData = vnic.TxData;
1917119Sgblack@eecs.umich.edu    regs.TxDone = txdone;
1927119Sgblack@eecs.umich.edu    regs.TxWait = txdone;
1937119Sgblack@eecs.umich.edu
1947119Sgblack@eecs.umich.edu    int head = 0xffff;
1957119Sgblack@eecs.umich.edu
1967119Sgblack@eecs.umich.edu    if (!rxFifo.empty()) {
1977119Sgblack@eecs.umich.edu        int vnic = rxFifo.begin()->priv;
1987597Sminkyu.jeong@arm.com        if (vnic != -1 && virtualRegs[vnic].rxPacketOffset > 0)
1997597Sminkyu.jeong@arm.com            head = vnic;
2007119Sgblack@eecs.umich.edu    }
2017119Sgblack@eecs.umich.edu
2027646Sgene.wu@arm.com    regs.RxStatus = set_RxStatus_Head(regs.RxStatus, head);
2037646Sgene.wu@arm.com    regs.RxStatus = set_RxStatus_Busy(regs.RxStatus, rxBusyCount);
2047408Sgblack@eecs.umich.edu    regs.RxStatus = set_RxStatus_Mapped(regs.RxStatus, rxMappedCount);
2057408Sgblack@eecs.umich.edu    regs.RxStatus = set_RxStatus_Dirty(regs.RxStatus, rxDirtyCount);
2067408Sgblack@eecs.umich.edu}
2077119Sgblack@eecs.umich.edu
2087119Sgblack@eecs.umich.eduvoid
2097119Sgblack@eecs.umich.eduDevice::prepareWrite(ContextID cpu, int index)
2107119Sgblack@eecs.umich.edu{
2117639Sgblack@eecs.umich.edu    prepareIO(cpu, index);
2127639Sgblack@eecs.umich.edu}
2137639Sgblack@eecs.umich.edu
2147639Sgblack@eecs.umich.edu/**
2157639Sgblack@eecs.umich.edu * I/O read of device register
2167639Sgblack@eecs.umich.edu */
2177639Sgblack@eecs.umich.eduTick
2187639Sgblack@eecs.umich.eduDevice::read(PacketPtr pkt)
2197639Sgblack@eecs.umich.edu{
2207639Sgblack@eecs.umich.edu    assert(config.command & PCI_CMD_MSE);
2217639Sgblack@eecs.umich.edu    assert(pkt->getAddr() >= BARAddrs[0] && pkt->getSize() < BARSize[0]);
2227639Sgblack@eecs.umich.edu
2237639Sgblack@eecs.umich.edu    ContextID cpu = pkt->req->contextId();
2247639Sgblack@eecs.umich.edu    Addr daddr = pkt->getAddr() - BARAddrs[0];
2257639Sgblack@eecs.umich.edu    Addr index = daddr >> Regs::VirtualShift;
2267639Sgblack@eecs.umich.edu    Addr raddr = daddr & Regs::VirtualMask;
2277639Sgblack@eecs.umich.edu
2287639Sgblack@eecs.umich.edu    if (!regValid(raddr))
2297639Sgblack@eecs.umich.edu        panic("invalid register: cpu=%d vnic=%d da=%#x pa=%#x size=%d",
2307639Sgblack@eecs.umich.edu              cpu, index, daddr, pkt->getAddr(), pkt->getSize());
2317639Sgblack@eecs.umich.edu
2327639Sgblack@eecs.umich.edu    const Regs::Info &info = regInfo(raddr);
2337639Sgblack@eecs.umich.edu    if (!info.read)
2347639Sgblack@eecs.umich.edu        panic("read %s (write only): "
2357639Sgblack@eecs.umich.edu              "cpu=%d vnic=%d da=%#x pa=%#x size=%d",
2367639Sgblack@eecs.umich.edu              info.name, cpu, index, daddr, pkt->getAddr(), pkt->getSize());
2378072SGiacomo.Gabrielli@arm.com
2388072SGiacomo.Gabrielli@arm.com        panic("read %s (invalid size): "
2397639Sgblack@eecs.umich.edu              "cpu=%d vnic=%d da=%#x pa=%#x size=%d",
2407639Sgblack@eecs.umich.edu              info.name, cpu, index, daddr, pkt->getAddr(), pkt->getSize());
2417646Sgene.wu@arm.com
2427646Sgene.wu@arm.com    prepareRead(cpu, index);
2437639Sgblack@eecs.umich.edu
2447639Sgblack@eecs.umich.edu    uint64_t value M5_VAR_USED = 0;
2457639Sgblack@eecs.umich.edu    if (pkt->getSize() == 4) {
2467639Sgblack@eecs.umich.edu        uint32_t reg = regData32(raddr);
2477639Sgblack@eecs.umich.edu        pkt->set(reg);
2487639Sgblack@eecs.umich.edu        value = reg;
2497639Sgblack@eecs.umich.edu    }
2507120Sgblack@eecs.umich.edu
2517120Sgblack@eecs.umich.edu    if (pkt->getSize() == 8) {
2527120Sgblack@eecs.umich.edu        uint64_t reg = regData64(raddr);
2537120Sgblack@eecs.umich.edu        pkt->set(reg);
2547120Sgblack@eecs.umich.edu        value = reg;
2557120Sgblack@eecs.umich.edu    }
2567120Sgblack@eecs.umich.edu
2577120Sgblack@eecs.umich.edu    DPRINTF(EthernetPIO,
2587120Sgblack@eecs.umich.edu            "read %s: cpu=%d vnic=%d da=%#x pa=%#x size=%d val=%#x\n",
2597120Sgblack@eecs.umich.edu            info.name, cpu, index, daddr, pkt->getAddr(), pkt->getSize(), value);
2607120Sgblack@eecs.umich.edu
2617120Sgblack@eecs.umich.edu    // reading the interrupt status register has the side effect of
2627120Sgblack@eecs.umich.edu    // clearing it
2637120Sgblack@eecs.umich.edu    if (raddr == Regs::IntrStatus)
2647120Sgblack@eecs.umich.edu        devIntrClear();
2657120Sgblack@eecs.umich.edu
2667120Sgblack@eecs.umich.edu    return pioDelay;
2677120Sgblack@eecs.umich.edu}
2687120Sgblack@eecs.umich.edu
2697120Sgblack@eecs.umich.edu/**
2707120Sgblack@eecs.umich.edu * IPR read of device register
2717120Sgblack@eecs.umich.edu
2727120Sgblack@eecs.umich.edu    Fault
2737120Sgblack@eecs.umich.eduDevice::iprRead(Addr daddr, ContextID cpu, uint64_t &result)
2747120Sgblack@eecs.umich.edu{
2757597Sminkyu.jeong@arm.com    if (!regValid(daddr))
2767597Sminkyu.jeong@arm.com        panic("invalid address: da=%#x", daddr);
2777120Sgblack@eecs.umich.edu
2787120Sgblack@eecs.umich.edu    const Regs::Info &info = regInfo(daddr);
2797646Sgene.wu@arm.com    if (!info.read)
2807646Sgene.wu@arm.com        panic("reading %s (write only): cpu=%d da=%#x", info.name, cpu, daddr);
2817408Sgblack@eecs.umich.edu
2827408Sgblack@eecs.umich.edu    DPRINTF(EthernetPIO, "IPR read %s: cpu=%d da=%#x\n",
2837408Sgblack@eecs.umich.edu            info.name, cpu, daddr);
2847120Sgblack@eecs.umich.edu
2857120Sgblack@eecs.umich.edu    prepareRead(cpu, 0);
2867120Sgblack@eecs.umich.edu
2877120Sgblack@eecs.umich.edu    if (info.size == 4)
2887639Sgblack@eecs.umich.edu        result = regData32(daddr);
2897639Sgblack@eecs.umich.edu
2907639Sgblack@eecs.umich.edu    if (info.size == 8)
2917639Sgblack@eecs.umich.edu        result = regData64(daddr);
2927639Sgblack@eecs.umich.edu
2937639Sgblack@eecs.umich.edu    DPRINTF(EthernetPIO, "IPR read %s: cpu=%s da=%#x val=%#x\n",
2947639Sgblack@eecs.umich.edu            info.name, cpu, result);
2957639Sgblack@eecs.umich.edu
2967639Sgblack@eecs.umich.edu    return NoFault;
2977639Sgblack@eecs.umich.edu}
2987639Sgblack@eecs.umich.edu*/
2997639Sgblack@eecs.umich.edu/**
3007639Sgblack@eecs.umich.edu * I/O write of device register
3017639Sgblack@eecs.umich.edu */
3027639Sgblack@eecs.umich.eduTick
3037639Sgblack@eecs.umich.eduDevice::write(PacketPtr pkt)
3047639Sgblack@eecs.umich.edu{
3057639Sgblack@eecs.umich.edu    assert(config.command & PCI_CMD_MSE);
3067639Sgblack@eecs.umich.edu    assert(pkt->getAddr() >= BARAddrs[0] && pkt->getSize() < BARSize[0]);
3077639Sgblack@eecs.umich.edu
3087639Sgblack@eecs.umich.edu    ContextID cpu = pkt->req->contextId();
3097639Sgblack@eecs.umich.edu    Addr daddr = pkt->getAddr() - BARAddrs[0];
3107639Sgblack@eecs.umich.edu    Addr index = daddr >> Regs::VirtualShift;
3117639Sgblack@eecs.umich.edu    Addr raddr = daddr & Regs::VirtualMask;
3127639Sgblack@eecs.umich.edu
3137639Sgblack@eecs.umich.edu    if (!regValid(raddr))
3147639Sgblack@eecs.umich.edu        panic("invalid register: cpu=%d, da=%#x pa=%#x size=%d",
3157639Sgblack@eecs.umich.edu                cpu, daddr, pkt->getAddr(), pkt->getSize());
3167639Sgblack@eecs.umich.edu
3177639Sgblack@eecs.umich.edu    const Regs::Info &info = regInfo(raddr);
3188072SGiacomo.Gabrielli@arm.com    if (!info.write)
3198072SGiacomo.Gabrielli@arm.com        panic("write %s (read only): "
3207639Sgblack@eecs.umich.edu              "cpu=%d vnic=%d da=%#x pa=%#x size=%d",
3217639Sgblack@eecs.umich.edu              info.name, cpu, index, daddr, pkt->getAddr(), pkt->getSize());
3227646Sgene.wu@arm.com
3237646Sgene.wu@arm.com    if (pkt->getSize() != info.size)
3247639Sgblack@eecs.umich.edu        panic("write %s (invalid size): "
3257639Sgblack@eecs.umich.edu              "cpu=%d vnic=%d da=%#x pa=%#x size=%d",
3267639Sgblack@eecs.umich.edu              info.name, cpu, index, daddr, pkt->getAddr(), pkt->getSize());
3277639Sgblack@eecs.umich.edu
3287639Sgblack@eecs.umich.edu    VirtualReg &vnic = virtualRegs[index];
3297639Sgblack@eecs.umich.edu
3307639Sgblack@eecs.umich.edu    DPRINTF(EthernetPIO,
3317303Sgblack@eecs.umich.edu            "write %s vnic %d: cpu=%d val=%#x da=%#x pa=%#x size=%d\n",
3327303Sgblack@eecs.umich.edu            info.name, index, cpu, info.size == 4 ? pkt->get<uint32_t>() :
3337303Sgblack@eecs.umich.edu            pkt->get<uint64_t>(), daddr, pkt->getAddr(), pkt->getSize());
3347303Sgblack@eecs.umich.edu
3357303Sgblack@eecs.umich.edu    prepareWrite(cpu, index);
3367303Sgblack@eecs.umich.edu
3377303Sgblack@eecs.umich.edu    switch (raddr) {
3387303Sgblack@eecs.umich.edu      case Regs::Config:
3397303Sgblack@eecs.umich.edu        changeConfig(pkt->get<uint32_t>());
3407303Sgblack@eecs.umich.edu        break;
3417303Sgblack@eecs.umich.edu
3427303Sgblack@eecs.umich.edu      case Regs::Command:
3437303Sgblack@eecs.umich.edu        command(pkt->get<uint32_t>());
3447303Sgblack@eecs.umich.edu        break;
3457303Sgblack@eecs.umich.edu
3467303Sgblack@eecs.umich.edu      case Regs::IntrStatus:
3477303Sgblack@eecs.umich.edu        devIntrClear(regs.IntrStatus & pkt->get<uint32_t>());
3487303Sgblack@eecs.umich.edu        break;
3497303Sgblack@eecs.umich.edu
3507303Sgblack@eecs.umich.edu      case Regs::IntrMask:
3517303Sgblack@eecs.umich.edu        devIntrChangeMask(pkt->get<uint32_t>());
3527303Sgblack@eecs.umich.edu        break;
3537303Sgblack@eecs.umich.edu
3547303Sgblack@eecs.umich.edu      case Regs::RxData:
3557303Sgblack@eecs.umich.edu        if (Regs::get_RxDone_Busy(vnic.RxDone))
3567303Sgblack@eecs.umich.edu            panic("receive machine busy with another request! rxState=%s",
3577303Sgblack@eecs.umich.edu                  RxStateStrings[rxState]);
3587303Sgblack@eecs.umich.edu
3597303Sgblack@eecs.umich.edu        vnic.rxUnique = rxUnique++;
3607303Sgblack@eecs.umich.edu        vnic.RxDone = Regs::RxDone_Busy;
3617303Sgblack@eecs.umich.edu        vnic.RxData = pkt->get<uint64_t>();
3627597Sminkyu.jeong@arm.com        rxBusyCount++;
3637597Sminkyu.jeong@arm.com
3647303Sgblack@eecs.umich.edu        if (Regs::get_RxData_Vaddr(pkt->get<uint64_t>())) {
3657303Sgblack@eecs.umich.edu            panic("vtophys not implemented in newmem");
3667646Sgene.wu@arm.com#ifdef SINIC_VTOPHYS
3677646Sgene.wu@arm.com            Addr vaddr = Regs::get_RxData_Addr(reg64);
3687408Sgblack@eecs.umich.edu            Addr paddr = vtophys(req->xc, vaddr);
3697408Sgblack@eecs.umich.edu            DPRINTF(EthernetPIO, "write RxData vnic %d (rxunique %d): "
3707408Sgblack@eecs.umich.edu                    "vaddr=%#x, paddr=%#x\n",
3717303Sgblack@eecs.umich.edu                    index, vnic.rxUnique, vaddr, paddr);
3727303Sgblack@eecs.umich.edu
3737303Sgblack@eecs.umich.edu            vnic.RxData = Regs::set_RxData_Addr(vnic.RxData, paddr);
3747303Sgblack@eecs.umich.edu#endif
3757303Sgblack@eecs.umich.edu        } else {
3767303Sgblack@eecs.umich.edu            DPRINTF(EthernetPIO, "write RxData vnic %d (rxunique %d)\n",
3777303Sgblack@eecs.umich.edu                    index, vnic.rxUnique);
3787303Sgblack@eecs.umich.edu        }
3797303Sgblack@eecs.umich.edu
3807303Sgblack@eecs.umich.edu        if (vnic.rxIndex == rxFifo.end()) {
3817303Sgblack@eecs.umich.edu            DPRINTF(EthernetPIO, "request new packet...appending to rxList\n");
3827303Sgblack@eecs.umich.edu            rxList.push_back(index);
3837303Sgblack@eecs.umich.edu        } else {
3847303Sgblack@eecs.umich.edu            DPRINTF(EthernetPIO, "packet exists...appending to rxBusy\n");
3857303Sgblack@eecs.umich.edu            rxBusy.push_back(index);
3867303Sgblack@eecs.umich.edu        }
3877303Sgblack@eecs.umich.edu
3887303Sgblack@eecs.umich.edu        if (rxEnable && (rxState == rxIdle || rxState == rxFifoBlock)) {
3897303Sgblack@eecs.umich.edu            rxState = rxFifoBlock;
3907303Sgblack@eecs.umich.edu            rxKick();
3917303Sgblack@eecs.umich.edu        }
3927303Sgblack@eecs.umich.edu        break;
3937303Sgblack@eecs.umich.edu
3947303Sgblack@eecs.umich.edu      case Regs::TxData:
3957303Sgblack@eecs.umich.edu        if (Regs::get_TxDone_Busy(vnic.TxDone))
3967597Sminkyu.jeong@arm.com            panic("transmit machine busy with another request! txState=%s",
3977597Sminkyu.jeong@arm.com                  TxStateStrings[txState]);
3987303Sgblack@eecs.umich.edu
3997646Sgene.wu@arm.com        vnic.txUnique = txUnique++;
4007646Sgene.wu@arm.com        vnic.TxDone = Regs::TxDone_Busy;
4017408Sgblack@eecs.umich.edu
4027408Sgblack@eecs.umich.edu        if (Regs::get_TxData_Vaddr(pkt->get<uint64_t>())) {
4037408Sgblack@eecs.umich.edu            panic("vtophys won't work here in newmem.\n");
4047303Sgblack@eecs.umich.edu#ifdef SINIC_VTOPHYS
4057303Sgblack@eecs.umich.edu            Addr vaddr = Regs::get_TxData_Addr(reg64);
4067303Sgblack@eecs.umich.edu            Addr paddr = vtophys(req->xc, vaddr);
4077303Sgblack@eecs.umich.edu            DPRINTF(EthernetPIO, "write TxData vnic %d (txunique %d): "
4087120Sgblack@eecs.umich.edu                    "vaddr=%#x, paddr=%#x\n",
4097120Sgblack@eecs.umich.edu                    index, vnic.txUnique, vaddr, paddr);
4107120Sgblack@eecs.umich.edu
4117120Sgblack@eecs.umich.edu            vnic.TxData = Regs::set_TxData_Addr(vnic.TxData, paddr);
4127120Sgblack@eecs.umich.edu#endif
4137120Sgblack@eecs.umich.edu        } else {
4147120Sgblack@eecs.umich.edu            DPRINTF(EthernetPIO, "write TxData vnic %d (txunique %d)\n",
4157120Sgblack@eecs.umich.edu                    index, vnic.txUnique);
4167120Sgblack@eecs.umich.edu        }
4177120Sgblack@eecs.umich.edu
4187120Sgblack@eecs.umich.edu        if (txList.empty() || txList.front() != index)
4197120Sgblack@eecs.umich.edu            txList.push_back(index);
4207120Sgblack@eecs.umich.edu        if (txEnable && txState == txIdle && txList.front() == index) {
4217120Sgblack@eecs.umich.edu            txState = txFifoBlock;
4227120Sgblack@eecs.umich.edu            txKick();
4237120Sgblack@eecs.umich.edu        }
4247120Sgblack@eecs.umich.edu        break;
4257120Sgblack@eecs.umich.edu    }
4267120Sgblack@eecs.umich.edu
4277120Sgblack@eecs.umich.edu    return pioDelay;
4287120Sgblack@eecs.umich.edu}
4297597Sminkyu.jeong@arm.com
4307597Sminkyu.jeong@arm.comvoid
4317120Sgblack@eecs.umich.eduDevice::devIntrPost(uint32_t interrupts)
4327120Sgblack@eecs.umich.edu{
4337646Sgene.wu@arm.com    if ((interrupts & Regs::Intr_Res))
4347646Sgene.wu@arm.com        panic("Cannot set a reserved interrupt");
4357408Sgblack@eecs.umich.edu
4367408Sgblack@eecs.umich.edu    regs.IntrStatus |= interrupts;
4377408Sgblack@eecs.umich.edu
4387120Sgblack@eecs.umich.edu    DPRINTF(EthernetIntr,
4397120Sgblack@eecs.umich.edu            "interrupt written to intStatus: intr=%#x status=%#x mask=%#x\n",
4407120Sgblack@eecs.umich.edu            interrupts, regs.IntrStatus, regs.IntrMask);
4417120Sgblack@eecs.umich.edu
4427639Sgblack@eecs.umich.edu    interrupts = regs.IntrStatus & regs.IntrMask;
4437639Sgblack@eecs.umich.edu
4447639Sgblack@eecs.umich.edu    // Intr_RxHigh is special, we only signal it if we've emptied the fifo
4457639Sgblack@eecs.umich.edu    // and then filled it above the high watermark
4467639Sgblack@eecs.umich.edu    if (rxEmpty)
4477639Sgblack@eecs.umich.edu        rxEmpty = false;
4487639Sgblack@eecs.umich.edu    else
4497639Sgblack@eecs.umich.edu        interrupts &= ~Regs::Intr_RxHigh;
4507639Sgblack@eecs.umich.edu
4517639Sgblack@eecs.umich.edu    // Intr_TxLow is special, we only signal it if we've filled up the fifo
4527639Sgblack@eecs.umich.edu    // and then dropped below the low watermark
4537639Sgblack@eecs.umich.edu    if (txFull)
4547639Sgblack@eecs.umich.edu        txFull = false;
4557639Sgblack@eecs.umich.edu    else
4567639Sgblack@eecs.umich.edu        interrupts &= ~Regs::Intr_TxLow;
4577639Sgblack@eecs.umich.edu
4587639Sgblack@eecs.umich.edu    if (interrupts) {
4597639Sgblack@eecs.umich.edu        Tick when = curTick();
4607639Sgblack@eecs.umich.edu        if ((interrupts & Regs::Intr_NoDelay) == 0)
4617639Sgblack@eecs.umich.edu            when += intrDelay;
4627639Sgblack@eecs.umich.edu        cpuIntrPost(when);
4637639Sgblack@eecs.umich.edu    }
4647639Sgblack@eecs.umich.edu}
4657639Sgblack@eecs.umich.edu
4668072SGiacomo.Gabrielli@arm.comvoid
4678072SGiacomo.Gabrielli@arm.comDevice::devIntrClear(uint32_t interrupts)
4687639Sgblack@eecs.umich.edu{
4697639Sgblack@eecs.umich.edu    if ((interrupts & Regs::Intr_Res))
4707646Sgene.wu@arm.com        panic("Cannot clear a reserved interrupt");
4717646Sgene.wu@arm.com
4727639Sgblack@eecs.umich.edu    regs.IntrStatus &= ~interrupts;
4737639Sgblack@eecs.umich.edu
4747639Sgblack@eecs.umich.edu    DPRINTF(EthernetIntr,
4757639Sgblack@eecs.umich.edu            "interrupt cleared from intStatus: intr=%x status=%x mask=%x\n",
4767639Sgblack@eecs.umich.edu            interrupts, regs.IntrStatus, regs.IntrMask);
4777639Sgblack@eecs.umich.edu
4787639Sgblack@eecs.umich.edu    if (!(regs.IntrStatus & regs.IntrMask))
4797119Sgblack@eecs.umich.edu        cpuIntrClear();
4807119Sgblack@eecs.umich.edu}
4817119Sgblack@eecs.umich.edu
4827119Sgblack@eecs.umich.eduvoid
4837119Sgblack@eecs.umich.eduDevice::devIntrChangeMask(uint32_t newmask)
4847119Sgblack@eecs.umich.edu{
4857119Sgblack@eecs.umich.edu    if (regs.IntrMask == newmask)
4867119Sgblack@eecs.umich.edu        return;
4877119Sgblack@eecs.umich.edu
4887119Sgblack@eecs.umich.edu    regs.IntrMask = newmask;
4897119Sgblack@eecs.umich.edu
4907119Sgblack@eecs.umich.edu    DPRINTF(EthernetIntr,
4917119Sgblack@eecs.umich.edu            "interrupt mask changed: intStatus=%x intMask=%x masked=%x\n",
4927119Sgblack@eecs.umich.edu            regs.IntrStatus, regs.IntrMask, regs.IntrStatus & regs.IntrMask);
4937119Sgblack@eecs.umich.edu
4947119Sgblack@eecs.umich.edu    if (regs.IntrStatus & regs.IntrMask)
4957597Sminkyu.jeong@arm.com        cpuIntrPost(curTick());
4967597Sminkyu.jeong@arm.com    else
4977646Sgene.wu@arm.com        cpuIntrClear();
4987646Sgene.wu@arm.com}
4997597Sminkyu.jeong@arm.com
5007597Sminkyu.jeong@arm.comvoid
5017119Sgblack@eecs.umich.eduBase::cpuIntrPost(Tick when)
5027119Sgblack@eecs.umich.edu{
5037119Sgblack@eecs.umich.edu    // If the interrupt you want to post is later than an interrupt
5047119Sgblack@eecs.umich.edu    // already scheduled, just let it post in the coming one and don't
5057119Sgblack@eecs.umich.edu    // schedule another.
5067119Sgblack@eecs.umich.edu    // HOWEVER, must be sure that the scheduled intrTick is in the
5077639Sgblack@eecs.umich.edu    // future (this was formerly the source of a bug)
5087639Sgblack@eecs.umich.edu    /**
5097639Sgblack@eecs.umich.edu     * @todo this warning should be removed and the intrTick code should
5107639Sgblack@eecs.umich.edu     * be fixed.
5117639Sgblack@eecs.umich.edu     */
5127639Sgblack@eecs.umich.edu    assert(when >= curTick());
5137639Sgblack@eecs.umich.edu    assert(intrTick >= curTick() || intrTick == 0);
5147639Sgblack@eecs.umich.edu    if (!cpuIntrEnable) {
5157639Sgblack@eecs.umich.edu        DPRINTF(EthernetIntr, "interrupts not enabled.\n",
5167639Sgblack@eecs.umich.edu                intrTick);
5177639Sgblack@eecs.umich.edu        return;
5187639Sgblack@eecs.umich.edu    }
5197639Sgblack@eecs.umich.edu
5207639Sgblack@eecs.umich.edu    if (when > intrTick && intrTick != 0) {
5217639Sgblack@eecs.umich.edu        DPRINTF(EthernetIntr, "don't need to schedule event...intrTick=%d\n",
5227639Sgblack@eecs.umich.edu                intrTick);
5237639Sgblack@eecs.umich.edu        return;
5248072SGiacomo.Gabrielli@arm.com    }
5258072SGiacomo.Gabrielli@arm.com
5268072SGiacomo.Gabrielli@arm.com    intrTick = when;
5278072SGiacomo.Gabrielli@arm.com    if (intrTick < curTick()) {
5288072SGiacomo.Gabrielli@arm.com        Debug::breakpoint();
5298072SGiacomo.Gabrielli@arm.com        intrTick = curTick();
5307639Sgblack@eecs.umich.edu    }
5317639Sgblack@eecs.umich.edu
5327639Sgblack@eecs.umich.edu    DPRINTF(EthernetIntr, "going to schedule an interrupt for intrTick=%d\n",
5337639Sgblack@eecs.umich.edu            intrTick);
5347639Sgblack@eecs.umich.edu
5357639Sgblack@eecs.umich.edu    if (intrEvent)
5367119Sgblack@eecs.umich.edu        intrEvent->squash();
5377119Sgblack@eecs.umich.edu    intrEvent = new IntrEvent(this, true);
5387119Sgblack@eecs.umich.edu    schedule(intrEvent, intrTick);
5397119Sgblack@eecs.umich.edu}
5407119Sgblack@eecs.umich.edu
5417119Sgblack@eecs.umich.eduvoid
5427119Sgblack@eecs.umich.eduBase::cpuInterrupt()
5437119Sgblack@eecs.umich.edu{
5447119Sgblack@eecs.umich.edu    assert(intrTick == curTick());
5457119Sgblack@eecs.umich.edu
5467119Sgblack@eecs.umich.edu    // Whether or not there's a pending interrupt, we don't care about
5477119Sgblack@eecs.umich.edu    // it anymore
5487119Sgblack@eecs.umich.edu    intrEvent = 0;
5497119Sgblack@eecs.umich.edu    intrTick = 0;
5507119Sgblack@eecs.umich.edu
5517119Sgblack@eecs.umich.edu    // Don't send an interrupt if there's already one
5527119Sgblack@eecs.umich.edu    if (cpuPendingIntr) {
5537119Sgblack@eecs.umich.edu        DPRINTF(EthernetIntr,
5547119Sgblack@eecs.umich.edu                "would send an interrupt now, but there's already pending\n");
5557119Sgblack@eecs.umich.edu    } else {
5567119Sgblack@eecs.umich.edu        // Send interrupt
5577119Sgblack@eecs.umich.edu        cpuPendingIntr = true;
5587119Sgblack@eecs.umich.edu
5597119Sgblack@eecs.umich.edu        DPRINTF(EthernetIntr, "posting interrupt\n");
5607408Sgblack@eecs.umich.edu        intrPost();
5617408Sgblack@eecs.umich.edu    }
5627408Sgblack@eecs.umich.edu}
5637408Sgblack@eecs.umich.edu
5647119Sgblack@eecs.umich.eduvoid
5657119Sgblack@eecs.umich.eduBase::cpuIntrClear()
5667119Sgblack@eecs.umich.edu{
5677119Sgblack@eecs.umich.edu    if (!cpuPendingIntr)
5687639Sgblack@eecs.umich.edu        return;
5697639Sgblack@eecs.umich.edu
5707639Sgblack@eecs.umich.edu    if (intrEvent) {
5717639Sgblack@eecs.umich.edu        intrEvent->squash();
5727639Sgblack@eecs.umich.edu        intrEvent = 0;
5737639Sgblack@eecs.umich.edu    }
5747639Sgblack@eecs.umich.edu
5757639Sgblack@eecs.umich.edu    intrTick = 0;
5767639Sgblack@eecs.umich.edu
5777639Sgblack@eecs.umich.edu    cpuPendingIntr = false;
5787639Sgblack@eecs.umich.edu
5797639Sgblack@eecs.umich.edu    DPRINTF(EthernetIntr, "clearing cchip interrupt\n");
5807639Sgblack@eecs.umich.edu    intrClear();
5817639Sgblack@eecs.umich.edu}
5827639Sgblack@eecs.umich.edu
5837639Sgblack@eecs.umich.edubool
5847639Sgblack@eecs.umich.eduBase::cpuIntrPending() const
5857639Sgblack@eecs.umich.edu{ return cpuPendingIntr; }
5867639Sgblack@eecs.umich.edu
5877639Sgblack@eecs.umich.eduvoid
5887639Sgblack@eecs.umich.eduDevice::changeConfig(uint32_t newconf)
5897639Sgblack@eecs.umich.edu{
5907639Sgblack@eecs.umich.edu    uint32_t changed = regs.Config ^ newconf;
5917639Sgblack@eecs.umich.edu    if (!changed)
5927639Sgblack@eecs.umich.edu        return;
5937639Sgblack@eecs.umich.edu
5947639Sgblack@eecs.umich.edu    regs.Config = newconf;
5957639Sgblack@eecs.umich.edu
5967639Sgblack@eecs.umich.edu    if ((changed & Regs::Config_IntEn)) {
5977639Sgblack@eecs.umich.edu        cpuIntrEnable = regs.Config & Regs::Config_IntEn;
5987639Sgblack@eecs.umich.edu        if (cpuIntrEnable) {
5997639Sgblack@eecs.umich.edu            if (regs.IntrStatus & regs.IntrMask)
6007639Sgblack@eecs.umich.edu                cpuIntrPost(curTick());
6017639Sgblack@eecs.umich.edu        } else {
6027120Sgblack@eecs.umich.edu            cpuIntrClear();
6037120Sgblack@eecs.umich.edu        }
6047120Sgblack@eecs.umich.edu    }
6057120Sgblack@eecs.umich.edu
6067120Sgblack@eecs.umich.edu    if ((changed & Regs::Config_TxEn)) {
6077712Sgblack@eecs.umich.edu        txEnable = regs.Config & Regs::Config_TxEn;
6087712Sgblack@eecs.umich.edu        if (txEnable)
6097408Sgblack@eecs.umich.edu            txKick();
6107408Sgblack@eecs.umich.edu    }
6117712Sgblack@eecs.umich.edu
6127120Sgblack@eecs.umich.edu    if ((changed & Regs::Config_RxEn)) {
6137120Sgblack@eecs.umich.edu        rxEnable = regs.Config & Regs::Config_RxEn;
6147120Sgblack@eecs.umich.edu        if (rxEnable)
6157639Sgblack@eecs.umich.edu            rxKick();
6167639Sgblack@eecs.umich.edu    }
6177639Sgblack@eecs.umich.edu}
6187639Sgblack@eecs.umich.edu
6197639Sgblack@eecs.umich.eduvoid
6207639Sgblack@eecs.umich.eduDevice::command(uint32_t command)
6217712Sgblack@eecs.umich.edu{
6227712Sgblack@eecs.umich.edu    if (command & Regs::Command_Intr)
6237639Sgblack@eecs.umich.edu        devIntrPost(Regs::Intr_Soft);
6247639Sgblack@eecs.umich.edu
6257712Sgblack@eecs.umich.edu    if (command & Regs::Command_Reset)
6267639Sgblack@eecs.umich.edu        reset();
6277639Sgblack@eecs.umich.edu}
6287639Sgblack@eecs.umich.edu
6297303Sgblack@eecs.umich.eduvoid
6307303Sgblack@eecs.umich.eduDevice::reset()
6317303Sgblack@eecs.umich.edu{
6327303Sgblack@eecs.umich.edu    using namespace Regs;
6337303Sgblack@eecs.umich.edu
6347303Sgblack@eecs.umich.edu    memset(&regs, 0, sizeof(regs));
6357303Sgblack@eecs.umich.edu
6367303Sgblack@eecs.umich.edu    regs.Config = 0;
6377303Sgblack@eecs.umich.edu    if (params()->rx_thread)
6387303Sgblack@eecs.umich.edu        regs.Config |= Config_RxThread;
6397303Sgblack@eecs.umich.edu    if (params()->tx_thread)
6407303Sgblack@eecs.umich.edu        regs.Config |= Config_TxThread;
6417303Sgblack@eecs.umich.edu    if (params()->rss)
6427303Sgblack@eecs.umich.edu        regs.Config |= Config_RSS;
6437303Sgblack@eecs.umich.edu    if (params()->zero_copy)
6447303Sgblack@eecs.umich.edu        regs.Config |= Config_ZeroCopy;
6457303Sgblack@eecs.umich.edu    if (params()->delay_copy)
6467303Sgblack@eecs.umich.edu        regs.Config |= Config_DelayCopy;
6477303Sgblack@eecs.umich.edu    if (params()->virtual_addr)
6487303Sgblack@eecs.umich.edu        regs.Config |= Config_Vaddr;
6497408Sgblack@eecs.umich.edu
6507408Sgblack@eecs.umich.edu    if (params()->delay_copy && params()->zero_copy)
6517408Sgblack@eecs.umich.edu        panic("Can't delay copy and zero copy");
6527408Sgblack@eecs.umich.edu
6537303Sgblack@eecs.umich.edu    regs.IntrMask = Intr_Soft | Intr_RxHigh | Intr_RxPacket | Intr_TxLow;
6547303Sgblack@eecs.umich.edu    regs.RxMaxCopy = params()->rx_max_copy;
6557303Sgblack@eecs.umich.edu    regs.TxMaxCopy = params()->tx_max_copy;
6567303Sgblack@eecs.umich.edu    regs.ZeroCopySize = params()->zero_copy_size;
6577291Sgblack@eecs.umich.edu    regs.ZeroCopyMark = params()->zero_copy_threshold;
6587291Sgblack@eecs.umich.edu    regs.VirtualCount = params()->virtual_count;
6597291Sgblack@eecs.umich.edu    regs.RxMaxIntr = params()->rx_max_intr;
6607291Sgblack@eecs.umich.edu    regs.RxFifoSize = params()->rx_fifo_size;
6617291Sgblack@eecs.umich.edu    regs.TxFifoSize = params()->tx_fifo_size;
6627291Sgblack@eecs.umich.edu    regs.RxFifoLow = params()->rx_fifo_low_mark;
6637291Sgblack@eecs.umich.edu    regs.TxFifoLow = params()->tx_fifo_threshold;
6647291Sgblack@eecs.umich.edu    regs.RxFifoHigh = params()->rx_fifo_threshold;
6657291Sgblack@eecs.umich.edu    regs.TxFifoHigh = params()->tx_fifo_high_mark;
6667291Sgblack@eecs.umich.edu    regs.HwAddr = params()->hardware_address;
6677291Sgblack@eecs.umich.edu
6687291Sgblack@eecs.umich.edu    if (regs.RxMaxCopy < regs.ZeroCopyMark)
6697291Sgblack@eecs.umich.edu        panic("Must be able to copy at least as many bytes as the threshold");
6707291Sgblack@eecs.umich.edu
6717291Sgblack@eecs.umich.edu    if (regs.ZeroCopySize >= regs.ZeroCopyMark)
6727291Sgblack@eecs.umich.edu        panic("The number of bytes to copy must be less than the threshold");
6737291Sgblack@eecs.umich.edu
6747291Sgblack@eecs.umich.edu    rxList.clear();
6757291Sgblack@eecs.umich.edu    rxBusy.clear();
6767291Sgblack@eecs.umich.edu    rxActive = -1;
6777312Sgblack@eecs.umich.edu    txList.clear();
6787312Sgblack@eecs.umich.edu    rxBusyCount = 0;
6797312Sgblack@eecs.umich.edu    rxDirtyCount = 0;
6807312Sgblack@eecs.umich.edu    rxMappedCount = 0;
6817312Sgblack@eecs.umich.edu
6827312Sgblack@eecs.umich.edu    rxState = rxIdle;
6837312Sgblack@eecs.umich.edu    txState = txIdle;
6847312Sgblack@eecs.umich.edu
6857312Sgblack@eecs.umich.edu    rxFifo.clear();
6867312Sgblack@eecs.umich.edu    rxFifoPtr = rxFifo.end();
6877312Sgblack@eecs.umich.edu    txFifo.clear();
6887312Sgblack@eecs.umich.edu    rxEmpty = false;
6897312Sgblack@eecs.umich.edu    rxLow = true;
6907312Sgblack@eecs.umich.edu    txFull = false;
6917312Sgblack@eecs.umich.edu
6927312Sgblack@eecs.umich.edu    int size = virtualRegs.size();
6937312Sgblack@eecs.umich.edu    virtualRegs.clear();
6947312Sgblack@eecs.umich.edu    virtualRegs.resize(size);
6957312Sgblack@eecs.umich.edu    for (int i = 0; i < size; ++i)
6967312Sgblack@eecs.umich.edu        virtualRegs[i].rxIndex = rxFifo.end();
6977205Sgblack@eecs.umich.edu}
6987205Sgblack@eecs.umich.edu
6997205Sgblack@eecs.umich.eduvoid
7007205Sgblack@eecs.umich.eduDevice::rxDmaDone()
7017205Sgblack@eecs.umich.edu{
7027205Sgblack@eecs.umich.edu    assert(rxState == rxCopy);
7037205Sgblack@eecs.umich.edu    rxState = rxCopyDone;
7047205Sgblack@eecs.umich.edu    DPRINTF(EthernetDMA, "end rx dma write paddr=%#x len=%d\n",
7057205Sgblack@eecs.umich.edu            rxDmaAddr, rxDmaLen);
7067205Sgblack@eecs.umich.edu    DDUMP(EthernetData, rxDmaData, rxDmaLen);
7077205Sgblack@eecs.umich.edu
7087205Sgblack@eecs.umich.edu    // If the transmit state machine  has a pending DMA, let it go first
7097205Sgblack@eecs.umich.edu    if (txState == txBeginCopy)
7107205Sgblack@eecs.umich.edu        txKick();
7117205Sgblack@eecs.umich.edu
7127205Sgblack@eecs.umich.edu    rxKick();
7137205Sgblack@eecs.umich.edu}
7147205Sgblack@eecs.umich.edu
7157205Sgblack@eecs.umich.eduvoid
7167205Sgblack@eecs.umich.eduDevice::rxKick()
7177279Sgblack@eecs.umich.edu{
7187279Sgblack@eecs.umich.edu    VirtualReg *vnic = NULL;
7197279Sgblack@eecs.umich.edu
7207279Sgblack@eecs.umich.edu    DPRINTF(EthernetSM, "rxKick: rxState=%s (rxFifo.size=%d)\n",
7217279Sgblack@eecs.umich.edu            RxStateStrings[rxState], rxFifo.size());
7227279Sgblack@eecs.umich.edu
7237279Sgblack@eecs.umich.edu    if (rxKickTick > curTick()) {
7247279Sgblack@eecs.umich.edu        DPRINTF(EthernetSM, "rxKick: exiting, can't run till %d\n",
7257279Sgblack@eecs.umich.edu                rxKickTick);
7267279Sgblack@eecs.umich.edu        return;
7277279Sgblack@eecs.umich.edu    }
7287279Sgblack@eecs.umich.edu
7297279Sgblack@eecs.umich.edu  next:
7307279Sgblack@eecs.umich.edu    rxFifo.check();
7317279Sgblack@eecs.umich.edu    if (rxState == rxIdle)
7327279Sgblack@eecs.umich.edu        goto exit;
7337279Sgblack@eecs.umich.edu
7347279Sgblack@eecs.umich.edu    if (rxActive == -1) {
7357279Sgblack@eecs.umich.edu        if (rxState != rxFifoBlock)
7367279Sgblack@eecs.umich.edu            panic("no active vnic while in state %s", RxStateStrings[rxState]);
7377279Sgblack@eecs.umich.edu
7387303Sgblack@eecs.umich.edu        DPRINTF(EthernetSM, "processing rxState=%s\n",
7397303Sgblack@eecs.umich.edu                RxStateStrings[rxState]);
7407303Sgblack@eecs.umich.edu    } else {
7417303Sgblack@eecs.umich.edu        vnic = &virtualRegs[rxActive];
7427303Sgblack@eecs.umich.edu        DPRINTF(EthernetSM,
7437303Sgblack@eecs.umich.edu                "processing rxState=%s for vnic %d (rxunique %d)\n",
7447303Sgblack@eecs.umich.edu                RxStateStrings[rxState], rxActive, vnic->rxUnique);
7457303Sgblack@eecs.umich.edu    }
7467303Sgblack@eecs.umich.edu
7477303Sgblack@eecs.umich.edu    switch (rxState) {
7487303Sgblack@eecs.umich.edu      case rxFifoBlock:
7497303Sgblack@eecs.umich.edu        if (DTRACE(EthernetSM)) {
7507303Sgblack@eecs.umich.edu            PacketFifo::iterator end = rxFifo.end();
7517303Sgblack@eecs.umich.edu            int size = virtualRegs.size();
7527303Sgblack@eecs.umich.edu            for (int i = 0; i < size; ++i) {
7537303Sgblack@eecs.umich.edu                VirtualReg *vn = &virtualRegs[i];
7547303Sgblack@eecs.umich.edu                bool busy = Regs::get_RxDone_Busy(vn->RxDone);
7557303Sgblack@eecs.umich.edu                if (vn->rxIndex != end) {
7567303Sgblack@eecs.umich.edu#ifndef NDEBUG
7577303Sgblack@eecs.umich.edu                    bool dirty = vn->rxPacketOffset > 0;
7587303Sgblack@eecs.umich.edu                    const char *status;
7597119Sgblack@eecs.umich.edu
7607119Sgblack@eecs.umich.edu                    if (busy && dirty)
7617119Sgblack@eecs.umich.edu                        status = "busy,dirty";
7627119Sgblack@eecs.umich.edu                    else if (busy)
7637119Sgblack@eecs.umich.edu                        status = "busy";
7647119Sgblack@eecs.umich.edu                    else if (dirty)
7657119Sgblack@eecs.umich.edu                        status = "dirty";
7667119Sgblack@eecs.umich.edu                    else
7677119Sgblack@eecs.umich.edu                        status = "mapped";
7687119Sgblack@eecs.umich.edu
7697119Sgblack@eecs.umich.edu                    DPRINTF(EthernetSM,
7707119Sgblack@eecs.umich.edu                            "vnic %d %s (rxunique %d), packet %d, slack %d\n",
7717119Sgblack@eecs.umich.edu                            i, status, vn->rxUnique,
7727119Sgblack@eecs.umich.edu                            rxFifo.countPacketsBefore(vn->rxIndex),
7737119Sgblack@eecs.umich.edu                            vn->rxIndex->slack);
7747119Sgblack@eecs.umich.edu#endif
7757119Sgblack@eecs.umich.edu                } else if (busy) {
7767119Sgblack@eecs.umich.edu                    DPRINTF(EthernetSM, "vnic %d unmapped (rxunique %d)\n",
7777119Sgblack@eecs.umich.edu                            i, vn->rxUnique);
7787119Sgblack@eecs.umich.edu                }
7797303Sgblack@eecs.umich.edu            }
7807303Sgblack@eecs.umich.edu        }
7817303Sgblack@eecs.umich.edu
7827303Sgblack@eecs.umich.edu        if (!rxBusy.empty()) {
7837303Sgblack@eecs.umich.edu            rxActive = rxBusy.front();
7847303Sgblack@eecs.umich.edu            rxBusy.pop_front();
7857303Sgblack@eecs.umich.edu            vnic = &virtualRegs[rxActive];
7867303Sgblack@eecs.umich.edu
7877303Sgblack@eecs.umich.edu            if (vnic->rxIndex == rxFifo.end())
7887303Sgblack@eecs.umich.edu                panic("continuing vnic without packet\n");
7897303Sgblack@eecs.umich.edu
7907303Sgblack@eecs.umich.edu            DPRINTF(EthernetSM,
7917303Sgblack@eecs.umich.edu                    "continue processing for vnic %d (rxunique %d)\n",
7927303Sgblack@eecs.umich.edu                    rxActive, vnic->rxUnique);
7937303Sgblack@eecs.umich.edu
7947303Sgblack@eecs.umich.edu            rxState = rxBeginCopy;
7957303Sgblack@eecs.umich.edu
7967303Sgblack@eecs.umich.edu            int vnic_distance = rxFifo.countPacketsBefore(vnic->rxIndex);
7977303Sgblack@eecs.umich.edu            totalVnicDistance += vnic_distance;
7987303Sgblack@eecs.umich.edu            numVnicDistance += 1;
7997303Sgblack@eecs.umich.edu            if (vnic_distance > _maxVnicDistance) {
8007646Sgene.wu@arm.com                maxVnicDistance = vnic_distance;
8017279Sgblack@eecs.umich.edu                _maxVnicDistance = vnic_distance;
8027279Sgblack@eecs.umich.edu            }
8037279Sgblack@eecs.umich.edu
8047279Sgblack@eecs.umich.edu            break;
8057279Sgblack@eecs.umich.edu        }
8067279Sgblack@eecs.umich.edu
8077279Sgblack@eecs.umich.edu        if (rxFifoPtr == rxFifo.end()) {
8087279Sgblack@eecs.umich.edu            DPRINTF(EthernetSM, "receive waiting for data.  Nothing to do.\n");
8097279Sgblack@eecs.umich.edu            goto exit;
8107279Sgblack@eecs.umich.edu        }
8117279Sgblack@eecs.umich.edu
8127279Sgblack@eecs.umich.edu        if (rxList.empty())
8137279Sgblack@eecs.umich.edu            panic("Not idle, but nothing to do!");
8147279Sgblack@eecs.umich.edu
8157279Sgblack@eecs.umich.edu        assert(!rxFifo.empty());
8167279Sgblack@eecs.umich.edu
8177279Sgblack@eecs.umich.edu        rxActive = rxList.front();
8187279Sgblack@eecs.umich.edu        rxList.pop_front();
8197279Sgblack@eecs.umich.edu        vnic = &virtualRegs[rxActive];
8207279Sgblack@eecs.umich.edu
8217279Sgblack@eecs.umich.edu        DPRINTF(EthernetSM,
8227279Sgblack@eecs.umich.edu                "processing new packet for vnic %d (rxunique %d)\n",
8237646Sgene.wu@arm.com                rxActive, vnic->rxUnique);
8247119Sgblack@eecs.umich.edu
8257119Sgblack@eecs.umich.edu        // Grab a new packet from the fifo.
8267119Sgblack@eecs.umich.edu        vnic->rxIndex = rxFifoPtr++;
8277119Sgblack@eecs.umich.edu        vnic->rxIndex->priv = rxActive;
8287119Sgblack@eecs.umich.edu        vnic->rxPacketOffset = 0;
8297119Sgblack@eecs.umich.edu        vnic->rxPacketBytes = vnic->rxIndex->packet->length;
8307119Sgblack@eecs.umich.edu        assert(vnic->rxPacketBytes);
8317119Sgblack@eecs.umich.edu        rxMappedCount++;
8327119Sgblack@eecs.umich.edu
8337119Sgblack@eecs.umich.edu        vnic->rxDoneData = 0;
8347119Sgblack@eecs.umich.edu        /* scope for variables */ {
8357119Sgblack@eecs.umich.edu            IpPtr ip(vnic->rxIndex->packet);
8367119Sgblack@eecs.umich.edu            if (ip) {
8377119Sgblack@eecs.umich.edu                DPRINTF(Ethernet, "ID is %d\n", ip->id());
8387119Sgblack@eecs.umich.edu                vnic->rxDoneData |= Regs::RxDone_IpPacket;
8397119Sgblack@eecs.umich.edu                rxIpChecksums++;
8407119Sgblack@eecs.umich.edu                if (cksum(ip) != 0) {
8417119Sgblack@eecs.umich.edu                    DPRINTF(EthernetCksum, "Rx IP Checksum Error\n");
8427119Sgblack@eecs.umich.edu                    vnic->rxDoneData |= Regs::RxDone_IpError;
8437119Sgblack@eecs.umich.edu                }
8447119Sgblack@eecs.umich.edu                TcpPtr tcp(ip);
8457646Sgene.wu@arm.com                UdpPtr udp(ip);
8467646Sgene.wu@arm.com                if (tcp) {
8477646Sgene.wu@arm.com                    DPRINTF(Ethernet,
8487646Sgene.wu@arm.com                            "Src Port=%d, Dest Port=%d, Seq=%d, Ack=%d\n",
8497646Sgene.wu@arm.com                            tcp->sport(), tcp->dport(), tcp->seq(),
8507646Sgene.wu@arm.com                            tcp->ack());
8517646Sgene.wu@arm.com                    vnic->rxDoneData |= Regs::RxDone_TcpPacket;
8527646Sgene.wu@arm.com                    rxTcpChecksums++;
8537646Sgene.wu@arm.com                    if (cksum(tcp) != 0) {
8547646Sgene.wu@arm.com                        DPRINTF(EthernetCksum, "Rx TCP Checksum Error\n");
8557646Sgene.wu@arm.com                        vnic->rxDoneData |= Regs::RxDone_TcpError;
8567646Sgene.wu@arm.com                    }
8577646Sgene.wu@arm.com                } else if (udp) {
8587646Sgene.wu@arm.com                    vnic->rxDoneData |= Regs::RxDone_UdpPacket;
8597646Sgene.wu@arm.com                    rxUdpChecksums++;
8607646Sgene.wu@arm.com                    if (cksum(udp) != 0) {
8617646Sgene.wu@arm.com                        DPRINTF(EthernetCksum, "Rx UDP Checksum Error\n");
8627646Sgene.wu@arm.com                        vnic->rxDoneData |= Regs::RxDone_UdpError;
8637646Sgene.wu@arm.com                    }
8647646Sgene.wu@arm.com                }
8657646Sgene.wu@arm.com            }
8667646Sgene.wu@arm.com        }
8677646Sgene.wu@arm.com        rxState = rxBeginCopy;
8687646Sgene.wu@arm.com        break;
8697646Sgene.wu@arm.com
8707646Sgene.wu@arm.com      case rxBeginCopy:
8717646Sgene.wu@arm.com        if (dmaPending() || drainState() != DrainState::Running)
8727646Sgene.wu@arm.com            goto exit;
8737646Sgene.wu@arm.com
8747646Sgene.wu@arm.com        rxDmaAddr = params()->platform->pciToDma(
8757646Sgene.wu@arm.com                Regs::get_RxData_Addr(vnic->RxData));
8767646Sgene.wu@arm.com        rxDmaLen = min<unsigned>(Regs::get_RxData_Len(vnic->RxData),
8777646Sgene.wu@arm.com                                 vnic->rxPacketBytes);
8787646Sgene.wu@arm.com
8797646Sgene.wu@arm.com        /*
8807646Sgene.wu@arm.com         * if we're doing zero/delay copy and we're below the fifo
8817646Sgene.wu@arm.com         * threshold, see if we should try to do the zero/defer copy
8827646Sgene.wu@arm.com         */
8837646Sgene.wu@arm.com        if ((Regs::get_Config_ZeroCopy(regs.Config) ||
8847646Sgene.wu@arm.com             Regs::get_Config_DelayCopy(regs.Config)) &&
8857646Sgene.wu@arm.com            !Regs::get_RxData_NoDelay(vnic->RxData) && rxLow) {
8867646Sgene.wu@arm.com            if (rxDmaLen > regs.ZeroCopyMark)
8877646Sgene.wu@arm.com                rxDmaLen = regs.ZeroCopySize;
8887646Sgene.wu@arm.com        }
8897646Sgene.wu@arm.com        rxDmaData = vnic->rxIndex->packet->data + vnic->rxPacketOffset;
8907646Sgene.wu@arm.com        rxState = rxCopy;
8917646Sgene.wu@arm.com        if (rxDmaAddr == 1LL) {
8927646Sgene.wu@arm.com            rxState = rxCopyDone;
8937646Sgene.wu@arm.com            break;
8947646Sgene.wu@arm.com        }
8957646Sgene.wu@arm.com
8967646Sgene.wu@arm.com        dmaWrite(rxDmaAddr, rxDmaLen, &rxDmaEvent, rxDmaData);
8977646Sgene.wu@arm.com        break;
8987646Sgene.wu@arm.com
8997646Sgene.wu@arm.com      case rxCopy:
9007646Sgene.wu@arm.com        DPRINTF(EthernetSM, "receive machine still copying\n");
9017646Sgene.wu@arm.com        goto exit;
9027646Sgene.wu@arm.com
9037646Sgene.wu@arm.com      case rxCopyDone:
9047646Sgene.wu@arm.com        vnic->RxDone = vnic->rxDoneData;
9057646Sgene.wu@arm.com        vnic->RxDone |= Regs::RxDone_Complete;
9067646Sgene.wu@arm.com        rxBusyCount--;
9077646Sgene.wu@arm.com
9087646Sgene.wu@arm.com        if (vnic->rxPacketBytes == rxDmaLen) {
9097646Sgene.wu@arm.com            if (vnic->rxPacketOffset)
9107119Sgblack@eecs.umich.edu                rxDirtyCount--;
9117119Sgblack@eecs.umich.edu
9127119Sgblack@eecs.umich.edu            // Packet is complete.  Indicate how many bytes were copied
9137119Sgblack@eecs.umich.edu            vnic->RxDone = Regs::set_RxDone_CopyLen(vnic->RxDone, rxDmaLen);
9147119Sgblack@eecs.umich.edu
9157119Sgblack@eecs.umich.edu            DPRINTF(EthernetSM,
9167119Sgblack@eecs.umich.edu                    "rxKick: packet complete on vnic %d (rxunique %d)\n",
9177119Sgblack@eecs.umich.edu                    rxActive, vnic->rxUnique);
9187291Sgblack@eecs.umich.edu            rxFifo.remove(vnic->rxIndex);
9197291Sgblack@eecs.umich.edu            vnic->rxIndex = rxFifo.end();
9208140SMatt.Horsnell@arm.com            rxMappedCount--;
9218140SMatt.Horsnell@arm.com        } else {
9228140SMatt.Horsnell@arm.com            if (!vnic->rxPacketOffset)
9237291Sgblack@eecs.umich.edu                rxDirtyCount++;
9247291Sgblack@eecs.umich.edu
9257848SAli.Saidi@ARM.com            vnic->rxPacketBytes -= rxDmaLen;
9267848SAli.Saidi@ARM.com            vnic->rxPacketOffset += rxDmaLen;
9277848SAli.Saidi@ARM.com            vnic->RxDone |= Regs::RxDone_More;
9287848SAli.Saidi@ARM.com            vnic->RxDone = Regs::set_RxDone_CopyLen(vnic->RxDone,
9297848SAli.Saidi@ARM.com                                                    vnic->rxPacketBytes);
9307646Sgene.wu@arm.com            DPRINTF(EthernetSM,
9318140SMatt.Horsnell@arm.com                    "rxKick: packet not complete on vnic %d (rxunique %d): "
9328140SMatt.Horsnell@arm.com                    "%d bytes left\n",
9338140SMatt.Horsnell@arm.com                    rxActive, vnic->rxUnique, vnic->rxPacketBytes);
9348140SMatt.Horsnell@arm.com        }
9358140SMatt.Horsnell@arm.com
9368140SMatt.Horsnell@arm.com        rxActive = -1;
9378140SMatt.Horsnell@arm.com        rxState = rxBusy.empty() && rxList.empty() ? rxIdle : rxFifoBlock;
9388140SMatt.Horsnell@arm.com
9398140SMatt.Horsnell@arm.com        if (rxFifo.empty()) {
9408140SMatt.Horsnell@arm.com            devIntrPost(Regs::Intr_RxEmpty);
9418140SMatt.Horsnell@arm.com            rxEmpty = true;
9428140SMatt.Horsnell@arm.com        }
9437646Sgene.wu@arm.com
9447291Sgblack@eecs.umich.edu        if (rxFifo.size() < regs.RxFifoLow)
9457291Sgblack@eecs.umich.edu            rxLow = true;
9467291Sgblack@eecs.umich.edu
9477312Sgblack@eecs.umich.edu        if (rxFifo.size() > regs.RxFifoHigh)
9487312Sgblack@eecs.umich.edu            rxLow = false;
9497312Sgblack@eecs.umich.edu
9507312Sgblack@eecs.umich.edu        devIntrPost(Regs::Intr_RxDMA);
9517312Sgblack@eecs.umich.edu        break;
9527312Sgblack@eecs.umich.edu
9537312Sgblack@eecs.umich.edu      default:
9547848SAli.Saidi@ARM.com        panic("Invalid rxState!");
9557848SAli.Saidi@ARM.com    }
9567848SAli.Saidi@ARM.com
9577848SAli.Saidi@ARM.com    DPRINTF(EthernetSM, "entering next rxState=%s\n",
9587848SAli.Saidi@ARM.com            RxStateStrings[rxState]);
9597646Sgene.wu@arm.com
9607646Sgene.wu@arm.com    goto next;
9617646Sgene.wu@arm.com
9627646Sgene.wu@arm.com  exit:
9637724SAli.Saidi@ARM.com    /**
9647646Sgene.wu@arm.com     * @todo do we want to schedule a future kick?
9657646Sgene.wu@arm.com     */
9667646Sgene.wu@arm.com    DPRINTF(EthernetSM, "rx state machine exited rxState=%s\n",
9677312Sgblack@eecs.umich.edu            RxStateStrings[rxState]);
9687312Sgblack@eecs.umich.edu}
9697312Sgblack@eecs.umich.edu
9707205Sgblack@eecs.umich.eduvoid
9717205Sgblack@eecs.umich.eduDevice::txDmaDone()
9727205Sgblack@eecs.umich.edu{
9737205Sgblack@eecs.umich.edu    assert(txState == txCopy);
9747205Sgblack@eecs.umich.edu    txState = txCopyDone;
9757205Sgblack@eecs.umich.edu    DPRINTF(EthernetDMA, "tx dma read paddr=%#x len=%d\n",
9767205Sgblack@eecs.umich.edu            txDmaAddr, txDmaLen);
9777848SAli.Saidi@ARM.com    DDUMP(EthernetData, txDmaData, txDmaLen);
9787848SAli.Saidi@ARM.com
9797848SAli.Saidi@ARM.com    // If the receive state machine  has a pending DMA, let it go first
9807848SAli.Saidi@ARM.com    if (rxState == rxBeginCopy)
9817848SAli.Saidi@ARM.com        rxKick();
9827205Sgblack@eecs.umich.edu
9837205Sgblack@eecs.umich.edu    txKick();
9847205Sgblack@eecs.umich.edu}
9857279Sgblack@eecs.umich.edu
9867279Sgblack@eecs.umich.eduvoid
9877279Sgblack@eecs.umich.eduDevice::transmit()
9887279Sgblack@eecs.umich.edu{
9897279Sgblack@eecs.umich.edu    if (txFifo.empty()) {
9907279Sgblack@eecs.umich.edu        DPRINTF(Ethernet, "nothing to transmit\n");
9917279Sgblack@eecs.umich.edu        return;
9927279Sgblack@eecs.umich.edu    }
9937279Sgblack@eecs.umich.edu
9947848SAli.Saidi@ARM.com    uint32_t interrupts;
9957848SAli.Saidi@ARM.com    EthPacketPtr packet = txFifo.front();
9967848SAli.Saidi@ARM.com    if (!interface->sendPacket(packet)) {
9977848SAli.Saidi@ARM.com        DPRINTF(Ethernet, "Packet Transmit: failed txFifo available %d\n",
9987848SAli.Saidi@ARM.com                txFifo.avail());
9997646Sgene.wu@arm.com        return;
10007646Sgene.wu@arm.com    }
10017646Sgene.wu@arm.com
10027646Sgene.wu@arm.com    txFifo.pop();
10037724SAli.Saidi@ARM.com#if TRACING_ON
10047646Sgene.wu@arm.com    if (DTRACE(Ethernet)) {
10057646Sgene.wu@arm.com        IpPtr ip(packet);
10067646Sgene.wu@arm.com        if (ip) {
10077279Sgblack@eecs.umich.edu            DPRINTF(Ethernet, "ID is %d\n", ip->id());
10087279Sgblack@eecs.umich.edu            TcpPtr tcp(ip);
10097279Sgblack@eecs.umich.edu            if (tcp) {
10107303Sgblack@eecs.umich.edu                DPRINTF(Ethernet,
10117303Sgblack@eecs.umich.edu                        "Src Port=%d, Dest Port=%d, Seq=%d, Ack=%d\n",
10127303Sgblack@eecs.umich.edu                        tcp->sport(), tcp->dport(), tcp->seq(),
10137303Sgblack@eecs.umich.edu                        tcp->ack());
10147303Sgblack@eecs.umich.edu            }
10157303Sgblack@eecs.umich.edu        }
10167303Sgblack@eecs.umich.edu    }
10177303Sgblack@eecs.umich.edu#endif
10187303Sgblack@eecs.umich.edu
10197303Sgblack@eecs.umich.edu    DDUMP(EthernetData, packet->data, packet->length);
10207848SAli.Saidi@ARM.com    txBytes += packet->length;
10217848SAli.Saidi@ARM.com    txPackets++;
10227848SAli.Saidi@ARM.com
10237848SAli.Saidi@ARM.com    DPRINTF(Ethernet, "Packet Transmit: successful txFifo Available %d\n",
10247848SAli.Saidi@ARM.com            txFifo.avail());
10257646Sgene.wu@arm.com
10267646Sgene.wu@arm.com    interrupts = Regs::Intr_TxPacket;
10277646Sgene.wu@arm.com    if (txFifo.size() < regs.TxFifoLow)
10287646Sgene.wu@arm.com        interrupts |= Regs::Intr_TxLow;
10297646Sgene.wu@arm.com    devIntrPost(interrupts);
10307724SAli.Saidi@ARM.com}
10317646Sgene.wu@arm.com
10327646Sgene.wu@arm.comvoid
10337646Sgene.wu@arm.comDevice::txKick()
10347303Sgblack@eecs.umich.edu{
10357303Sgblack@eecs.umich.edu    VirtualReg *vnic;
10367303Sgblack@eecs.umich.edu    DPRINTF(EthernetSM, "txKick: txState=%s (txFifo.size=%d)\n",
10377119Sgblack@eecs.umich.edu            TxStateStrings[txState], txFifo.size());
10387119Sgblack@eecs.umich.edu
10397119Sgblack@eecs.umich.edu    if (txKickTick > curTick()) {
10407119Sgblack@eecs.umich.edu        DPRINTF(EthernetSM, "txKick: exiting, can't run till %d\n",
10417119Sgblack@eecs.umich.edu                txKickTick);
10427119Sgblack@eecs.umich.edu        return;
10437119Sgblack@eecs.umich.edu    }
10447848SAli.Saidi@ARM.com
10457848SAli.Saidi@ARM.com  next:
10467848SAli.Saidi@ARM.com    if (txState == txIdle)
10477848SAli.Saidi@ARM.com        goto exit;
10487848SAli.Saidi@ARM.com
10497646Sgene.wu@arm.com    assert(!txList.empty());
10507646Sgene.wu@arm.com    vnic = &virtualRegs[txList.front()];
10517646Sgene.wu@arm.com
10527646Sgene.wu@arm.com    switch (txState) {
10537724SAli.Saidi@ARM.com      case txFifoBlock:
10547646Sgene.wu@arm.com        assert(Regs::get_TxDone_Busy(vnic->TxDone));
10557646Sgene.wu@arm.com        if (!txPacket) {
10567646Sgene.wu@arm.com            // Grab a new packet from the fifo.
10577119Sgblack@eecs.umich.edu            txPacket = make_shared<EthPacketData>(16384);
10587119Sgblack@eecs.umich.edu            txPacketOffset = 0;
10597119Sgblack@eecs.umich.edu        }
10607303Sgblack@eecs.umich.edu
10617303Sgblack@eecs.umich.edu        if (txFifo.avail() - txPacket->length <
10627303Sgblack@eecs.umich.edu            Regs::get_TxData_Len(vnic->TxData)) {
10637303Sgblack@eecs.umich.edu            DPRINTF(EthernetSM, "transmit fifo full.  Nothing to do.\n");
10647303Sgblack@eecs.umich.edu            goto exit;
10657303Sgblack@eecs.umich.edu        }
10667303Sgblack@eecs.umich.edu
10677303Sgblack@eecs.umich.edu        txState = txBeginCopy;
10687303Sgblack@eecs.umich.edu        break;
10697848SAli.Saidi@ARM.com
10707848SAli.Saidi@ARM.com      case txBeginCopy:
10717848SAli.Saidi@ARM.com        if (dmaPending() || drainState() != DrainState::Running)
10727848SAli.Saidi@ARM.com            goto exit;
10737848SAli.Saidi@ARM.com
10747646Sgene.wu@arm.com        txDmaAddr = params()->platform->pciToDma(
10757646Sgene.wu@arm.com                Regs::get_TxData_Addr(vnic->TxData));
10767646Sgene.wu@arm.com        txDmaLen = Regs::get_TxData_Len(vnic->TxData);
10777646Sgene.wu@arm.com        txDmaData = txPacket->data + txPacketOffset;
10787646Sgene.wu@arm.com        txState = txCopy;
10797724SAli.Saidi@ARM.com
10807646Sgene.wu@arm.com        dmaRead(txDmaAddr, txDmaLen, &txDmaEvent, txDmaData);
10817646Sgene.wu@arm.com        break;
10827646Sgene.wu@arm.com
10837303Sgblack@eecs.umich.edu      case txCopy:
10847303Sgblack@eecs.umich.edu        DPRINTF(EthernetSM, "transmit machine still copying\n");
10857303Sgblack@eecs.umich.edu        goto exit;
10867646Sgene.wu@arm.com
10877279Sgblack@eecs.umich.edu      case txCopyDone:
10887279Sgblack@eecs.umich.edu        vnic->TxDone = txDmaLen | Regs::TxDone_Complete;
10897279Sgblack@eecs.umich.edu        txPacket->length += txDmaLen;
10907279Sgblack@eecs.umich.edu        if ((vnic->TxData & Regs::TxData_More)) {
10917279Sgblack@eecs.umich.edu            txPacketOffset += txDmaLen;
10927279Sgblack@eecs.umich.edu            txState = txIdle;
10937279Sgblack@eecs.umich.edu            devIntrPost(Regs::Intr_TxDMA);
10947279Sgblack@eecs.umich.edu            break;
10957279Sgblack@eecs.umich.edu        }
10967279Sgblack@eecs.umich.edu
10977848SAli.Saidi@ARM.com        assert(txPacket->length <= txFifo.avail());
10987848SAli.Saidi@ARM.com        if ((vnic->TxData & Regs::TxData_Checksum)) {
10997848SAli.Saidi@ARM.com            IpPtr ip(txPacket);
11007848SAli.Saidi@ARM.com            if (ip) {
11017848SAli.Saidi@ARM.com                TcpPtr tcp(ip);
11027646Sgene.wu@arm.com                if (tcp) {
11037646Sgene.wu@arm.com                    tcp->sum(0);
11047646Sgene.wu@arm.com                    tcp->sum(cksum(tcp));
11057646Sgene.wu@arm.com                    txTcpChecksums++;
11067646Sgene.wu@arm.com                }
11077724SAli.Saidi@ARM.com
11087646Sgene.wu@arm.com                UdpPtr udp(ip);
11097646Sgene.wu@arm.com                if (udp) {
11107646Sgene.wu@arm.com                    udp->sum(0);
11117279Sgblack@eecs.umich.edu                    udp->sum(cksum(udp));
11127279Sgblack@eecs.umich.edu                    txUdpChecksums++;
11137279Sgblack@eecs.umich.edu                }
11147646Sgene.wu@arm.com
11157119Sgblack@eecs.umich.edu                ip->sum(0);
11167119Sgblack@eecs.umich.edu                ip->sum(cksum(ip));
11177119Sgblack@eecs.umich.edu                txIpChecksums++;
11187119Sgblack@eecs.umich.edu            }
11197119Sgblack@eecs.umich.edu        }
11207119Sgblack@eecs.umich.edu
11217119Sgblack@eecs.umich.edu        txFifo.push(txPacket);
11227119Sgblack@eecs.umich.edu        if (txFifo.avail() < regs.TxMaxCopy) {
11237119Sgblack@eecs.umich.edu            devIntrPost(Regs::Intr_TxFull);
11247848SAli.Saidi@ARM.com            txFull = true;
11257848SAli.Saidi@ARM.com        }
11267848SAli.Saidi@ARM.com        txPacket = 0;
11277848SAli.Saidi@ARM.com        transmit();
11287848SAli.Saidi@ARM.com        txList.pop_front();
11297646Sgene.wu@arm.com        txState = txList.empty() ? txIdle : txFifoBlock;
11307646Sgene.wu@arm.com        devIntrPost(Regs::Intr_TxDMA);
11317646Sgene.wu@arm.com        break;
11327646Sgene.wu@arm.com
11337646Sgene.wu@arm.com      default:
11347724SAli.Saidi@ARM.com        panic("Invalid txState!");
11357646Sgene.wu@arm.com    }
11367646Sgene.wu@arm.com
11377646Sgene.wu@arm.com    DPRINTF(EthernetSM, "entering next txState=%s\n",
11387119Sgblack@eecs.umich.edu            TxStateStrings[txState]);
11397119Sgblack@eecs.umich.edu
11407646Sgene.wu@arm.com    goto next;
11417646Sgene.wu@arm.com
11427646Sgene.wu@arm.com  exit:
11437646Sgene.wu@arm.com    /**
11447646Sgene.wu@arm.com     * @todo do we want to schedule a future kick?
11457646Sgene.wu@arm.com     */
11467646Sgene.wu@arm.com    DPRINTF(EthernetSM, "tx state machine exited txState=%s\n",
11477646Sgene.wu@arm.com            TxStateStrings[txState]);
11487646Sgene.wu@arm.com}
11497646Sgene.wu@arm.com
11507646Sgene.wu@arm.comvoid
11517646Sgene.wu@arm.comDevice::transferDone()
11527848SAli.Saidi@ARM.com{
11537848SAli.Saidi@ARM.com    if (txFifo.empty()) {
11547848SAli.Saidi@ARM.com        DPRINTF(Ethernet, "transfer complete: txFifo empty...nothing to do\n");
11557848SAli.Saidi@ARM.com        return;
11567848SAli.Saidi@ARM.com    }
11577646Sgene.wu@arm.com
11587646Sgene.wu@arm.com    DPRINTF(Ethernet, "transfer complete: data in txFifo...schedule xmit\n");
11597646Sgene.wu@arm.com
11607646Sgene.wu@arm.com    reschedule(txEvent, clockEdge(Cycles(1)), true);
11617646Sgene.wu@arm.com}
11627646Sgene.wu@arm.com
11637724SAli.Saidi@ARM.combool
11647646Sgene.wu@arm.comDevice::rxFilter(const EthPacketPtr &packet)
11657646Sgene.wu@arm.com{
11667724SAli.Saidi@ARM.com    if (!Regs::get_Config_Filter(regs.Config))
11677646Sgene.wu@arm.com        return false;
11687646Sgene.wu@arm.com
11697646Sgene.wu@arm.com    panic("receive filter not implemented\n");
11707646Sgene.wu@arm.com    bool drop = true;
11717646Sgene.wu@arm.com
11727646Sgene.wu@arm.com#if 0
11737724SAli.Saidi@ARM.com    string type;
11747646Sgene.wu@arm.com
11757646Sgene.wu@arm.com    EthHdr *eth = packet->eth();
11767646Sgene.wu@arm.com    if (eth->unicast()) {
11777646Sgene.wu@arm.com        // If we're accepting all unicast addresses
11787646Sgene.wu@arm.com        if (acceptUnicast)
11797646Sgene.wu@arm.com            drop = false;
11807646Sgene.wu@arm.com
11817646Sgene.wu@arm.com        // If we make a perfect match
11827646Sgene.wu@arm.com        if (acceptPerfect && params->eaddr == eth.dst())
11837646Sgene.wu@arm.com            drop = false;
11847646Sgene.wu@arm.com
11857646Sgene.wu@arm.com        if (acceptArp && eth->type() == ETH_TYPE_ARP)
11867646Sgene.wu@arm.com            drop = false;
11877646Sgene.wu@arm.com
11887646Sgene.wu@arm.com    } else if (eth->broadcast()) {
11897646Sgene.wu@arm.com        // if we're accepting broadcasts
11907646Sgene.wu@arm.com        if (acceptBroadcast)
11917848SAli.Saidi@ARM.com            drop = false;
11927848SAli.Saidi@ARM.com
11937848SAli.Saidi@ARM.com    } else if (eth->multicast()) {
11947848SAli.Saidi@ARM.com        // if we're accepting all multicasts
11957848SAli.Saidi@ARM.com        if (acceptMulticast)
11967646Sgene.wu@arm.com            drop = false;
11977646Sgene.wu@arm.com
11987646Sgene.wu@arm.com    }
11997646Sgene.wu@arm.com
12007646Sgene.wu@arm.com    if (drop) {
12017646Sgene.wu@arm.com        DPRINTF(Ethernet, "rxFilter drop\n");
12027646Sgene.wu@arm.com        DDUMP(EthernetData, packet->data, packet->length);
12037724SAli.Saidi@ARM.com    }
12047646Sgene.wu@arm.com#endif
12057724SAli.Saidi@ARM.com    return drop;
12067646Sgene.wu@arm.com}
12077646Sgene.wu@arm.com
12087646Sgene.wu@arm.combool
12097646Sgene.wu@arm.comDevice::recvPacket(EthPacketPtr packet)
12107646Sgene.wu@arm.com{
12117724SAli.Saidi@ARM.com    rxBytes += packet->length;
12127646Sgene.wu@arm.com    rxPackets++;
12137646Sgene.wu@arm.com
12147724SAli.Saidi@ARM.com    DPRINTF(Ethernet, "Receiving packet from wire, rxFifo Available is %d\n",
12157646Sgene.wu@arm.com            rxFifo.avail());
12167646Sgene.wu@arm.com
12177646Sgene.wu@arm.com    if (!rxEnable) {
12187646Sgene.wu@arm.com        DPRINTF(Ethernet, "receive disabled...packet dropped\n");
12197646Sgene.wu@arm.com        return true;
12207646Sgene.wu@arm.com    }
12217724SAli.Saidi@ARM.com
12227646Sgene.wu@arm.com    if (rxFilter(packet)) {
12237646Sgene.wu@arm.com        DPRINTF(Ethernet, "packet filtered...dropped\n");
12247646Sgene.wu@arm.com        return true;
12257646Sgene.wu@arm.com    }
12267646Sgene.wu@arm.com
12277646Sgene.wu@arm.com    if (rxFifo.size() >= regs.RxFifoHigh)
12287646Sgene.wu@arm.com        devIntrPost(Regs::Intr_RxHigh);
12297646Sgene.wu@arm.com
12307646Sgene.wu@arm.com    if (!rxFifo.push(packet)) {
12317646Sgene.wu@arm.com        DPRINTF(Ethernet,
12327646Sgene.wu@arm.com                "packet will not fit in receive buffer...packet dropped\n");
12337646Sgene.wu@arm.com        return false;
12347646Sgene.wu@arm.com    }
12357646Sgene.wu@arm.com
12367646Sgene.wu@arm.com    // If we were at the last element, back up one ot go to the new
12377848SAli.Saidi@ARM.com    // last element of the list.
12387848SAli.Saidi@ARM.com    if (rxFifoPtr == rxFifo.end())
12397848SAli.Saidi@ARM.com        --rxFifoPtr;
12407848SAli.Saidi@ARM.com
12417848SAli.Saidi@ARM.com    devIntrPost(Regs::Intr_RxPacket);
12427646Sgene.wu@arm.com    rxKick();
12437646Sgene.wu@arm.com    return true;
12447646Sgene.wu@arm.com}
12457646Sgene.wu@arm.com
12467646Sgene.wu@arm.comvoid
12477646Sgene.wu@arm.comDevice::drainResume()
12487724SAli.Saidi@ARM.com{
12497646Sgene.wu@arm.com    Drainable::drainResume();
12507724SAli.Saidi@ARM.com
12517646Sgene.wu@arm.com    // During drain we could have left the state machines in a waiting state and
12527646Sgene.wu@arm.com    // they wouldn't get out until some other event occured to kick them.
12537646Sgene.wu@arm.com    // This way they'll get out immediately
12547646Sgene.wu@arm.com    txKick();
12557724SAli.Saidi@ARM.com    rxKick();
12567646Sgene.wu@arm.com}
12577646Sgene.wu@arm.com
12587646Sgene.wu@arm.com//=====================================================================
12597646Sgene.wu@arm.com//
12607646Sgene.wu@arm.com//
12617646Sgene.wu@arm.comvoid
12627646Sgene.wu@arm.comBase::serialize(CheckpointOut &cp) const
1263{
1264    // Serialize the PciDevice base class
1265    PciDevice::serialize(cp);
1266
1267    SERIALIZE_SCALAR(rxEnable);
1268    SERIALIZE_SCALAR(txEnable);
1269    SERIALIZE_SCALAR(cpuIntrEnable);
1270
1271    /*
1272     * Keep track of pending interrupt status.
1273     */
1274    SERIALIZE_SCALAR(intrTick);
1275    SERIALIZE_SCALAR(cpuPendingIntr);
1276    Tick intrEventTick = 0;
1277    if (intrEvent)
1278        intrEventTick = intrEvent->when();
1279    SERIALIZE_SCALAR(intrEventTick);
1280}
1281
1282void
1283Base::unserialize(CheckpointIn &cp)
1284{
1285    // Unserialize the PciDevice base class
1286    PciDevice::unserialize(cp);
1287
1288    UNSERIALIZE_SCALAR(rxEnable);
1289    UNSERIALIZE_SCALAR(txEnable);
1290    UNSERIALIZE_SCALAR(cpuIntrEnable);
1291
1292    /*
1293     * Keep track of pending interrupt status.
1294     */
1295    UNSERIALIZE_SCALAR(intrTick);
1296    UNSERIALIZE_SCALAR(cpuPendingIntr);
1297    Tick intrEventTick;
1298    UNSERIALIZE_SCALAR(intrEventTick);
1299    if (intrEventTick) {
1300        intrEvent = new IntrEvent(this, true);
1301        schedule(intrEvent, intrEventTick);
1302    }
1303}
1304
1305void
1306Device::serialize(CheckpointOut &cp) const
1307{
1308    int count;
1309
1310    // Serialize the PciDevice base class
1311    Base::serialize(cp);
1312
1313    if (rxState == rxCopy)
1314        panic("can't serialize with an in flight dma request rxState=%s",
1315              RxStateStrings[rxState]);
1316
1317    if (txState == txCopy)
1318        panic("can't serialize with an in flight dma request txState=%s",
1319              TxStateStrings[txState]);
1320
1321    /*
1322     * Serialize the device registers that could be modified by the OS.
1323     */
1324    SERIALIZE_SCALAR(regs.Config);
1325    SERIALIZE_SCALAR(regs.IntrStatus);
1326    SERIALIZE_SCALAR(regs.IntrMask);
1327    SERIALIZE_SCALAR(regs.RxData);
1328    SERIALIZE_SCALAR(regs.TxData);
1329
1330    /*
1331     * Serialize the virtual nic state
1332     */
1333    int virtualRegsSize = virtualRegs.size();
1334    SERIALIZE_SCALAR(virtualRegsSize);
1335    for (int i = 0; i < virtualRegsSize; ++i) {
1336        const VirtualReg *vnic = &virtualRegs[i];
1337
1338        std::string reg = csprintf("vnic%d", i);
1339        paramOut(cp, reg + ".RxData", vnic->RxData);
1340        paramOut(cp, reg + ".RxDone", vnic->RxDone);
1341        paramOut(cp, reg + ".TxData", vnic->TxData);
1342        paramOut(cp, reg + ".TxDone", vnic->TxDone);
1343
1344        bool rxPacketExists = vnic->rxIndex != rxFifo.end();
1345        paramOut(cp, reg + ".rxPacketExists", rxPacketExists);
1346        if (rxPacketExists) {
1347            int rxPacket = 0;
1348            auto i = rxFifo.begin();
1349            while (i != vnic->rxIndex) {
1350                assert(i != rxFifo.end());
1351                ++i;
1352                ++rxPacket;
1353            }
1354
1355            paramOut(cp, reg + ".rxPacket", rxPacket);
1356            paramOut(cp, reg + ".rxPacketOffset", vnic->rxPacketOffset);
1357            paramOut(cp, reg + ".rxPacketBytes", vnic->rxPacketBytes);
1358        }
1359        paramOut(cp, reg + ".rxDoneData", vnic->rxDoneData);
1360    }
1361
1362    int rxFifoPtr = -1;
1363    if (this->rxFifoPtr != rxFifo.end())
1364        rxFifoPtr = rxFifo.countPacketsBefore(this->rxFifoPtr);
1365    SERIALIZE_SCALAR(rxFifoPtr);
1366
1367    SERIALIZE_SCALAR(rxActive);
1368    SERIALIZE_SCALAR(rxBusyCount);
1369    SERIALIZE_SCALAR(rxDirtyCount);
1370    SERIALIZE_SCALAR(rxMappedCount);
1371
1372    VirtualList::const_iterator i, end;
1373    for (count = 0, i = rxList.begin(), end = rxList.end(); i != end; ++i)
1374        paramOut(cp, csprintf("rxList%d", count++), *i);
1375    int rxListSize = count;
1376    SERIALIZE_SCALAR(rxListSize);
1377
1378    for (count = 0, i = rxBusy.begin(), end = rxBusy.end(); i != end; ++i)
1379        paramOut(cp, csprintf("rxBusy%d", count++), *i);
1380    int rxBusySize = count;
1381    SERIALIZE_SCALAR(rxBusySize);
1382
1383    for (count = 0, i = txList.begin(), end = txList.end(); i != end; ++i)
1384        paramOut(cp, csprintf("txList%d", count++), *i);
1385    int txListSize = count;
1386    SERIALIZE_SCALAR(txListSize);
1387
1388    /*
1389     * Serialize rx state machine
1390     */
1391    int rxState = this->rxState;
1392    SERIALIZE_SCALAR(rxState);
1393    SERIALIZE_SCALAR(rxEmpty);
1394    SERIALIZE_SCALAR(rxLow);
1395    rxFifo.serialize("rxFifo", cp);
1396
1397    /*
1398     * Serialize tx state machine
1399     */
1400    int txState = this->txState;
1401    SERIALIZE_SCALAR(txState);
1402    SERIALIZE_SCALAR(txFull);
1403    txFifo.serialize("txFifo", cp);
1404    bool txPacketExists = txPacket != nullptr;
1405    SERIALIZE_SCALAR(txPacketExists);
1406    if (txPacketExists) {
1407        txPacket->serialize("txPacket", cp);
1408        SERIALIZE_SCALAR(txPacketOffset);
1409        SERIALIZE_SCALAR(txPacketBytes);
1410    }
1411
1412    /*
1413     * If there's a pending transmit, store the time so we can
1414     * reschedule it later
1415     */
1416    Tick transmitTick = txEvent.scheduled() ? txEvent.when() - curTick() : 0;
1417    SERIALIZE_SCALAR(transmitTick);
1418}
1419
1420void
1421Device::unserialize(CheckpointIn &cp)
1422{
1423    // Unserialize the PciDevice base class
1424    Base::unserialize(cp);
1425
1426    /*
1427     * Unserialize the device registers that may have been written by the OS.
1428     */
1429    UNSERIALIZE_SCALAR(regs.Config);
1430    UNSERIALIZE_SCALAR(regs.IntrStatus);
1431    UNSERIALIZE_SCALAR(regs.IntrMask);
1432    UNSERIALIZE_SCALAR(regs.RxData);
1433    UNSERIALIZE_SCALAR(regs.TxData);
1434
1435    UNSERIALIZE_SCALAR(rxActive);
1436    UNSERIALIZE_SCALAR(rxBusyCount);
1437    UNSERIALIZE_SCALAR(rxDirtyCount);
1438    UNSERIALIZE_SCALAR(rxMappedCount);
1439
1440    int rxListSize;
1441    UNSERIALIZE_SCALAR(rxListSize);
1442    rxList.clear();
1443    for (int i = 0; i < rxListSize; ++i) {
1444        int value;
1445        paramIn(cp, csprintf("rxList%d", i), value);
1446        rxList.push_back(value);
1447    }
1448
1449    int rxBusySize;
1450    UNSERIALIZE_SCALAR(rxBusySize);
1451    rxBusy.clear();
1452    for (int i = 0; i < rxBusySize; ++i) {
1453        int value;
1454        paramIn(cp, csprintf("rxBusy%d", i), value);
1455        rxBusy.push_back(value);
1456    }
1457
1458    int txListSize;
1459    UNSERIALIZE_SCALAR(txListSize);
1460    txList.clear();
1461    for (int i = 0; i < txListSize; ++i) {
1462        int value;
1463        paramIn(cp, csprintf("txList%d", i), value);
1464        txList.push_back(value);
1465    }
1466
1467    /*
1468     * Unserialize rx state machine
1469     */
1470    int rxState;
1471    UNSERIALIZE_SCALAR(rxState);
1472    UNSERIALIZE_SCALAR(rxEmpty);
1473    UNSERIALIZE_SCALAR(rxLow);
1474    this->rxState = (RxState) rxState;
1475    rxFifo.unserialize("rxFifo", cp);
1476
1477    int rxFifoPtr;
1478    UNSERIALIZE_SCALAR(rxFifoPtr);
1479    if (rxFifoPtr >= 0) {
1480        this->rxFifoPtr = rxFifo.begin();
1481        for (int i = 0; i < rxFifoPtr; ++i)
1482            ++this->rxFifoPtr;
1483    } else {
1484        this->rxFifoPtr = rxFifo.end();
1485    }
1486
1487    /*
1488     * Unserialize tx state machine
1489     */
1490    int txState;
1491    UNSERIALIZE_SCALAR(txState);
1492    UNSERIALIZE_SCALAR(txFull);
1493    this->txState = (TxState) txState;
1494    txFifo.unserialize("txFifo", cp);
1495    bool txPacketExists;
1496    UNSERIALIZE_SCALAR(txPacketExists);
1497    txPacket = 0;
1498    if (txPacketExists) {
1499        txPacket = make_shared<EthPacketData>(16384);
1500        txPacket->unserialize("txPacket", cp);
1501        UNSERIALIZE_SCALAR(txPacketOffset);
1502        UNSERIALIZE_SCALAR(txPacketBytes);
1503    }
1504
1505    /*
1506     * unserialize the virtual nic registers/state
1507     *
1508     * this must be done after the unserialization of the rxFifo
1509     * because the packet iterators depend on the fifo being populated
1510     */
1511    int virtualRegsSize;
1512    UNSERIALIZE_SCALAR(virtualRegsSize);
1513    virtualRegs.clear();
1514    virtualRegs.resize(virtualRegsSize);
1515    for (int i = 0; i < virtualRegsSize; ++i) {
1516        VirtualReg *vnic = &virtualRegs[i];
1517        std::string reg = csprintf("vnic%d", i);
1518
1519        paramIn(cp, reg + ".RxData", vnic->RxData);
1520        paramIn(cp, reg + ".RxDone", vnic->RxDone);
1521        paramIn(cp, reg + ".TxData", vnic->TxData);
1522        paramIn(cp, reg + ".TxDone", vnic->TxDone);
1523
1524        vnic->rxUnique = rxUnique++;
1525        vnic->txUnique = txUnique++;
1526
1527        bool rxPacketExists;
1528        paramIn(cp, reg + ".rxPacketExists", rxPacketExists);
1529        if (rxPacketExists) {
1530            int rxPacket;
1531            paramIn(cp, reg + ".rxPacket", rxPacket);
1532            vnic->rxIndex = rxFifo.begin();
1533            while (rxPacket--)
1534                ++vnic->rxIndex;
1535
1536            paramIn(cp, reg + ".rxPacketOffset",
1537                    vnic->rxPacketOffset);
1538            paramIn(cp, reg + ".rxPacketBytes", vnic->rxPacketBytes);
1539        } else {
1540            vnic->rxIndex = rxFifo.end();
1541        }
1542        paramIn(cp, reg + ".rxDoneData", vnic->rxDoneData);
1543    }
1544
1545    /*
1546     * If there's a pending transmit, reschedule it now
1547     */
1548    Tick transmitTick;
1549    UNSERIALIZE_SCALAR(transmitTick);
1550    if (transmitTick)
1551        schedule(txEvent, curTick() + transmitTick);
1552
1553    pioPort.sendRangeChange();
1554
1555}
1556
1557} // namespace Sinic
1558
1559Sinic::Device *
1560SinicParams::create()
1561{
1562    return new Sinic::Device(this);
1563}
1564