sinic.cc revision 11263
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),
941156SN/A      txEvent(this), rxDmaEvent(this), txDmaEvent(this),
951156SN/A      dmaReadDelay(p->dma_read_delay), dmaReadFactor(p->dma_read_factor),
961156SN/A      dmaWriteDelay(p->dma_write_delay), dmaWriteFactor(p->dma_write_factor)
971156SN/A{
984981SN/A    interface = new Interface(name() + ".int0", this);
991156SN/A    reset();
1001156SN/A
1011156SN/A}
1021156SN/A
1031156SN/ADevice::~Device()
1041156SN/A{}
1051156SN/A
1061156SN/Avoid
1071156SN/ADevice::regStats()
1081156SN/A{
1099339SN/A    Base::regStats();
1105603SN/A
1115603SN/A    _maxVnicDistance = 0;
1125603SN/A
1135603SN/A    maxVnicDistance
1145603SN/A        .name(name() + ".maxVnicDistance")
1155603SN/A        .desc("maximum vnic distance")
1165603SN/A        ;
1175603SN/A
1185603SN/A    totalVnicDistance
1195603SN/A        .name(name() + ".totalVnicDistance")
1205603SN/A        .desc("total vnic distance")
1215603SN/A        ;
1225603SN/A    numVnicDistance
1235603SN/A        .name(name() + ".numVnicDistance")
1245603SN/A        .desc("number of vnic distance measurements")
1255603SN/A        ;
1265603SN/A
1275603SN/A    avgVnicDistance
1285603SN/A        .name(name() + ".avgVnicDistance")
1295603SN/A        .desc("average vnic distance")
1305603SN/A        ;
1315603SN/A
1325603SN/A    avgVnicDistance = totalVnicDistance / numVnicDistance;
1335603SN/A}
1345603SN/A
1355603SN/Avoid
1365603SN/ADevice::resetStats()
1375603SN/A{
1389339SN/A    Base::resetStats();
1399339SN/A
1405603SN/A    _maxVnicDistance = 0;
1411156SN/A}
1421156SN/A
1434981SN/AEtherInt*
1444981SN/ADevice::getEthPort(const std::string &if_name, int idx)
1454981SN/A{
1464981SN/A    if (if_name == "interface") {
1474981SN/A        if (interface->getPeer())
1484981SN/A            panic("interface already connected to\n");
1494981SN/A
1504981SN/A        return interface;
1514981SN/A    }
1524981SN/A    return NULL;
1534981SN/A}
1544981SN/A
1554981SN/A
1561939SN/Avoid
15711005SN/ADevice::prepareIO(ContextID cpu, int index)
1582008SN/A{
1592008SN/A    int size = virtualRegs.size();
1602282SN/A    if (index > size)
1612282SN/A        panic("Trying to access a vnic that doesn't exist %d > %d\n",
1622282SN/A              index, size);
1632008SN/A}
1642008SN/A
1655603SN/A//add stats for head of line blocking
1665603SN/A//add stats for average fifo length
1675603SN/A//add stats for average number of vnics busy
1685603SN/A
1692008SN/Avoid
17011005SN/ADevice::prepareRead(ContextID cpu, int index)
1712008SN/A{
1722008SN/A    using namespace Regs;
1732008SN/A    prepareIO(cpu, index);
1742008SN/A
1752008SN/A    VirtualReg &vnic = virtualRegs[index];
1762008SN/A
1772008SN/A    // update rx registers
1782008SN/A    uint64_t rxdone = vnic.RxDone;
1792282SN/A    rxdone = set_RxDone_Packets(rxdone, rxFifo.countPacketsAfter(rxFifoPtr));
1802282SN/A    rxdone = set_RxDone_Empty(rxdone, rxFifo.empty());
1815603SN/A    rxdone = set_RxDone_High(rxdone, rxFifo.size() > regs.RxFifoHigh);
1822282SN/A    rxdone = set_RxDone_NotHigh(rxdone, rxLow);
1832008SN/A    regs.RxData = vnic.RxData;
1842008SN/A    regs.RxDone = rxdone;
1852008SN/A    regs.RxWait = rxdone;
1862008SN/A
1872008SN/A    // update tx regsiters
1882008SN/A    uint64_t txdone = vnic.TxDone;
1892008SN/A    txdone = set_TxDone_Packets(txdone, txFifo.packets());
1902008SN/A    txdone = set_TxDone_Full(txdone, txFifo.avail() < regs.TxMaxCopy);
1915603SN/A    txdone = set_TxDone_Low(txdone, txFifo.size() < regs.TxFifoLow);
1922008SN/A    regs.TxData = vnic.TxData;
1932008SN/A    regs.TxDone = txdone;
1942008SN/A    regs.TxWait = txdone;
1955603SN/A
1965603SN/A    int head = 0xffff;
1975603SN/A
1985603SN/A    if (!rxFifo.empty()) {
1995603SN/A        int vnic = rxFifo.begin()->priv;
2005603SN/A        if (vnic != -1 && virtualRegs[vnic].rxPacketOffset > 0)
2015603SN/A            head = vnic;
2025603SN/A    }
2035603SN/A
2045603SN/A    regs.RxStatus = set_RxStatus_Head(regs.RxStatus, head);
2055603SN/A    regs.RxStatus = set_RxStatus_Busy(regs.RxStatus, rxBusyCount);
2065603SN/A    regs.RxStatus = set_RxStatus_Mapped(regs.RxStatus, rxMappedCount);
2075603SN/A    regs.RxStatus = set_RxStatus_Dirty(regs.RxStatus, rxDirtyCount);
2082008SN/A}
2092008SN/A
2102008SN/Avoid
21111005SN/ADevice::prepareWrite(ContextID cpu, int index)
2121997SN/A{
2132008SN/A    prepareIO(cpu, index);
2141997SN/A}
2151997SN/A
2161156SN/A/**
2171939SN/A * I/O read of device register
2181156SN/A */
2192566SN/ATick
2203349SN/ADevice::read(PacketPtr pkt)
2211156SN/A{
2221817SN/A    assert(config.command & PCI_CMD_MSE);
2232641SN/A    assert(pkt->getAddr() >= BARAddrs[0] && pkt->getSize() < BARSize[0]);
2241156SN/A
22511005SN/A    ContextID cpu = pkt->req->contextId();
2262641SN/A    Addr daddr = pkt->getAddr() - BARAddrs[0];
2272008SN/A    Addr index = daddr >> Regs::VirtualShift;
2282008SN/A    Addr raddr = daddr & Regs::VirtualMask;
2291997SN/A
2302008SN/A    if (!regValid(raddr))
2312617SN/A        panic("invalid register: cpu=%d vnic=%d da=%#x pa=%#x size=%d",
2322641SN/A              cpu, index, daddr, pkt->getAddr(), pkt->getSize());
2331156SN/A
2342008SN/A    const Regs::Info &info = regInfo(raddr);
2351939SN/A    if (!info.read)
2362279SN/A        panic("read %s (write only): "
2372617SN/A              "cpu=%d vnic=%d da=%#x pa=%#x size=%d",
2382641SN/A              info.name, cpu, index, daddr, pkt->getAddr(), pkt->getSize());
2391939SN/A
2402279SN/A        panic("read %s (invalid size): "
2412617SN/A              "cpu=%d vnic=%d da=%#x pa=%#x size=%d",
2422641SN/A              info.name, cpu, index, daddr, pkt->getAddr(), pkt->getSize());
2431156SN/A
2442008SN/A    prepareRead(cpu, index);
2451156SN/A
2468641SN/A    uint64_t value M5_VAR_USED = 0;
2472641SN/A    if (pkt->getSize() == 4) {
2482566SN/A        uint32_t reg = regData32(raddr);
2492630SN/A        pkt->set(reg);
2501939SN/A        value = reg;
2511156SN/A    }
2521156SN/A
2532641SN/A    if (pkt->getSize() == 8) {
2542566SN/A        uint64_t reg = regData64(raddr);
2552630SN/A        pkt->set(reg);
2561939SN/A        value = reg;
2571939SN/A    }
2581939SN/A
2591998SN/A    DPRINTF(EthernetPIO,
2602617SN/A            "read %s: cpu=%d vnic=%d da=%#x pa=%#x size=%d val=%#x\n",
2612641SN/A            info.name, cpu, index, daddr, pkt->getAddr(), pkt->getSize(), value);
2621939SN/A
2631939SN/A    // reading the interrupt status register has the side effect of
2641939SN/A    // clearing it
2652008SN/A    if (raddr == Regs::IntrStatus)
2661939SN/A        devIntrClear();
2671156SN/A
2682566SN/A    return pioDelay;
2691156SN/A}
2701156SN/A
2711939SN/A/**
2721939SN/A * IPR read of device register
2732566SN/A
2742566SN/A    Fault
27511005SN/ADevice::iprRead(Addr daddr, ContextID cpu, uint64_t &result)
2761939SN/A{
2771939SN/A    if (!regValid(daddr))
2781939SN/A        panic("invalid address: da=%#x", daddr);
2791939SN/A
2801939SN/A    const Regs::Info &info = regInfo(daddr);
2811939SN/A    if (!info.read)
2821998SN/A        panic("reading %s (write only): cpu=%d da=%#x", info.name, cpu, daddr);
2831939SN/A
2841998SN/A    DPRINTF(EthernetPIO, "IPR read %s: cpu=%d da=%#x\n",
2851998SN/A            info.name, cpu, daddr);
2861939SN/A
2872008SN/A    prepareRead(cpu, 0);
2881939SN/A
2891939SN/A    if (info.size == 4)
2901939SN/A        result = regData32(daddr);
2911939SN/A
2921939SN/A    if (info.size == 8)
2931939SN/A        result = regData64(daddr);
2941939SN/A
2951998SN/A    DPRINTF(EthernetPIO, "IPR read %s: cpu=%s da=%#x val=%#x\n",
2961998SN/A            info.name, cpu, result);
2971939SN/A
2982090SN/A    return NoFault;
2991939SN/A}
3002566SN/A*/
3011939SN/A/**
3021939SN/A * I/O write of device register
3031939SN/A */
3042566SN/ATick
3053349SN/ADevice::write(PacketPtr pkt)
3061156SN/A{
3071817SN/A    assert(config.command & PCI_CMD_MSE);
3082641SN/A    assert(pkt->getAddr() >= BARAddrs[0] && pkt->getSize() < BARSize[0]);
3091939SN/A
31011005SN/A    ContextID cpu = pkt->req->contextId();
3112641SN/A    Addr daddr = pkt->getAddr() - BARAddrs[0];
3122008SN/A    Addr index = daddr >> Regs::VirtualShift;
3132008SN/A    Addr raddr = daddr & Regs::VirtualMask;
3141997SN/A
3152008SN/A    if (!regValid(raddr))
3162566SN/A        panic("invalid register: cpu=%d, da=%#x pa=%#x size=%d",
3172641SN/A                cpu, daddr, pkt->getAddr(), pkt->getSize());
3181156SN/A
3192008SN/A    const Regs::Info &info = regInfo(raddr);
3201939SN/A    if (!info.write)
3212279SN/A        panic("write %s (read only): "
3222617SN/A              "cpu=%d vnic=%d da=%#x pa=%#x size=%d",
3232641SN/A              info.name, cpu, index, daddr, pkt->getAddr(), pkt->getSize());
3241939SN/A
3252641SN/A    if (pkt->getSize() != info.size)
3262279SN/A        panic("write %s (invalid size): "
3272617SN/A              "cpu=%d vnic=%d da=%#x pa=%#x size=%d",
3282641SN/A              info.name, cpu, index, daddr, pkt->getAddr(), pkt->getSize());
3291156SN/A
3302176SN/A    VirtualReg &vnic = virtualRegs[index];
3312176SN/A
3321998SN/A    DPRINTF(EthernetPIO,
3332617SN/A            "write %s vnic %d: cpu=%d val=%#x da=%#x pa=%#x size=%d\n",
3342630SN/A            info.name, index, cpu, info.size == 4 ? pkt->get<uint32_t>() :
3352641SN/A            pkt->get<uint64_t>(), daddr, pkt->getAddr(), pkt->getSize());
3361156SN/A
3372008SN/A    prepareWrite(cpu, index);
3381156SN/A
3392008SN/A    switch (raddr) {
3401156SN/A      case Regs::Config:
3412630SN/A        changeConfig(pkt->get<uint32_t>());
3421156SN/A        break;
3431156SN/A
3441939SN/A      case Regs::Command:
3452630SN/A        command(pkt->get<uint32_t>());
3461156SN/A        break;
3471156SN/A
3481939SN/A      case Regs::IntrStatus:
3492630SN/A        devIntrClear(regs.IntrStatus & pkt->get<uint32_t>());
3501156SN/A        break;
3511156SN/A
3521156SN/A      case Regs::IntrMask:
3532630SN/A        devIntrChangeMask(pkt->get<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;
3632630SN/A        vnic.RxData = pkt->get<uint64_t>();
3645603SN/A        rxBusyCount++;
3652282SN/A
3662630SN/A        if (Regs::get_RxData_Vaddr(pkt->get<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
4042630SN/A        if (Regs::get_TxData_Vaddr(pkt->get<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()) {
5308231SN/A        Debug::breakpoint();
5317823SN/A        intrTick = curTick();
5321156SN/A    }
5331156SN/A
5341156SN/A    DPRINTF(EthernetIntr, "going to schedule an interrupt for intrTick=%d\n",
5351156SN/A            intrTick);
5361156SN/A
5371156SN/A    if (intrEvent)
5381156SN/A        intrEvent->squash();
5395606SN/A    intrEvent = new IntrEvent(this, true);
5405606SN/A    schedule(intrEvent, intrTick);
5411156SN/A}
5421156SN/A
5431156SN/Avoid
5441156SN/ABase::cpuInterrupt()
5451156SN/A{
5467823SN/A    assert(intrTick == curTick());
5471156SN/A
5481156SN/A    // Whether or not there's a pending interrupt, we don't care about
5491156SN/A    // it anymore
5501156SN/A    intrEvent = 0;
5511156SN/A    intrTick = 0;
5521156SN/A
5531156SN/A    // Don't send an interrupt if there's already one
5541156SN/A    if (cpuPendingIntr) {
5551156SN/A        DPRINTF(EthernetIntr,
5561156SN/A                "would send an interrupt now, but there's already pending\n");
5571156SN/A    } else {
5581156SN/A        // Send interrupt
5591156SN/A        cpuPendingIntr = true;
5601156SN/A
5611156SN/A        DPRINTF(EthernetIntr, "posting interrupt\n");
5621156SN/A        intrPost();
5631156SN/A    }
5641156SN/A}
5651156SN/A
5661156SN/Avoid
5671156SN/ABase::cpuIntrClear()
5681156SN/A{
5691156SN/A    if (!cpuPendingIntr)
5701156SN/A        return;
5711156SN/A
5721156SN/A    if (intrEvent) {
5731156SN/A        intrEvent->squash();
5741156SN/A        intrEvent = 0;
5751156SN/A    }
5761156SN/A
5771156SN/A    intrTick = 0;
5781156SN/A
5791156SN/A    cpuPendingIntr = false;
5801156SN/A
5811156SN/A    DPRINTF(EthernetIntr, "clearing cchip interrupt\n");
5821156SN/A    intrClear();
5831156SN/A}
5841156SN/A
5851156SN/Abool
5861156SN/ABase::cpuIntrPending() const
5871156SN/A{ return cpuPendingIntr; }
5881156SN/A
5891156SN/Avoid
5901156SN/ADevice::changeConfig(uint32_t newconf)
5911156SN/A{
5921156SN/A    uint32_t changed = regs.Config ^ newconf;
5931156SN/A    if (!changed)
5941156SN/A        return;
5951156SN/A
5961156SN/A    regs.Config = newconf;
5971156SN/A
5981156SN/A    if ((changed & Regs::Config_IntEn)) {
5991156SN/A        cpuIntrEnable = regs.Config & Regs::Config_IntEn;
6001156SN/A        if (cpuIntrEnable) {
6011156SN/A            if (regs.IntrStatus & regs.IntrMask)
6027823SN/A                cpuIntrPost(curTick());
6031156SN/A        } else {
6041156SN/A            cpuIntrClear();
6051156SN/A        }
6061156SN/A    }
6071156SN/A
6081156SN/A    if ((changed & Regs::Config_TxEn)) {
6091156SN/A        txEnable = regs.Config & Regs::Config_TxEn;
6101156SN/A        if (txEnable)
6111156SN/A            txKick();
6121156SN/A    }
6131156SN/A
6141156SN/A    if ((changed & Regs::Config_RxEn)) {
6151156SN/A        rxEnable = regs.Config & Regs::Config_RxEn;
6161156SN/A        if (rxEnable)
6171156SN/A            rxKick();
6181156SN/A    }
6191156SN/A}
6201156SN/A
6211156SN/Avoid
6221939SN/ADevice::command(uint32_t command)
6231939SN/A{
6242008SN/A    if (command & Regs::Command_Intr)
6252008SN/A        devIntrPost(Regs::Intr_Soft);
6262008SN/A
6271939SN/A    if (command & Regs::Command_Reset)
6281939SN/A        reset();
6291939SN/A}
6301939SN/A
6311939SN/Avoid
6321156SN/ADevice::reset()
6331156SN/A{
6341156SN/A    using namespace Regs;
6351939SN/A
6361156SN/A    memset(&regs, 0, sizeof(regs));
6371939SN/A
6381939SN/A    regs.Config = 0;
6392008SN/A    if (params()->rx_thread)
6402008SN/A        regs.Config |= Config_RxThread;
6412008SN/A    if (params()->tx_thread)
6422008SN/A        regs.Config |= Config_TxThread;
6432210SN/A    if (params()->rss)
6442210SN/A        regs.Config |= Config_RSS;
6452282SN/A    if (params()->zero_copy)
6462282SN/A        regs.Config |= Config_ZeroCopy;
6472282SN/A    if (params()->delay_copy)
6482282SN/A        regs.Config |= Config_DelayCopy;
6492282SN/A    if (params()->virtual_addr)
6502282SN/A        regs.Config |= Config_Vaddr;
6512282SN/A
6522282SN/A    if (params()->delay_copy && params()->zero_copy)
6532282SN/A        panic("Can't delay copy and zero copy");
6542282SN/A
6552008SN/A    regs.IntrMask = Intr_Soft | Intr_RxHigh | Intr_RxPacket | Intr_TxLow;
6561156SN/A    regs.RxMaxCopy = params()->rx_max_copy;
6571156SN/A    regs.TxMaxCopy = params()->tx_max_copy;
6585603SN/A    regs.ZeroCopySize = params()->zero_copy_size;
6595603SN/A    regs.ZeroCopyMark = params()->zero_copy_threshold;
6605603SN/A    regs.VirtualCount = params()->virtual_count;
6611939SN/A    regs.RxMaxIntr = params()->rx_max_intr;
6621939SN/A    regs.RxFifoSize = params()->rx_fifo_size;
6631939SN/A    regs.TxFifoSize = params()->tx_fifo_size;
6645603SN/A    regs.RxFifoLow = params()->rx_fifo_low_mark;
6655603SN/A    regs.TxFifoLow = params()->tx_fifo_threshold;
6665603SN/A    regs.RxFifoHigh = params()->rx_fifo_threshold;
6675603SN/A    regs.TxFifoHigh = params()->tx_fifo_high_mark;
6684762SN/A    regs.HwAddr = params()->hardware_address;
6691156SN/A
6705603SN/A    if (regs.RxMaxCopy < regs.ZeroCopyMark)
6715603SN/A        panic("Must be able to copy at least as many bytes as the threshold");
6725603SN/A
6735603SN/A    if (regs.ZeroCopySize >= regs.ZeroCopyMark)
6745603SN/A        panic("The number of bytes to copy must be less than the threshold");
6755603SN/A
6762008SN/A    rxList.clear();
6772282SN/A    rxBusy.clear();
6782282SN/A    rxActive = -1;
6792008SN/A    txList.clear();
6805603SN/A    rxBusyCount = 0;
6815603SN/A    rxDirtyCount = 0;
6825603SN/A    rxMappedCount = 0;
6832008SN/A
6841156SN/A    rxState = rxIdle;
6851156SN/A    txState = txIdle;
6861156SN/A
6871156SN/A    rxFifo.clear();
6882008SN/A    rxFifoPtr = rxFifo.end();
6891156SN/A    txFifo.clear();
6901939SN/A    rxEmpty = false;
6912282SN/A    rxLow = true;
6921939SN/A    txFull = false;
6932008SN/A
6942008SN/A    int size = virtualRegs.size();
6952008SN/A    virtualRegs.clear();
6962008SN/A    virtualRegs.resize(size);
6972008SN/A    for (int i = 0; i < size; ++i)
6985603SN/A        virtualRegs[i].rxIndex = rxFifo.end();
6991156SN/A}
7001156SN/A
7011156SN/Avoid
7022566SN/ADevice::rxDmaDone()
7031156SN/A{
7041156SN/A    assert(rxState == rxCopy);
7051156SN/A    rxState = rxCopyDone;
7062280SN/A    DPRINTF(EthernetDMA, "end rx dma write paddr=%#x len=%d\n",
7071156SN/A            rxDmaAddr, rxDmaLen);
7081939SN/A    DDUMP(EthernetData, rxDmaData, rxDmaLen);
7091939SN/A
7101939SN/A    // If the transmit state machine  has a pending DMA, let it go first
7111939SN/A    if (txState == txBeginCopy)
7121939SN/A        txKick();
7131939SN/A
7141156SN/A    rxKick();
7151156SN/A}
7161156SN/A
7171156SN/Avoid
7181156SN/ADevice::rxKick()
7191156SN/A{
7202282SN/A    VirtualReg *vnic = NULL;
7212008SN/A
7222279SN/A    DPRINTF(EthernetSM, "rxKick: rxState=%s (rxFifo.size=%d)\n",
7231156SN/A            RxStateStrings[rxState], rxFifo.size());
7241156SN/A
7257823SN/A    if (rxKickTick > curTick()) {
7262279SN/A        DPRINTF(EthernetSM, "rxKick: exiting, can't run till %d\n",
7271156SN/A                rxKickTick);
7281156SN/A        return;
7291156SN/A    }
7301156SN/A
7311156SN/A  next:
7325603SN/A    rxFifo.check();
7332008SN/A    if (rxState == rxIdle)
7341156SN/A        goto exit;
7351156SN/A
7362282SN/A    if (rxActive == -1) {
7372282SN/A        if (rxState != rxFifoBlock)
7382282SN/A            panic("no active vnic while in state %s", RxStateStrings[rxState]);
7392008SN/A
7402282SN/A        DPRINTF(EthernetSM, "processing rxState=%s\n",
7412282SN/A                RxStateStrings[rxState]);
7422282SN/A    } else {
7432282SN/A        vnic = &virtualRegs[rxActive];
7442282SN/A        DPRINTF(EthernetSM,
7452282SN/A                "processing rxState=%s for vnic %d (rxunique %d)\n",
7462282SN/A                RxStateStrings[rxState], rxActive, vnic->rxUnique);
7472282SN/A    }
7482008SN/A
7492008SN/A    switch (rxState) {
7501156SN/A      case rxFifoBlock:
7512282SN/A        if (DTRACE(EthernetSM)) {
7522282SN/A            PacketFifo::iterator end = rxFifo.end();
7532282SN/A            int size = virtualRegs.size();
7542282SN/A            for (int i = 0; i < size; ++i) {
7552282SN/A                VirtualReg *vn = &virtualRegs[i];
7565603SN/A                bool busy = Regs::get_RxDone_Busy(vn->RxDone);
7575603SN/A                if (vn->rxIndex != end) {
7588641SN/A#ifndef NDEBUG
7595603SN/A                    bool dirty = vn->rxPacketOffset > 0;
7605603SN/A                    const char *status;
7615603SN/A
7625603SN/A                    if (busy && dirty)
7635603SN/A                        status = "busy,dirty";
7645603SN/A                    else if (busy)
7655603SN/A                        status = "busy";
7665603SN/A                    else if (dirty)
7675603SN/A                        status = "dirty";
7685603SN/A                    else
7695603SN/A                        status = "mapped";
7705603SN/A
7712282SN/A                    DPRINTF(EthernetSM,
7725603SN/A                            "vnic %d %s (rxunique %d), packet %d, slack %d\n",
7735603SN/A                            i, status, vn->rxUnique,
7745603SN/A                            rxFifo.countPacketsBefore(vn->rxIndex),
7755603SN/A                            vn->rxIndex->slack);
7768641SN/A#endif
7775603SN/A                } else if (busy) {
7785603SN/A                    DPRINTF(EthernetSM, "vnic %d unmapped (rxunique %d)\n",
7795603SN/A                            i, vn->rxUnique);
7802282SN/A                }
7812282SN/A            }
7822282SN/A        }
7832282SN/A
7842282SN/A        if (!rxBusy.empty()) {
7852282SN/A            rxActive = rxBusy.front();
7862282SN/A            rxBusy.pop_front();
7872282SN/A            vnic = &virtualRegs[rxActive];
7882282SN/A
7895603SN/A            if (vnic->rxIndex == rxFifo.end())
7902282SN/A                panic("continuing vnic without packet\n");
7912282SN/A
7922282SN/A            DPRINTF(EthernetSM,
7932282SN/A                    "continue processing for vnic %d (rxunique %d)\n",
7942282SN/A                    rxActive, vnic->rxUnique);
7952282SN/A
7961156SN/A            rxState = rxBeginCopy;
7972282SN/A
7985603SN/A            int vnic_distance = rxFifo.countPacketsBefore(vnic->rxIndex);
7995603SN/A            totalVnicDistance += vnic_distance;
8005603SN/A            numVnicDistance += 1;
8015603SN/A            if (vnic_distance > _maxVnicDistance) {
8025603SN/A                maxVnicDistance = vnic_distance;
8035603SN/A                _maxVnicDistance = vnic_distance;
8045603SN/A            }
8055603SN/A
8061156SN/A            break;
8071156SN/A        }
8081156SN/A
8092008SN/A        if (rxFifoPtr == rxFifo.end()) {
8101156SN/A            DPRINTF(EthernetSM, "receive waiting for data.  Nothing to do.\n");
8111156SN/A            goto exit;
8121156SN/A        }
8131156SN/A
8142282SN/A        if (rxList.empty())
8152282SN/A            panic("Not idle, but nothing to do!");
8162282SN/A
8172008SN/A        assert(!rxFifo.empty());
8182008SN/A
8192282SN/A        rxActive = rxList.front();
8202282SN/A        rxList.pop_front();
8212282SN/A        vnic = &virtualRegs[rxActive];
8222282SN/A
8232282SN/A        DPRINTF(EthernetSM,
8242282SN/A                "processing new packet for vnic %d (rxunique %d)\n",
8252282SN/A                rxActive, vnic->rxUnique);
8262282SN/A
8271156SN/A        // Grab a new packet from the fifo.
8285603SN/A        vnic->rxIndex = rxFifoPtr++;
8295603SN/A        vnic->rxIndex->priv = rxActive;
8302008SN/A        vnic->rxPacketOffset = 0;
8315603SN/A        vnic->rxPacketBytes = vnic->rxIndex->packet->length;
8322008SN/A        assert(vnic->rxPacketBytes);
8335603SN/A        rxMappedCount++;
8341156SN/A
8352008SN/A        vnic->rxDoneData = 0;
8361156SN/A        /* scope for variables */ {
8375603SN/A            IpPtr ip(vnic->rxIndex->packet);
8381156SN/A            if (ip) {
8392280SN/A                DPRINTF(Ethernet, "ID is %d\n", ip->id());
8402008SN/A                vnic->rxDoneData |= Regs::RxDone_IpPacket;
8411156SN/A                rxIpChecksums++;
8421156SN/A                if (cksum(ip) != 0) {
8431156SN/A                    DPRINTF(EthernetCksum, "Rx IP Checksum Error\n");
8442008SN/A                    vnic->rxDoneData |= Regs::RxDone_IpError;
8451156SN/A                }
8461156SN/A                TcpPtr tcp(ip);
8471156SN/A                UdpPtr udp(ip);
8481156SN/A                if (tcp) {
8492279SN/A                    DPRINTF(Ethernet,
8502279SN/A                            "Src Port=%d, Dest Port=%d, Seq=%d, Ack=%d\n",
8512279SN/A                            tcp->sport(), tcp->dport(), tcp->seq(),
8522279SN/A                            tcp->ack());
8532008SN/A                    vnic->rxDoneData |= Regs::RxDone_TcpPacket;
8541156SN/A                    rxTcpChecksums++;
8551156SN/A                    if (cksum(tcp) != 0) {
8561156SN/A                        DPRINTF(EthernetCksum, "Rx TCP Checksum Error\n");
8572008SN/A                        vnic->rxDoneData |= Regs::RxDone_TcpError;
8581156SN/A                    }
8591156SN/A                } else if (udp) {
8602008SN/A                    vnic->rxDoneData |= Regs::RxDone_UdpPacket;
8611156SN/A                    rxUdpChecksums++;
8621156SN/A                    if (cksum(udp) != 0) {
8631156SN/A                        DPRINTF(EthernetCksum, "Rx UDP Checksum Error\n");
8642008SN/A                        vnic->rxDoneData |= Regs::RxDone_UdpError;
8651156SN/A                    }
8661156SN/A                }
8671156SN/A            }
8681156SN/A        }
8691156SN/A        rxState = rxBeginCopy;
8701156SN/A        break;
8711156SN/A
8721156SN/A      case rxBeginCopy:
87310913SN/A        if (dmaPending() || drainState() != DrainState::Running)
8741939SN/A            goto exit;
8751939SN/A
87611202SN/A        rxDmaAddr = pciToDma(Regs::get_RxData_Addr(vnic->RxData));
8776227SN/A        rxDmaLen = min<unsigned>(Regs::get_RxData_Len(vnic->RxData),
8786227SN/A                                 vnic->rxPacketBytes);
8795603SN/A
8805603SN/A        /*
8815603SN/A         * if we're doing zero/delay copy and we're below the fifo
8825603SN/A         * threshold, see if we should try to do the zero/defer copy
8835603SN/A         */
8845603SN/A        if ((Regs::get_Config_ZeroCopy(regs.Config) ||
8855603SN/A             Regs::get_Config_DelayCopy(regs.Config)) &&
8865603SN/A            !Regs::get_RxData_NoDelay(vnic->RxData) && rxLow) {
8875603SN/A            if (rxDmaLen > regs.ZeroCopyMark)
8885603SN/A                rxDmaLen = regs.ZeroCopySize;
8895603SN/A        }
8905603SN/A        rxDmaData = vnic->rxIndex->packet->data + vnic->rxPacketOffset;
8911939SN/A        rxState = rxCopy;
8922282SN/A        if (rxDmaAddr == 1LL) {
8932282SN/A            rxState = rxCopyDone;
8942282SN/A            break;
8952282SN/A        }
8962282SN/A
8972566SN/A        dmaWrite(rxDmaAddr, rxDmaLen, &rxDmaEvent, rxDmaData);
8981156SN/A        break;
8991156SN/A
9001156SN/A      case rxCopy:
9011156SN/A        DPRINTF(EthernetSM, "receive machine still copying\n");
9021156SN/A        goto exit;
9031156SN/A
9041156SN/A      case rxCopyDone:
9052282SN/A        vnic->RxDone = vnic->rxDoneData;
9062008SN/A        vnic->RxDone |= Regs::RxDone_Complete;
9075603SN/A        rxBusyCount--;
9081156SN/A
9092008SN/A        if (vnic->rxPacketBytes == rxDmaLen) {
9105603SN/A            if (vnic->rxPacketOffset)
9115603SN/A                rxDirtyCount--;
9125603SN/A
9132282SN/A            // Packet is complete.  Indicate how many bytes were copied
9142282SN/A            vnic->RxDone = Regs::set_RxDone_CopyLen(vnic->RxDone, rxDmaLen);
9152282SN/A
9162282SN/A            DPRINTF(EthernetSM,
9172282SN/A                    "rxKick: packet complete on vnic %d (rxunique %d)\n",
9182282SN/A                    rxActive, vnic->rxUnique);
9195603SN/A            rxFifo.remove(vnic->rxIndex);
9205603SN/A            vnic->rxIndex = rxFifo.end();
9215603SN/A            rxMappedCount--;
9221156SN/A        } else {
9235603SN/A            if (!vnic->rxPacketOffset)
9245603SN/A                rxDirtyCount++;
9255603SN/A
9262008SN/A            vnic->rxPacketBytes -= rxDmaLen;
9272008SN/A            vnic->rxPacketOffset += rxDmaLen;
9282282SN/A            vnic->RxDone |= Regs::RxDone_More;
9292282SN/A            vnic->RxDone = Regs::set_RxDone_CopyLen(vnic->RxDone,
9302282SN/A                                                    vnic->rxPacketBytes);
9312010SN/A            DPRINTF(EthernetSM,
9322282SN/A                    "rxKick: packet not complete on vnic %d (rxunique %d): "
9332282SN/A                    "%d bytes left\n",
9342282SN/A                    rxActive, vnic->rxUnique, vnic->rxPacketBytes);
9351156SN/A        }
9361156SN/A
9372282SN/A        rxActive = -1;
9382282SN/A        rxState = rxBusy.empty() && rxList.empty() ? rxIdle : rxFifoBlock;
9392008SN/A
9402008SN/A        if (rxFifo.empty()) {
9412008SN/A            devIntrPost(Regs::Intr_RxEmpty);
9422008SN/A            rxEmpty = true;
9432008SN/A        }
9442008SN/A
9455603SN/A        if (rxFifo.size() < regs.RxFifoLow)
9462282SN/A            rxLow = true;
9472282SN/A
9485603SN/A        if (rxFifo.size() > regs.RxFifoHigh)
9492282SN/A            rxLow = false;
9502282SN/A
9511939SN/A        devIntrPost(Regs::Intr_RxDMA);
9521156SN/A        break;
9531156SN/A
9541156SN/A      default:
9551156SN/A        panic("Invalid rxState!");
9561156SN/A    }
9571156SN/A
9581156SN/A    DPRINTF(EthernetSM, "entering next rxState=%s\n",
9591156SN/A            RxStateStrings[rxState]);
9601156SN/A
9611156SN/A    goto next;
9621156SN/A
9631156SN/A  exit:
9641156SN/A    /**
9651156SN/A     * @todo do we want to schedule a future kick?
9661156SN/A     */
9671156SN/A    DPRINTF(EthernetSM, "rx state machine exited rxState=%s\n",
9681156SN/A            RxStateStrings[rxState]);
9691156SN/A}
9701156SN/A
9711156SN/Avoid
9722566SN/ADevice::txDmaDone()
9731156SN/A{
9741156SN/A    assert(txState == txCopy);
9751156SN/A    txState = txCopyDone;
9761156SN/A    DPRINTF(EthernetDMA, "tx dma read paddr=%#x len=%d\n",
9771156SN/A            txDmaAddr, txDmaLen);
9781939SN/A    DDUMP(EthernetData, txDmaData, txDmaLen);
9791939SN/A
9801939SN/A    // If the receive state machine  has a pending DMA, let it go first
9811939SN/A    if (rxState == rxBeginCopy)
9821939SN/A        rxKick();
9831939SN/A
9841156SN/A    txKick();
9851156SN/A}
9861156SN/A
9871156SN/Avoid
9881156SN/ADevice::transmit()
9891156SN/A{
9901156SN/A    if (txFifo.empty()) {
9911156SN/A        DPRINTF(Ethernet, "nothing to transmit\n");
9921156SN/A        return;
9931156SN/A    }
9941156SN/A
9951939SN/A    uint32_t interrupts;
9962566SN/A    EthPacketPtr packet = txFifo.front();
9971156SN/A    if (!interface->sendPacket(packet)) {
9981156SN/A        DPRINTF(Ethernet, "Packet Transmit: failed txFifo available %d\n",
9991156SN/A                txFifo.avail());
10005603SN/A        return;
10011156SN/A    }
10021156SN/A
10031156SN/A    txFifo.pop();
10041156SN/A#if TRACING_ON
10051156SN/A    if (DTRACE(Ethernet)) {
10061156SN/A        IpPtr ip(packet);
10071156SN/A        if (ip) {
10081156SN/A            DPRINTF(Ethernet, "ID is %d\n", ip->id());
10091156SN/A            TcpPtr tcp(ip);
10101156SN/A            if (tcp) {
10112280SN/A                DPRINTF(Ethernet,
10122280SN/A                        "Src Port=%d, Dest Port=%d, Seq=%d, Ack=%d\n",
10132280SN/A                        tcp->sport(), tcp->dport(), tcp->seq(),
10142280SN/A                        tcp->ack());
10151156SN/A            }
10161156SN/A        }
10171156SN/A    }
10181156SN/A#endif
10191156SN/A
10201939SN/A    DDUMP(EthernetData, packet->data, packet->length);
10211156SN/A    txBytes += packet->length;
10221156SN/A    txPackets++;
10231156SN/A
10241156SN/A    DPRINTF(Ethernet, "Packet Transmit: successful txFifo Available %d\n",
10251156SN/A            txFifo.avail());
10261156SN/A
10271939SN/A    interrupts = Regs::Intr_TxPacket;
10285603SN/A    if (txFifo.size() < regs.TxFifoLow)
10291939SN/A        interrupts |= Regs::Intr_TxLow;
10301939SN/A    devIntrPost(interrupts);
10311156SN/A}
10321156SN/A
10331156SN/Avoid
10341156SN/ADevice::txKick()
10351156SN/A{
10362008SN/A    VirtualReg *vnic;
10372279SN/A    DPRINTF(EthernetSM, "txKick: txState=%s (txFifo.size=%d)\n",
10381156SN/A            TxStateStrings[txState], txFifo.size());
10391156SN/A
10407823SN/A    if (txKickTick > curTick()) {
10412279SN/A        DPRINTF(EthernetSM, "txKick: exiting, can't run till %d\n",
10421156SN/A                txKickTick);
10431156SN/A        return;
10441156SN/A    }
10451156SN/A
10461156SN/A  next:
10472008SN/A    if (txState == txIdle)
10481156SN/A        goto exit;
10491156SN/A
10502008SN/A    assert(!txList.empty());
10512008SN/A    vnic = &virtualRegs[txList.front()];
10522008SN/A
10532008SN/A    switch (txState) {
10541156SN/A      case txFifoBlock:
10552280SN/A        assert(Regs::get_TxDone_Busy(vnic->TxDone));
10561156SN/A        if (!txPacket) {
10571156SN/A            // Grab a new packet from the fifo.
105810469SN/A            txPacket = make_shared<EthPacketData>(16384);
10592008SN/A            txPacketOffset = 0;
10601156SN/A        }
10611156SN/A
10621156SN/A        if (txFifo.avail() - txPacket->length <
10632008SN/A            Regs::get_TxData_Len(vnic->TxData)) {
10641156SN/A            DPRINTF(EthernetSM, "transmit fifo full.  Nothing to do.\n");
10651156SN/A            goto exit;
10661156SN/A        }
10671156SN/A
10681156SN/A        txState = txBeginCopy;
10691156SN/A        break;
10701156SN/A
10711156SN/A      case txBeginCopy:
107210913SN/A        if (dmaPending() || drainState() != DrainState::Running)
10731939SN/A            goto exit;
10741939SN/A
107511202SN/A        txDmaAddr = pciToDma(Regs::get_TxData_Addr(vnic->TxData));
10762008SN/A        txDmaLen = Regs::get_TxData_Len(vnic->TxData);
10772008SN/A        txDmaData = txPacket->data + txPacketOffset;
10781939SN/A        txState = txCopy;
10791156SN/A
10802566SN/A        dmaRead(txDmaAddr, txDmaLen, &txDmaEvent, txDmaData);
10811156SN/A        break;
10821156SN/A
10831156SN/A      case txCopy:
10841156SN/A        DPRINTF(EthernetSM, "transmit machine still copying\n");
10851156SN/A        goto exit;
10861156SN/A
10871156SN/A      case txCopyDone:
10882008SN/A        vnic->TxDone = txDmaLen | Regs::TxDone_Complete;
10891156SN/A        txPacket->length += txDmaLen;
10902008SN/A        if ((vnic->TxData & Regs::TxData_More)) {
10912008SN/A            txPacketOffset += txDmaLen;
10922008SN/A            txState = txIdle;
10932008SN/A            devIntrPost(Regs::Intr_TxDMA);
10942008SN/A            break;
10951156SN/A        }
10961156SN/A
10972008SN/A        assert(txPacket->length <= txFifo.avail());
10982008SN/A        if ((vnic->TxData & Regs::TxData_Checksum)) {
10992008SN/A            IpPtr ip(txPacket);
11002008SN/A            if (ip) {
11012008SN/A                TcpPtr tcp(ip);
11022008SN/A                if (tcp) {
11032008SN/A                    tcp->sum(0);
11042008SN/A                    tcp->sum(cksum(tcp));
11052008SN/A                    txTcpChecksums++;
11062008SN/A                }
11072008SN/A
11082008SN/A                UdpPtr udp(ip);
11092008SN/A                if (udp) {
11102008SN/A                    udp->sum(0);
11112008SN/A                    udp->sum(cksum(udp));
11122008SN/A                    txUdpChecksums++;
11132008SN/A                }
11142008SN/A
11152008SN/A                ip->sum(0);
11162008SN/A                ip->sum(cksum(ip));
11172008SN/A                txIpChecksums++;
11182008SN/A            }
11192008SN/A        }
11202008SN/A
11212008SN/A        txFifo.push(txPacket);
11222008SN/A        if (txFifo.avail() < regs.TxMaxCopy) {
11232008SN/A            devIntrPost(Regs::Intr_TxFull);
11242008SN/A            txFull = true;
11252008SN/A        }
11262008SN/A        txPacket = 0;
11272008SN/A        transmit();
11282008SN/A        txList.pop_front();
11292008SN/A        txState = txList.empty() ? txIdle : txFifoBlock;
11301939SN/A        devIntrPost(Regs::Intr_TxDMA);
11311156SN/A        break;
11321156SN/A
11331156SN/A      default:
11341156SN/A        panic("Invalid txState!");
11351156SN/A    }
11361156SN/A
11371156SN/A    DPRINTF(EthernetSM, "entering next txState=%s\n",
11381156SN/A            TxStateStrings[txState]);
11391156SN/A
11401156SN/A    goto next;
11411156SN/A
11421156SN/A  exit:
11431156SN/A    /**
11441156SN/A     * @todo do we want to schedule a future kick?
11451156SN/A     */
11461156SN/A    DPRINTF(EthernetSM, "tx state machine exited txState=%s\n",
11471156SN/A            TxStateStrings[txState]);
11481156SN/A}
11491156SN/A
11501156SN/Avoid
11511156SN/ADevice::transferDone()
11521156SN/A{
11531156SN/A    if (txFifo.empty()) {
11541156SN/A        DPRINTF(Ethernet, "transfer complete: txFifo empty...nothing to do\n");
11551156SN/A        return;
11561156SN/A    }
11571156SN/A
11581156SN/A    DPRINTF(Ethernet, "transfer complete: data in txFifo...schedule xmit\n");
11591156SN/A
11609417SN/A    reschedule(txEvent, clockEdge(Cycles(1)), true);
11611156SN/A}
11621156SN/A
11631156SN/Abool
11642566SN/ADevice::rxFilter(const EthPacketPtr &packet)
11651156SN/A{
11661156SN/A    if (!Regs::get_Config_Filter(regs.Config))
11671156SN/A        return false;
11681156SN/A
11691156SN/A    panic("receive filter not implemented\n");
11701156SN/A    bool drop = true;
11711156SN/A
11721156SN/A#if 0
11731156SN/A    string type;
11741156SN/A
11751156SN/A    EthHdr *eth = packet->eth();
11761156SN/A    if (eth->unicast()) {
11771156SN/A        // If we're accepting all unicast addresses
11781156SN/A        if (acceptUnicast)
11791156SN/A            drop = false;
11801156SN/A
11811156SN/A        // If we make a perfect match
11821156SN/A        if (acceptPerfect && params->eaddr == eth.dst())
11831156SN/A            drop = false;
11841156SN/A
11851156SN/A        if (acceptArp && eth->type() == ETH_TYPE_ARP)
11861156SN/A            drop = false;
11871156SN/A
11881156SN/A    } else if (eth->broadcast()) {
11891156SN/A        // if we're accepting broadcasts
11901156SN/A        if (acceptBroadcast)
11911156SN/A            drop = false;
11921156SN/A
11931156SN/A    } else if (eth->multicast()) {
11941156SN/A        // if we're accepting all multicasts
11951156SN/A        if (acceptMulticast)
11961156SN/A            drop = false;
11971156SN/A
11981156SN/A    }
11991156SN/A
12001156SN/A    if (drop) {
12011156SN/A        DPRINTF(Ethernet, "rxFilter drop\n");
12021156SN/A        DDUMP(EthernetData, packet->data, packet->length);
12031156SN/A    }
12041156SN/A#endif
12051156SN/A    return drop;
12061156SN/A}
12071156SN/A
12081156SN/Abool
12092566SN/ADevice::recvPacket(EthPacketPtr packet)
12101156SN/A{
12111156SN/A    rxBytes += packet->length;
12121156SN/A    rxPackets++;
12131156SN/A
12141156SN/A    DPRINTF(Ethernet, "Receiving packet from wire, rxFifo Available is %d\n",
12151156SN/A            rxFifo.avail());
12161156SN/A
12171156SN/A    if (!rxEnable) {
12181156SN/A        DPRINTF(Ethernet, "receive disabled...packet dropped\n");
12191156SN/A        return true;
12201156SN/A    }
12211156SN/A
12221156SN/A    if (rxFilter(packet)) {
12231156SN/A        DPRINTF(Ethernet, "packet filtered...dropped\n");
12241156SN/A        return true;
12251156SN/A    }
12261156SN/A
12275603SN/A    if (rxFifo.size() >= regs.RxFifoHigh)
12281939SN/A        devIntrPost(Regs::Intr_RxHigh);
12291156SN/A
12301156SN/A    if (!rxFifo.push(packet)) {
12311156SN/A        DPRINTF(Ethernet,
12321156SN/A                "packet will not fit in receive buffer...packet dropped\n");
12331156SN/A        return false;
12341156SN/A    }
12351156SN/A
12362008SN/A    // If we were at the last element, back up one ot go to the new
12372008SN/A    // last element of the list.
12382008SN/A    if (rxFifoPtr == rxFifo.end())
12392008SN/A        --rxFifoPtr;
12402008SN/A
12411939SN/A    devIntrPost(Regs::Intr_RxPacket);
12421156SN/A    rxKick();
12431156SN/A    return true;
12441156SN/A}
12451156SN/A
12462901SN/Avoid
12479342SN/ADevice::drainResume()
12482901SN/A{
12499342SN/A    Drainable::drainResume();
12502901SN/A
12512901SN/A    // During drain we could have left the state machines in a waiting state and
12522901SN/A    // they wouldn't get out until some other event occured to kick them.
12532901SN/A    // This way they'll get out immediately
12542901SN/A    txKick();
12552901SN/A    rxKick();
12562901SN/A}
12572901SN/A
12581156SN/A//=====================================================================
12591156SN/A//
12601156SN/A//
12611156SN/Avoid
126210905SN/ABase::serialize(CheckpointOut &cp) const
12631156SN/A{
12649807SN/A    // Serialize the PciDevice base class
126510905SN/A    PciDevice::serialize(cp);
12661156SN/A
12671156SN/A    SERIALIZE_SCALAR(rxEnable);
12681156SN/A    SERIALIZE_SCALAR(txEnable);
12691156SN/A    SERIALIZE_SCALAR(cpuIntrEnable);
12701156SN/A
12711156SN/A    /*
12721156SN/A     * Keep track of pending interrupt status.
12731156SN/A     */
12741156SN/A    SERIALIZE_SCALAR(intrTick);
12751156SN/A    SERIALIZE_SCALAR(cpuPendingIntr);
12761156SN/A    Tick intrEventTick = 0;
12771156SN/A    if (intrEvent)
12781156SN/A        intrEventTick = intrEvent->when();
12791156SN/A    SERIALIZE_SCALAR(intrEventTick);
12801156SN/A}
12811156SN/A
12821156SN/Avoid
128310905SN/ABase::unserialize(CheckpointIn &cp)
12841156SN/A{
12859807SN/A    // Unserialize the PciDevice base class
128610905SN/A    PciDevice::unserialize(cp);
12871156SN/A
12881156SN/A    UNSERIALIZE_SCALAR(rxEnable);
12891156SN/A    UNSERIALIZE_SCALAR(txEnable);
12901156SN/A    UNSERIALIZE_SCALAR(cpuIntrEnable);
12911156SN/A
12921156SN/A    /*
12931156SN/A     * Keep track of pending interrupt status.
12941156SN/A     */
12951156SN/A    UNSERIALIZE_SCALAR(intrTick);
12961156SN/A    UNSERIALIZE_SCALAR(cpuPendingIntr);
12971156SN/A    Tick intrEventTick;
12981156SN/A    UNSERIALIZE_SCALAR(intrEventTick);
12991156SN/A    if (intrEventTick) {
13005606SN/A        intrEvent = new IntrEvent(this, true);
13015606SN/A        schedule(intrEvent, intrEventTick);
13021156SN/A    }
13031156SN/A}
13041156SN/A
13051156SN/Avoid
130611006SN/ADevice::serialize(CheckpointOut &cp) const
13071156SN/A{
13082287SN/A    int count;
13092287SN/A
13109807SN/A    // Serialize the PciDevice base class
131110905SN/A    Base::serialize(cp);
13121156SN/A
13131939SN/A    if (rxState == rxCopy)
13141939SN/A        panic("can't serialize with an in flight dma request rxState=%s",
13151939SN/A              RxStateStrings[rxState]);
13161156SN/A
13171939SN/A    if (txState == txCopy)
13181939SN/A        panic("can't serialize with an in flight dma request txState=%s",
13191939SN/A              TxStateStrings[txState]);
13201156SN/A
13211156SN/A    /*
13225603SN/A     * Serialize the device registers that could be modified by the OS.
13231156SN/A     */
13241156SN/A    SERIALIZE_SCALAR(regs.Config);
13251939SN/A    SERIALIZE_SCALAR(regs.IntrStatus);
13261939SN/A    SERIALIZE_SCALAR(regs.IntrMask);
13271156SN/A    SERIALIZE_SCALAR(regs.RxData);
13281156SN/A    SERIALIZE_SCALAR(regs.TxData);
13291156SN/A
13301156SN/A    /*
13312008SN/A     * Serialize the virtual nic state
13322008SN/A     */
13332008SN/A    int virtualRegsSize = virtualRegs.size();
13342008SN/A    SERIALIZE_SCALAR(virtualRegsSize);
13352008SN/A    for (int i = 0; i < virtualRegsSize; ++i) {
133610905SN/A        const VirtualReg *vnic = &virtualRegs[i];
13372008SN/A
13382566SN/A        std::string reg = csprintf("vnic%d", i);
133910905SN/A        paramOut(cp, reg + ".RxData", vnic->RxData);
134010905SN/A        paramOut(cp, reg + ".RxDone", vnic->RxDone);
134110905SN/A        paramOut(cp, reg + ".TxData", vnic->TxData);
134210905SN/A        paramOut(cp, reg + ".TxDone", vnic->TxDone);
13432008SN/A
13445603SN/A        bool rxPacketExists = vnic->rxIndex != rxFifo.end();
134510905SN/A        paramOut(cp, reg + ".rxPacketExists", rxPacketExists);
13462008SN/A        if (rxPacketExists) {
13472008SN/A            int rxPacket = 0;
134811006SN/A            auto i = rxFifo.begin();
13495603SN/A            while (i != vnic->rxIndex) {
13502008SN/A                assert(i != rxFifo.end());
13512008SN/A                ++i;
13522008SN/A                ++rxPacket;
13532008SN/A            }
13542008SN/A
135510905SN/A            paramOut(cp, reg + ".rxPacket", rxPacket);
135610905SN/A            paramOut(cp, reg + ".rxPacketOffset", vnic->rxPacketOffset);
135710905SN/A            paramOut(cp, reg + ".rxPacketBytes", vnic->rxPacketBytes);
13582008SN/A        }
135910905SN/A        paramOut(cp, reg + ".rxDoneData", vnic->rxDoneData);
13602008SN/A    }
13612008SN/A
13625603SN/A    int rxFifoPtr = -1;
13635603SN/A    if (this->rxFifoPtr != rxFifo.end())
13645603SN/A        rxFifoPtr = rxFifo.countPacketsBefore(this->rxFifoPtr);
13652282SN/A    SERIALIZE_SCALAR(rxFifoPtr);
13662282SN/A
13672282SN/A    SERIALIZE_SCALAR(rxActive);
13685603SN/A    SERIALIZE_SCALAR(rxBusyCount);
13695603SN/A    SERIALIZE_SCALAR(rxDirtyCount);
13705603SN/A    SERIALIZE_SCALAR(rxMappedCount);
13712282SN/A
137211006SN/A    VirtualList::const_iterator i, end;
13732008SN/A    for (count = 0, i = rxList.begin(), end = rxList.end(); i != end; ++i)
137410905SN/A        paramOut(cp, csprintf("rxList%d", count++), *i);
13752282SN/A    int rxListSize = count;
13762282SN/A    SERIALIZE_SCALAR(rxListSize);
13772008SN/A
13782282SN/A    for (count = 0, i = rxBusy.begin(), end = rxBusy.end(); i != end; ++i)
137910905SN/A        paramOut(cp, csprintf("rxBusy%d", count++), *i);
13802282SN/A    int rxBusySize = count;
13812282SN/A    SERIALIZE_SCALAR(rxBusySize);
13822282SN/A
13832008SN/A    for (count = 0, i = txList.begin(), end = txList.end(); i != end; ++i)
138410905SN/A        paramOut(cp, csprintf("txList%d", count++), *i);
13852282SN/A    int txListSize = count;
13862282SN/A    SERIALIZE_SCALAR(txListSize);
13872008SN/A
13882008SN/A    /*
13891156SN/A     * Serialize rx state machine
13901156SN/A     */
13911156SN/A    int rxState = this->rxState;
13921156SN/A    SERIALIZE_SCALAR(rxState);
13931939SN/A    SERIALIZE_SCALAR(rxEmpty);
13942282SN/A    SERIALIZE_SCALAR(rxLow);
139510905SN/A    rxFifo.serialize("rxFifo", cp);
13961156SN/A
13971156SN/A    /*
13981156SN/A     * Serialize tx state machine
13991156SN/A     */
14001156SN/A    int txState = this->txState;
14011156SN/A    SERIALIZE_SCALAR(txState);
14021939SN/A    SERIALIZE_SCALAR(txFull);
140310905SN/A    txFifo.serialize("txFifo", cp);
140410469SN/A    bool txPacketExists = txPacket != nullptr;
14051156SN/A    SERIALIZE_SCALAR(txPacketExists);
14061156SN/A    if (txPacketExists) {
140710905SN/A        txPacket->serialize("txPacket", cp);
14082008SN/A        SERIALIZE_SCALAR(txPacketOffset);
14092008SN/A        SERIALIZE_SCALAR(txPacketBytes);
14101156SN/A    }
14111156SN/A
14121156SN/A    /*
14131156SN/A     * If there's a pending transmit, store the time so we can
14141156SN/A     * reschedule it later
14151156SN/A     */
14167823SN/A    Tick transmitTick = txEvent.scheduled() ? txEvent.when() - curTick() : 0;
14171156SN/A    SERIALIZE_SCALAR(transmitTick);
14181156SN/A}
14191156SN/A
14201156SN/Avoid
142110905SN/ADevice::unserialize(CheckpointIn &cp)
14221156SN/A{
14239807SN/A    // Unserialize the PciDevice base class
142410905SN/A    Base::unserialize(cp);
14251156SN/A
14261156SN/A    /*
14275603SN/A     * Unserialize the device registers that may have been written by the OS.
14281156SN/A     */
14291156SN/A    UNSERIALIZE_SCALAR(regs.Config);
14301939SN/A    UNSERIALIZE_SCALAR(regs.IntrStatus);
14311939SN/A    UNSERIALIZE_SCALAR(regs.IntrMask);
14321156SN/A    UNSERIALIZE_SCALAR(regs.RxData);
14331156SN/A    UNSERIALIZE_SCALAR(regs.TxData);
14341156SN/A
14352282SN/A    UNSERIALIZE_SCALAR(rxActive);
14365603SN/A    UNSERIALIZE_SCALAR(rxBusyCount);
14375603SN/A    UNSERIALIZE_SCALAR(rxDirtyCount);
14385603SN/A    UNSERIALIZE_SCALAR(rxMappedCount);
14392282SN/A
14402008SN/A    int rxListSize;
14412008SN/A    UNSERIALIZE_SCALAR(rxListSize);
14422008SN/A    rxList.clear();
14432008SN/A    for (int i = 0; i < rxListSize; ++i) {
14442008SN/A        int value;
144510905SN/A        paramIn(cp, csprintf("rxList%d", i), value);
14462008SN/A        rxList.push_back(value);
14472008SN/A    }
14482008SN/A
14492282SN/A    int rxBusySize;
14502282SN/A    UNSERIALIZE_SCALAR(rxBusySize);
14512282SN/A    rxBusy.clear();
14522282SN/A    for (int i = 0; i < rxBusySize; ++i) {
14532282SN/A        int value;
145410905SN/A        paramIn(cp, csprintf("rxBusy%d", i), value);
14552282SN/A        rxBusy.push_back(value);
14562282SN/A    }
14572282SN/A
14582008SN/A    int txListSize;
14592008SN/A    UNSERIALIZE_SCALAR(txListSize);
14602008SN/A    txList.clear();
14612008SN/A    for (int i = 0; i < txListSize; ++i) {
14622008SN/A        int value;
146310905SN/A        paramIn(cp, csprintf("txList%d", i), value);
14642008SN/A        txList.push_back(value);
14652008SN/A    }
14662008SN/A
14671156SN/A    /*
14681156SN/A     * Unserialize rx state machine
14691156SN/A     */
14701156SN/A    int rxState;
14711156SN/A    UNSERIALIZE_SCALAR(rxState);
14721939SN/A    UNSERIALIZE_SCALAR(rxEmpty);
14732282SN/A    UNSERIALIZE_SCALAR(rxLow);
14741156SN/A    this->rxState = (RxState) rxState;
147510905SN/A    rxFifo.unserialize("rxFifo", cp);
14761156SN/A
14772282SN/A    int rxFifoPtr;
14782282SN/A    UNSERIALIZE_SCALAR(rxFifoPtr);
14795603SN/A    if (rxFifoPtr >= 0) {
14805603SN/A        this->rxFifoPtr = rxFifo.begin();
14815603SN/A        for (int i = 0; i < rxFifoPtr; ++i)
14825603SN/A            ++this->rxFifoPtr;
14835603SN/A    } else {
14845603SN/A        this->rxFifoPtr = rxFifo.end();
14855603SN/A    }
14862282SN/A
14871156SN/A    /*
14881156SN/A     * Unserialize tx state machine
14891156SN/A     */
14901156SN/A    int txState;
14911156SN/A    UNSERIALIZE_SCALAR(txState);
14921939SN/A    UNSERIALIZE_SCALAR(txFull);
14931156SN/A    this->txState = (TxState) txState;
149410905SN/A    txFifo.unserialize("txFifo", cp);
14951156SN/A    bool txPacketExists;
14961156SN/A    UNSERIALIZE_SCALAR(txPacketExists);
14971156SN/A    txPacket = 0;
14981156SN/A    if (txPacketExists) {
149910469SN/A        txPacket = make_shared<EthPacketData>(16384);
150010905SN/A        txPacket->unserialize("txPacket", cp);
15012008SN/A        UNSERIALIZE_SCALAR(txPacketOffset);
15022008SN/A        UNSERIALIZE_SCALAR(txPacketBytes);
15032008SN/A    }
15042008SN/A
15052008SN/A    /*
15062008SN/A     * unserialize the virtual nic registers/state
15072008SN/A     *
15082008SN/A     * this must be done after the unserialization of the rxFifo
15092008SN/A     * because the packet iterators depend on the fifo being populated
15102008SN/A     */
15112008SN/A    int virtualRegsSize;
15122008SN/A    UNSERIALIZE_SCALAR(virtualRegsSize);
15132008SN/A    virtualRegs.clear();
15142008SN/A    virtualRegs.resize(virtualRegsSize);
15152008SN/A    for (int i = 0; i < virtualRegsSize; ++i) {
15162008SN/A        VirtualReg *vnic = &virtualRegs[i];
15172566SN/A        std::string reg = csprintf("vnic%d", i);
15182008SN/A
151910905SN/A        paramIn(cp, reg + ".RxData", vnic->RxData);
152010905SN/A        paramIn(cp, reg + ".RxDone", vnic->RxDone);
152110905SN/A        paramIn(cp, reg + ".TxData", vnic->TxData);
152210905SN/A        paramIn(cp, reg + ".TxDone", vnic->TxDone);
15232008SN/A
15242282SN/A        vnic->rxUnique = rxUnique++;
15252282SN/A        vnic->txUnique = txUnique++;
15262282SN/A
15272008SN/A        bool rxPacketExists;
152810905SN/A        paramIn(cp, reg + ".rxPacketExists", rxPacketExists);
15292008SN/A        if (rxPacketExists) {
15302008SN/A            int rxPacket;
153110905SN/A            paramIn(cp, reg + ".rxPacket", rxPacket);
15325603SN/A            vnic->rxIndex = rxFifo.begin();
15332008SN/A            while (rxPacket--)
15345603SN/A                ++vnic->rxIndex;
15352008SN/A
153610905SN/A            paramIn(cp, reg + ".rxPacketOffset",
15372008SN/A                    vnic->rxPacketOffset);
153810905SN/A            paramIn(cp, reg + ".rxPacketBytes", vnic->rxPacketBytes);
15392008SN/A        } else {
15405603SN/A            vnic->rxIndex = rxFifo.end();
15412008SN/A        }
154210905SN/A        paramIn(cp, reg + ".rxDoneData", vnic->rxDoneData);
15431156SN/A    }
15441156SN/A
15451156SN/A    /*
15461156SN/A     * If there's a pending transmit, reschedule it now
15471156SN/A     */
15481156SN/A    Tick transmitTick;
15491156SN/A    UNSERIALIZE_SCALAR(transmitTick);
15501156SN/A    if (transmitTick)
15517823SN/A        schedule(txEvent, curTick() + transmitTick);
15521156SN/A
15538851SN/A    pioPort.sendRangeChange();
15542566SN/A
15551156SN/A}
15561156SN/A
15577811SN/A} // namespace Sinic
15581156SN/A
15594762SN/ASinic::Device *
15604762SN/ASinicParams::create()
15611156SN/A{
15624762SN/A    return new Sinic::Device(this);
15631156SN/A}
1564