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
14513784Sgabeblack@google.comPort &
14613784Sgabeblack@google.comDevice::getPort(const std::string &if_name, PortID idx)
1474981SN/A{
14813784Sgabeblack@google.com    if (if_name == "interface")
14913784Sgabeblack@google.com        return *interface;
15013784Sgabeblack@google.com    return EtherDevBase::getPort(if_name, idx);
1514981SN/A}
1524981SN/A
1534981SN/A
1541939SN/Avoid
15511005SN/ADevice::prepareIO(ContextID cpu, int index)
1562008SN/A{
1572008SN/A    int size = virtualRegs.size();
1582282SN/A    if (index > size)
1592282SN/A        panic("Trying to access a vnic that doesn't exist %d > %d\n",
1602282SN/A              index, size);
1612008SN/A}
1622008SN/A
1635603SN/A//add stats for head of line blocking
1645603SN/A//add stats for average fifo length
1655603SN/A//add stats for average number of vnics busy
1665603SN/A
1672008SN/Avoid
16811005SN/ADevice::prepareRead(ContextID cpu, int index)
1692008SN/A{
1702008SN/A    using namespace Regs;
1712008SN/A    prepareIO(cpu, index);
1722008SN/A
1732008SN/A    VirtualReg &vnic = virtualRegs[index];
1742008SN/A
1752008SN/A    // update rx registers
1762008SN/A    uint64_t rxdone = vnic.RxDone;
1772282SN/A    rxdone = set_RxDone_Packets(rxdone, rxFifo.countPacketsAfter(rxFifoPtr));
1782282SN/A    rxdone = set_RxDone_Empty(rxdone, rxFifo.empty());
1795603SN/A    rxdone = set_RxDone_High(rxdone, rxFifo.size() > regs.RxFifoHigh);
1802282SN/A    rxdone = set_RxDone_NotHigh(rxdone, rxLow);
1812008SN/A    regs.RxData = vnic.RxData;
1822008SN/A    regs.RxDone = rxdone;
1832008SN/A    regs.RxWait = rxdone;
1842008SN/A
1852008SN/A    // update tx regsiters
1862008SN/A    uint64_t txdone = vnic.TxDone;
1872008SN/A    txdone = set_TxDone_Packets(txdone, txFifo.packets());
1882008SN/A    txdone = set_TxDone_Full(txdone, txFifo.avail() < regs.TxMaxCopy);
1895603SN/A    txdone = set_TxDone_Low(txdone, txFifo.size() < regs.TxFifoLow);
1902008SN/A    regs.TxData = vnic.TxData;
1912008SN/A    regs.TxDone = txdone;
1922008SN/A    regs.TxWait = txdone;
1935603SN/A
1945603SN/A    int head = 0xffff;
1955603SN/A
1965603SN/A    if (!rxFifo.empty()) {
1975603SN/A        int vnic = rxFifo.begin()->priv;
1985603SN/A        if (vnic != -1 && virtualRegs[vnic].rxPacketOffset > 0)
1995603SN/A            head = vnic;
2005603SN/A    }
2015603SN/A
2025603SN/A    regs.RxStatus = set_RxStatus_Head(regs.RxStatus, head);
2035603SN/A    regs.RxStatus = set_RxStatus_Busy(regs.RxStatus, rxBusyCount);
2045603SN/A    regs.RxStatus = set_RxStatus_Mapped(regs.RxStatus, rxMappedCount);
2055603SN/A    regs.RxStatus = set_RxStatus_Dirty(regs.RxStatus, rxDirtyCount);
2062008SN/A}
2072008SN/A
2082008SN/Avoid
20911005SN/ADevice::prepareWrite(ContextID cpu, int index)
2101997SN/A{
2112008SN/A    prepareIO(cpu, index);
2121997SN/A}
2131997SN/A
2141156SN/A/**
2151939SN/A * I/O read of device register
2161156SN/A */
2172566SN/ATick
2183349SN/ADevice::read(PacketPtr pkt)
2191156SN/A{
2201817SN/A    assert(config.command & PCI_CMD_MSE);
2212641SN/A    assert(pkt->getAddr() >= BARAddrs[0] && pkt->getSize() < BARSize[0]);
2221156SN/A
22311005SN/A    ContextID cpu = pkt->req->contextId();
2242641SN/A    Addr daddr = pkt->getAddr() - BARAddrs[0];
2252008SN/A    Addr index = daddr >> Regs::VirtualShift;
2262008SN/A    Addr raddr = daddr & Regs::VirtualMask;
2271997SN/A
2282008SN/A    if (!regValid(raddr))
2292617SN/A        panic("invalid register: cpu=%d vnic=%d da=%#x pa=%#x size=%d",
2302641SN/A              cpu, index, daddr, pkt->getAddr(), pkt->getSize());
2311156SN/A
2322008SN/A    const Regs::Info &info = regInfo(raddr);
2331939SN/A    if (!info.read)
2342279SN/A        panic("read %s (write only): "
2352617SN/A              "cpu=%d vnic=%d da=%#x pa=%#x size=%d",
2362641SN/A              info.name, cpu, index, daddr, pkt->getAddr(), pkt->getSize());
2371939SN/A
2382279SN/A        panic("read %s (invalid size): "
2392617SN/A              "cpu=%d vnic=%d da=%#x pa=%#x size=%d",
2402641SN/A              info.name, cpu, index, daddr, pkt->getAddr(), pkt->getSize());
2411156SN/A
2422008SN/A    prepareRead(cpu, index);
2431156SN/A
2448641SN/A    uint64_t value M5_VAR_USED = 0;
2452641SN/A    if (pkt->getSize() == 4) {
2462566SN/A        uint32_t reg = regData32(raddr);
24713342Sgabeblack@google.com        pkt->setLE(reg);
2481939SN/A        value = reg;
2491156SN/A    }
2501156SN/A
2512641SN/A    if (pkt->getSize() == 8) {
2522566SN/A        uint64_t reg = regData64(raddr);
25313342Sgabeblack@google.com        pkt->setLE(reg);
2541939SN/A        value = reg;
2551939SN/A    }
2561939SN/A
2571998SN/A    DPRINTF(EthernetPIO,
2582617SN/A            "read %s: cpu=%d vnic=%d da=%#x pa=%#x size=%d val=%#x\n",
2592641SN/A            info.name, cpu, index, daddr, pkt->getAddr(), pkt->getSize(), value);
2601939SN/A
2611939SN/A    // reading the interrupt status register has the side effect of
2621939SN/A    // clearing it
2632008SN/A    if (raddr == Regs::IntrStatus)
2641939SN/A        devIntrClear();
2651156SN/A
2662566SN/A    return pioDelay;
2671156SN/A}
2681156SN/A
2691939SN/A/**
2701939SN/A * IPR read of device register
2712566SN/A
2722566SN/A    Fault
27311005SN/ADevice::iprRead(Addr daddr, ContextID cpu, uint64_t &result)
2741939SN/A{
2751939SN/A    if (!regValid(daddr))
2761939SN/A        panic("invalid address: da=%#x", daddr);
2771939SN/A
2781939SN/A    const Regs::Info &info = regInfo(daddr);
2791939SN/A    if (!info.read)
2801998SN/A        panic("reading %s (write only): cpu=%d da=%#x", info.name, cpu, daddr);
2811939SN/A
2821998SN/A    DPRINTF(EthernetPIO, "IPR read %s: cpu=%d da=%#x\n",
2831998SN/A            info.name, cpu, daddr);
2841939SN/A
2852008SN/A    prepareRead(cpu, 0);
2861939SN/A
2871939SN/A    if (info.size == 4)
2881939SN/A        result = regData32(daddr);
2891939SN/A
2901939SN/A    if (info.size == 8)
2911939SN/A        result = regData64(daddr);
2921939SN/A
2931998SN/A    DPRINTF(EthernetPIO, "IPR read %s: cpu=%s da=%#x val=%#x\n",
2941998SN/A            info.name, cpu, result);
2951939SN/A
2962090SN/A    return NoFault;
2971939SN/A}
2982566SN/A*/
2991939SN/A/**
3001939SN/A * I/O write of device register
3011939SN/A */
3022566SN/ATick
3033349SN/ADevice::write(PacketPtr pkt)
3041156SN/A{
3051817SN/A    assert(config.command & PCI_CMD_MSE);
3062641SN/A    assert(pkt->getAddr() >= BARAddrs[0] && pkt->getSize() < BARSize[0]);
3071939SN/A
30811005SN/A    ContextID cpu = pkt->req->contextId();
3092641SN/A    Addr daddr = pkt->getAddr() - BARAddrs[0];
3102008SN/A    Addr index = daddr >> Regs::VirtualShift;
3112008SN/A    Addr raddr = daddr & Regs::VirtualMask;
3121997SN/A
3132008SN/A    if (!regValid(raddr))
3142566SN/A        panic("invalid register: cpu=%d, da=%#x pa=%#x size=%d",
3152641SN/A                cpu, daddr, pkt->getAddr(), pkt->getSize());
3161156SN/A
3172008SN/A    const Regs::Info &info = regInfo(raddr);
3181939SN/A    if (!info.write)
3192279SN/A        panic("write %s (read only): "
3202617SN/A              "cpu=%d vnic=%d da=%#x pa=%#x size=%d",
3212641SN/A              info.name, cpu, index, daddr, pkt->getAddr(), pkt->getSize());
3221939SN/A
3232641SN/A    if (pkt->getSize() != info.size)
3242279SN/A        panic("write %s (invalid size): "
3252617SN/A              "cpu=%d vnic=%d da=%#x pa=%#x size=%d",
3262641SN/A              info.name, cpu, index, daddr, pkt->getAddr(), pkt->getSize());
3271156SN/A
3282176SN/A    VirtualReg &vnic = virtualRegs[index];
3292176SN/A
3301998SN/A    DPRINTF(EthernetPIO,
3312617SN/A            "write %s vnic %d: cpu=%d val=%#x da=%#x pa=%#x size=%d\n",
33213342Sgabeblack@google.com            info.name, index, cpu, info.size == 4 ?
33313342Sgabeblack@google.com            pkt->getLE<uint32_t>() : pkt->getLE<uint64_t>(),
33413342Sgabeblack@google.com            daddr, pkt->getAddr(), pkt->getSize());
3351156SN/A
3362008SN/A    prepareWrite(cpu, index);
3371156SN/A
3382008SN/A    switch (raddr) {
3391156SN/A      case Regs::Config:
34013342Sgabeblack@google.com        changeConfig(pkt->getLE<uint32_t>());
3411156SN/A        break;
3421156SN/A
3431939SN/A      case Regs::Command:
34413342Sgabeblack@google.com        command(pkt->getLE<uint32_t>());
3451156SN/A        break;
3461156SN/A
3471939SN/A      case Regs::IntrStatus:
34813342Sgabeblack@google.com        devIntrClear(regs.IntrStatus &
34913342Sgabeblack@google.com                pkt->getLE<uint32_t>());
3501156SN/A        break;
3511156SN/A
3521156SN/A      case Regs::IntrMask:
35313342Sgabeblack@google.com        devIntrChangeMask(pkt->getLE<uint32_t>());
3541156SN/A        break;
3551156SN/A
3561156SN/A      case Regs::RxData:
3572008SN/A        if (Regs::get_RxDone_Busy(vnic.RxDone))
3581939SN/A            panic("receive machine busy with another request! rxState=%s",
3591939SN/A                  RxStateStrings[rxState]);
3601156SN/A
3612282SN/A        vnic.rxUnique = rxUnique++;
3622008SN/A        vnic.RxDone = Regs::RxDone_Busy;
36313342Sgabeblack@google.com        vnic.RxData = pkt->getLE<uint64_t>();
3645603SN/A        rxBusyCount++;
3652282SN/A
36613342Sgabeblack@google.com        if (Regs::get_RxData_Vaddr(pkt->getLE<uint64_t>())) {
3672627SN/A            panic("vtophys not implemented in newmem");
3685603SN/A#ifdef SINIC_VTOPHYS
3695603SN/A            Addr vaddr = Regs::get_RxData_Addr(reg64);
3702282SN/A            Addr paddr = vtophys(req->xc, vaddr);
3712282SN/A            DPRINTF(EthernetPIO, "write RxData vnic %d (rxunique %d): "
3722282SN/A                    "vaddr=%#x, paddr=%#x\n",
3732282SN/A                    index, vnic.rxUnique, vaddr, paddr);
3742282SN/A
3755603SN/A            vnic.RxData = Regs::set_RxData_Addr(vnic.RxData, paddr);
3765603SN/A#endif
3772282SN/A        } else {
3782282SN/A            DPRINTF(EthernetPIO, "write RxData vnic %d (rxunique %d)\n",
3792282SN/A                    index, vnic.rxUnique);
3802282SN/A        }
3812282SN/A
3825603SN/A        if (vnic.rxIndex == rxFifo.end()) {
3832282SN/A            DPRINTF(EthernetPIO, "request new packet...appending to rxList\n");
3842282SN/A            rxList.push_back(index);
3852282SN/A        } else {
3862282SN/A            DPRINTF(EthernetPIO, "packet exists...appending to rxBusy\n");
3872282SN/A            rxBusy.push_back(index);
3882282SN/A        }
3892282SN/A
3902282SN/A        if (rxEnable && (rxState == rxIdle || rxState == rxFifoBlock)) {
3911156SN/A            rxState = rxFifoBlock;
3921156SN/A            rxKick();
3931156SN/A        }
3941156SN/A        break;
3951156SN/A
3961156SN/A      case Regs::TxData:
3972008SN/A        if (Regs::get_TxDone_Busy(vnic.TxDone))
3981939SN/A            panic("transmit machine busy with another request! txState=%s",
3991939SN/A                  TxStateStrings[txState]);
4001156SN/A
4012282SN/A        vnic.txUnique = txUnique++;
4022008SN/A        vnic.TxDone = Regs::TxDone_Busy;
4032282SN/A
40413342Sgabeblack@google.com        if (Regs::get_TxData_Vaddr(pkt->getLE<uint64_t>())) {
4052617SN/A            panic("vtophys won't work here in newmem.\n");
4065603SN/A#ifdef SINIC_VTOPHYS
4075603SN/A            Addr vaddr = Regs::get_TxData_Addr(reg64);
4082282SN/A            Addr paddr = vtophys(req->xc, vaddr);
4095603SN/A            DPRINTF(EthernetPIO, "write TxData vnic %d (txunique %d): "
4102282SN/A                    "vaddr=%#x, paddr=%#x\n",
4112282SN/A                    index, vnic.txUnique, vaddr, paddr);
4122282SN/A
4135603SN/A            vnic.TxData = Regs::set_TxData_Addr(vnic.TxData, paddr);
4145603SN/A#endif
4152282SN/A        } else {
4165603SN/A            DPRINTF(EthernetPIO, "write TxData vnic %d (txunique %d)\n",
4172282SN/A                    index, vnic.txUnique);
4182282SN/A        }
4192282SN/A
4202008SN/A        if (txList.empty() || txList.front() != index)
4212008SN/A            txList.push_back(index);
4222010SN/A        if (txEnable && txState == txIdle && txList.front() == index) {
4231156SN/A            txState = txFifoBlock;
4241156SN/A            txKick();
4251156SN/A        }
4261156SN/A        break;
4271156SN/A    }
4282176SN/A
4292566SN/A    return pioDelay;
4301156SN/A}
4311156SN/A
4321156SN/Avoid
4331156SN/ADevice::devIntrPost(uint32_t interrupts)
4341156SN/A{
4351156SN/A    if ((interrupts & Regs::Intr_Res))
4361156SN/A        panic("Cannot set a reserved interrupt");
4371156SN/A
4381156SN/A    regs.IntrStatus |= interrupts;
4391156SN/A
4401156SN/A    DPRINTF(EthernetIntr,
4411156SN/A            "interrupt written to intStatus: intr=%#x status=%#x mask=%#x\n",
4421156SN/A            interrupts, regs.IntrStatus, regs.IntrMask);
4431156SN/A
4441939SN/A    interrupts = regs.IntrStatus & regs.IntrMask;
4451939SN/A
4461939SN/A    // Intr_RxHigh is special, we only signal it if we've emptied the fifo
4471939SN/A    // and then filled it above the high watermark
4481939SN/A    if (rxEmpty)
4491939SN/A        rxEmpty = false;
4501939SN/A    else
4511939SN/A        interrupts &= ~Regs::Intr_RxHigh;
4521939SN/A
4531939SN/A    // Intr_TxLow is special, we only signal it if we've filled up the fifo
4541939SN/A    // and then dropped below the low watermark
4551939SN/A    if (txFull)
4561939SN/A        txFull = false;
4571939SN/A    else
4581939SN/A        interrupts &= ~Regs::Intr_TxLow;
4591939SN/A
4601939SN/A    if (interrupts) {
4617823SN/A        Tick when = curTick();
4621939SN/A        if ((interrupts & Regs::Intr_NoDelay) == 0)
4631156SN/A            when += intrDelay;
4641156SN/A        cpuIntrPost(when);
4651156SN/A    }
4661156SN/A}
4671156SN/A
4681156SN/Avoid
4691156SN/ADevice::devIntrClear(uint32_t interrupts)
4701156SN/A{
4711156SN/A    if ((interrupts & Regs::Intr_Res))
4721156SN/A        panic("Cannot clear a reserved interrupt");
4731156SN/A
4741156SN/A    regs.IntrStatus &= ~interrupts;
4751156SN/A
4761156SN/A    DPRINTF(EthernetIntr,
4771156SN/A            "interrupt cleared from intStatus: intr=%x status=%x mask=%x\n",
4781156SN/A            interrupts, regs.IntrStatus, regs.IntrMask);
4791156SN/A
4801156SN/A    if (!(regs.IntrStatus & regs.IntrMask))
4811156SN/A        cpuIntrClear();
4821156SN/A}
4831156SN/A
4841156SN/Avoid
4851156SN/ADevice::devIntrChangeMask(uint32_t newmask)
4861156SN/A{
4871156SN/A    if (regs.IntrMask == newmask)
4881156SN/A        return;
4891156SN/A
4901156SN/A    regs.IntrMask = newmask;
4911156SN/A
4921156SN/A    DPRINTF(EthernetIntr,
4931156SN/A            "interrupt mask changed: intStatus=%x intMask=%x masked=%x\n",
4941156SN/A            regs.IntrStatus, regs.IntrMask, regs.IntrStatus & regs.IntrMask);
4951156SN/A
4961156SN/A    if (regs.IntrStatus & regs.IntrMask)
4977823SN/A        cpuIntrPost(curTick());
4981156SN/A    else
4991156SN/A        cpuIntrClear();
5001156SN/A}
5011156SN/A
5021156SN/Avoid
5031156SN/ABase::cpuIntrPost(Tick when)
5041156SN/A{
5051156SN/A    // If the interrupt you want to post is later than an interrupt
5061156SN/A    // already scheduled, just let it post in the coming one and don't
5071156SN/A    // schedule another.
5081156SN/A    // HOWEVER, must be sure that the scheduled intrTick is in the
5091156SN/A    // future (this was formerly the source of a bug)
5101156SN/A    /**
5111156SN/A     * @todo this warning should be removed and the intrTick code should
5121156SN/A     * be fixed.
5131156SN/A     */
5147823SN/A    assert(when >= curTick());
5157823SN/A    assert(intrTick >= curTick() || intrTick == 0);
5161156SN/A    if (!cpuIntrEnable) {
5171156SN/A        DPRINTF(EthernetIntr, "interrupts not enabled.\n",
5181156SN/A                intrTick);
5191156SN/A        return;
5201156SN/A    }
5211156SN/A
5221156SN/A    if (when > intrTick && intrTick != 0) {
5231156SN/A        DPRINTF(EthernetIntr, "don't need to schedule event...intrTick=%d\n",
5241156SN/A                intrTick);
5251156SN/A        return;
5261156SN/A    }
5271156SN/A
5281156SN/A    intrTick = when;
5297823SN/A    if (intrTick < curTick()) {
5307823SN/A        intrTick = curTick();
5311156SN/A    }
5321156SN/A
5331156SN/A    DPRINTF(EthernetIntr, "going to schedule an interrupt for intrTick=%d\n",
5341156SN/A            intrTick);
5351156SN/A
5361156SN/A    if (intrEvent)
5371156SN/A        intrEvent->squash();
53812087Sspwilson2@wisc.edu
53912087Sspwilson2@wisc.edu    intrEvent = new EventFunctionWrapper([this]{ cpuInterrupt(); },
54012087Sspwilson2@wisc.edu                                         name(), true);
5415606SN/A    schedule(intrEvent, intrTick);
5421156SN/A}
5431156SN/A
5441156SN/Avoid
5451156SN/ABase::cpuInterrupt()
5461156SN/A{
5477823SN/A    assert(intrTick == curTick());
5481156SN/A
5491156SN/A    // Whether or not there's a pending interrupt, we don't care about
5501156SN/A    // it anymore
5511156SN/A    intrEvent = 0;
5521156SN/A    intrTick = 0;
5531156SN/A
5541156SN/A    // Don't send an interrupt if there's already one
5551156SN/A    if (cpuPendingIntr) {
5561156SN/A        DPRINTF(EthernetIntr,
5571156SN/A                "would send an interrupt now, but there's already pending\n");
5581156SN/A    } else {
5591156SN/A        // Send interrupt
5601156SN/A        cpuPendingIntr = true;
5611156SN/A
5621156SN/A        DPRINTF(EthernetIntr, "posting interrupt\n");
5631156SN/A        intrPost();
5641156SN/A    }
5651156SN/A}
5661156SN/A
5671156SN/Avoid
5681156SN/ABase::cpuIntrClear()
5691156SN/A{
5701156SN/A    if (!cpuPendingIntr)
5711156SN/A        return;
5721156SN/A
5731156SN/A    if (intrEvent) {
5741156SN/A        intrEvent->squash();
5751156SN/A        intrEvent = 0;
5761156SN/A    }
5771156SN/A
5781156SN/A    intrTick = 0;
5791156SN/A
5801156SN/A    cpuPendingIntr = false;
5811156SN/A
5821156SN/A    DPRINTF(EthernetIntr, "clearing cchip interrupt\n");
5831156SN/A    intrClear();
5841156SN/A}
5851156SN/A
5861156SN/Abool
5871156SN/ABase::cpuIntrPending() const
5881156SN/A{ return cpuPendingIntr; }
5891156SN/A
5901156SN/Avoid
5911156SN/ADevice::changeConfig(uint32_t newconf)
5921156SN/A{
5931156SN/A    uint32_t changed = regs.Config ^ newconf;
5941156SN/A    if (!changed)
5951156SN/A        return;
5961156SN/A
5971156SN/A    regs.Config = newconf;
5981156SN/A
5991156SN/A    if ((changed & Regs::Config_IntEn)) {
6001156SN/A        cpuIntrEnable = regs.Config & Regs::Config_IntEn;
6011156SN/A        if (cpuIntrEnable) {
6021156SN/A            if (regs.IntrStatus & regs.IntrMask)
6037823SN/A                cpuIntrPost(curTick());
6041156SN/A        } else {
6051156SN/A            cpuIntrClear();
6061156SN/A        }
6071156SN/A    }
6081156SN/A
6091156SN/A    if ((changed & Regs::Config_TxEn)) {
6101156SN/A        txEnable = regs.Config & Regs::Config_TxEn;
6111156SN/A        if (txEnable)
6121156SN/A            txKick();
6131156SN/A    }
6141156SN/A
6151156SN/A    if ((changed & Regs::Config_RxEn)) {
6161156SN/A        rxEnable = regs.Config & Regs::Config_RxEn;
6171156SN/A        if (rxEnable)
6181156SN/A            rxKick();
6191156SN/A    }
6201156SN/A}
6211156SN/A
6221156SN/Avoid
6231939SN/ADevice::command(uint32_t command)
6241939SN/A{
6252008SN/A    if (command & Regs::Command_Intr)
6262008SN/A        devIntrPost(Regs::Intr_Soft);
6272008SN/A
6281939SN/A    if (command & Regs::Command_Reset)
6291939SN/A        reset();
6301939SN/A}
6311939SN/A
6321939SN/Avoid
6331156SN/ADevice::reset()
6341156SN/A{
6351156SN/A    using namespace Regs;
6361939SN/A
6371156SN/A    memset(&regs, 0, sizeof(regs));
6381939SN/A
6391939SN/A    regs.Config = 0;
6402008SN/A    if (params()->rx_thread)
6412008SN/A        regs.Config |= Config_RxThread;
6422008SN/A    if (params()->tx_thread)
6432008SN/A        regs.Config |= Config_TxThread;
6442210SN/A    if (params()->rss)
6452210SN/A        regs.Config |= Config_RSS;
6462282SN/A    if (params()->zero_copy)
6472282SN/A        regs.Config |= Config_ZeroCopy;
6482282SN/A    if (params()->delay_copy)
6492282SN/A        regs.Config |= Config_DelayCopy;
6502282SN/A    if (params()->virtual_addr)
6512282SN/A        regs.Config |= Config_Vaddr;
6522282SN/A
6532282SN/A    if (params()->delay_copy && params()->zero_copy)
6542282SN/A        panic("Can't delay copy and zero copy");
6552282SN/A
6562008SN/A    regs.IntrMask = Intr_Soft | Intr_RxHigh | Intr_RxPacket | Intr_TxLow;
6571156SN/A    regs.RxMaxCopy = params()->rx_max_copy;
6581156SN/A    regs.TxMaxCopy = params()->tx_max_copy;
6595603SN/A    regs.ZeroCopySize = params()->zero_copy_size;
6605603SN/A    regs.ZeroCopyMark = params()->zero_copy_threshold;
6615603SN/A    regs.VirtualCount = params()->virtual_count;
6621939SN/A    regs.RxMaxIntr = params()->rx_max_intr;
6631939SN/A    regs.RxFifoSize = params()->rx_fifo_size;
6641939SN/A    regs.TxFifoSize = params()->tx_fifo_size;
6655603SN/A    regs.RxFifoLow = params()->rx_fifo_low_mark;
6665603SN/A    regs.TxFifoLow = params()->tx_fifo_threshold;
6675603SN/A    regs.RxFifoHigh = params()->rx_fifo_threshold;
6685603SN/A    regs.TxFifoHigh = params()->tx_fifo_high_mark;
6694762SN/A    regs.HwAddr = params()->hardware_address;
6701156SN/A
6715603SN/A    if (regs.RxMaxCopy < regs.ZeroCopyMark)
6725603SN/A        panic("Must be able to copy at least as many bytes as the threshold");
6735603SN/A
6745603SN/A    if (regs.ZeroCopySize >= regs.ZeroCopyMark)
6755603SN/A        panic("The number of bytes to copy must be less than the threshold");
6765603SN/A
6772008SN/A    rxList.clear();
6782282SN/A    rxBusy.clear();
6792282SN/A    rxActive = -1;
6802008SN/A    txList.clear();
6815603SN/A    rxBusyCount = 0;
6825603SN/A    rxDirtyCount = 0;
6835603SN/A    rxMappedCount = 0;
6842008SN/A
6851156SN/A    rxState = rxIdle;
6861156SN/A    txState = txIdle;
6871156SN/A
6881156SN/A    rxFifo.clear();
6892008SN/A    rxFifoPtr = rxFifo.end();
6901156SN/A    txFifo.clear();
6911939SN/A    rxEmpty = false;
6922282SN/A    rxLow = true;
6931939SN/A    txFull = false;
6942008SN/A
6952008SN/A    int size = virtualRegs.size();
6962008SN/A    virtualRegs.clear();
6972008SN/A    virtualRegs.resize(size);
6982008SN/A    for (int i = 0; i < size; ++i)
6995603SN/A        virtualRegs[i].rxIndex = rxFifo.end();
7001156SN/A}
7011156SN/A
7021156SN/Avoid
7032566SN/ADevice::rxDmaDone()
7041156SN/A{
7051156SN/A    assert(rxState == rxCopy);
7061156SN/A    rxState = rxCopyDone;
7072280SN/A    DPRINTF(EthernetDMA, "end rx dma write paddr=%#x len=%d\n",
7081156SN/A            rxDmaAddr, rxDmaLen);
7091939SN/A    DDUMP(EthernetData, rxDmaData, rxDmaLen);
7101939SN/A
7111939SN/A    // If the transmit state machine  has a pending DMA, let it go first
7121939SN/A    if (txState == txBeginCopy)
7131939SN/A        txKick();
7141939SN/A
7151156SN/A    rxKick();
7161156SN/A}
7171156SN/A
7181156SN/Avoid
7191156SN/ADevice::rxKick()
7201156SN/A{
7212282SN/A    VirtualReg *vnic = NULL;
7222008SN/A
7232279SN/A    DPRINTF(EthernetSM, "rxKick: rxState=%s (rxFifo.size=%d)\n",
7241156SN/A            RxStateStrings[rxState], rxFifo.size());
7251156SN/A
7267823SN/A    if (rxKickTick > curTick()) {
7272279SN/A        DPRINTF(EthernetSM, "rxKick: exiting, can't run till %d\n",
7281156SN/A                rxKickTick);
7291156SN/A        return;
7301156SN/A    }
7311156SN/A
7321156SN/A  next:
7335603SN/A    rxFifo.check();
7342008SN/A    if (rxState == rxIdle)
7351156SN/A        goto exit;
7361156SN/A
7372282SN/A    if (rxActive == -1) {
7382282SN/A        if (rxState != rxFifoBlock)
7392282SN/A            panic("no active vnic while in state %s", RxStateStrings[rxState]);
7402008SN/A
7412282SN/A        DPRINTF(EthernetSM, "processing rxState=%s\n",
7422282SN/A                RxStateStrings[rxState]);
7432282SN/A    } else {
7442282SN/A        vnic = &virtualRegs[rxActive];
7452282SN/A        DPRINTF(EthernetSM,
7462282SN/A                "processing rxState=%s for vnic %d (rxunique %d)\n",
7472282SN/A                RxStateStrings[rxState], rxActive, vnic->rxUnique);
7482282SN/A    }
7492008SN/A
7502008SN/A    switch (rxState) {
7511156SN/A      case rxFifoBlock:
7522282SN/A        if (DTRACE(EthernetSM)) {
7532282SN/A            PacketFifo::iterator end = rxFifo.end();
7542282SN/A            int size = virtualRegs.size();
7552282SN/A            for (int i = 0; i < size; ++i) {
7562282SN/A                VirtualReg *vn = &virtualRegs[i];
7575603SN/A                bool busy = Regs::get_RxDone_Busy(vn->RxDone);
7585603SN/A                if (vn->rxIndex != end) {
7598641SN/A#ifndef NDEBUG
7605603SN/A                    bool dirty = vn->rxPacketOffset > 0;
7615603SN/A                    const char *status;
7625603SN/A
7635603SN/A                    if (busy && dirty)
7645603SN/A                        status = "busy,dirty";
7655603SN/A                    else if (busy)
7665603SN/A                        status = "busy";
7675603SN/A                    else if (dirty)
7685603SN/A                        status = "dirty";
7695603SN/A                    else
7705603SN/A                        status = "mapped";
7715603SN/A
7722282SN/A                    DPRINTF(EthernetSM,
7735603SN/A                            "vnic %d %s (rxunique %d), packet %d, slack %d\n",
7745603SN/A                            i, status, vn->rxUnique,
7755603SN/A                            rxFifo.countPacketsBefore(vn->rxIndex),
7765603SN/A                            vn->rxIndex->slack);
7778641SN/A#endif
7785603SN/A                } else if (busy) {
7795603SN/A                    DPRINTF(EthernetSM, "vnic %d unmapped (rxunique %d)\n",
7805603SN/A                            i, vn->rxUnique);
7812282SN/A                }
7822282SN/A            }
7832282SN/A        }
7842282SN/A
7852282SN/A        if (!rxBusy.empty()) {
7862282SN/A            rxActive = rxBusy.front();
7872282SN/A            rxBusy.pop_front();
7882282SN/A            vnic = &virtualRegs[rxActive];
7892282SN/A
7905603SN/A            if (vnic->rxIndex == rxFifo.end())
7912282SN/A                panic("continuing vnic without packet\n");
7922282SN/A
7932282SN/A            DPRINTF(EthernetSM,
7942282SN/A                    "continue processing for vnic %d (rxunique %d)\n",
7952282SN/A                    rxActive, vnic->rxUnique);
7962282SN/A
7971156SN/A            rxState = rxBeginCopy;
7982282SN/A
7995603SN/A            int vnic_distance = rxFifo.countPacketsBefore(vnic->rxIndex);
8005603SN/A            totalVnicDistance += vnic_distance;
8015603SN/A            numVnicDistance += 1;
8025603SN/A            if (vnic_distance > _maxVnicDistance) {
8035603SN/A                maxVnicDistance = vnic_distance;
8045603SN/A                _maxVnicDistance = vnic_distance;
8055603SN/A            }
8065603SN/A
8071156SN/A            break;
8081156SN/A        }
8091156SN/A
8102008SN/A        if (rxFifoPtr == rxFifo.end()) {
8111156SN/A            DPRINTF(EthernetSM, "receive waiting for data.  Nothing to do.\n");
8121156SN/A            goto exit;
8131156SN/A        }
8141156SN/A
8152282SN/A        if (rxList.empty())
8162282SN/A            panic("Not idle, but nothing to do!");
8172282SN/A
8182008SN/A        assert(!rxFifo.empty());
8192008SN/A
8202282SN/A        rxActive = rxList.front();
8212282SN/A        rxList.pop_front();
8222282SN/A        vnic = &virtualRegs[rxActive];
8232282SN/A
8242282SN/A        DPRINTF(EthernetSM,
8252282SN/A                "processing new packet for vnic %d (rxunique %d)\n",
8262282SN/A                rxActive, vnic->rxUnique);
8272282SN/A
8281156SN/A        // Grab a new packet from the fifo.
8295603SN/A        vnic->rxIndex = rxFifoPtr++;
8305603SN/A        vnic->rxIndex->priv = rxActive;
8312008SN/A        vnic->rxPacketOffset = 0;
8325603SN/A        vnic->rxPacketBytes = vnic->rxIndex->packet->length;
8332008SN/A        assert(vnic->rxPacketBytes);
8345603SN/A        rxMappedCount++;
8351156SN/A
8362008SN/A        vnic->rxDoneData = 0;
8371156SN/A        /* scope for variables */ {
8385603SN/A            IpPtr ip(vnic->rxIndex->packet);
8391156SN/A            if (ip) {
8402280SN/A                DPRINTF(Ethernet, "ID is %d\n", ip->id());
8412008SN/A                vnic->rxDoneData |= Regs::RxDone_IpPacket;
8421156SN/A                rxIpChecksums++;
8431156SN/A                if (cksum(ip) != 0) {
8441156SN/A                    DPRINTF(EthernetCksum, "Rx IP Checksum Error\n");
8452008SN/A                    vnic->rxDoneData |= Regs::RxDone_IpError;
8461156SN/A                }
8471156SN/A                TcpPtr tcp(ip);
8481156SN/A                UdpPtr udp(ip);
8491156SN/A                if (tcp) {
8502279SN/A                    DPRINTF(Ethernet,
8512279SN/A                            "Src Port=%d, Dest Port=%d, Seq=%d, Ack=%d\n",
8522279SN/A                            tcp->sport(), tcp->dport(), tcp->seq(),
8532279SN/A                            tcp->ack());
8542008SN/A                    vnic->rxDoneData |= Regs::RxDone_TcpPacket;
8551156SN/A                    rxTcpChecksums++;
8561156SN/A                    if (cksum(tcp) != 0) {
8571156SN/A                        DPRINTF(EthernetCksum, "Rx TCP Checksum Error\n");
8582008SN/A                        vnic->rxDoneData |= Regs::RxDone_TcpError;
8591156SN/A                    }
8601156SN/A                } else if (udp) {
8612008SN/A                    vnic->rxDoneData |= Regs::RxDone_UdpPacket;
8621156SN/A                    rxUdpChecksums++;
8631156SN/A                    if (cksum(udp) != 0) {
8641156SN/A                        DPRINTF(EthernetCksum, "Rx UDP Checksum Error\n");
8652008SN/A                        vnic->rxDoneData |= Regs::RxDone_UdpError;
8661156SN/A                    }
8671156SN/A                }
8681156SN/A            }
8691156SN/A        }
8701156SN/A        rxState = rxBeginCopy;
8711156SN/A        break;
8721156SN/A
8731156SN/A      case rxBeginCopy:
87410913SN/A        if (dmaPending() || drainState() != DrainState::Running)
8751939SN/A            goto exit;
8761939SN/A
87711202SN/A        rxDmaAddr = pciToDma(Regs::get_RxData_Addr(vnic->RxData));
8786227SN/A        rxDmaLen = min<unsigned>(Regs::get_RxData_Len(vnic->RxData),
8796227SN/A                                 vnic->rxPacketBytes);
8805603SN/A
8815603SN/A        /*
8825603SN/A         * if we're doing zero/delay copy and we're below the fifo
8835603SN/A         * threshold, see if we should try to do the zero/defer copy
8845603SN/A         */
8855603SN/A        if ((Regs::get_Config_ZeroCopy(regs.Config) ||
8865603SN/A             Regs::get_Config_DelayCopy(regs.Config)) &&
8875603SN/A            !Regs::get_RxData_NoDelay(vnic->RxData) && rxLow) {
8885603SN/A            if (rxDmaLen > regs.ZeroCopyMark)
8895603SN/A                rxDmaLen = regs.ZeroCopySize;
8905603SN/A        }
8915603SN/A        rxDmaData = vnic->rxIndex->packet->data + vnic->rxPacketOffset;
8921939SN/A        rxState = rxCopy;
8932282SN/A        if (rxDmaAddr == 1LL) {
8942282SN/A            rxState = rxCopyDone;
8952282SN/A            break;
8962282SN/A        }
8972282SN/A
8982566SN/A        dmaWrite(rxDmaAddr, rxDmaLen, &rxDmaEvent, rxDmaData);
8991156SN/A        break;
9001156SN/A
9011156SN/A      case rxCopy:
9021156SN/A        DPRINTF(EthernetSM, "receive machine still copying\n");
9031156SN/A        goto exit;
9041156SN/A
9051156SN/A      case rxCopyDone:
9062282SN/A        vnic->RxDone = vnic->rxDoneData;
9072008SN/A        vnic->RxDone |= Regs::RxDone_Complete;
9085603SN/A        rxBusyCount--;
9091156SN/A
9102008SN/A        if (vnic->rxPacketBytes == rxDmaLen) {
9115603SN/A            if (vnic->rxPacketOffset)
9125603SN/A                rxDirtyCount--;
9135603SN/A
9142282SN/A            // Packet is complete.  Indicate how many bytes were copied
9152282SN/A            vnic->RxDone = Regs::set_RxDone_CopyLen(vnic->RxDone, rxDmaLen);
9162282SN/A
9172282SN/A            DPRINTF(EthernetSM,
9182282SN/A                    "rxKick: packet complete on vnic %d (rxunique %d)\n",
9192282SN/A                    rxActive, vnic->rxUnique);
9205603SN/A            rxFifo.remove(vnic->rxIndex);
9215603SN/A            vnic->rxIndex = rxFifo.end();
9225603SN/A            rxMappedCount--;
9231156SN/A        } else {
9245603SN/A            if (!vnic->rxPacketOffset)
9255603SN/A                rxDirtyCount++;
9265603SN/A
9272008SN/A            vnic->rxPacketBytes -= rxDmaLen;
9282008SN/A            vnic->rxPacketOffset += rxDmaLen;
9292282SN/A            vnic->RxDone |= Regs::RxDone_More;
9302282SN/A            vnic->RxDone = Regs::set_RxDone_CopyLen(vnic->RxDone,
9312282SN/A                                                    vnic->rxPacketBytes);
9322010SN/A            DPRINTF(EthernetSM,
9332282SN/A                    "rxKick: packet not complete on vnic %d (rxunique %d): "
9342282SN/A                    "%d bytes left\n",
9352282SN/A                    rxActive, vnic->rxUnique, vnic->rxPacketBytes);
9361156SN/A        }
9371156SN/A
9382282SN/A        rxActive = -1;
9392282SN/A        rxState = rxBusy.empty() && rxList.empty() ? rxIdle : rxFifoBlock;
9402008SN/A
9412008SN/A        if (rxFifo.empty()) {
9422008SN/A            devIntrPost(Regs::Intr_RxEmpty);
9432008SN/A            rxEmpty = true;
9442008SN/A        }
9452008SN/A
9465603SN/A        if (rxFifo.size() < regs.RxFifoLow)
9472282SN/A            rxLow = true;
9482282SN/A
9495603SN/A        if (rxFifo.size() > regs.RxFifoHigh)
9502282SN/A            rxLow = false;
9512282SN/A
9521939SN/A        devIntrPost(Regs::Intr_RxDMA);
9531156SN/A        break;
9541156SN/A
9551156SN/A      default:
9561156SN/A        panic("Invalid rxState!");
9571156SN/A    }
9581156SN/A
9591156SN/A    DPRINTF(EthernetSM, "entering next rxState=%s\n",
9601156SN/A            RxStateStrings[rxState]);
9611156SN/A
9621156SN/A    goto next;
9631156SN/A
9641156SN/A  exit:
9651156SN/A    /**
9661156SN/A     * @todo do we want to schedule a future kick?
9671156SN/A     */
9681156SN/A    DPRINTF(EthernetSM, "rx state machine exited rxState=%s\n",
9691156SN/A            RxStateStrings[rxState]);
9701156SN/A}
9711156SN/A
9721156SN/Avoid
9732566SN/ADevice::txDmaDone()
9741156SN/A{
9751156SN/A    assert(txState == txCopy);
9761156SN/A    txState = txCopyDone;
9771156SN/A    DPRINTF(EthernetDMA, "tx dma read paddr=%#x len=%d\n",
9781156SN/A            txDmaAddr, txDmaLen);
9791939SN/A    DDUMP(EthernetData, txDmaData, txDmaLen);
9801939SN/A
9811939SN/A    // If the receive state machine  has a pending DMA, let it go first
9821939SN/A    if (rxState == rxBeginCopy)
9831939SN/A        rxKick();
9841939SN/A
9851156SN/A    txKick();
9861156SN/A}
9871156SN/A
9881156SN/Avoid
9891156SN/ADevice::transmit()
9901156SN/A{
9911156SN/A    if (txFifo.empty()) {
9921156SN/A        DPRINTF(Ethernet, "nothing to transmit\n");
9931156SN/A        return;
9941156SN/A    }
9951156SN/A
9961939SN/A    uint32_t interrupts;
9972566SN/A    EthPacketPtr packet = txFifo.front();
9981156SN/A    if (!interface->sendPacket(packet)) {
9991156SN/A        DPRINTF(Ethernet, "Packet Transmit: failed txFifo available %d\n",
10001156SN/A                txFifo.avail());
10015603SN/A        return;
10021156SN/A    }
10031156SN/A
10041156SN/A    txFifo.pop();
10051156SN/A#if TRACING_ON
10061156SN/A    if (DTRACE(Ethernet)) {
10071156SN/A        IpPtr ip(packet);
10081156SN/A        if (ip) {
10091156SN/A            DPRINTF(Ethernet, "ID is %d\n", ip->id());
10101156SN/A            TcpPtr tcp(ip);
10111156SN/A            if (tcp) {
10122280SN/A                DPRINTF(Ethernet,
10132280SN/A                        "Src Port=%d, Dest Port=%d, Seq=%d, Ack=%d\n",
10142280SN/A                        tcp->sport(), tcp->dport(), tcp->seq(),
10152280SN/A                        tcp->ack());
10161156SN/A            }
10171156SN/A        }
10181156SN/A    }
10191156SN/A#endif
10201156SN/A
10211939SN/A    DDUMP(EthernetData, packet->data, packet->length);
10221156SN/A    txBytes += packet->length;
10231156SN/A    txPackets++;
10241156SN/A
10251156SN/A    DPRINTF(Ethernet, "Packet Transmit: successful txFifo Available %d\n",
10261156SN/A            txFifo.avail());
10271156SN/A
10281939SN/A    interrupts = Regs::Intr_TxPacket;
10295603SN/A    if (txFifo.size() < regs.TxFifoLow)
10301939SN/A        interrupts |= Regs::Intr_TxLow;
10311939SN/A    devIntrPost(interrupts);
10321156SN/A}
10331156SN/A
10341156SN/Avoid
10351156SN/ADevice::txKick()
10361156SN/A{
10372008SN/A    VirtualReg *vnic;
10382279SN/A    DPRINTF(EthernetSM, "txKick: txState=%s (txFifo.size=%d)\n",
10391156SN/A            TxStateStrings[txState], txFifo.size());
10401156SN/A
10417823SN/A    if (txKickTick > curTick()) {
10422279SN/A        DPRINTF(EthernetSM, "txKick: exiting, can't run till %d\n",
10431156SN/A                txKickTick);
10441156SN/A        return;
10451156SN/A    }
10461156SN/A
10471156SN/A  next:
10482008SN/A    if (txState == txIdle)
10491156SN/A        goto exit;
10501156SN/A
10512008SN/A    assert(!txList.empty());
10522008SN/A    vnic = &virtualRegs[txList.front()];
10532008SN/A
10542008SN/A    switch (txState) {
10551156SN/A      case txFifoBlock:
10562280SN/A        assert(Regs::get_TxDone_Busy(vnic->TxDone));
10571156SN/A        if (!txPacket) {
10581156SN/A            // Grab a new packet from the fifo.
105910469SN/A            txPacket = make_shared<EthPacketData>(16384);
10602008SN/A            txPacketOffset = 0;
10611156SN/A        }
10621156SN/A
10631156SN/A        if (txFifo.avail() - txPacket->length <
10642008SN/A            Regs::get_TxData_Len(vnic->TxData)) {
10651156SN/A            DPRINTF(EthernetSM, "transmit fifo full.  Nothing to do.\n");
10661156SN/A            goto exit;
10671156SN/A        }
10681156SN/A
10691156SN/A        txState = txBeginCopy;
10701156SN/A        break;
10711156SN/A
10721156SN/A      case txBeginCopy:
107310913SN/A        if (dmaPending() || drainState() != DrainState::Running)
10741939SN/A            goto exit;
10751939SN/A
107611202SN/A        txDmaAddr = pciToDma(Regs::get_TxData_Addr(vnic->TxData));
10772008SN/A        txDmaLen = Regs::get_TxData_Len(vnic->TxData);
10782008SN/A        txDmaData = txPacket->data + txPacketOffset;
10791939SN/A        txState = txCopy;
10801156SN/A
10812566SN/A        dmaRead(txDmaAddr, txDmaLen, &txDmaEvent, txDmaData);
10821156SN/A        break;
10831156SN/A
10841156SN/A      case txCopy:
10851156SN/A        DPRINTF(EthernetSM, "transmit machine still copying\n");
10861156SN/A        goto exit;
10871156SN/A
10881156SN/A      case txCopyDone:
10892008SN/A        vnic->TxDone = txDmaLen | Regs::TxDone_Complete;
109011701Smichael.lebeane@amd.com        txPacket->simLength += txDmaLen;
10911156SN/A        txPacket->length += txDmaLen;
10922008SN/A        if ((vnic->TxData & Regs::TxData_More)) {
10932008SN/A            txPacketOffset += txDmaLen;
10942008SN/A            txState = txIdle;
10952008SN/A            devIntrPost(Regs::Intr_TxDMA);
10962008SN/A            break;
10971156SN/A        }
10981156SN/A
10992008SN/A        assert(txPacket->length <= txFifo.avail());
11002008SN/A        if ((vnic->TxData & Regs::TxData_Checksum)) {
11012008SN/A            IpPtr ip(txPacket);
11022008SN/A            if (ip) {
11032008SN/A                TcpPtr tcp(ip);
11042008SN/A                if (tcp) {
11052008SN/A                    tcp->sum(0);
11062008SN/A                    tcp->sum(cksum(tcp));
11072008SN/A                    txTcpChecksums++;
11082008SN/A                }
11092008SN/A
11102008SN/A                UdpPtr udp(ip);
11112008SN/A                if (udp) {
11122008SN/A                    udp->sum(0);
11132008SN/A                    udp->sum(cksum(udp));
11142008SN/A                    txUdpChecksums++;
11152008SN/A                }
11162008SN/A
11172008SN/A                ip->sum(0);
11182008SN/A                ip->sum(cksum(ip));
11192008SN/A                txIpChecksums++;
11202008SN/A            }
11212008SN/A        }
11222008SN/A
11232008SN/A        txFifo.push(txPacket);
11242008SN/A        if (txFifo.avail() < regs.TxMaxCopy) {
11252008SN/A            devIntrPost(Regs::Intr_TxFull);
11262008SN/A            txFull = true;
11272008SN/A        }
11282008SN/A        txPacket = 0;
11292008SN/A        transmit();
11302008SN/A        txList.pop_front();
11312008SN/A        txState = txList.empty() ? txIdle : txFifoBlock;
11321939SN/A        devIntrPost(Regs::Intr_TxDMA);
11331156SN/A        break;
11341156SN/A
11351156SN/A      default:
11361156SN/A        panic("Invalid txState!");
11371156SN/A    }
11381156SN/A
11391156SN/A    DPRINTF(EthernetSM, "entering next txState=%s\n",
11401156SN/A            TxStateStrings[txState]);
11411156SN/A
11421156SN/A    goto next;
11431156SN/A
11441156SN/A  exit:
11451156SN/A    /**
11461156SN/A     * @todo do we want to schedule a future kick?
11471156SN/A     */
11481156SN/A    DPRINTF(EthernetSM, "tx state machine exited txState=%s\n",
11491156SN/A            TxStateStrings[txState]);
11501156SN/A}
11511156SN/A
11521156SN/Avoid
11531156SN/ADevice::transferDone()
11541156SN/A{
11551156SN/A    if (txFifo.empty()) {
11561156SN/A        DPRINTF(Ethernet, "transfer complete: txFifo empty...nothing to do\n");
11571156SN/A        return;
11581156SN/A    }
11591156SN/A
11601156SN/A    DPRINTF(Ethernet, "transfer complete: data in txFifo...schedule xmit\n");
11611156SN/A
11629417SN/A    reschedule(txEvent, clockEdge(Cycles(1)), true);
11631156SN/A}
11641156SN/A
11651156SN/Abool
11662566SN/ADevice::rxFilter(const EthPacketPtr &packet)
11671156SN/A{
11681156SN/A    if (!Regs::get_Config_Filter(regs.Config))
11691156SN/A        return false;
11701156SN/A
11711156SN/A    panic("receive filter not implemented\n");
11721156SN/A    bool drop = true;
11731156SN/A    return drop;
11741156SN/A}
11751156SN/A
11761156SN/Abool
11772566SN/ADevice::recvPacket(EthPacketPtr packet)
11781156SN/A{
11791156SN/A    rxBytes += packet->length;
11801156SN/A    rxPackets++;
11811156SN/A
11821156SN/A    DPRINTF(Ethernet, "Receiving packet from wire, rxFifo Available is %d\n",
11831156SN/A            rxFifo.avail());
11841156SN/A
11851156SN/A    if (!rxEnable) {
11861156SN/A        DPRINTF(Ethernet, "receive disabled...packet dropped\n");
11871156SN/A        return true;
11881156SN/A    }
11891156SN/A
11901156SN/A    if (rxFilter(packet)) {
11911156SN/A        DPRINTF(Ethernet, "packet filtered...dropped\n");
11921156SN/A        return true;
11931156SN/A    }
11941156SN/A
11955603SN/A    if (rxFifo.size() >= regs.RxFifoHigh)
11961939SN/A        devIntrPost(Regs::Intr_RxHigh);
11971156SN/A
11981156SN/A    if (!rxFifo.push(packet)) {
11991156SN/A        DPRINTF(Ethernet,
12001156SN/A                "packet will not fit in receive buffer...packet dropped\n");
12011156SN/A        return false;
12021156SN/A    }
12031156SN/A
12042008SN/A    // If we were at the last element, back up one ot go to the new
12052008SN/A    // last element of the list.
12062008SN/A    if (rxFifoPtr == rxFifo.end())
12072008SN/A        --rxFifoPtr;
12082008SN/A
12091939SN/A    devIntrPost(Regs::Intr_RxPacket);
12101156SN/A    rxKick();
12111156SN/A    return true;
12121156SN/A}
12131156SN/A
12142901SN/Avoid
12159342SN/ADevice::drainResume()
12162901SN/A{
12179342SN/A    Drainable::drainResume();
12182901SN/A
12192901SN/A    // During drain we could have left the state machines in a waiting state and
12202901SN/A    // they wouldn't get out until some other event occured to kick them.
12212901SN/A    // This way they'll get out immediately
12222901SN/A    txKick();
12232901SN/A    rxKick();
12242901SN/A}
12252901SN/A
12261156SN/A//=====================================================================
12271156SN/A//
12281156SN/A//
12291156SN/Avoid
123010905SN/ABase::serialize(CheckpointOut &cp) const
12311156SN/A{
12329807SN/A    // Serialize the PciDevice base class
123310905SN/A    PciDevice::serialize(cp);
12341156SN/A
12351156SN/A    SERIALIZE_SCALAR(rxEnable);
12361156SN/A    SERIALIZE_SCALAR(txEnable);
12371156SN/A    SERIALIZE_SCALAR(cpuIntrEnable);
12381156SN/A
12391156SN/A    /*
12401156SN/A     * Keep track of pending interrupt status.
12411156SN/A     */
12421156SN/A    SERIALIZE_SCALAR(intrTick);
12431156SN/A    SERIALIZE_SCALAR(cpuPendingIntr);
12441156SN/A    Tick intrEventTick = 0;
12451156SN/A    if (intrEvent)
12461156SN/A        intrEventTick = intrEvent->when();
12471156SN/A    SERIALIZE_SCALAR(intrEventTick);
12481156SN/A}
12491156SN/A
12501156SN/Avoid
125110905SN/ABase::unserialize(CheckpointIn &cp)
12521156SN/A{
12539807SN/A    // Unserialize the PciDevice base class
125410905SN/A    PciDevice::unserialize(cp);
12551156SN/A
12561156SN/A    UNSERIALIZE_SCALAR(rxEnable);
12571156SN/A    UNSERIALIZE_SCALAR(txEnable);
12581156SN/A    UNSERIALIZE_SCALAR(cpuIntrEnable);
12591156SN/A
12601156SN/A    /*
12611156SN/A     * Keep track of pending interrupt status.
12621156SN/A     */
12631156SN/A    UNSERIALIZE_SCALAR(intrTick);
12641156SN/A    UNSERIALIZE_SCALAR(cpuPendingIntr);
12651156SN/A    Tick intrEventTick;
12661156SN/A    UNSERIALIZE_SCALAR(intrEventTick);
12671156SN/A    if (intrEventTick) {
126812087Sspwilson2@wisc.edu        intrEvent = new EventFunctionWrapper([this]{ cpuInterrupt(); },
126912087Sspwilson2@wisc.edu                                             name(), true);
12705606SN/A        schedule(intrEvent, intrEventTick);
12711156SN/A    }
12721156SN/A}
12731156SN/A
12741156SN/Avoid
127511006SN/ADevice::serialize(CheckpointOut &cp) const
12761156SN/A{
12772287SN/A    int count;
12782287SN/A
12799807SN/A    // Serialize the PciDevice base class
128010905SN/A    Base::serialize(cp);
12811156SN/A
12821939SN/A    if (rxState == rxCopy)
12831939SN/A        panic("can't serialize with an in flight dma request rxState=%s",
12841939SN/A              RxStateStrings[rxState]);
12851156SN/A
12861939SN/A    if (txState == txCopy)
12871939SN/A        panic("can't serialize with an in flight dma request txState=%s",
12881939SN/A              TxStateStrings[txState]);
12891156SN/A
12901156SN/A    /*
12915603SN/A     * Serialize the device registers that could be modified by the OS.
12921156SN/A     */
12931156SN/A    SERIALIZE_SCALAR(regs.Config);
12941939SN/A    SERIALIZE_SCALAR(regs.IntrStatus);
12951939SN/A    SERIALIZE_SCALAR(regs.IntrMask);
12961156SN/A    SERIALIZE_SCALAR(regs.RxData);
12971156SN/A    SERIALIZE_SCALAR(regs.TxData);
12981156SN/A
12991156SN/A    /*
13002008SN/A     * Serialize the virtual nic state
13012008SN/A     */
13022008SN/A    int virtualRegsSize = virtualRegs.size();
13032008SN/A    SERIALIZE_SCALAR(virtualRegsSize);
13042008SN/A    for (int i = 0; i < virtualRegsSize; ++i) {
130510905SN/A        const VirtualReg *vnic = &virtualRegs[i];
13062008SN/A
13072566SN/A        std::string reg = csprintf("vnic%d", i);
130810905SN/A        paramOut(cp, reg + ".RxData", vnic->RxData);
130910905SN/A        paramOut(cp, reg + ".RxDone", vnic->RxDone);
131010905SN/A        paramOut(cp, reg + ".TxData", vnic->TxData);
131110905SN/A        paramOut(cp, reg + ".TxDone", vnic->TxDone);
13122008SN/A
13135603SN/A        bool rxPacketExists = vnic->rxIndex != rxFifo.end();
131410905SN/A        paramOut(cp, reg + ".rxPacketExists", rxPacketExists);
13152008SN/A        if (rxPacketExists) {
13162008SN/A            int rxPacket = 0;
131711006SN/A            auto i = rxFifo.begin();
13185603SN/A            while (i != vnic->rxIndex) {
13192008SN/A                assert(i != rxFifo.end());
13202008SN/A                ++i;
13212008SN/A                ++rxPacket;
13222008SN/A            }
13232008SN/A
132410905SN/A            paramOut(cp, reg + ".rxPacket", rxPacket);
132510905SN/A            paramOut(cp, reg + ".rxPacketOffset", vnic->rxPacketOffset);
132610905SN/A            paramOut(cp, reg + ".rxPacketBytes", vnic->rxPacketBytes);
13272008SN/A        }
132810905SN/A        paramOut(cp, reg + ".rxDoneData", vnic->rxDoneData);
13292008SN/A    }
13302008SN/A
13315603SN/A    int rxFifoPtr = -1;
13325603SN/A    if (this->rxFifoPtr != rxFifo.end())
13335603SN/A        rxFifoPtr = rxFifo.countPacketsBefore(this->rxFifoPtr);
13342282SN/A    SERIALIZE_SCALAR(rxFifoPtr);
13352282SN/A
13362282SN/A    SERIALIZE_SCALAR(rxActive);
13375603SN/A    SERIALIZE_SCALAR(rxBusyCount);
13385603SN/A    SERIALIZE_SCALAR(rxDirtyCount);
13395603SN/A    SERIALIZE_SCALAR(rxMappedCount);
13402282SN/A
134111006SN/A    VirtualList::const_iterator i, end;
13422008SN/A    for (count = 0, i = rxList.begin(), end = rxList.end(); i != end; ++i)
134310905SN/A        paramOut(cp, csprintf("rxList%d", count++), *i);
13442282SN/A    int rxListSize = count;
13452282SN/A    SERIALIZE_SCALAR(rxListSize);
13462008SN/A
13472282SN/A    for (count = 0, i = rxBusy.begin(), end = rxBusy.end(); i != end; ++i)
134810905SN/A        paramOut(cp, csprintf("rxBusy%d", count++), *i);
13492282SN/A    int rxBusySize = count;
13502282SN/A    SERIALIZE_SCALAR(rxBusySize);
13512282SN/A
13522008SN/A    for (count = 0, i = txList.begin(), end = txList.end(); i != end; ++i)
135310905SN/A        paramOut(cp, csprintf("txList%d", count++), *i);
13542282SN/A    int txListSize = count;
13552282SN/A    SERIALIZE_SCALAR(txListSize);
13562008SN/A
13572008SN/A    /*
13581156SN/A     * Serialize rx state machine
13591156SN/A     */
13601156SN/A    int rxState = this->rxState;
13611156SN/A    SERIALIZE_SCALAR(rxState);
13621939SN/A    SERIALIZE_SCALAR(rxEmpty);
13632282SN/A    SERIALIZE_SCALAR(rxLow);
136410905SN/A    rxFifo.serialize("rxFifo", cp);
13651156SN/A
13661156SN/A    /*
13671156SN/A     * Serialize tx state machine
13681156SN/A     */
13691156SN/A    int txState = this->txState;
13701156SN/A    SERIALIZE_SCALAR(txState);
13711939SN/A    SERIALIZE_SCALAR(txFull);
137210905SN/A    txFifo.serialize("txFifo", cp);
137310469SN/A    bool txPacketExists = txPacket != nullptr;
13741156SN/A    SERIALIZE_SCALAR(txPacketExists);
13751156SN/A    if (txPacketExists) {
137610905SN/A        txPacket->serialize("txPacket", cp);
13772008SN/A        SERIALIZE_SCALAR(txPacketOffset);
13782008SN/A        SERIALIZE_SCALAR(txPacketBytes);
13791156SN/A    }
13801156SN/A
13811156SN/A    /*
13821156SN/A     * If there's a pending transmit, store the time so we can
13831156SN/A     * reschedule it later
13841156SN/A     */
13857823SN/A    Tick transmitTick = txEvent.scheduled() ? txEvent.when() - curTick() : 0;
13861156SN/A    SERIALIZE_SCALAR(transmitTick);
13871156SN/A}
13881156SN/A
13891156SN/Avoid
139010905SN/ADevice::unserialize(CheckpointIn &cp)
13911156SN/A{
13929807SN/A    // Unserialize the PciDevice base class
139310905SN/A    Base::unserialize(cp);
13941156SN/A
13951156SN/A    /*
13965603SN/A     * Unserialize the device registers that may have been written by the OS.
13971156SN/A     */
13981156SN/A    UNSERIALIZE_SCALAR(regs.Config);
13991939SN/A    UNSERIALIZE_SCALAR(regs.IntrStatus);
14001939SN/A    UNSERIALIZE_SCALAR(regs.IntrMask);
14011156SN/A    UNSERIALIZE_SCALAR(regs.RxData);
14021156SN/A    UNSERIALIZE_SCALAR(regs.TxData);
14031156SN/A
14042282SN/A    UNSERIALIZE_SCALAR(rxActive);
14055603SN/A    UNSERIALIZE_SCALAR(rxBusyCount);
14065603SN/A    UNSERIALIZE_SCALAR(rxDirtyCount);
14075603SN/A    UNSERIALIZE_SCALAR(rxMappedCount);
14082282SN/A
14092008SN/A    int rxListSize;
14102008SN/A    UNSERIALIZE_SCALAR(rxListSize);
14112008SN/A    rxList.clear();
14122008SN/A    for (int i = 0; i < rxListSize; ++i) {
14132008SN/A        int value;
141410905SN/A        paramIn(cp, csprintf("rxList%d", i), value);
14152008SN/A        rxList.push_back(value);
14162008SN/A    }
14172008SN/A
14182282SN/A    int rxBusySize;
14192282SN/A    UNSERIALIZE_SCALAR(rxBusySize);
14202282SN/A    rxBusy.clear();
14212282SN/A    for (int i = 0; i < rxBusySize; ++i) {
14222282SN/A        int value;
142310905SN/A        paramIn(cp, csprintf("rxBusy%d", i), value);
14242282SN/A        rxBusy.push_back(value);
14252282SN/A    }
14262282SN/A
14272008SN/A    int txListSize;
14282008SN/A    UNSERIALIZE_SCALAR(txListSize);
14292008SN/A    txList.clear();
14302008SN/A    for (int i = 0; i < txListSize; ++i) {
14312008SN/A        int value;
143210905SN/A        paramIn(cp, csprintf("txList%d", i), value);
14332008SN/A        txList.push_back(value);
14342008SN/A    }
14352008SN/A
14361156SN/A    /*
14371156SN/A     * Unserialize rx state machine
14381156SN/A     */
14391156SN/A    int rxState;
14401156SN/A    UNSERIALIZE_SCALAR(rxState);
14411939SN/A    UNSERIALIZE_SCALAR(rxEmpty);
14422282SN/A    UNSERIALIZE_SCALAR(rxLow);
14431156SN/A    this->rxState = (RxState) rxState;
144410905SN/A    rxFifo.unserialize("rxFifo", cp);
14451156SN/A
14462282SN/A    int rxFifoPtr;
14472282SN/A    UNSERIALIZE_SCALAR(rxFifoPtr);
14485603SN/A    if (rxFifoPtr >= 0) {
14495603SN/A        this->rxFifoPtr = rxFifo.begin();
14505603SN/A        for (int i = 0; i < rxFifoPtr; ++i)
14515603SN/A            ++this->rxFifoPtr;
14525603SN/A    } else {
14535603SN/A        this->rxFifoPtr = rxFifo.end();
14545603SN/A    }
14552282SN/A
14561156SN/A    /*
14571156SN/A     * Unserialize tx state machine
14581156SN/A     */
14591156SN/A    int txState;
14601156SN/A    UNSERIALIZE_SCALAR(txState);
14611939SN/A    UNSERIALIZE_SCALAR(txFull);
14621156SN/A    this->txState = (TxState) txState;
146310905SN/A    txFifo.unserialize("txFifo", cp);
14641156SN/A    bool txPacketExists;
14651156SN/A    UNSERIALIZE_SCALAR(txPacketExists);
14661156SN/A    txPacket = 0;
14671156SN/A    if (txPacketExists) {
146811719Smichael.lebeane@amd.com        txPacket = make_shared<EthPacketData>(16384);
146910905SN/A        txPacket->unserialize("txPacket", cp);
14702008SN/A        UNSERIALIZE_SCALAR(txPacketOffset);
14712008SN/A        UNSERIALIZE_SCALAR(txPacketBytes);
14722008SN/A    }
14732008SN/A
14742008SN/A    /*
14752008SN/A     * unserialize the virtual nic registers/state
14762008SN/A     *
14772008SN/A     * this must be done after the unserialization of the rxFifo
14782008SN/A     * because the packet iterators depend on the fifo being populated
14792008SN/A     */
14802008SN/A    int virtualRegsSize;
14812008SN/A    UNSERIALIZE_SCALAR(virtualRegsSize);
14822008SN/A    virtualRegs.clear();
14832008SN/A    virtualRegs.resize(virtualRegsSize);
14842008SN/A    for (int i = 0; i < virtualRegsSize; ++i) {
14852008SN/A        VirtualReg *vnic = &virtualRegs[i];
14862566SN/A        std::string reg = csprintf("vnic%d", i);
14872008SN/A
148810905SN/A        paramIn(cp, reg + ".RxData", vnic->RxData);
148910905SN/A        paramIn(cp, reg + ".RxDone", vnic->RxDone);
149010905SN/A        paramIn(cp, reg + ".TxData", vnic->TxData);
149110905SN/A        paramIn(cp, reg + ".TxDone", vnic->TxDone);
14922008SN/A
14932282SN/A        vnic->rxUnique = rxUnique++;
14942282SN/A        vnic->txUnique = txUnique++;
14952282SN/A
14962008SN/A        bool rxPacketExists;
149710905SN/A        paramIn(cp, reg + ".rxPacketExists", rxPacketExists);
14982008SN/A        if (rxPacketExists) {
14992008SN/A            int rxPacket;
150010905SN/A            paramIn(cp, reg + ".rxPacket", rxPacket);
15015603SN/A            vnic->rxIndex = rxFifo.begin();
15022008SN/A            while (rxPacket--)
15035603SN/A                ++vnic->rxIndex;
15042008SN/A
150510905SN/A            paramIn(cp, reg + ".rxPacketOffset",
15062008SN/A                    vnic->rxPacketOffset);
150710905SN/A            paramIn(cp, reg + ".rxPacketBytes", vnic->rxPacketBytes);
15082008SN/A        } else {
15095603SN/A            vnic->rxIndex = rxFifo.end();
15102008SN/A        }
151110905SN/A        paramIn(cp, reg + ".rxDoneData", vnic->rxDoneData);
15121156SN/A    }
15131156SN/A
15141156SN/A    /*
15151156SN/A     * If there's a pending transmit, reschedule it now
15161156SN/A     */
15171156SN/A    Tick transmitTick;
15181156SN/A    UNSERIALIZE_SCALAR(transmitTick);
15191156SN/A    if (transmitTick)
15207823SN/A        schedule(txEvent, curTick() + transmitTick);
15211156SN/A
15228851SN/A    pioPort.sendRangeChange();
15232566SN/A
15241156SN/A}
15251156SN/A
15267811SN/A} // namespace Sinic
15271156SN/A
15284762SN/ASinic::Device *
15294762SN/ASinicParams::create()
15301156SN/A{
15314762SN/A    return new Sinic::Device(this);
15321156SN/A}
1533