sinic.cc revision 13342
11156SN/A/*
21762SN/A * Copyright (c) 2004-2005 The Regents of The University of Michigan
31156SN/A * All rights reserved.
41156SN/A *
51156SN/A * Redistribution and use in source and binary forms, with or without
61156SN/A * modification, are permitted provided that the following conditions are
71156SN/A * met: redistributions of source code must retain the above copyright
81156SN/A * notice, this list of conditions and the following disclaimer;
91156SN/A * redistributions in binary form must reproduce the above copyright
101156SN/A * notice, this list of conditions and the following disclaimer in the
111156SN/A * documentation and/or other materials provided with the distribution;
121156SN/A * neither the name of the copyright holders nor the names of its
131156SN/A * contributors may be used to endorse or promote products derived from
141156SN/A * this software without specific prior written permission.
151156SN/A *
161156SN/A * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
171156SN/A * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
181156SN/A * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
191156SN/A * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
201156SN/A * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
211156SN/A * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
221156SN/A * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
231156SN/A * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
241156SN/A * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
251156SN/A * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
261156SN/A * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
272665SN/A *
282665SN/A * Authors: Nathan Binkert
291156SN/A */
301156SN/A
3111263Sandreas.sandberg@arm.com#include "dev/net/sinic.hh"
3211263Sandreas.sandberg@arm.com
331156SN/A#include <deque>
342566SN/A#include <limits>
351156SN/A#include <string>
361156SN/A
379850SN/A#ifdef SINIC_VTOPHYS
384762SN/A#include "arch/vtophys.hh"
3911263Sandreas.sandberg@arm.com
409850SN/A#endif
418641SN/A#include "base/compiler.hh"
425882SN/A#include "base/debug.hh"
431156SN/A#include "base/inet.hh"
446216SN/A#include "base/types.hh"
456658SN/A#include "config/the_isa.hh"
468232SN/A#include "debug/EthernetAll.hh"
4711263Sandreas.sandberg@arm.com#include "dev/net/etherlink.hh"
482566SN/A#include "mem/packet.hh"
493348SN/A#include "mem/packet_access.hh"
501156SN/A#include "sim/eventq.hh"
511157SN/A#include "sim/stats.hh"
521156SN/A
535603SN/Ausing namespace std;
541156SN/Ausing namespace Net;
552107SN/Ausing namespace TheISA;
561156SN/A
571156SN/Anamespace Sinic {
581156SN/A
591156SN/Aconst char *RxStateStrings[] =
601156SN/A{
611156SN/A    "rxIdle",
621156SN/A    "rxFifoBlock",
631156SN/A    "rxBeginCopy",
641156SN/A    "rxCopy",
651156SN/A    "rxCopyDone"
661156SN/A};
671156SN/A
681156SN/Aconst char *TxStateStrings[] =
691156SN/A{
701156SN/A    "txIdle",
711156SN/A    "txFifoBlock",
721156SN/A    "txBeginCopy",
731156SN/A    "txCopy",
741156SN/A    "txCopyDone"
751156SN/A};
761156SN/A
771156SN/A
781156SN/A///////////////////////////////////////////////////////////////////////
791156SN/A//
801156SN/A// Sinic PCI Device
811156SN/A//
824981SN/ABase::Base(const Params *p)
839339SN/A    : EtherDevBase(p), rxEnable(false), txEnable(false),
841634SN/A      intrDelay(p->intr_delay), intrTick(0), cpuIntrEnable(false),
851634SN/A      cpuPendingIntr(false), intrEvent(0), interface(NULL)
861156SN/A{
871156SN/A}
881156SN/A
894981SN/ADevice::Device(const Params *p)
902627SN/A    : Base(p), rxUnique(0), txUnique(0),
912282SN/A      virtualRegs(p->virtual_count < 1 ? 1 : p->virtual_count),
922627SN/A      rxFifo(p->rx_fifo_size), txFifo(p->tx_fifo_size),
931156SN/A      rxKickTick(0), txKickTick(0),
9412087Sspwilson2@wisc.edu      txEvent([this]{ txEventTransmit(); }, name()),
9512087Sspwilson2@wisc.edu      rxDmaEvent([this]{ rxDmaDone(); }, name()),
9612087Sspwilson2@wisc.edu      txDmaEvent([this]{ txDmaDone(); }, name()),
971156SN/A      dmaReadDelay(p->dma_read_delay), dmaReadFactor(p->dma_read_factor),
981156SN/A      dmaWriteDelay(p->dma_write_delay), dmaWriteFactor(p->dma_write_factor)
991156SN/A{
1004981SN/A    interface = new Interface(name() + ".int0", this);
1011156SN/A    reset();
1021156SN/A
1031156SN/A}
1041156SN/A
1051156SN/ADevice::~Device()
1061156SN/A{}
1071156SN/A
1081156SN/Avoid
1091156SN/ADevice::regStats()
1101156SN/A{
1119339SN/A    Base::regStats();
1125603SN/A
1135603SN/A    _maxVnicDistance = 0;
1145603SN/A
1155603SN/A    maxVnicDistance
1165603SN/A        .name(name() + ".maxVnicDistance")
1175603SN/A        .desc("maximum vnic distance")
1185603SN/A        ;
1195603SN/A
1205603SN/A    totalVnicDistance
1215603SN/A        .name(name() + ".totalVnicDistance")
1225603SN/A        .desc("total vnic distance")
1235603SN/A        ;
1245603SN/A    numVnicDistance
1255603SN/A        .name(name() + ".numVnicDistance")
1265603SN/A        .desc("number of vnic distance measurements")
1275603SN/A        ;
1285603SN/A
1295603SN/A    avgVnicDistance
1305603SN/A        .name(name() + ".avgVnicDistance")
1315603SN/A        .desc("average vnic distance")
1325603SN/A        ;
1335603SN/A
1345603SN/A    avgVnicDistance = totalVnicDistance / numVnicDistance;
1355603SN/A}
1365603SN/A
1375603SN/Avoid
1385603SN/ADevice::resetStats()
1395603SN/A{
1409339SN/A    Base::resetStats();
1419339SN/A
1425603SN/A    _maxVnicDistance = 0;
1431156SN/A}
1441156SN/A
1454981SN/AEtherInt*
1464981SN/ADevice::getEthPort(const std::string &if_name, int idx)
1474981SN/A{
1484981SN/A    if (if_name == "interface") {
1494981SN/A        if (interface->getPeer())
1504981SN/A            panic("interface already connected to\n");
1514981SN/A
1524981SN/A        return interface;
1534981SN/A    }
1544981SN/A    return NULL;
1554981SN/A}
1564981SN/A
1574981SN/A
1581939SN/Avoid
15911005SN/ADevice::prepareIO(ContextID cpu, int index)
1602008SN/A{
1612008SN/A    int size = virtualRegs.size();
1622282SN/A    if (index > size)
1632282SN/A        panic("Trying to access a vnic that doesn't exist %d > %d\n",
1642282SN/A              index, size);
1652008SN/A}
1662008SN/A
1675603SN/A//add stats for head of line blocking
1685603SN/A//add stats for average fifo length
1695603SN/A//add stats for average number of vnics busy
1705603SN/A
1712008SN/Avoid
17211005SN/ADevice::prepareRead(ContextID cpu, int index)
1732008SN/A{
1742008SN/A    using namespace Regs;
1752008SN/A    prepareIO(cpu, index);
1762008SN/A
1772008SN/A    VirtualReg &vnic = virtualRegs[index];
1782008SN/A
1792008SN/A    // update rx registers
1802008SN/A    uint64_t rxdone = vnic.RxDone;
1812282SN/A    rxdone = set_RxDone_Packets(rxdone, rxFifo.countPacketsAfter(rxFifoPtr));
1822282SN/A    rxdone = set_RxDone_Empty(rxdone, rxFifo.empty());
1835603SN/A    rxdone = set_RxDone_High(rxdone, rxFifo.size() > regs.RxFifoHigh);
1842282SN/A    rxdone = set_RxDone_NotHigh(rxdone, rxLow);
1852008SN/A    regs.RxData = vnic.RxData;
1862008SN/A    regs.RxDone = rxdone;
1872008SN/A    regs.RxWait = rxdone;
1882008SN/A
1892008SN/A    // update tx regsiters
1902008SN/A    uint64_t txdone = vnic.TxDone;
1912008SN/A    txdone = set_TxDone_Packets(txdone, txFifo.packets());
1922008SN/A    txdone = set_TxDone_Full(txdone, txFifo.avail() < regs.TxMaxCopy);
1935603SN/A    txdone = set_TxDone_Low(txdone, txFifo.size() < regs.TxFifoLow);
1942008SN/A    regs.TxData = vnic.TxData;
1952008SN/A    regs.TxDone = txdone;
1962008SN/A    regs.TxWait = txdone;
1975603SN/A
1985603SN/A    int head = 0xffff;
1995603SN/A
2005603SN/A    if (!rxFifo.empty()) {
2015603SN/A        int vnic = rxFifo.begin()->priv;
2025603SN/A        if (vnic != -1 && virtualRegs[vnic].rxPacketOffset > 0)
2035603SN/A            head = vnic;
2045603SN/A    }
2055603SN/A
2065603SN/A    regs.RxStatus = set_RxStatus_Head(regs.RxStatus, head);
2075603SN/A    regs.RxStatus = set_RxStatus_Busy(regs.RxStatus, rxBusyCount);
2085603SN/A    regs.RxStatus = set_RxStatus_Mapped(regs.RxStatus, rxMappedCount);
2095603SN/A    regs.RxStatus = set_RxStatus_Dirty(regs.RxStatus, rxDirtyCount);
2102008SN/A}
2112008SN/A
2122008SN/Avoid
21311005SN/ADevice::prepareWrite(ContextID cpu, int index)
2141997SN/A{
2152008SN/A    prepareIO(cpu, index);
2161997SN/A}
2171997SN/A
2181156SN/A/**
2191939SN/A * I/O read of device register
2201156SN/A */
2212566SN/ATick
2223349SN/ADevice::read(PacketPtr pkt)
2231156SN/A{
2241817SN/A    assert(config.command & PCI_CMD_MSE);
2252641SN/A    assert(pkt->getAddr() >= BARAddrs[0] && pkt->getSize() < BARSize[0]);
2261156SN/A
22711005SN/A    ContextID cpu = pkt->req->contextId();
2282641SN/A    Addr daddr = pkt->getAddr() - BARAddrs[0];
2292008SN/A    Addr index = daddr >> Regs::VirtualShift;
2302008SN/A    Addr raddr = daddr & Regs::VirtualMask;
2311997SN/A
2322008SN/A    if (!regValid(raddr))
2332617SN/A        panic("invalid register: cpu=%d vnic=%d da=%#x pa=%#x size=%d",
2342641SN/A              cpu, index, daddr, pkt->getAddr(), pkt->getSize());
2351156SN/A
2362008SN/A    const Regs::Info &info = regInfo(raddr);
2371939SN/A    if (!info.read)
2382279SN/A        panic("read %s (write only): "
2392617SN/A              "cpu=%d vnic=%d da=%#x pa=%#x size=%d",
2402641SN/A              info.name, cpu, index, daddr, pkt->getAddr(), pkt->getSize());
2411939SN/A
2422279SN/A        panic("read %s (invalid size): "
2432617SN/A              "cpu=%d vnic=%d da=%#x pa=%#x size=%d",
2442641SN/A              info.name, cpu, index, daddr, pkt->getAddr(), pkt->getSize());
2451156SN/A
2462008SN/A    prepareRead(cpu, index);
2471156SN/A
2488641SN/A    uint64_t value M5_VAR_USED = 0;
2492641SN/A    if (pkt->getSize() == 4) {
2502566SN/A        uint32_t reg = regData32(raddr);
25113342Sgabeblack@google.com        pkt->setLE(reg);
2521939SN/A        value = reg;
2531156SN/A    }
2541156SN/A
2552641SN/A    if (pkt->getSize() == 8) {
2562566SN/A        uint64_t reg = regData64(raddr);
25713342Sgabeblack@google.com        pkt->setLE(reg);
2581939SN/A        value = reg;
2591939SN/A    }
2601939SN/A
2611998SN/A    DPRINTF(EthernetPIO,
2622617SN/A            "read %s: cpu=%d vnic=%d da=%#x pa=%#x size=%d val=%#x\n",
2632641SN/A            info.name, cpu, index, daddr, pkt->getAddr(), pkt->getSize(), value);
2641939SN/A
2651939SN/A    // reading the interrupt status register has the side effect of
2661939SN/A    // clearing it
2672008SN/A    if (raddr == Regs::IntrStatus)
2681939SN/A        devIntrClear();
2691156SN/A
2702566SN/A    return pioDelay;
2711156SN/A}
2721156SN/A
2731939SN/A/**
2741939SN/A * IPR read of device register
2752566SN/A
2762566SN/A    Fault
27711005SN/ADevice::iprRead(Addr daddr, ContextID cpu, uint64_t &result)
2781939SN/A{
2791939SN/A    if (!regValid(daddr))
2801939SN/A        panic("invalid address: da=%#x", daddr);
2811939SN/A
2821939SN/A    const Regs::Info &info = regInfo(daddr);
2831939SN/A    if (!info.read)
2841998SN/A        panic("reading %s (write only): cpu=%d da=%#x", info.name, cpu, daddr);
2851939SN/A
2861998SN/A    DPRINTF(EthernetPIO, "IPR read %s: cpu=%d da=%#x\n",
2871998SN/A            info.name, cpu, daddr);
2881939SN/A
2892008SN/A    prepareRead(cpu, 0);
2901939SN/A
2911939SN/A    if (info.size == 4)
2921939SN/A        result = regData32(daddr);
2931939SN/A
2941939SN/A    if (info.size == 8)
2951939SN/A        result = regData64(daddr);
2961939SN/A
2971998SN/A    DPRINTF(EthernetPIO, "IPR read %s: cpu=%s da=%#x val=%#x\n",
2981998SN/A            info.name, cpu, result);
2991939SN/A
3002090SN/A    return NoFault;
3011939SN/A}
3022566SN/A*/
3031939SN/A/**
3041939SN/A * I/O write of device register
3051939SN/A */
3062566SN/ATick
3073349SN/ADevice::write(PacketPtr pkt)
3081156SN/A{
3091817SN/A    assert(config.command & PCI_CMD_MSE);
3102641SN/A    assert(pkt->getAddr() >= BARAddrs[0] && pkt->getSize() < BARSize[0]);
3111939SN/A
31211005SN/A    ContextID cpu = pkt->req->contextId();
3132641SN/A    Addr daddr = pkt->getAddr() - BARAddrs[0];
3142008SN/A    Addr index = daddr >> Regs::VirtualShift;
3152008SN/A    Addr raddr = daddr & Regs::VirtualMask;
3161997SN/A
3172008SN/A    if (!regValid(raddr))
3182566SN/A        panic("invalid register: cpu=%d, da=%#x pa=%#x size=%d",
3192641SN/A                cpu, daddr, pkt->getAddr(), pkt->getSize());
3201156SN/A
3212008SN/A    const Regs::Info &info = regInfo(raddr);
3221939SN/A    if (!info.write)
3232279SN/A        panic("write %s (read only): "
3242617SN/A              "cpu=%d vnic=%d da=%#x pa=%#x size=%d",
3252641SN/A              info.name, cpu, index, daddr, pkt->getAddr(), pkt->getSize());
3261939SN/A
3272641SN/A    if (pkt->getSize() != info.size)
3282279SN/A        panic("write %s (invalid size): "
3292617SN/A              "cpu=%d vnic=%d da=%#x pa=%#x size=%d",
3302641SN/A              info.name, cpu, index, daddr, pkt->getAddr(), pkt->getSize());
3311156SN/A
3322176SN/A    VirtualReg &vnic = virtualRegs[index];
3332176SN/A
3341998SN/A    DPRINTF(EthernetPIO,
3352617SN/A            "write %s vnic %d: cpu=%d val=%#x da=%#x pa=%#x size=%d\n",
33613342Sgabeblack@google.com            info.name, index, cpu, info.size == 4 ?
33713342Sgabeblack@google.com            pkt->getLE<uint32_t>() : pkt->getLE<uint64_t>(),
33813342Sgabeblack@google.com            daddr, pkt->getAddr(), pkt->getSize());
3391156SN/A
3402008SN/A    prepareWrite(cpu, index);
3411156SN/A
3422008SN/A    switch (raddr) {
3431156SN/A      case Regs::Config:
34413342Sgabeblack@google.com        changeConfig(pkt->getLE<uint32_t>());
3451156SN/A        break;
3461156SN/A
3471939SN/A      case Regs::Command:
34813342Sgabeblack@google.com        command(pkt->getLE<uint32_t>());
3491156SN/A        break;
3501156SN/A
3511939SN/A      case Regs::IntrStatus:
35213342Sgabeblack@google.com        devIntrClear(regs.IntrStatus &
35313342Sgabeblack@google.com                pkt->getLE<uint32_t>());
3541156SN/A        break;
3551156SN/A
3561156SN/A      case Regs::IntrMask:
35713342Sgabeblack@google.com        devIntrChangeMask(pkt->getLE<uint32_t>());
3581156SN/A        break;
3591156SN/A
3601156SN/A      case Regs::RxData:
3612008SN/A        if (Regs::get_RxDone_Busy(vnic.RxDone))
3621939SN/A            panic("receive machine busy with another request! rxState=%s",
3631939SN/A                  RxStateStrings[rxState]);
3641156SN/A
3652282SN/A        vnic.rxUnique = rxUnique++;
3662008SN/A        vnic.RxDone = Regs::RxDone_Busy;
36713342Sgabeblack@google.com        vnic.RxData = pkt->getLE<uint64_t>();
3685603SN/A        rxBusyCount++;
3692282SN/A
37013342Sgabeblack@google.com        if (Regs::get_RxData_Vaddr(pkt->getLE<uint64_t>())) {
3712627SN/A            panic("vtophys not implemented in newmem");
3725603SN/A#ifdef SINIC_VTOPHYS
3735603SN/A            Addr vaddr = Regs::get_RxData_Addr(reg64);
3742282SN/A            Addr paddr = vtophys(req->xc, vaddr);
3752282SN/A            DPRINTF(EthernetPIO, "write RxData vnic %d (rxunique %d): "
3762282SN/A                    "vaddr=%#x, paddr=%#x\n",
3772282SN/A                    index, vnic.rxUnique, vaddr, paddr);
3782282SN/A
3795603SN/A            vnic.RxData = Regs::set_RxData_Addr(vnic.RxData, paddr);
3805603SN/A#endif
3812282SN/A        } else {
3822282SN/A            DPRINTF(EthernetPIO, "write RxData vnic %d (rxunique %d)\n",
3832282SN/A                    index, vnic.rxUnique);
3842282SN/A        }
3852282SN/A
3865603SN/A        if (vnic.rxIndex == rxFifo.end()) {
3872282SN/A            DPRINTF(EthernetPIO, "request new packet...appending to rxList\n");
3882282SN/A            rxList.push_back(index);
3892282SN/A        } else {
3902282SN/A            DPRINTF(EthernetPIO, "packet exists...appending to rxBusy\n");
3912282SN/A            rxBusy.push_back(index);
3922282SN/A        }
3932282SN/A
3942282SN/A        if (rxEnable && (rxState == rxIdle || rxState == rxFifoBlock)) {
3951156SN/A            rxState = rxFifoBlock;
3961156SN/A            rxKick();
3971156SN/A        }
3981156SN/A        break;
3991156SN/A
4001156SN/A      case Regs::TxData:
4012008SN/A        if (Regs::get_TxDone_Busy(vnic.TxDone))
4021939SN/A            panic("transmit machine busy with another request! txState=%s",
4031939SN/A                  TxStateStrings[txState]);
4041156SN/A
4052282SN/A        vnic.txUnique = txUnique++;
4062008SN/A        vnic.TxDone = Regs::TxDone_Busy;
4072282SN/A
40813342Sgabeblack@google.com        if (Regs::get_TxData_Vaddr(pkt->getLE<uint64_t>())) {
4092617SN/A            panic("vtophys won't work here in newmem.\n");
4105603SN/A#ifdef SINIC_VTOPHYS
4115603SN/A            Addr vaddr = Regs::get_TxData_Addr(reg64);
4122282SN/A            Addr paddr = vtophys(req->xc, vaddr);
4135603SN/A            DPRINTF(EthernetPIO, "write TxData vnic %d (txunique %d): "
4142282SN/A                    "vaddr=%#x, paddr=%#x\n",
4152282SN/A                    index, vnic.txUnique, vaddr, paddr);
4162282SN/A
4175603SN/A            vnic.TxData = Regs::set_TxData_Addr(vnic.TxData, paddr);
4185603SN/A#endif
4192282SN/A        } else {
4205603SN/A            DPRINTF(EthernetPIO, "write TxData vnic %d (txunique %d)\n",
4212282SN/A                    index, vnic.txUnique);
4222282SN/A        }
4232282SN/A
4242008SN/A        if (txList.empty() || txList.front() != index)
4252008SN/A            txList.push_back(index);
4262010SN/A        if (txEnable && txState == txIdle && txList.front() == index) {
4271156SN/A            txState = txFifoBlock;
4281156SN/A            txKick();
4291156SN/A        }
4301156SN/A        break;
4311156SN/A    }
4322176SN/A
4332566SN/A    return pioDelay;
4341156SN/A}
4351156SN/A
4361156SN/Avoid
4371156SN/ADevice::devIntrPost(uint32_t interrupts)
4381156SN/A{
4391156SN/A    if ((interrupts & Regs::Intr_Res))
4401156SN/A        panic("Cannot set a reserved interrupt");
4411156SN/A
4421156SN/A    regs.IntrStatus |= interrupts;
4431156SN/A
4441156SN/A    DPRINTF(EthernetIntr,
4451156SN/A            "interrupt written to intStatus: intr=%#x status=%#x mask=%#x\n",
4461156SN/A            interrupts, regs.IntrStatus, regs.IntrMask);
4471156SN/A
4481939SN/A    interrupts = regs.IntrStatus & regs.IntrMask;
4491939SN/A
4501939SN/A    // Intr_RxHigh is special, we only signal it if we've emptied the fifo
4511939SN/A    // and then filled it above the high watermark
4521939SN/A    if (rxEmpty)
4531939SN/A        rxEmpty = false;
4541939SN/A    else
4551939SN/A        interrupts &= ~Regs::Intr_RxHigh;
4561939SN/A
4571939SN/A    // Intr_TxLow is special, we only signal it if we've filled up the fifo
4581939SN/A    // and then dropped below the low watermark
4591939SN/A    if (txFull)
4601939SN/A        txFull = false;
4611939SN/A    else
4621939SN/A        interrupts &= ~Regs::Intr_TxLow;
4631939SN/A
4641939SN/A    if (interrupts) {
4657823SN/A        Tick when = curTick();
4661939SN/A        if ((interrupts & Regs::Intr_NoDelay) == 0)
4671156SN/A            when += intrDelay;
4681156SN/A        cpuIntrPost(when);
4691156SN/A    }
4701156SN/A}
4711156SN/A
4721156SN/Avoid
4731156SN/ADevice::devIntrClear(uint32_t interrupts)
4741156SN/A{
4751156SN/A    if ((interrupts & Regs::Intr_Res))
4761156SN/A        panic("Cannot clear a reserved interrupt");
4771156SN/A
4781156SN/A    regs.IntrStatus &= ~interrupts;
4791156SN/A
4801156SN/A    DPRINTF(EthernetIntr,
4811156SN/A            "interrupt cleared from intStatus: intr=%x status=%x mask=%x\n",
4821156SN/A            interrupts, regs.IntrStatus, regs.IntrMask);
4831156SN/A
4841156SN/A    if (!(regs.IntrStatus & regs.IntrMask))
4851156SN/A        cpuIntrClear();
4861156SN/A}
4871156SN/A
4881156SN/Avoid
4891156SN/ADevice::devIntrChangeMask(uint32_t newmask)
4901156SN/A{
4911156SN/A    if (regs.IntrMask == newmask)
4921156SN/A        return;
4931156SN/A
4941156SN/A    regs.IntrMask = newmask;
4951156SN/A
4961156SN/A    DPRINTF(EthernetIntr,
4971156SN/A            "interrupt mask changed: intStatus=%x intMask=%x masked=%x\n",
4981156SN/A            regs.IntrStatus, regs.IntrMask, regs.IntrStatus & regs.IntrMask);
4991156SN/A
5001156SN/A    if (regs.IntrStatus & regs.IntrMask)
5017823SN/A        cpuIntrPost(curTick());
5021156SN/A    else
5031156SN/A        cpuIntrClear();
5041156SN/A}
5051156SN/A
5061156SN/Avoid
5071156SN/ABase::cpuIntrPost(Tick when)
5081156SN/A{
5091156SN/A    // If the interrupt you want to post is later than an interrupt
5101156SN/A    // already scheduled, just let it post in the coming one and don't
5111156SN/A    // schedule another.
5121156SN/A    // HOWEVER, must be sure that the scheduled intrTick is in the
5131156SN/A    // future (this was formerly the source of a bug)
5141156SN/A    /**
5151156SN/A     * @todo this warning should be removed and the intrTick code should
5161156SN/A     * be fixed.
5171156SN/A     */
5187823SN/A    assert(when >= curTick());
5197823SN/A    assert(intrTick >= curTick() || intrTick == 0);
5201156SN/A    if (!cpuIntrEnable) {
5211156SN/A        DPRINTF(EthernetIntr, "interrupts not enabled.\n",
5221156SN/A                intrTick);
5231156SN/A        return;
5241156SN/A    }
5251156SN/A
5261156SN/A    if (when > intrTick && intrTick != 0) {
5271156SN/A        DPRINTF(EthernetIntr, "don't need to schedule event...intrTick=%d\n",
5281156SN/A                intrTick);
5291156SN/A        return;
5301156SN/A    }
5311156SN/A
5321156SN/A    intrTick = when;
5337823SN/A    if (intrTick < curTick()) {
5347823SN/A        intrTick = curTick();
5351156SN/A    }
5361156SN/A
5371156SN/A    DPRINTF(EthernetIntr, "going to schedule an interrupt for intrTick=%d\n",
5381156SN/A            intrTick);
5391156SN/A
5401156SN/A    if (intrEvent)
5411156SN/A        intrEvent->squash();
54212087Sspwilson2@wisc.edu
54312087Sspwilson2@wisc.edu    intrEvent = new EventFunctionWrapper([this]{ cpuInterrupt(); },
54412087Sspwilson2@wisc.edu                                         name(), true);
5455606SN/A    schedule(intrEvent, intrTick);
5461156SN/A}
5471156SN/A
5481156SN/Avoid
5491156SN/ABase::cpuInterrupt()
5501156SN/A{
5517823SN/A    assert(intrTick == curTick());
5521156SN/A
5531156SN/A    // Whether or not there's a pending interrupt, we don't care about
5541156SN/A    // it anymore
5551156SN/A    intrEvent = 0;
5561156SN/A    intrTick = 0;
5571156SN/A
5581156SN/A    // Don't send an interrupt if there's already one
5591156SN/A    if (cpuPendingIntr) {
5601156SN/A        DPRINTF(EthernetIntr,
5611156SN/A                "would send an interrupt now, but there's already pending\n");
5621156SN/A    } else {
5631156SN/A        // Send interrupt
5641156SN/A        cpuPendingIntr = true;
5651156SN/A
5661156SN/A        DPRINTF(EthernetIntr, "posting interrupt\n");
5671156SN/A        intrPost();
5681156SN/A    }
5691156SN/A}
5701156SN/A
5711156SN/Avoid
5721156SN/ABase::cpuIntrClear()
5731156SN/A{
5741156SN/A    if (!cpuPendingIntr)
5751156SN/A        return;
5761156SN/A
5771156SN/A    if (intrEvent) {
5781156SN/A        intrEvent->squash();
5791156SN/A        intrEvent = 0;
5801156SN/A    }
5811156SN/A
5821156SN/A    intrTick = 0;
5831156SN/A
5841156SN/A    cpuPendingIntr = false;
5851156SN/A
5861156SN/A    DPRINTF(EthernetIntr, "clearing cchip interrupt\n");
5871156SN/A    intrClear();
5881156SN/A}
5891156SN/A
5901156SN/Abool
5911156SN/ABase::cpuIntrPending() const
5921156SN/A{ return cpuPendingIntr; }
5931156SN/A
5941156SN/Avoid
5951156SN/ADevice::changeConfig(uint32_t newconf)
5961156SN/A{
5971156SN/A    uint32_t changed = regs.Config ^ newconf;
5981156SN/A    if (!changed)
5991156SN/A        return;
6001156SN/A
6011156SN/A    regs.Config = newconf;
6021156SN/A
6031156SN/A    if ((changed & Regs::Config_IntEn)) {
6041156SN/A        cpuIntrEnable = regs.Config & Regs::Config_IntEn;
6051156SN/A        if (cpuIntrEnable) {
6061156SN/A            if (regs.IntrStatus & regs.IntrMask)
6077823SN/A                cpuIntrPost(curTick());
6081156SN/A        } else {
6091156SN/A            cpuIntrClear();
6101156SN/A        }
6111156SN/A    }
6121156SN/A
6131156SN/A    if ((changed & Regs::Config_TxEn)) {
6141156SN/A        txEnable = regs.Config & Regs::Config_TxEn;
6151156SN/A        if (txEnable)
6161156SN/A            txKick();
6171156SN/A    }
6181156SN/A
6191156SN/A    if ((changed & Regs::Config_RxEn)) {
6201156SN/A        rxEnable = regs.Config & Regs::Config_RxEn;
6211156SN/A        if (rxEnable)
6221156SN/A            rxKick();
6231156SN/A    }
6241156SN/A}
6251156SN/A
6261156SN/Avoid
6271939SN/ADevice::command(uint32_t command)
6281939SN/A{
6292008SN/A    if (command & Regs::Command_Intr)
6302008SN/A        devIntrPost(Regs::Intr_Soft);
6312008SN/A
6321939SN/A    if (command & Regs::Command_Reset)
6331939SN/A        reset();
6341939SN/A}
6351939SN/A
6361939SN/Avoid
6371156SN/ADevice::reset()
6381156SN/A{
6391156SN/A    using namespace Regs;
6401939SN/A
6411156SN/A    memset(&regs, 0, sizeof(regs));
6421939SN/A
6431939SN/A    regs.Config = 0;
6442008SN/A    if (params()->rx_thread)
6452008SN/A        regs.Config |= Config_RxThread;
6462008SN/A    if (params()->tx_thread)
6472008SN/A        regs.Config |= Config_TxThread;
6482210SN/A    if (params()->rss)
6492210SN/A        regs.Config |= Config_RSS;
6502282SN/A    if (params()->zero_copy)
6512282SN/A        regs.Config |= Config_ZeroCopy;
6522282SN/A    if (params()->delay_copy)
6532282SN/A        regs.Config |= Config_DelayCopy;
6542282SN/A    if (params()->virtual_addr)
6552282SN/A        regs.Config |= Config_Vaddr;
6562282SN/A
6572282SN/A    if (params()->delay_copy && params()->zero_copy)
6582282SN/A        panic("Can't delay copy and zero copy");
6592282SN/A
6602008SN/A    regs.IntrMask = Intr_Soft | Intr_RxHigh | Intr_RxPacket | Intr_TxLow;
6611156SN/A    regs.RxMaxCopy = params()->rx_max_copy;
6621156SN/A    regs.TxMaxCopy = params()->tx_max_copy;
6635603SN/A    regs.ZeroCopySize = params()->zero_copy_size;
6645603SN/A    regs.ZeroCopyMark = params()->zero_copy_threshold;
6655603SN/A    regs.VirtualCount = params()->virtual_count;
6661939SN/A    regs.RxMaxIntr = params()->rx_max_intr;
6671939SN/A    regs.RxFifoSize = params()->rx_fifo_size;
6681939SN/A    regs.TxFifoSize = params()->tx_fifo_size;
6695603SN/A    regs.RxFifoLow = params()->rx_fifo_low_mark;
6705603SN/A    regs.TxFifoLow = params()->tx_fifo_threshold;
6715603SN/A    regs.RxFifoHigh = params()->rx_fifo_threshold;
6725603SN/A    regs.TxFifoHigh = params()->tx_fifo_high_mark;
6734762SN/A    regs.HwAddr = params()->hardware_address;
6741156SN/A
6755603SN/A    if (regs.RxMaxCopy < regs.ZeroCopyMark)
6765603SN/A        panic("Must be able to copy at least as many bytes as the threshold");
6775603SN/A
6785603SN/A    if (regs.ZeroCopySize >= regs.ZeroCopyMark)
6795603SN/A        panic("The number of bytes to copy must be less than the threshold");
6805603SN/A
6812008SN/A    rxList.clear();
6822282SN/A    rxBusy.clear();
6832282SN/A    rxActive = -1;
6842008SN/A    txList.clear();
6855603SN/A    rxBusyCount = 0;
6865603SN/A    rxDirtyCount = 0;
6875603SN/A    rxMappedCount = 0;
6882008SN/A
6891156SN/A    rxState = rxIdle;
6901156SN/A    txState = txIdle;
6911156SN/A
6921156SN/A    rxFifo.clear();
6932008SN/A    rxFifoPtr = rxFifo.end();
6941156SN/A    txFifo.clear();
6951939SN/A    rxEmpty = false;
6962282SN/A    rxLow = true;
6971939SN/A    txFull = false;
6982008SN/A
6992008SN/A    int size = virtualRegs.size();
7002008SN/A    virtualRegs.clear();
7012008SN/A    virtualRegs.resize(size);
7022008SN/A    for (int i = 0; i < size; ++i)
7035603SN/A        virtualRegs[i].rxIndex = rxFifo.end();
7041156SN/A}
7051156SN/A
7061156SN/Avoid
7072566SN/ADevice::rxDmaDone()
7081156SN/A{
7091156SN/A    assert(rxState == rxCopy);
7101156SN/A    rxState = rxCopyDone;
7112280SN/A    DPRINTF(EthernetDMA, "end rx dma write paddr=%#x len=%d\n",
7121156SN/A            rxDmaAddr, rxDmaLen);
7131939SN/A    DDUMP(EthernetData, rxDmaData, rxDmaLen);
7141939SN/A
7151939SN/A    // If the transmit state machine  has a pending DMA, let it go first
7161939SN/A    if (txState == txBeginCopy)
7171939SN/A        txKick();
7181939SN/A
7191156SN/A    rxKick();
7201156SN/A}
7211156SN/A
7221156SN/Avoid
7231156SN/ADevice::rxKick()
7241156SN/A{
7252282SN/A    VirtualReg *vnic = NULL;
7262008SN/A
7272279SN/A    DPRINTF(EthernetSM, "rxKick: rxState=%s (rxFifo.size=%d)\n",
7281156SN/A            RxStateStrings[rxState], rxFifo.size());
7291156SN/A
7307823SN/A    if (rxKickTick > curTick()) {
7312279SN/A        DPRINTF(EthernetSM, "rxKick: exiting, can't run till %d\n",
7321156SN/A                rxKickTick);
7331156SN/A        return;
7341156SN/A    }
7351156SN/A
7361156SN/A  next:
7375603SN/A    rxFifo.check();
7382008SN/A    if (rxState == rxIdle)
7391156SN/A        goto exit;
7401156SN/A
7412282SN/A    if (rxActive == -1) {
7422282SN/A        if (rxState != rxFifoBlock)
7432282SN/A            panic("no active vnic while in state %s", RxStateStrings[rxState]);
7442008SN/A
7452282SN/A        DPRINTF(EthernetSM, "processing rxState=%s\n",
7462282SN/A                RxStateStrings[rxState]);
7472282SN/A    } else {
7482282SN/A        vnic = &virtualRegs[rxActive];
7492282SN/A        DPRINTF(EthernetSM,
7502282SN/A                "processing rxState=%s for vnic %d (rxunique %d)\n",
7512282SN/A                RxStateStrings[rxState], rxActive, vnic->rxUnique);
7522282SN/A    }
7532008SN/A
7542008SN/A    switch (rxState) {
7551156SN/A      case rxFifoBlock:
7562282SN/A        if (DTRACE(EthernetSM)) {
7572282SN/A            PacketFifo::iterator end = rxFifo.end();
7582282SN/A            int size = virtualRegs.size();
7592282SN/A            for (int i = 0; i < size; ++i) {
7602282SN/A                VirtualReg *vn = &virtualRegs[i];
7615603SN/A                bool busy = Regs::get_RxDone_Busy(vn->RxDone);
7625603SN/A                if (vn->rxIndex != end) {
7638641SN/A#ifndef NDEBUG
7645603SN/A                    bool dirty = vn->rxPacketOffset > 0;
7655603SN/A                    const char *status;
7665603SN/A
7675603SN/A                    if (busy && dirty)
7685603SN/A                        status = "busy,dirty";
7695603SN/A                    else if (busy)
7705603SN/A                        status = "busy";
7715603SN/A                    else if (dirty)
7725603SN/A                        status = "dirty";
7735603SN/A                    else
7745603SN/A                        status = "mapped";
7755603SN/A
7762282SN/A                    DPRINTF(EthernetSM,
7775603SN/A                            "vnic %d %s (rxunique %d), packet %d, slack %d\n",
7785603SN/A                            i, status, vn->rxUnique,
7795603SN/A                            rxFifo.countPacketsBefore(vn->rxIndex),
7805603SN/A                            vn->rxIndex->slack);
7818641SN/A#endif
7825603SN/A                } else if (busy) {
7835603SN/A                    DPRINTF(EthernetSM, "vnic %d unmapped (rxunique %d)\n",
7845603SN/A                            i, vn->rxUnique);
7852282SN/A                }
7862282SN/A            }
7872282SN/A        }
7882282SN/A
7892282SN/A        if (!rxBusy.empty()) {
7902282SN/A            rxActive = rxBusy.front();
7912282SN/A            rxBusy.pop_front();
7922282SN/A            vnic = &virtualRegs[rxActive];
7932282SN/A
7945603SN/A            if (vnic->rxIndex == rxFifo.end())
7952282SN/A                panic("continuing vnic without packet\n");
7962282SN/A
7972282SN/A            DPRINTF(EthernetSM,
7982282SN/A                    "continue processing for vnic %d (rxunique %d)\n",
7992282SN/A                    rxActive, vnic->rxUnique);
8002282SN/A
8011156SN/A            rxState = rxBeginCopy;
8022282SN/A
8035603SN/A            int vnic_distance = rxFifo.countPacketsBefore(vnic->rxIndex);
8045603SN/A            totalVnicDistance += vnic_distance;
8055603SN/A            numVnicDistance += 1;
8065603SN/A            if (vnic_distance > _maxVnicDistance) {
8075603SN/A                maxVnicDistance = vnic_distance;
8085603SN/A                _maxVnicDistance = vnic_distance;
8095603SN/A            }
8105603SN/A
8111156SN/A            break;
8121156SN/A        }
8131156SN/A
8142008SN/A        if (rxFifoPtr == rxFifo.end()) {
8151156SN/A            DPRINTF(EthernetSM, "receive waiting for data.  Nothing to do.\n");
8161156SN/A            goto exit;
8171156SN/A        }
8181156SN/A
8192282SN/A        if (rxList.empty())
8202282SN/A            panic("Not idle, but nothing to do!");
8212282SN/A
8222008SN/A        assert(!rxFifo.empty());
8232008SN/A
8242282SN/A        rxActive = rxList.front();
8252282SN/A        rxList.pop_front();
8262282SN/A        vnic = &virtualRegs[rxActive];
8272282SN/A
8282282SN/A        DPRINTF(EthernetSM,
8292282SN/A                "processing new packet for vnic %d (rxunique %d)\n",
8302282SN/A                rxActive, vnic->rxUnique);
8312282SN/A
8321156SN/A        // Grab a new packet from the fifo.
8335603SN/A        vnic->rxIndex = rxFifoPtr++;
8345603SN/A        vnic->rxIndex->priv = rxActive;
8352008SN/A        vnic->rxPacketOffset = 0;
8365603SN/A        vnic->rxPacketBytes = vnic->rxIndex->packet->length;
8372008SN/A        assert(vnic->rxPacketBytes);
8385603SN/A        rxMappedCount++;
8391156SN/A
8402008SN/A        vnic->rxDoneData = 0;
8411156SN/A        /* scope for variables */ {
8425603SN/A            IpPtr ip(vnic->rxIndex->packet);
8431156SN/A            if (ip) {
8442280SN/A                DPRINTF(Ethernet, "ID is %d\n", ip->id());
8452008SN/A                vnic->rxDoneData |= Regs::RxDone_IpPacket;
8461156SN/A                rxIpChecksums++;
8471156SN/A                if (cksum(ip) != 0) {
8481156SN/A                    DPRINTF(EthernetCksum, "Rx IP Checksum Error\n");
8492008SN/A                    vnic->rxDoneData |= Regs::RxDone_IpError;
8501156SN/A                }
8511156SN/A                TcpPtr tcp(ip);
8521156SN/A                UdpPtr udp(ip);
8531156SN/A                if (tcp) {
8542279SN/A                    DPRINTF(Ethernet,
8552279SN/A                            "Src Port=%d, Dest Port=%d, Seq=%d, Ack=%d\n",
8562279SN/A                            tcp->sport(), tcp->dport(), tcp->seq(),
8572279SN/A                            tcp->ack());
8582008SN/A                    vnic->rxDoneData |= Regs::RxDone_TcpPacket;
8591156SN/A                    rxTcpChecksums++;
8601156SN/A                    if (cksum(tcp) != 0) {
8611156SN/A                        DPRINTF(EthernetCksum, "Rx TCP Checksum Error\n");
8622008SN/A                        vnic->rxDoneData |= Regs::RxDone_TcpError;
8631156SN/A                    }
8641156SN/A                } else if (udp) {
8652008SN/A                    vnic->rxDoneData |= Regs::RxDone_UdpPacket;
8661156SN/A                    rxUdpChecksums++;
8671156SN/A                    if (cksum(udp) != 0) {
8681156SN/A                        DPRINTF(EthernetCksum, "Rx UDP Checksum Error\n");
8692008SN/A                        vnic->rxDoneData |= Regs::RxDone_UdpError;
8701156SN/A                    }
8711156SN/A                }
8721156SN/A            }
8731156SN/A        }
8741156SN/A        rxState = rxBeginCopy;
8751156SN/A        break;
8761156SN/A
8771156SN/A      case rxBeginCopy:
87810913SN/A        if (dmaPending() || drainState() != DrainState::Running)
8791939SN/A            goto exit;
8801939SN/A
88111202SN/A        rxDmaAddr = pciToDma(Regs::get_RxData_Addr(vnic->RxData));
8826227SN/A        rxDmaLen = min<unsigned>(Regs::get_RxData_Len(vnic->RxData),
8836227SN/A                                 vnic->rxPacketBytes);
8845603SN/A
8855603SN/A        /*
8865603SN/A         * if we're doing zero/delay copy and we're below the fifo
8875603SN/A         * threshold, see if we should try to do the zero/defer copy
8885603SN/A         */
8895603SN/A        if ((Regs::get_Config_ZeroCopy(regs.Config) ||
8905603SN/A             Regs::get_Config_DelayCopy(regs.Config)) &&
8915603SN/A            !Regs::get_RxData_NoDelay(vnic->RxData) && rxLow) {
8925603SN/A            if (rxDmaLen > regs.ZeroCopyMark)
8935603SN/A                rxDmaLen = regs.ZeroCopySize;
8945603SN/A        }
8955603SN/A        rxDmaData = vnic->rxIndex->packet->data + vnic->rxPacketOffset;
8961939SN/A        rxState = rxCopy;
8972282SN/A        if (rxDmaAddr == 1LL) {
8982282SN/A            rxState = rxCopyDone;
8992282SN/A            break;
9002282SN/A        }
9012282SN/A
9022566SN/A        dmaWrite(rxDmaAddr, rxDmaLen, &rxDmaEvent, rxDmaData);
9031156SN/A        break;
9041156SN/A
9051156SN/A      case rxCopy:
9061156SN/A        DPRINTF(EthernetSM, "receive machine still copying\n");
9071156SN/A        goto exit;
9081156SN/A
9091156SN/A      case rxCopyDone:
9102282SN/A        vnic->RxDone = vnic->rxDoneData;
9112008SN/A        vnic->RxDone |= Regs::RxDone_Complete;
9125603SN/A        rxBusyCount--;
9131156SN/A
9142008SN/A        if (vnic->rxPacketBytes == rxDmaLen) {
9155603SN/A            if (vnic->rxPacketOffset)
9165603SN/A                rxDirtyCount--;
9175603SN/A
9182282SN/A            // Packet is complete.  Indicate how many bytes were copied
9192282SN/A            vnic->RxDone = Regs::set_RxDone_CopyLen(vnic->RxDone, rxDmaLen);
9202282SN/A
9212282SN/A            DPRINTF(EthernetSM,
9222282SN/A                    "rxKick: packet complete on vnic %d (rxunique %d)\n",
9232282SN/A                    rxActive, vnic->rxUnique);
9245603SN/A            rxFifo.remove(vnic->rxIndex);
9255603SN/A            vnic->rxIndex = rxFifo.end();
9265603SN/A            rxMappedCount--;
9271156SN/A        } else {
9285603SN/A            if (!vnic->rxPacketOffset)
9295603SN/A                rxDirtyCount++;
9305603SN/A
9312008SN/A            vnic->rxPacketBytes -= rxDmaLen;
9322008SN/A            vnic->rxPacketOffset += rxDmaLen;
9332282SN/A            vnic->RxDone |= Regs::RxDone_More;
9342282SN/A            vnic->RxDone = Regs::set_RxDone_CopyLen(vnic->RxDone,
9352282SN/A                                                    vnic->rxPacketBytes);
9362010SN/A            DPRINTF(EthernetSM,
9372282SN/A                    "rxKick: packet not complete on vnic %d (rxunique %d): "
9382282SN/A                    "%d bytes left\n",
9392282SN/A                    rxActive, vnic->rxUnique, vnic->rxPacketBytes);
9401156SN/A        }
9411156SN/A
9422282SN/A        rxActive = -1;
9432282SN/A        rxState = rxBusy.empty() && rxList.empty() ? rxIdle : rxFifoBlock;
9442008SN/A
9452008SN/A        if (rxFifo.empty()) {
9462008SN/A            devIntrPost(Regs::Intr_RxEmpty);
9472008SN/A            rxEmpty = true;
9482008SN/A        }
9492008SN/A
9505603SN/A        if (rxFifo.size() < regs.RxFifoLow)
9512282SN/A            rxLow = true;
9522282SN/A
9535603SN/A        if (rxFifo.size() > regs.RxFifoHigh)
9542282SN/A            rxLow = false;
9552282SN/A
9561939SN/A        devIntrPost(Regs::Intr_RxDMA);
9571156SN/A        break;
9581156SN/A
9591156SN/A      default:
9601156SN/A        panic("Invalid rxState!");
9611156SN/A    }
9621156SN/A
9631156SN/A    DPRINTF(EthernetSM, "entering next rxState=%s\n",
9641156SN/A            RxStateStrings[rxState]);
9651156SN/A
9661156SN/A    goto next;
9671156SN/A
9681156SN/A  exit:
9691156SN/A    /**
9701156SN/A     * @todo do we want to schedule a future kick?
9711156SN/A     */
9721156SN/A    DPRINTF(EthernetSM, "rx state machine exited rxState=%s\n",
9731156SN/A            RxStateStrings[rxState]);
9741156SN/A}
9751156SN/A
9761156SN/Avoid
9772566SN/ADevice::txDmaDone()
9781156SN/A{
9791156SN/A    assert(txState == txCopy);
9801156SN/A    txState = txCopyDone;
9811156SN/A    DPRINTF(EthernetDMA, "tx dma read paddr=%#x len=%d\n",
9821156SN/A            txDmaAddr, txDmaLen);
9831939SN/A    DDUMP(EthernetData, txDmaData, txDmaLen);
9841939SN/A
9851939SN/A    // If the receive state machine  has a pending DMA, let it go first
9861939SN/A    if (rxState == rxBeginCopy)
9871939SN/A        rxKick();
9881939SN/A
9891156SN/A    txKick();
9901156SN/A}
9911156SN/A
9921156SN/Avoid
9931156SN/ADevice::transmit()
9941156SN/A{
9951156SN/A    if (txFifo.empty()) {
9961156SN/A        DPRINTF(Ethernet, "nothing to transmit\n");
9971156SN/A        return;
9981156SN/A    }
9991156SN/A
10001939SN/A    uint32_t interrupts;
10012566SN/A    EthPacketPtr packet = txFifo.front();
10021156SN/A    if (!interface->sendPacket(packet)) {
10031156SN/A        DPRINTF(Ethernet, "Packet Transmit: failed txFifo available %d\n",
10041156SN/A                txFifo.avail());
10055603SN/A        return;
10061156SN/A    }
10071156SN/A
10081156SN/A    txFifo.pop();
10091156SN/A#if TRACING_ON
10101156SN/A    if (DTRACE(Ethernet)) {
10111156SN/A        IpPtr ip(packet);
10121156SN/A        if (ip) {
10131156SN/A            DPRINTF(Ethernet, "ID is %d\n", ip->id());
10141156SN/A            TcpPtr tcp(ip);
10151156SN/A            if (tcp) {
10162280SN/A                DPRINTF(Ethernet,
10172280SN/A                        "Src Port=%d, Dest Port=%d, Seq=%d, Ack=%d\n",
10182280SN/A                        tcp->sport(), tcp->dport(), tcp->seq(),
10192280SN/A                        tcp->ack());
10201156SN/A            }
10211156SN/A        }
10221156SN/A    }
10231156SN/A#endif
10241156SN/A
10251939SN/A    DDUMP(EthernetData, packet->data, packet->length);
10261156SN/A    txBytes += packet->length;
10271156SN/A    txPackets++;
10281156SN/A
10291156SN/A    DPRINTF(Ethernet, "Packet Transmit: successful txFifo Available %d\n",
10301156SN/A            txFifo.avail());
10311156SN/A
10321939SN/A    interrupts = Regs::Intr_TxPacket;
10335603SN/A    if (txFifo.size() < regs.TxFifoLow)
10341939SN/A        interrupts |= Regs::Intr_TxLow;
10351939SN/A    devIntrPost(interrupts);
10361156SN/A}
10371156SN/A
10381156SN/Avoid
10391156SN/ADevice::txKick()
10401156SN/A{
10412008SN/A    VirtualReg *vnic;
10422279SN/A    DPRINTF(EthernetSM, "txKick: txState=%s (txFifo.size=%d)\n",
10431156SN/A            TxStateStrings[txState], txFifo.size());
10441156SN/A
10457823SN/A    if (txKickTick > curTick()) {
10462279SN/A        DPRINTF(EthernetSM, "txKick: exiting, can't run till %d\n",
10471156SN/A                txKickTick);
10481156SN/A        return;
10491156SN/A    }
10501156SN/A
10511156SN/A  next:
10522008SN/A    if (txState == txIdle)
10531156SN/A        goto exit;
10541156SN/A
10552008SN/A    assert(!txList.empty());
10562008SN/A    vnic = &virtualRegs[txList.front()];
10572008SN/A
10582008SN/A    switch (txState) {
10591156SN/A      case txFifoBlock:
10602280SN/A        assert(Regs::get_TxDone_Busy(vnic->TxDone));
10611156SN/A        if (!txPacket) {
10621156SN/A            // Grab a new packet from the fifo.
106310469SN/A            txPacket = make_shared<EthPacketData>(16384);
10642008SN/A            txPacketOffset = 0;
10651156SN/A        }
10661156SN/A
10671156SN/A        if (txFifo.avail() - txPacket->length <
10682008SN/A            Regs::get_TxData_Len(vnic->TxData)) {
10691156SN/A            DPRINTF(EthernetSM, "transmit fifo full.  Nothing to do.\n");
10701156SN/A            goto exit;
10711156SN/A        }
10721156SN/A
10731156SN/A        txState = txBeginCopy;
10741156SN/A        break;
10751156SN/A
10761156SN/A      case txBeginCopy:
107710913SN/A        if (dmaPending() || drainState() != DrainState::Running)
10781939SN/A            goto exit;
10791939SN/A
108011202SN/A        txDmaAddr = pciToDma(Regs::get_TxData_Addr(vnic->TxData));
10812008SN/A        txDmaLen = Regs::get_TxData_Len(vnic->TxData);
10822008SN/A        txDmaData = txPacket->data + txPacketOffset;
10831939SN/A        txState = txCopy;
10841156SN/A
10852566SN/A        dmaRead(txDmaAddr, txDmaLen, &txDmaEvent, txDmaData);
10861156SN/A        break;
10871156SN/A
10881156SN/A      case txCopy:
10891156SN/A        DPRINTF(EthernetSM, "transmit machine still copying\n");
10901156SN/A        goto exit;
10911156SN/A
10921156SN/A      case txCopyDone:
10932008SN/A        vnic->TxDone = txDmaLen | Regs::TxDone_Complete;
109411701Smichael.lebeane@amd.com        txPacket->simLength += txDmaLen;
10951156SN/A        txPacket->length += txDmaLen;
10962008SN/A        if ((vnic->TxData & Regs::TxData_More)) {
10972008SN/A            txPacketOffset += txDmaLen;
10982008SN/A            txState = txIdle;
10992008SN/A            devIntrPost(Regs::Intr_TxDMA);
11002008SN/A            break;
11011156SN/A        }
11021156SN/A
11032008SN/A        assert(txPacket->length <= txFifo.avail());
11042008SN/A        if ((vnic->TxData & Regs::TxData_Checksum)) {
11052008SN/A            IpPtr ip(txPacket);
11062008SN/A            if (ip) {
11072008SN/A                TcpPtr tcp(ip);
11082008SN/A                if (tcp) {
11092008SN/A                    tcp->sum(0);
11102008SN/A                    tcp->sum(cksum(tcp));
11112008SN/A                    txTcpChecksums++;
11122008SN/A                }
11132008SN/A
11142008SN/A                UdpPtr udp(ip);
11152008SN/A                if (udp) {
11162008SN/A                    udp->sum(0);
11172008SN/A                    udp->sum(cksum(udp));
11182008SN/A                    txUdpChecksums++;
11192008SN/A                }
11202008SN/A
11212008SN/A                ip->sum(0);
11222008SN/A                ip->sum(cksum(ip));
11232008SN/A                txIpChecksums++;
11242008SN/A            }
11252008SN/A        }
11262008SN/A
11272008SN/A        txFifo.push(txPacket);
11282008SN/A        if (txFifo.avail() < regs.TxMaxCopy) {
11292008SN/A            devIntrPost(Regs::Intr_TxFull);
11302008SN/A            txFull = true;
11312008SN/A        }
11322008SN/A        txPacket = 0;
11332008SN/A        transmit();
11342008SN/A        txList.pop_front();
11352008SN/A        txState = txList.empty() ? txIdle : txFifoBlock;
11361939SN/A        devIntrPost(Regs::Intr_TxDMA);
11371156SN/A        break;
11381156SN/A
11391156SN/A      default:
11401156SN/A        panic("Invalid txState!");
11411156SN/A    }
11421156SN/A
11431156SN/A    DPRINTF(EthernetSM, "entering next txState=%s\n",
11441156SN/A            TxStateStrings[txState]);
11451156SN/A
11461156SN/A    goto next;
11471156SN/A
11481156SN/A  exit:
11491156SN/A    /**
11501156SN/A     * @todo do we want to schedule a future kick?
11511156SN/A     */
11521156SN/A    DPRINTF(EthernetSM, "tx state machine exited txState=%s\n",
11531156SN/A            TxStateStrings[txState]);
11541156SN/A}
11551156SN/A
11561156SN/Avoid
11571156SN/ADevice::transferDone()
11581156SN/A{
11591156SN/A    if (txFifo.empty()) {
11601156SN/A        DPRINTF(Ethernet, "transfer complete: txFifo empty...nothing to do\n");
11611156SN/A        return;
11621156SN/A    }
11631156SN/A
11641156SN/A    DPRINTF(Ethernet, "transfer complete: data in txFifo...schedule xmit\n");
11651156SN/A
11669417SN/A    reschedule(txEvent, clockEdge(Cycles(1)), true);
11671156SN/A}
11681156SN/A
11691156SN/Abool
11702566SN/ADevice::rxFilter(const EthPacketPtr &packet)
11711156SN/A{
11721156SN/A    if (!Regs::get_Config_Filter(regs.Config))
11731156SN/A        return false;
11741156SN/A
11751156SN/A    panic("receive filter not implemented\n");
11761156SN/A    bool drop = true;
11771156SN/A
11781156SN/A#if 0
11791156SN/A    string type;
11801156SN/A
11811156SN/A    EthHdr *eth = packet->eth();
11821156SN/A    if (eth->unicast()) {
11831156SN/A        // If we're accepting all unicast addresses
11841156SN/A        if (acceptUnicast)
11851156SN/A            drop = false;
11861156SN/A
11871156SN/A        // If we make a perfect match
11881156SN/A        if (acceptPerfect && params->eaddr == eth.dst())
11891156SN/A            drop = false;
11901156SN/A
11911156SN/A        if (acceptArp && eth->type() == ETH_TYPE_ARP)
11921156SN/A            drop = false;
11931156SN/A
11941156SN/A    } else if (eth->broadcast()) {
11951156SN/A        // if we're accepting broadcasts
11961156SN/A        if (acceptBroadcast)
11971156SN/A            drop = false;
11981156SN/A
11991156SN/A    } else if (eth->multicast()) {
12001156SN/A        // if we're accepting all multicasts
12011156SN/A        if (acceptMulticast)
12021156SN/A            drop = false;
12031156SN/A
12041156SN/A    }
12051156SN/A
12061156SN/A    if (drop) {
12071156SN/A        DPRINTF(Ethernet, "rxFilter drop\n");
12081156SN/A        DDUMP(EthernetData, packet->data, packet->length);
12091156SN/A    }
12101156SN/A#endif
12111156SN/A    return drop;
12121156SN/A}
12131156SN/A
12141156SN/Abool
12152566SN/ADevice::recvPacket(EthPacketPtr packet)
12161156SN/A{
12171156SN/A    rxBytes += packet->length;
12181156SN/A    rxPackets++;
12191156SN/A
12201156SN/A    DPRINTF(Ethernet, "Receiving packet from wire, rxFifo Available is %d\n",
12211156SN/A            rxFifo.avail());
12221156SN/A
12231156SN/A    if (!rxEnable) {
12241156SN/A        DPRINTF(Ethernet, "receive disabled...packet dropped\n");
12251156SN/A        return true;
12261156SN/A    }
12271156SN/A
12281156SN/A    if (rxFilter(packet)) {
12291156SN/A        DPRINTF(Ethernet, "packet filtered...dropped\n");
12301156SN/A        return true;
12311156SN/A    }
12321156SN/A
12335603SN/A    if (rxFifo.size() >= regs.RxFifoHigh)
12341939SN/A        devIntrPost(Regs::Intr_RxHigh);
12351156SN/A
12361156SN/A    if (!rxFifo.push(packet)) {
12371156SN/A        DPRINTF(Ethernet,
12381156SN/A                "packet will not fit in receive buffer...packet dropped\n");
12391156SN/A        return false;
12401156SN/A    }
12411156SN/A
12422008SN/A    // If we were at the last element, back up one ot go to the new
12432008SN/A    // last element of the list.
12442008SN/A    if (rxFifoPtr == rxFifo.end())
12452008SN/A        --rxFifoPtr;
12462008SN/A
12471939SN/A    devIntrPost(Regs::Intr_RxPacket);
12481156SN/A    rxKick();
12491156SN/A    return true;
12501156SN/A}
12511156SN/A
12522901SN/Avoid
12539342SN/ADevice::drainResume()
12542901SN/A{
12559342SN/A    Drainable::drainResume();
12562901SN/A
12572901SN/A    // During drain we could have left the state machines in a waiting state and
12582901SN/A    // they wouldn't get out until some other event occured to kick them.
12592901SN/A    // This way they'll get out immediately
12602901SN/A    txKick();
12612901SN/A    rxKick();
12622901SN/A}
12632901SN/A
12641156SN/A//=====================================================================
12651156SN/A//
12661156SN/A//
12671156SN/Avoid
126810905SN/ABase::serialize(CheckpointOut &cp) const
12691156SN/A{
12709807SN/A    // Serialize the PciDevice base class
127110905SN/A    PciDevice::serialize(cp);
12721156SN/A
12731156SN/A    SERIALIZE_SCALAR(rxEnable);
12741156SN/A    SERIALIZE_SCALAR(txEnable);
12751156SN/A    SERIALIZE_SCALAR(cpuIntrEnable);
12761156SN/A
12771156SN/A    /*
12781156SN/A     * Keep track of pending interrupt status.
12791156SN/A     */
12801156SN/A    SERIALIZE_SCALAR(intrTick);
12811156SN/A    SERIALIZE_SCALAR(cpuPendingIntr);
12821156SN/A    Tick intrEventTick = 0;
12831156SN/A    if (intrEvent)
12841156SN/A        intrEventTick = intrEvent->when();
12851156SN/A    SERIALIZE_SCALAR(intrEventTick);
12861156SN/A}
12871156SN/A
12881156SN/Avoid
128910905SN/ABase::unserialize(CheckpointIn &cp)
12901156SN/A{
12919807SN/A    // Unserialize the PciDevice base class
129210905SN/A    PciDevice::unserialize(cp);
12931156SN/A
12941156SN/A    UNSERIALIZE_SCALAR(rxEnable);
12951156SN/A    UNSERIALIZE_SCALAR(txEnable);
12961156SN/A    UNSERIALIZE_SCALAR(cpuIntrEnable);
12971156SN/A
12981156SN/A    /*
12991156SN/A     * Keep track of pending interrupt status.
13001156SN/A     */
13011156SN/A    UNSERIALIZE_SCALAR(intrTick);
13021156SN/A    UNSERIALIZE_SCALAR(cpuPendingIntr);
13031156SN/A    Tick intrEventTick;
13041156SN/A    UNSERIALIZE_SCALAR(intrEventTick);
13051156SN/A    if (intrEventTick) {
130612087Sspwilson2@wisc.edu        intrEvent = new EventFunctionWrapper([this]{ cpuInterrupt(); },
130712087Sspwilson2@wisc.edu                                             name(), true);
13085606SN/A        schedule(intrEvent, intrEventTick);
13091156SN/A    }
13101156SN/A}
13111156SN/A
13121156SN/Avoid
131311006SN/ADevice::serialize(CheckpointOut &cp) const
13141156SN/A{
13152287SN/A    int count;
13162287SN/A
13179807SN/A    // Serialize the PciDevice base class
131810905SN/A    Base::serialize(cp);
13191156SN/A
13201939SN/A    if (rxState == rxCopy)
13211939SN/A        panic("can't serialize with an in flight dma request rxState=%s",
13221939SN/A              RxStateStrings[rxState]);
13231156SN/A
13241939SN/A    if (txState == txCopy)
13251939SN/A        panic("can't serialize with an in flight dma request txState=%s",
13261939SN/A              TxStateStrings[txState]);
13271156SN/A
13281156SN/A    /*
13295603SN/A     * Serialize the device registers that could be modified by the OS.
13301156SN/A     */
13311156SN/A    SERIALIZE_SCALAR(regs.Config);
13321939SN/A    SERIALIZE_SCALAR(regs.IntrStatus);
13331939SN/A    SERIALIZE_SCALAR(regs.IntrMask);
13341156SN/A    SERIALIZE_SCALAR(regs.RxData);
13351156SN/A    SERIALIZE_SCALAR(regs.TxData);
13361156SN/A
13371156SN/A    /*
13382008SN/A     * Serialize the virtual nic state
13392008SN/A     */
13402008SN/A    int virtualRegsSize = virtualRegs.size();
13412008SN/A    SERIALIZE_SCALAR(virtualRegsSize);
13422008SN/A    for (int i = 0; i < virtualRegsSize; ++i) {
134310905SN/A        const VirtualReg *vnic = &virtualRegs[i];
13442008SN/A
13452566SN/A        std::string reg = csprintf("vnic%d", i);
134610905SN/A        paramOut(cp, reg + ".RxData", vnic->RxData);
134710905SN/A        paramOut(cp, reg + ".RxDone", vnic->RxDone);
134810905SN/A        paramOut(cp, reg + ".TxData", vnic->TxData);
134910905SN/A        paramOut(cp, reg + ".TxDone", vnic->TxDone);
13502008SN/A
13515603SN/A        bool rxPacketExists = vnic->rxIndex != rxFifo.end();
135210905SN/A        paramOut(cp, reg + ".rxPacketExists", rxPacketExists);
13532008SN/A        if (rxPacketExists) {
13542008SN/A            int rxPacket = 0;
135511006SN/A            auto i = rxFifo.begin();
13565603SN/A            while (i != vnic->rxIndex) {
13572008SN/A                assert(i != rxFifo.end());
13582008SN/A                ++i;
13592008SN/A                ++rxPacket;
13602008SN/A            }
13612008SN/A
136210905SN/A            paramOut(cp, reg + ".rxPacket", rxPacket);
136310905SN/A            paramOut(cp, reg + ".rxPacketOffset", vnic->rxPacketOffset);
136410905SN/A            paramOut(cp, reg + ".rxPacketBytes", vnic->rxPacketBytes);
13652008SN/A        }
136610905SN/A        paramOut(cp, reg + ".rxDoneData", vnic->rxDoneData);
13672008SN/A    }
13682008SN/A
13695603SN/A    int rxFifoPtr = -1;
13705603SN/A    if (this->rxFifoPtr != rxFifo.end())
13715603SN/A        rxFifoPtr = rxFifo.countPacketsBefore(this->rxFifoPtr);
13722282SN/A    SERIALIZE_SCALAR(rxFifoPtr);
13732282SN/A
13742282SN/A    SERIALIZE_SCALAR(rxActive);
13755603SN/A    SERIALIZE_SCALAR(rxBusyCount);
13765603SN/A    SERIALIZE_SCALAR(rxDirtyCount);
13775603SN/A    SERIALIZE_SCALAR(rxMappedCount);
13782282SN/A
137911006SN/A    VirtualList::const_iterator i, end;
13802008SN/A    for (count = 0, i = rxList.begin(), end = rxList.end(); i != end; ++i)
138110905SN/A        paramOut(cp, csprintf("rxList%d", count++), *i);
13822282SN/A    int rxListSize = count;
13832282SN/A    SERIALIZE_SCALAR(rxListSize);
13842008SN/A
13852282SN/A    for (count = 0, i = rxBusy.begin(), end = rxBusy.end(); i != end; ++i)
138610905SN/A        paramOut(cp, csprintf("rxBusy%d", count++), *i);
13872282SN/A    int rxBusySize = count;
13882282SN/A    SERIALIZE_SCALAR(rxBusySize);
13892282SN/A
13902008SN/A    for (count = 0, i = txList.begin(), end = txList.end(); i != end; ++i)
139110905SN/A        paramOut(cp, csprintf("txList%d", count++), *i);
13922282SN/A    int txListSize = count;
13932282SN/A    SERIALIZE_SCALAR(txListSize);
13942008SN/A
13952008SN/A    /*
13961156SN/A     * Serialize rx state machine
13971156SN/A     */
13981156SN/A    int rxState = this->rxState;
13991156SN/A    SERIALIZE_SCALAR(rxState);
14001939SN/A    SERIALIZE_SCALAR(rxEmpty);
14012282SN/A    SERIALIZE_SCALAR(rxLow);
140210905SN/A    rxFifo.serialize("rxFifo", cp);
14031156SN/A
14041156SN/A    /*
14051156SN/A     * Serialize tx state machine
14061156SN/A     */
14071156SN/A    int txState = this->txState;
14081156SN/A    SERIALIZE_SCALAR(txState);
14091939SN/A    SERIALIZE_SCALAR(txFull);
141010905SN/A    txFifo.serialize("txFifo", cp);
141110469SN/A    bool txPacketExists = txPacket != nullptr;
14121156SN/A    SERIALIZE_SCALAR(txPacketExists);
14131156SN/A    if (txPacketExists) {
141410905SN/A        txPacket->serialize("txPacket", cp);
14152008SN/A        SERIALIZE_SCALAR(txPacketOffset);
14162008SN/A        SERIALIZE_SCALAR(txPacketBytes);
14171156SN/A    }
14181156SN/A
14191156SN/A    /*
14201156SN/A     * If there's a pending transmit, store the time so we can
14211156SN/A     * reschedule it later
14221156SN/A     */
14237823SN/A    Tick transmitTick = txEvent.scheduled() ? txEvent.when() - curTick() : 0;
14241156SN/A    SERIALIZE_SCALAR(transmitTick);
14251156SN/A}
14261156SN/A
14271156SN/Avoid
142810905SN/ADevice::unserialize(CheckpointIn &cp)
14291156SN/A{
14309807SN/A    // Unserialize the PciDevice base class
143110905SN/A    Base::unserialize(cp);
14321156SN/A
14331156SN/A    /*
14345603SN/A     * Unserialize the device registers that may have been written by the OS.
14351156SN/A     */
14361156SN/A    UNSERIALIZE_SCALAR(regs.Config);
14371939SN/A    UNSERIALIZE_SCALAR(regs.IntrStatus);
14381939SN/A    UNSERIALIZE_SCALAR(regs.IntrMask);
14391156SN/A    UNSERIALIZE_SCALAR(regs.RxData);
14401156SN/A    UNSERIALIZE_SCALAR(regs.TxData);
14411156SN/A
14422282SN/A    UNSERIALIZE_SCALAR(rxActive);
14435603SN/A    UNSERIALIZE_SCALAR(rxBusyCount);
14445603SN/A    UNSERIALIZE_SCALAR(rxDirtyCount);
14455603SN/A    UNSERIALIZE_SCALAR(rxMappedCount);
14462282SN/A
14472008SN/A    int rxListSize;
14482008SN/A    UNSERIALIZE_SCALAR(rxListSize);
14492008SN/A    rxList.clear();
14502008SN/A    for (int i = 0; i < rxListSize; ++i) {
14512008SN/A        int value;
145210905SN/A        paramIn(cp, csprintf("rxList%d", i), value);
14532008SN/A        rxList.push_back(value);
14542008SN/A    }
14552008SN/A
14562282SN/A    int rxBusySize;
14572282SN/A    UNSERIALIZE_SCALAR(rxBusySize);
14582282SN/A    rxBusy.clear();
14592282SN/A    for (int i = 0; i < rxBusySize; ++i) {
14602282SN/A        int value;
146110905SN/A        paramIn(cp, csprintf("rxBusy%d", i), value);
14622282SN/A        rxBusy.push_back(value);
14632282SN/A    }
14642282SN/A
14652008SN/A    int txListSize;
14662008SN/A    UNSERIALIZE_SCALAR(txListSize);
14672008SN/A    txList.clear();
14682008SN/A    for (int i = 0; i < txListSize; ++i) {
14692008SN/A        int value;
147010905SN/A        paramIn(cp, csprintf("txList%d", i), value);
14712008SN/A        txList.push_back(value);
14722008SN/A    }
14732008SN/A
14741156SN/A    /*
14751156SN/A     * Unserialize rx state machine
14761156SN/A     */
14771156SN/A    int rxState;
14781156SN/A    UNSERIALIZE_SCALAR(rxState);
14791939SN/A    UNSERIALIZE_SCALAR(rxEmpty);
14802282SN/A    UNSERIALIZE_SCALAR(rxLow);
14811156SN/A    this->rxState = (RxState) rxState;
148210905SN/A    rxFifo.unserialize("rxFifo", cp);
14831156SN/A
14842282SN/A    int rxFifoPtr;
14852282SN/A    UNSERIALIZE_SCALAR(rxFifoPtr);
14865603SN/A    if (rxFifoPtr >= 0) {
14875603SN/A        this->rxFifoPtr = rxFifo.begin();
14885603SN/A        for (int i = 0; i < rxFifoPtr; ++i)
14895603SN/A            ++this->rxFifoPtr;
14905603SN/A    } else {
14915603SN/A        this->rxFifoPtr = rxFifo.end();
14925603SN/A    }
14932282SN/A
14941156SN/A    /*
14951156SN/A     * Unserialize tx state machine
14961156SN/A     */
14971156SN/A    int txState;
14981156SN/A    UNSERIALIZE_SCALAR(txState);
14991939SN/A    UNSERIALIZE_SCALAR(txFull);
15001156SN/A    this->txState = (TxState) txState;
150110905SN/A    txFifo.unserialize("txFifo", cp);
15021156SN/A    bool txPacketExists;
15031156SN/A    UNSERIALIZE_SCALAR(txPacketExists);
15041156SN/A    txPacket = 0;
15051156SN/A    if (txPacketExists) {
150611719Smichael.lebeane@amd.com        txPacket = make_shared<EthPacketData>(16384);
150710905SN/A        txPacket->unserialize("txPacket", cp);
15082008SN/A        UNSERIALIZE_SCALAR(txPacketOffset);
15092008SN/A        UNSERIALIZE_SCALAR(txPacketBytes);
15102008SN/A    }
15112008SN/A
15122008SN/A    /*
15132008SN/A     * unserialize the virtual nic registers/state
15142008SN/A     *
15152008SN/A     * this must be done after the unserialization of the rxFifo
15162008SN/A     * because the packet iterators depend on the fifo being populated
15172008SN/A     */
15182008SN/A    int virtualRegsSize;
15192008SN/A    UNSERIALIZE_SCALAR(virtualRegsSize);
15202008SN/A    virtualRegs.clear();
15212008SN/A    virtualRegs.resize(virtualRegsSize);
15222008SN/A    for (int i = 0; i < virtualRegsSize; ++i) {
15232008SN/A        VirtualReg *vnic = &virtualRegs[i];
15242566SN/A        std::string reg = csprintf("vnic%d", i);
15252008SN/A
152610905SN/A        paramIn(cp, reg + ".RxData", vnic->RxData);
152710905SN/A        paramIn(cp, reg + ".RxDone", vnic->RxDone);
152810905SN/A        paramIn(cp, reg + ".TxData", vnic->TxData);
152910905SN/A        paramIn(cp, reg + ".TxDone", vnic->TxDone);
15302008SN/A
15312282SN/A        vnic->rxUnique = rxUnique++;
15322282SN/A        vnic->txUnique = txUnique++;
15332282SN/A
15342008SN/A        bool rxPacketExists;
153510905SN/A        paramIn(cp, reg + ".rxPacketExists", rxPacketExists);
15362008SN/A        if (rxPacketExists) {
15372008SN/A            int rxPacket;
153810905SN/A            paramIn(cp, reg + ".rxPacket", rxPacket);
15395603SN/A            vnic->rxIndex = rxFifo.begin();
15402008SN/A            while (rxPacket--)
15415603SN/A                ++vnic->rxIndex;
15422008SN/A
154310905SN/A            paramIn(cp, reg + ".rxPacketOffset",
15442008SN/A                    vnic->rxPacketOffset);
154510905SN/A            paramIn(cp, reg + ".rxPacketBytes", vnic->rxPacketBytes);
15462008SN/A        } else {
15475603SN/A            vnic->rxIndex = rxFifo.end();
15482008SN/A        }
154910905SN/A        paramIn(cp, reg + ".rxDoneData", vnic->rxDoneData);
15501156SN/A    }
15511156SN/A
15521156SN/A    /*
15531156SN/A     * If there's a pending transmit, reschedule it now
15541156SN/A     */
15551156SN/A    Tick transmitTick;
15561156SN/A    UNSERIALIZE_SCALAR(transmitTick);
15571156SN/A    if (transmitTick)
15587823SN/A        schedule(txEvent, curTick() + transmitTick);
15591156SN/A
15608851SN/A    pioPort.sendRangeChange();
15612566SN/A
15621156SN/A}
15631156SN/A
15647811SN/A} // namespace Sinic
15651156SN/A
15664762SN/ASinic::Device *
15674762SN/ASinicParams::create()
15681156SN/A{
15694762SN/A    return new Sinic::Device(this);
15701156SN/A}
1571