sinic.cc revision 6658
12292SN/A/*
22292SN/A * Copyright (c) 2004-2005 The Regents of The University of Michigan
32292SN/A * All rights reserved.
42292SN/A *
52292SN/A * Redistribution and use in source and binary forms, with or without
62292SN/A * modification, are permitted provided that the following conditions are
72292SN/A * met: redistributions of source code must retain the above copyright
82292SN/A * notice, this list of conditions and the following disclaimer;
92292SN/A * redistributions in binary form must reproduce the above copyright
102292SN/A * notice, this list of conditions and the following disclaimer in the
112292SN/A * documentation and/or other materials provided with the distribution;
122292SN/A * neither the name of the copyright holders nor the names of its
132292SN/A * contributors may be used to endorse or promote products derived from
142292SN/A * this software without specific prior written permission.
152292SN/A *
162292SN/A * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
172292SN/A * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
182292SN/A * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
192292SN/A * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
202292SN/A * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
212292SN/A * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
222292SN/A * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
232292SN/A * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
242292SN/A * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
252292SN/A * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
262292SN/A * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
272689Sktlim@umich.edu *
282689Sktlim@umich.edu * Authors: Nathan Binkert
292689Sktlim@umich.edu */
302292SN/A
312292SN/A#include <deque>
323326Sktlim@umich.edu#include <limits>
332733Sktlim@umich.edu#include <string>
342733Sktlim@umich.edu
352907Sktlim@umich.edu#include "arch/vtophys.hh"
362292SN/A#include "base/debug.hh"
372292SN/A#include "base/inet.hh"
382722Sktlim@umich.edu#include "base/types.hh"
392669Sktlim@umich.edu#include "config/the_isa.hh"
402292SN/A#include "cpu/intr_control.hh"
412790Sktlim@umich.edu#include "cpu/thread_context.hh"
422790Sktlim@umich.edu#include "dev/etherlink.hh"
432790Sktlim@umich.edu#include "dev/sinic.hh"
442790Sktlim@umich.edu#include "mem/packet.hh"
452669Sktlim@umich.edu#include "mem/packet_access.hh"
462678Sktlim@umich.edu#include "sim/eventq.hh"
472678Sktlim@umich.edu#include "sim/stats.hh"
482678Sktlim@umich.edu
492292SN/Ausing namespace std;
502678Sktlim@umich.eduusing namespace Net;
512292SN/Ausing namespace TheISA;
522292SN/A
532669Sktlim@umich.edunamespace Sinic {
542292SN/A
552678Sktlim@umich.educonst char *RxStateStrings[] =
562292SN/A{
572678Sktlim@umich.edu    "rxIdle",
582678Sktlim@umich.edu    "rxFifoBlock",
592678Sktlim@umich.edu    "rxBeginCopy",
604319Sktlim@umich.edu    "rxCopy",
614319Sktlim@umich.edu    "rxCopyDone"
624319Sktlim@umich.edu};
634319Sktlim@umich.edu
644319Sktlim@umich.educonst char *TxStateStrings[] =
652678Sktlim@umich.edu{
662678Sktlim@umich.edu    "txIdle",
672292SN/A    "txFifoBlock",
682678Sktlim@umich.edu    "txBeginCopy",
692678Sktlim@umich.edu    "txCopy",
702678Sktlim@umich.edu    "txCopyDone"
712678Sktlim@umich.edu};
724873Sstever@eecs.umich.edu
732678Sktlim@umich.edu
742292SN/A///////////////////////////////////////////////////////////////////////
752678Sktlim@umich.edu//
762678Sktlim@umich.edu// Sinic PCI Device
772678Sktlim@umich.edu//
782678Sktlim@umich.eduBase::Base(const Params *p)
792678Sktlim@umich.edu    : PciDev(p), rxEnable(false), txEnable(false), clock(p->clock),
802678Sktlim@umich.edu      intrDelay(p->intr_delay), intrTick(0), cpuIntrEnable(false),
812678Sktlim@umich.edu      cpuPendingIntr(false), intrEvent(0), interface(NULL)
822698Sktlim@umich.edu{
832344SN/A}
842678Sktlim@umich.edu
852678Sktlim@umich.eduDevice::Device(const Params *p)
862678Sktlim@umich.edu    : Base(p), rxUnique(0), txUnique(0),
872820Sktlim@umich.edu      virtualRegs(p->virtual_count < 1 ? 1 : p->virtual_count),
882678Sktlim@umich.edu      rxFifo(p->rx_fifo_size), txFifo(p->tx_fifo_size),
892678Sktlim@umich.edu      rxKickTick(0), txKickTick(0),
902678Sktlim@umich.edu      txEvent(this), rxDmaEvent(this), txDmaEvent(this),
912678Sktlim@umich.edu      dmaReadDelay(p->dma_read_delay), dmaReadFactor(p->dma_read_factor),
922678Sktlim@umich.edu      dmaWriteDelay(p->dma_write_delay), dmaWriteFactor(p->dma_write_factor)
932678Sktlim@umich.edu{
942678Sktlim@umich.edu    interface = new Interface(name() + ".int0", this);
952678Sktlim@umich.edu    reset();
962344SN/A
972307SN/A}
982678Sktlim@umich.edu
994032Sktlim@umich.eduDevice::~Device()
1002678Sktlim@umich.edu{}
1012292SN/A
1022292SN/Avoid
1032292SN/ADevice::regStats()
1042292SN/A{
1052678Sktlim@umich.edu    rxBytes
1062678Sktlim@umich.edu        .name(name() + ".rxBytes")
1072292SN/A        .desc("Bytes Received")
1082292SN/A        .prereq(rxBytes)
1092292SN/A        ;
1102292SN/A
1112292SN/A    rxBandwidth
1122292SN/A        .name(name() + ".rxBandwidth")
1134329Sktlim@umich.edu        .desc("Receive Bandwidth (bits/s)")
1144329Sktlim@umich.edu        .precision(0)
1152292SN/A        .prereq(rxBytes)
1164329Sktlim@umich.edu        ;
1174329Sktlim@umich.edu
1184329Sktlim@umich.edu    rxPackets
1194329Sktlim@umich.edu        .name(name() + ".rxPackets")
1202292SN/A        .desc("Number of Packets Received")
1212307SN/A        .prereq(rxBytes)
1222307SN/A        ;
1232907Sktlim@umich.edu
1242907Sktlim@umich.edu    rxPacketRate
1252292SN/A        .name(name() + ".rxPPS")
1262292SN/A        .desc("Packet Reception Rate (packets/s)")
1272329SN/A        .precision(0)
1282329SN/A        .prereq(rxBytes)
1292329SN/A        ;
1302292SN/A
1312292SN/A    rxIpPackets
1322292SN/A        .name(name() + ".rxIpPackets")
1332292SN/A        .desc("Number of IP Packets Received")
1342292SN/A        .prereq(rxBytes)
1352292SN/A        ;
1362292SN/A
1372292SN/A    rxTcpPackets
1382292SN/A        .name(name() + ".rxTcpPackets")
1392292SN/A        .desc("Number of Packets Received")
1402292SN/A        .prereq(rxBytes)
1413492Sktlim@umich.edu        ;
1422329SN/A
1432292SN/A    rxUdpPackets
1442292SN/A        .name(name() + ".rxUdpPackets")
1452292SN/A        .desc("Number of UDP Packets Received")
1462292SN/A        .prereq(rxBytes)
1472292SN/A        ;
1482292SN/A
1492292SN/A    rxIpChecksums
1502292SN/A        .name(name() + ".rxIpChecksums")
1512292SN/A        .desc("Number of rx IP Checksums done by device")
1522292SN/A        .precision(0)
1532292SN/A        .prereq(rxBytes)
1542292SN/A        ;
1552292SN/A
1562292SN/A    rxTcpChecksums
1572292SN/A        .name(name() + ".rxTcpChecksums")
1582292SN/A        .desc("Number of rx TCP Checksums done by device")
1592292SN/A        .precision(0)
1602727Sktlim@umich.edu        .prereq(rxBytes)
1612727Sktlim@umich.edu        ;
1622727Sktlim@umich.edu
1632727Sktlim@umich.edu    rxUdpChecksums
1642727Sktlim@umich.edu        .name(name() + ".rxUdpChecksums")
1652727Sktlim@umich.edu        .desc("Number of rx UDP Checksums done by device")
1662727Sktlim@umich.edu        .precision(0)
1672727Sktlim@umich.edu        .prereq(rxBytes)
1682727Sktlim@umich.edu        ;
1692727Sktlim@umich.edu
1702727Sktlim@umich.edu    totBandwidth
1712727Sktlim@umich.edu        .name(name() + ".totBandwidth")
1722727Sktlim@umich.edu        .desc("Total Bandwidth (bits/s)")
1732727Sktlim@umich.edu        .precision(0)
1742727Sktlim@umich.edu        .prereq(totBytes)
1752727Sktlim@umich.edu        ;
1762727Sktlim@umich.edu
1772727Sktlim@umich.edu    totPackets
1782361SN/A        .name(name() + ".totPackets")
1792361SN/A        .desc("Total Packets")
1802361SN/A        .precision(0)
1812361SN/A        .prereq(totBytes)
1822727Sktlim@umich.edu        ;
1832727Sktlim@umich.edu
1842727Sktlim@umich.edu    totBytes
1852727Sktlim@umich.edu        .name(name() + ".totBytes")
1862727Sktlim@umich.edu        .desc("Total Bytes")
1872727Sktlim@umich.edu        .precision(0)
1882727Sktlim@umich.edu        .prereq(totBytes)
1892727Sktlim@umich.edu        ;
1902727Sktlim@umich.edu
1912727Sktlim@umich.edu    totPacketRate
1922727Sktlim@umich.edu        .name(name() + ".totPPS")
1932727Sktlim@umich.edu        .desc("Total Tranmission Rate (packets/s)")
1942727Sktlim@umich.edu        .precision(0)
1952727Sktlim@umich.edu        .prereq(totBytes)
1962727Sktlim@umich.edu        ;
1972727Sktlim@umich.edu
1982727Sktlim@umich.edu    txBytes
1992727Sktlim@umich.edu        .name(name() + ".txBytes")
2002727Sktlim@umich.edu        .desc("Bytes Transmitted")
2012727Sktlim@umich.edu        .prereq(txBytes)
2022727Sktlim@umich.edu        ;
2032727Sktlim@umich.edu
2042727Sktlim@umich.edu    txBandwidth
2054329Sktlim@umich.edu        .name(name() + ".txBandwidth")
2064329Sktlim@umich.edu        .desc("Transmit Bandwidth (bits/s)")
2074329Sktlim@umich.edu        .precision(0)
2084329Sktlim@umich.edu        .prereq(txBytes)
2094329Sktlim@umich.edu        ;
2104329Sktlim@umich.edu
2114329Sktlim@umich.edu    txPackets
2124329Sktlim@umich.edu        .name(name() + ".txPackets")
2134329Sktlim@umich.edu        .desc("Number of Packets Transmitted")
2144329Sktlim@umich.edu        .prereq(txBytes)
2154329Sktlim@umich.edu        ;
2164329Sktlim@umich.edu
2174329Sktlim@umich.edu    txPacketRate
2182292SN/A        .name(name() + ".txPPS")
2192292SN/A        .desc("Packet Tranmission Rate (packets/s)")
2202292SN/A        .precision(0)
2212292SN/A        .prereq(txBytes)
2222292SN/A        ;
2232292SN/A
2242292SN/A    txIpPackets
2252292SN/A        .name(name() + ".txIpPackets")
2262292SN/A        .desc("Number of IP Packets Transmitted")
2272292SN/A        .prereq(txBytes)
2282292SN/A        ;
2292292SN/A
2302292SN/A    txTcpPackets
2312292SN/A        .name(name() + ".txTcpPackets")
2322307SN/A        .desc("Number of TCP Packets Transmitted")
2332307SN/A        .prereq(txBytes)
2342307SN/A        ;
2352367SN/A
2362367SN/A    txUdpPackets
2372307SN/A        .name(name() + ".txUdpPackets")
2382367SN/A        .desc("Number of Packets Transmitted")
2392307SN/A        .prereq(txBytes)
2402329SN/A        ;
2412307SN/A
2422307SN/A    txIpChecksums
2432307SN/A        .name(name() + ".txIpChecksums")
2442307SN/A        .desc("Number of tx IP Checksums done by device")
2452307SN/A        .precision(0)
2462307SN/A        .prereq(txBytes)
2472307SN/A        ;
2482307SN/A
2492307SN/A    txTcpChecksums
2502307SN/A        .name(name() + ".txTcpChecksums")
2512307SN/A        .desc("Number of tx TCP Checksums done by device")
2522307SN/A        .precision(0)
2532307SN/A        .prereq(txBytes)
2542307SN/A        ;
2552307SN/A
2562329SN/A    txUdpChecksums
2572307SN/A        .name(name() + ".txUdpChecksums")
2582307SN/A        .desc("Number of tx UDP Checksums done by device")
2592307SN/A        .precision(0)
2602307SN/A        .prereq(txBytes)
2612307SN/A        ;
2622307SN/A
2632307SN/A    txBandwidth = txBytes * Stats::constant(8) / simSeconds;
2642307SN/A    rxBandwidth = rxBytes * Stats::constant(8) / simSeconds;
2652307SN/A    totBandwidth = txBandwidth + rxBandwidth;
2662307SN/A    totBytes = txBytes + rxBytes;
2672292SN/A    totPackets = txPackets + rxPackets;
2682292SN/A    txPacketRate = txPackets / simSeconds;
2692329SN/A    rxPacketRate = rxPackets / simSeconds;
2702329SN/A
2712292SN/A    _maxVnicDistance = 0;
2722329SN/A
2732329SN/A    maxVnicDistance
2742292SN/A        .name(name() + ".maxVnicDistance")
2752292SN/A        .desc("maximum vnic distance")
2762292SN/A        ;
2772292SN/A
2782292SN/A    totalVnicDistance
2792329SN/A        .name(name() + ".totalVnicDistance")
2802292SN/A        .desc("total vnic distance")
2812292SN/A        ;
2822292SN/A    numVnicDistance
2832292SN/A        .name(name() + ".numVnicDistance")
2842292SN/A        .desc("number of vnic distance measurements")
2852292SN/A        ;
2862292SN/A
2872292SN/A    avgVnicDistance
2882329SN/A        .name(name() + ".avgVnicDistance")
2892329SN/A        .desc("average vnic distance")
2902329SN/A        ;
2912292SN/A
2922292SN/A    avgVnicDistance = totalVnicDistance / numVnicDistance;
2932292SN/A}
2942292SN/A
2952292SN/Avoid
2962329SN/ADevice::resetStats()
2972292SN/A{
2982292SN/A    _maxVnicDistance = 0;
2992292SN/A}
3002292SN/A
3012292SN/AEtherInt*
3022292SN/ADevice::getEthPort(const std::string &if_name, int idx)
3032292SN/A{
3042292SN/A    if (if_name == "interface") {
3052292SN/A        if (interface->getPeer())
3062292SN/A            panic("interface already connected to\n");
3072292SN/A
3082292SN/A        return interface;
3092292SN/A    }
3102292SN/A    return NULL;
3112292SN/A}
3122292SN/A
3132292SN/A
3142292SN/Avoid
3152292SN/ADevice::prepareIO(int cpu, int index)
3162292SN/A{
3172292SN/A    int size = virtualRegs.size();
3182292SN/A    if (index > size)
3192292SN/A        panic("Trying to access a vnic that doesn't exist %d > %d\n",
3202292SN/A              index, size);
3212329SN/A}
3222329SN/A
3232292SN/A//add stats for head of line blocking
3242292SN/A//add stats for average fifo length
3252292SN/A//add stats for average number of vnics busy
3262292SN/A
3272292SN/Avoid
3282292SN/ADevice::prepareRead(int cpu, int index)
3292292SN/A{
3302292SN/A    using namespace Regs;
3312292SN/A    prepareIO(cpu, index);
3322292SN/A
3332292SN/A    VirtualReg &vnic = virtualRegs[index];
3342292SN/A
3352292SN/A    // update rx registers
3362292SN/A    uint64_t rxdone = vnic.RxDone;
3372292SN/A    rxdone = set_RxDone_Packets(rxdone, rxFifo.countPacketsAfter(rxFifoPtr));
3382292SN/A    rxdone = set_RxDone_Empty(rxdone, rxFifo.empty());
3392292SN/A    rxdone = set_RxDone_High(rxdone, rxFifo.size() > regs.RxFifoHigh);
3402292SN/A    rxdone = set_RxDone_NotHigh(rxdone, rxLow);
3412292SN/A    regs.RxData = vnic.RxData;
3422292SN/A    regs.RxDone = rxdone;
3432292SN/A    regs.RxWait = rxdone;
3442292SN/A
3452292SN/A    // update tx regsiters
3462292SN/A    uint64_t txdone = vnic.TxDone;
3472292SN/A    txdone = set_TxDone_Packets(txdone, txFifo.packets());
3482292SN/A    txdone = set_TxDone_Full(txdone, txFifo.avail() < regs.TxMaxCopy);
3492292SN/A    txdone = set_TxDone_Low(txdone, txFifo.size() < regs.TxFifoLow);
3502292SN/A    regs.TxData = vnic.TxData;
3512292SN/A    regs.TxDone = txdone;
3522292SN/A    regs.TxWait = txdone;
3532292SN/A
3542292SN/A    int head = 0xffff;
3552292SN/A
3562292SN/A    if (!rxFifo.empty()) {
3572292SN/A        int vnic = rxFifo.begin()->priv;
3582292SN/A        if (vnic != -1 && virtualRegs[vnic].rxPacketOffset > 0)
3592292SN/A            head = vnic;
3602292SN/A    }
3612292SN/A
3622292SN/A    regs.RxStatus = set_RxStatus_Head(regs.RxStatus, head);
3632292SN/A    regs.RxStatus = set_RxStatus_Busy(regs.RxStatus, rxBusyCount);
3642292SN/A    regs.RxStatus = set_RxStatus_Mapped(regs.RxStatus, rxMappedCount);
3652292SN/A    regs.RxStatus = set_RxStatus_Dirty(regs.RxStatus, rxDirtyCount);
3662292SN/A}
3672292SN/A
3682292SN/Avoid
3692292SN/ADevice::prepareWrite(int cpu, int index)
3702292SN/A{
3712292SN/A    prepareIO(cpu, index);
3722292SN/A}
3732292SN/A
3742292SN/A/**
3752292SN/A * I/O read of device register
3762292SN/A */
3772292SN/ATick
3782292SN/ADevice::read(PacketPtr pkt)
3792292SN/A{
3802292SN/A    assert(config.command & PCI_CMD_MSE);
3812292SN/A    assert(pkt->getAddr() >= BARAddrs[0] && pkt->getSize() < BARSize[0]);
3822292SN/A
3832292SN/A    int cpu = pkt->req->contextId();
3842292SN/A    Addr daddr = pkt->getAddr() - BARAddrs[0];
3852292SN/A    Addr index = daddr >> Regs::VirtualShift;
3862292SN/A    Addr raddr = daddr & Regs::VirtualMask;
3872292SN/A
3882292SN/A    pkt->allocate();
3892292SN/A
3902292SN/A    if (!regValid(raddr))
3912292SN/A        panic("invalid register: cpu=%d vnic=%d da=%#x pa=%#x size=%d",
3922292SN/A              cpu, index, daddr, pkt->getAddr(), pkt->getSize());
3932292SN/A
3942292SN/A    const Regs::Info &info = regInfo(raddr);
3952292SN/A    if (!info.read)
3962292SN/A        panic("read %s (write only): "
3972292SN/A              "cpu=%d vnic=%d da=%#x pa=%#x size=%d",
3982292SN/A              info.name, cpu, index, daddr, pkt->getAddr(), pkt->getSize());
3992292SN/A
4002292SN/A        panic("read %s (invalid size): "
4012292SN/A              "cpu=%d vnic=%d da=%#x pa=%#x size=%d",
4022292SN/A              info.name, cpu, index, daddr, pkt->getAddr(), pkt->getSize());
4032292SN/A
4042292SN/A    prepareRead(cpu, index);
4052292SN/A
4062292SN/A    uint64_t value = 0;
4072292SN/A    if (pkt->getSize() == 4) {
4082292SN/A        uint32_t reg = regData32(raddr);
4092292SN/A        pkt->set(reg);
4102292SN/A        value = reg;
4112292SN/A    }
4124032Sktlim@umich.edu
4132292SN/A    if (pkt->getSize() == 8) {
4142292SN/A        uint64_t reg = regData64(raddr);
4152292SN/A        pkt->set(reg);
4162292SN/A        value = reg;
4172292SN/A    }
4182292SN/A
4194032Sktlim@umich.edu    DPRINTF(EthernetPIO,
4204032Sktlim@umich.edu            "read %s: cpu=%d vnic=%d da=%#x pa=%#x size=%d val=%#x\n",
4212669Sktlim@umich.edu            info.name, cpu, index, daddr, pkt->getAddr(), pkt->getSize(), value);
4222292SN/A
4232292SN/A    // reading the interrupt status register has the side effect of
4242292SN/A    // clearing it
4252292SN/A    if (raddr == Regs::IntrStatus)
4262329SN/A        devIntrClear();
4272329SN/A
4282367SN/A    return pioDelay;
4292367SN/A}
4304032Sktlim@umich.edu
4313731Sktlim@umich.edu/**
4322367SN/A * IPR read of device register
4332367SN/A
4342292SN/A    Fault
4352292SN/ADevice::iprRead(Addr daddr, int cpu, uint64_t &result)
4364032Sktlim@umich.edu{
4374032Sktlim@umich.edu    if (!regValid(daddr))
4384032Sktlim@umich.edu        panic("invalid address: da=%#x", daddr);
4394032Sktlim@umich.edu
4404032Sktlim@umich.edu    const Regs::Info &info = regInfo(daddr);
4414032Sktlim@umich.edu    if (!info.read)
4424032Sktlim@umich.edu        panic("reading %s (write only): cpu=%d da=%#x", info.name, cpu, daddr);
4434032Sktlim@umich.edu
4444032Sktlim@umich.edu    DPRINTF(EthernetPIO, "IPR read %s: cpu=%d da=%#x\n",
4454032Sktlim@umich.edu            info.name, cpu, daddr);
4464032Sktlim@umich.edu
4474032Sktlim@umich.edu    prepareRead(cpu, 0);
4484032Sktlim@umich.edu
4494032Sktlim@umich.edu    if (info.size == 4)
4504032Sktlim@umich.edu        result = regData32(daddr);
4514032Sktlim@umich.edu
4524032Sktlim@umich.edu    if (info.size == 8)
4534032Sktlim@umich.edu        result = regData64(daddr);
4544032Sktlim@umich.edu
4554032Sktlim@umich.edu    DPRINTF(EthernetPIO, "IPR read %s: cpu=%s da=%#x val=%#x\n",
4564032Sktlim@umich.edu            info.name, cpu, result);
4574032Sktlim@umich.edu
4584032Sktlim@umich.edu    return NoFault;
4594032Sktlim@umich.edu}
4604032Sktlim@umich.edu*/
4614032Sktlim@umich.edu/**
4624032Sktlim@umich.edu * I/O write of device register
4634032Sktlim@umich.edu */
4644032Sktlim@umich.eduTick
4654032Sktlim@umich.eduDevice::write(PacketPtr pkt)
4664032Sktlim@umich.edu{
4674032Sktlim@umich.edu    assert(config.command & PCI_CMD_MSE);
4682292SN/A    assert(pkt->getAddr() >= BARAddrs[0] && pkt->getSize() < BARSize[0]);
4692292SN/A
4702292SN/A    int cpu = pkt->req->contextId();
4712292SN/A    Addr daddr = pkt->getAddr() - BARAddrs[0];
4722292SN/A    Addr index = daddr >> Regs::VirtualShift;
4732292SN/A    Addr raddr = daddr & Regs::VirtualMask;
4742292SN/A
4752292SN/A    if (!regValid(raddr))
4762292SN/A        panic("invalid register: cpu=%d, da=%#x pa=%#x size=%d",
4772292SN/A                cpu, daddr, pkt->getAddr(), pkt->getSize());
4782292SN/A
4792292SN/A    const Regs::Info &info = regInfo(raddr);
4802292SN/A    if (!info.write)
4812292SN/A        panic("write %s (read only): "
4822292SN/A              "cpu=%d vnic=%d da=%#x pa=%#x size=%d",
4832292SN/A              info.name, cpu, index, daddr, pkt->getAddr(), pkt->getSize());
4842292SN/A
4852292SN/A    if (pkt->getSize() != info.size)
4864032Sktlim@umich.edu        panic("write %s (invalid size): "
4874032Sktlim@umich.edu              "cpu=%d vnic=%d da=%#x pa=%#x size=%d",
4882292SN/A              info.name, cpu, index, daddr, pkt->getAddr(), pkt->getSize());
4892292SN/A
4902292SN/A    VirtualReg &vnic = virtualRegs[index];
4912292SN/A
4922292SN/A    DPRINTF(EthernetPIO,
4932292SN/A            "write %s vnic %d: cpu=%d val=%#x da=%#x pa=%#x size=%d\n",
4942329SN/A            info.name, index, cpu, info.size == 4 ? pkt->get<uint32_t>() :
4952292SN/A            pkt->get<uint64_t>(), daddr, pkt->getAddr(), pkt->getSize());
4962292SN/A
4972292SN/A    prepareWrite(cpu, index);
4982292SN/A
4992292SN/A    switch (raddr) {
5002292SN/A      case Regs::Config:
5012292SN/A        changeConfig(pkt->get<uint32_t>());
5022292SN/A        break;
5032336SN/A
5042336SN/A      case Regs::Command:
5052336SN/A        command(pkt->get<uint32_t>());
5062329SN/A        break;
5072292SN/A
5082329SN/A      case Regs::IntrStatus:
5092292SN/A        devIntrClear(regs.IntrStatus & pkt->get<uint32_t>());
5102292SN/A        break;
5114032Sktlim@umich.edu
5124032Sktlim@umich.edu      case Regs::IntrMask:
5134032Sktlim@umich.edu        devIntrChangeMask(pkt->get<uint32_t>());
5144032Sktlim@umich.edu        break;
5154032Sktlim@umich.edu
5162292SN/A      case Regs::RxData:
5174032Sktlim@umich.edu        if (Regs::get_RxDone_Busy(vnic.RxDone))
5184032Sktlim@umich.edu            panic("receive machine busy with another request! rxState=%s",
5194032Sktlim@umich.edu                  RxStateStrings[rxState]);
5202329SN/A
5214032Sktlim@umich.edu        vnic.rxUnique = rxUnique++;
5224032Sktlim@umich.edu        vnic.RxDone = Regs::RxDone_Busy;
5234032Sktlim@umich.edu        vnic.RxData = pkt->get<uint64_t>();
5244032Sktlim@umich.edu        rxBusyCount++;
5254032Sktlim@umich.edu
5264032Sktlim@umich.edu        if (Regs::get_RxData_Vaddr(pkt->get<uint64_t>())) {
5274032Sktlim@umich.edu            panic("vtophys not implemented in newmem");
5284032Sktlim@umich.edu#ifdef SINIC_VTOPHYS
5294032Sktlim@umich.edu            Addr vaddr = Regs::get_RxData_Addr(reg64);
5304032Sktlim@umich.edu            Addr paddr = vtophys(req->xc, vaddr);
5314032Sktlim@umich.edu            DPRINTF(EthernetPIO, "write RxData vnic %d (rxunique %d): "
5324032Sktlim@umich.edu                    "vaddr=%#x, paddr=%#x\n",
5332292SN/A                    index, vnic.rxUnique, vaddr, paddr);
5342292SN/A
5354032Sktlim@umich.edu            vnic.RxData = Regs::set_RxData_Addr(vnic.RxData, paddr);
5364032Sktlim@umich.edu#endif
5374032Sktlim@umich.edu        } else {
5382292SN/A            DPRINTF(EthernetPIO, "write RxData vnic %d (rxunique %d)\n",
5392292SN/A                    index, vnic.rxUnique);
5404032Sktlim@umich.edu        }
5412292SN/A
5422292SN/A        if (vnic.rxIndex == rxFifo.end()) {
5432292SN/A            DPRINTF(EthernetPIO, "request new packet...appending to rxList\n");
5442292SN/A            rxList.push_back(index);
5452292SN/A        } else {
5462292SN/A            DPRINTF(EthernetPIO, "packet exists...appending to rxBusy\n");
5472292SN/A            rxBusy.push_back(index);
5482292SN/A        }
5492292SN/A
5502292SN/A        if (rxEnable && (rxState == rxIdle || rxState == rxFifoBlock)) {
5512292SN/A            rxState = rxFifoBlock;
5522292SN/A            rxKick();
5532292SN/A        }
5542292SN/A        break;
5552292SN/A
5562292SN/A      case Regs::TxData:
5572292SN/A        if (Regs::get_TxDone_Busy(vnic.TxDone))
5582292SN/A            panic("transmit machine busy with another request! txState=%s",
5592292SN/A                  TxStateStrings[txState]);
5602292SN/A
5612292SN/A        vnic.txUnique = txUnique++;
5622292SN/A        vnic.TxDone = Regs::TxDone_Busy;
5632292SN/A
5642292SN/A        if (Regs::get_TxData_Vaddr(pkt->get<uint64_t>())) {
5652292SN/A            panic("vtophys won't work here in newmem.\n");
5662292SN/A#ifdef SINIC_VTOPHYS
5672292SN/A            Addr vaddr = Regs::get_TxData_Addr(reg64);
5682292SN/A            Addr paddr = vtophys(req->xc, vaddr);
5692292SN/A            DPRINTF(EthernetPIO, "write TxData vnic %d (txunique %d): "
5702292SN/A                    "vaddr=%#x, paddr=%#x\n",
5712292SN/A                    index, vnic.txUnique, vaddr, paddr);
5722292SN/A
5732292SN/A            vnic.TxData = Regs::set_TxData_Addr(vnic.TxData, paddr);
5742292SN/A#endif
5752292SN/A        } else {
5762292SN/A            DPRINTF(EthernetPIO, "write TxData vnic %d (txunique %d)\n",
5772292SN/A                    index, vnic.txUnique);
5782292SN/A        }
5792292SN/A
5802292SN/A        if (txList.empty() || txList.front() != index)
5812292SN/A            txList.push_back(index);
5822292SN/A        if (txEnable && txState == txIdle && txList.front() == index) {
5832329SN/A            txState = txFifoBlock;
5842329SN/A            txKick();
5852292SN/A        }
5862292SN/A        break;
5872292SN/A    }
5882292SN/A
5892292SN/A    return pioDelay;
5902292SN/A}
5912292SN/A
5922292SN/Avoid
5932292SN/ADevice::devIntrPost(uint32_t interrupts)
5942292SN/A{
5952292SN/A    if ((interrupts & Regs::Intr_Res))
5962292SN/A        panic("Cannot set a reserved interrupt");
5972292SN/A
5982292SN/A    regs.IntrStatus |= interrupts;
5992292SN/A
6002292SN/A    DPRINTF(EthernetIntr,
6012292SN/A            "interrupt written to intStatus: intr=%#x status=%#x mask=%#x\n",
6022292SN/A            interrupts, regs.IntrStatus, regs.IntrMask);
6032292SN/A
6042292SN/A    interrupts = regs.IntrStatus & regs.IntrMask;
6052292SN/A
6062292SN/A    // Intr_RxHigh is special, we only signal it if we've emptied the fifo
6072292SN/A    // and then filled it above the high watermark
6082292SN/A    if (rxEmpty)
6092292SN/A        rxEmpty = false;
6102292SN/A    else
6112292SN/A        interrupts &= ~Regs::Intr_RxHigh;
6122292SN/A
6132907Sktlim@umich.edu    // Intr_TxLow is special, we only signal it if we've filled up the fifo
6142678Sktlim@umich.edu    // and then dropped below the low watermark
6152678Sktlim@umich.edu    if (txFull)
6162678Sktlim@umich.edu        txFull = false;
6172678Sktlim@umich.edu    else
6182678Sktlim@umich.edu        interrupts &= ~Regs::Intr_TxLow;
6192329SN/A
6202329SN/A    if (interrupts) {
6212292SN/A        Tick when = curTick;
6222292SN/A        if ((interrupts & Regs::Intr_NoDelay) == 0)
6232292SN/A            when += intrDelay;
6242292SN/A        cpuIntrPost(when);
6252292SN/A    }
6262292SN/A}
6272292SN/A
6282678Sktlim@umich.eduvoid
6292292SN/ADevice::devIntrClear(uint32_t interrupts)
6302292SN/A{
6312292SN/A    if ((interrupts & Regs::Intr_Res))
6322292SN/A        panic("Cannot clear a reserved interrupt");
6332292SN/A
6342292SN/A    regs.IntrStatus &= ~interrupts;
6352292SN/A
6362292SN/A    DPRINTF(EthernetIntr,
6372292SN/A            "interrupt cleared from intStatus: intr=%x status=%x mask=%x\n",
6382292SN/A            interrupts, regs.IntrStatus, regs.IntrMask);
6392292SN/A
6402669Sktlim@umich.edu    if (!(regs.IntrStatus & regs.IntrMask))
6412669Sktlim@umich.edu        cpuIntrClear();
6422669Sktlim@umich.edu}
6432292SN/A
6442292SN/Avoid
6452669Sktlim@umich.eduDevice::devIntrChangeMask(uint32_t newmask)
6462669Sktlim@umich.edu{
6473772Sgblack@eecs.umich.edu    if (regs.IntrMask == newmask)
6484326Sgblack@eecs.umich.edu        return;
6492669Sktlim@umich.edu
6504878Sstever@eecs.umich.edu    regs.IntrMask = newmask;
6514878Sstever@eecs.umich.edu
6524909Sstever@eecs.umich.edu    DPRINTF(EthernetIntr,
6534350Sgblack@eecs.umich.edu            "interrupt mask changed: intStatus=%x intMask=%x masked=%x\n",
6544022Sstever@eecs.umich.edu            regs.IntrStatus, regs.IntrMask, regs.IntrStatus & regs.IntrMask);
6552669Sktlim@umich.edu
6562292SN/A    if (regs.IntrStatus & regs.IntrMask)
6572678Sktlim@umich.edu        cpuIntrPost(curTick);
6582678Sktlim@umich.edu    else
6592678Sktlim@umich.edu        cpuIntrClear();
6602678Sktlim@umich.edu}
6612678Sktlim@umich.edu
6622678Sktlim@umich.eduvoid
6632292SN/ABase::cpuIntrPost(Tick when)
6642292SN/A{
6653221Sktlim@umich.edu    // If the interrupt you want to post is later than an interrupt
6663797Sgblack@eecs.umich.edu    // already scheduled, just let it post in the coming one and don't
6673221Sktlim@umich.edu    // schedule another.
6682292SN/A    // HOWEVER, must be sure that the scheduled intrTick is in the
6692693Sktlim@umich.edu    // future (this was formerly the source of a bug)
6704350Sgblack@eecs.umich.edu    /**
6713326Sktlim@umich.edu     * @todo this warning should be removed and the intrTick code should
6723326Sktlim@umich.edu     * be fixed.
6733326Sktlim@umich.edu     */
6743326Sktlim@umich.edu    assert(when >= curTick);
6753326Sktlim@umich.edu    assert(intrTick >= curTick || intrTick == 0);
6763326Sktlim@umich.edu    if (!cpuIntrEnable) {
6773326Sktlim@umich.edu        DPRINTF(EthernetIntr, "interrupts not enabled.\n",
6783326Sktlim@umich.edu                intrTick);
6793326Sktlim@umich.edu        return;
6803326Sktlim@umich.edu    }
6813326Sktlim@umich.edu
6823326Sktlim@umich.edu    if (when > intrTick && intrTick != 0) {
6833326Sktlim@umich.edu        DPRINTF(EthernetIntr, "don't need to schedule event...intrTick=%d\n",
6843326Sktlim@umich.edu                intrTick);
6853326Sktlim@umich.edu        return;
6863326Sktlim@umich.edu    }
6873326Sktlim@umich.edu
6882693Sktlim@umich.edu    intrTick = when;
6892693Sktlim@umich.edu    if (intrTick < curTick) {
6902693Sktlim@umich.edu        debug_break();
6912693Sktlim@umich.edu        intrTick = curTick;
6922693Sktlim@umich.edu    }
6932693Sktlim@umich.edu
6942669Sktlim@umich.edu    DPRINTF(EthernetIntr, "going to schedule an interrupt for intrTick=%d\n",
6952669Sktlim@umich.edu            intrTick);
6964032Sktlim@umich.edu
6973221Sktlim@umich.edu    if (intrEvent)
6983221Sktlim@umich.edu        intrEvent->squash();
6992678Sktlim@umich.edu    intrEvent = new IntrEvent(this, true);
7002727Sktlim@umich.edu    schedule(intrEvent, intrTick);
7012698Sktlim@umich.edu}
7022698Sktlim@umich.edu
7033014Srdreslin@umich.eduvoid
7042669Sktlim@umich.eduBase::cpuInterrupt()
7052693Sktlim@umich.edu{
7062292SN/A    assert(intrTick == curTick);
7072292SN/A
7082292SN/A    // Whether or not there's a pending interrupt, we don't care about
7092292SN/A    // it anymore
7102292SN/A    intrEvent = 0;
7112292SN/A    intrTick = 0;
7122292SN/A
7132292SN/A    // Don't send an interrupt if there's already one
7142292SN/A    if (cpuPendingIntr) {
7152292SN/A        DPRINTF(EthernetIntr,
7162292SN/A                "would send an interrupt now, but there's already pending\n");
7172292SN/A    } else {
7182292SN/A        // Send interrupt
7192292SN/A        cpuPendingIntr = true;
7202292SN/A
7212292SN/A        DPRINTF(EthernetIntr, "posting interrupt\n");
7222292SN/A        intrPost();
7232292SN/A    }
7242292SN/A}
7252292SN/A
7262292SN/Avoid
7272292SN/ABase::cpuIntrClear()
7282292SN/A{
7292292SN/A    if (!cpuPendingIntr)
7302292SN/A        return;
7312292SN/A
7322292SN/A    if (intrEvent) {
7332292SN/A        intrEvent->squash();
7342329SN/A        intrEvent = 0;
7352292SN/A    }
7362292SN/A
7372292SN/A    intrTick = 0;
7382292SN/A
7392292SN/A    cpuPendingIntr = false;
7402292SN/A
7412292SN/A    DPRINTF(EthernetIntr, "clearing cchip interrupt\n");
7422292SN/A    intrClear();
7432292SN/A}
7442292SN/A
7452292SN/Abool
7462292SN/ABase::cpuIntrPending() const
7472292SN/A{ return cpuPendingIntr; }
7482292SN/A
7492292SN/Avoid
7502292SN/ADevice::changeConfig(uint32_t newconf)
7512329SN/A{
7522731Sktlim@umich.edu    uint32_t changed = regs.Config ^ newconf;
7532292SN/A    if (!changed)
7542292SN/A        return;
7552292SN/A
7562292SN/A    regs.Config = newconf;
7572292SN/A
7582292SN/A    if ((changed & Regs::Config_IntEn)) {
7592292SN/A        cpuIntrEnable = regs.Config & Regs::Config_IntEn;
7602727Sktlim@umich.edu        if (cpuIntrEnable) {
7612292SN/A            if (regs.IntrStatus & regs.IntrMask)
7622292SN/A                cpuIntrPost(curTick);
7632292SN/A        } else {
7642292SN/A            cpuIntrClear();
7652292SN/A        }
7662292SN/A    }
7672292SN/A
7682292SN/A    if ((changed & Regs::Config_TxEn)) {
7692292SN/A        txEnable = regs.Config & Regs::Config_TxEn;
7702292SN/A        if (txEnable)
7714032Sktlim@umich.edu            txKick();
7724032Sktlim@umich.edu    }
7734032Sktlim@umich.edu
7744032Sktlim@umich.edu    if ((changed & Regs::Config_RxEn)) {
7752292SN/A        rxEnable = regs.Config & Regs::Config_RxEn;
7762292SN/A        if (rxEnable)
7772292SN/A            rxKick();
7782292SN/A    }
7792292SN/A}
7802329SN/A
7812292SN/Avoid
7822292SN/ADevice::command(uint32_t command)
7832292SN/A{
7842292SN/A    if (command & Regs::Command_Intr)
7852292SN/A        devIntrPost(Regs::Intr_Soft);
7862292SN/A
7872292SN/A    if (command & Regs::Command_Reset)
7882292SN/A        reset();
7892292SN/A}
7902329SN/A
7912329SN/Avoid
7922292SN/ADevice::reset()
7932292SN/A{
7942292SN/A    using namespace Regs;
7952292SN/A
7962292SN/A    memset(&regs, 0, sizeof(regs));
7972292SN/A
7982292SN/A    regs.Config = 0;
7992329SN/A    if (params()->rx_thread)
8002731Sktlim@umich.edu        regs.Config |= Config_RxThread;
8012292SN/A    if (params()->tx_thread)
8022292SN/A        regs.Config |= Config_TxThread;
8032292SN/A    if (params()->rss)
8044032Sktlim@umich.edu        regs.Config |= Config_RSS;
8054032Sktlim@umich.edu    if (params()->zero_copy)
8064032Sktlim@umich.edu        regs.Config |= Config_ZeroCopy;
8074032Sktlim@umich.edu    if (params()->delay_copy)
8084032Sktlim@umich.edu        regs.Config |= Config_DelayCopy;
8092292SN/A    if (params()->virtual_addr)
8102292SN/A        regs.Config |= Config_Vaddr;
8112292SN/A
8122292SN/A    if (params()->delay_copy && params()->zero_copy)
8132292SN/A        panic("Can't delay copy and zero copy");
8142292SN/A
8152292SN/A    regs.IntrMask = Intr_Soft | Intr_RxHigh | Intr_RxPacket | Intr_TxLow;
8162727Sktlim@umich.edu    regs.RxMaxCopy = params()->rx_max_copy;
8172292SN/A    regs.TxMaxCopy = params()->tx_max_copy;
8182292SN/A    regs.ZeroCopySize = params()->zero_copy_size;
8192292SN/A    regs.ZeroCopyMark = params()->zero_copy_threshold;
8202292SN/A    regs.VirtualCount = params()->virtual_count;
8212292SN/A    regs.RxMaxIntr = params()->rx_max_intr;
8223349Sbinkertn@umich.edu    regs.RxFifoSize = params()->rx_fifo_size;
8232693Sktlim@umich.edu    regs.TxFifoSize = params()->tx_fifo_size;
8242693Sktlim@umich.edu    regs.RxFifoLow = params()->rx_fifo_low_mark;
8252693Sktlim@umich.edu    regs.TxFifoLow = params()->tx_fifo_threshold;
8262693Sktlim@umich.edu    regs.RxFifoHigh = params()->rx_fifo_threshold;
8272693Sktlim@umich.edu    regs.TxFifoHigh = params()->tx_fifo_high_mark;
8282693Sktlim@umich.edu    regs.HwAddr = params()->hardware_address;
8292693Sktlim@umich.edu
8302693Sktlim@umich.edu    if (regs.RxMaxCopy < regs.ZeroCopyMark)
8312693Sktlim@umich.edu        panic("Must be able to copy at least as many bytes as the threshold");
8322693Sktlim@umich.edu
8332693Sktlim@umich.edu    if (regs.ZeroCopySize >= regs.ZeroCopyMark)
8342693Sktlim@umich.edu        panic("The number of bytes to copy must be less than the threshold");
8352693Sktlim@umich.edu
8362693Sktlim@umich.edu    rxList.clear();
8372693Sktlim@umich.edu    rxBusy.clear();
8382693Sktlim@umich.edu    rxActive = -1;
8392733Sktlim@umich.edu    txList.clear();
8402693Sktlim@umich.edu    rxBusyCount = 0;
8412732Sktlim@umich.edu    rxDirtyCount = 0;
8422693Sktlim@umich.edu    rxMappedCount = 0;
8432733Sktlim@umich.edu
8442693Sktlim@umich.edu    rxState = rxIdle;
8452693Sktlim@umich.edu    txState = txIdle;
8462693Sktlim@umich.edu
8472693Sktlim@umich.edu    rxFifo.clear();
8482693Sktlim@umich.edu    rxFifoPtr = rxFifo.end();
8492693Sktlim@umich.edu    txFifo.clear();
8502693Sktlim@umich.edu    rxEmpty = false;
8512678Sktlim@umich.edu    rxLow = true;
8522678Sktlim@umich.edu    txFull = false;
8532678Sktlim@umich.edu
8542678Sktlim@umich.edu    int size = virtualRegs.size();
8552678Sktlim@umich.edu    virtualRegs.clear();
8562678Sktlim@umich.edu    virtualRegs.resize(size);
8572927Sktlim@umich.edu    for (int i = 0; i < size; ++i)
8582678Sktlim@umich.edu        virtualRegs[i].rxIndex = rxFifo.end();
8592727Sktlim@umich.edu}
8602678Sktlim@umich.edu
8612678Sktlim@umich.eduvoid
8622678Sktlim@umich.eduDevice::rxDmaDone()
8632678Sktlim@umich.edu{
8642678Sktlim@umich.edu    assert(rxState == rxCopy);
8652678Sktlim@umich.edu    rxState = rxCopyDone;
8662678Sktlim@umich.edu    DPRINTF(EthernetDMA, "end rx dma write paddr=%#x len=%d\n",
8672678Sktlim@umich.edu            rxDmaAddr, rxDmaLen);
8682678Sktlim@umich.edu    DDUMP(EthernetData, rxDmaData, rxDmaLen);
8692678Sktlim@umich.edu
8702678Sktlim@umich.edu    // If the transmit state machine  has a pending DMA, let it go first
8712678Sktlim@umich.edu    if (txState == txBeginCopy)
8722678Sktlim@umich.edu        txKick();
8732678Sktlim@umich.edu
8742678Sktlim@umich.edu    rxKick();
8752678Sktlim@umich.edu}
8762678Sktlim@umich.edu
8772678Sktlim@umich.eduvoid
8782292SN/ADevice::rxKick()
8792292SN/A{
8802292SN/A    VirtualReg *vnic = NULL;
8812292SN/A
8822292SN/A    DPRINTF(EthernetSM, "rxKick: rxState=%s (rxFifo.size=%d)\n",
8832292SN/A            RxStateStrings[rxState], rxFifo.size());
8842292SN/A
8852292SN/A    if (rxKickTick > curTick) {
8863126Sktlim@umich.edu        DPRINTF(EthernetSM, "rxKick: exiting, can't run till %d\n",
8872292SN/A                rxKickTick);
8882292SN/A        return;
8892292SN/A    }
8902292SN/A
8912292SN/A  next:
8922292SN/A    rxFifo.check();
8932292SN/A    if (rxState == rxIdle)
8942292SN/A        goto exit;
8952292SN/A
8962292SN/A    if (rxActive == -1) {
8972292SN/A        if (rxState != rxFifoBlock)
8982292SN/A            panic("no active vnic while in state %s", RxStateStrings[rxState]);
8992292SN/A
9002329SN/A        DPRINTF(EthernetSM, "processing rxState=%s\n",
9012329SN/A                RxStateStrings[rxState]);
9022329SN/A    } else {
9032292SN/A        vnic = &virtualRegs[rxActive];
9042292SN/A        DPRINTF(EthernetSM,
9052292SN/A                "processing rxState=%s for vnic %d (rxunique %d)\n",
9062292SN/A                RxStateStrings[rxState], rxActive, vnic->rxUnique);
9072292SN/A    }
9082292SN/A
9092292SN/A    switch (rxState) {
9102292SN/A      case rxFifoBlock:
9112292SN/A        if (DTRACE(EthernetSM)) {
9122292SN/A            PacketFifo::iterator end = rxFifo.end();
9132316SN/A            int size = virtualRegs.size();
9142316SN/A            for (int i = 0; i < size; ++i) {
9152329SN/A                VirtualReg *vn = &virtualRegs[i];
9162329SN/A                bool busy = Regs::get_RxDone_Busy(vn->RxDone);
9172329SN/A                if (vn->rxIndex != end) {
9182329SN/A                    bool dirty = vn->rxPacketOffset > 0;
9192733Sktlim@umich.edu                    const char *status;
9202316SN/A
9212732Sktlim@umich.edu                    if (busy && dirty)
9222316SN/A                        status = "busy,dirty";
9232733Sktlim@umich.edu                    else if (busy)
9242292SN/A                        status = "busy";
9252292SN/A                    else if (dirty)
9262292SN/A                        status = "dirty";
9272693Sktlim@umich.edu                    else
9282693Sktlim@umich.edu                        status = "mapped";
9292693Sktlim@umich.edu
9302698Sktlim@umich.edu                    DPRINTF(EthernetSM,
9312698Sktlim@umich.edu                            "vnic %d %s (rxunique %d), packet %d, slack %d\n",
9322693Sktlim@umich.edu                            i, status, vn->rxUnique,
9332698Sktlim@umich.edu                            rxFifo.countPacketsBefore(vn->rxIndex),
9342698Sktlim@umich.edu                            vn->rxIndex->slack);
9352699Sktlim@umich.edu                } else if (busy) {
9362693Sktlim@umich.edu                    DPRINTF(EthernetSM, "vnic %d unmapped (rxunique %d)\n",
9373014Srdreslin@umich.edu                            i, vn->rxUnique);
9382693Sktlim@umich.edu                }
9392693Sktlim@umich.edu            }
9402727Sktlim@umich.edu        }
9412907Sktlim@umich.edu
9422693Sktlim@umich.edu        if (!rxBusy.empty()) {
9432693Sktlim@umich.edu            rxActive = rxBusy.front();
9442693Sktlim@umich.edu            rxBusy.pop_front();
9452693Sktlim@umich.edu            vnic = &virtualRegs[rxActive];
9462693Sktlim@umich.edu
9472693Sktlim@umich.edu            if (vnic->rxIndex == rxFifo.end())
9482693Sktlim@umich.edu                panic("continuing vnic without packet\n");
9492693Sktlim@umich.edu
9502693Sktlim@umich.edu            DPRINTF(EthernetSM,
9512693Sktlim@umich.edu                    "continue processing for vnic %d (rxunique %d)\n",
9522292SN/A                    rxActive, vnic->rxUnique);
9532292SN/A
9542292SN/A            rxState = rxBeginCopy;
9552292SN/A
9562292SN/A            int vnic_distance = rxFifo.countPacketsBefore(vnic->rxIndex);
9572292SN/A            totalVnicDistance += vnic_distance;
9582292SN/A            numVnicDistance += 1;
9592292SN/A            if (vnic_distance > _maxVnicDistance) {
9602292SN/A                maxVnicDistance = vnic_distance;
9612292SN/A                _maxVnicDistance = vnic_distance;
9622292SN/A            }
9632292SN/A
9642292SN/A            break;
9652292SN/A        }
9662292SN/A
9672292SN/A        if (rxFifoPtr == rxFifo.end()) {
9682292SN/A            DPRINTF(EthernetSM, "receive waiting for data.  Nothing to do.\n");
9692292SN/A            goto exit;
9702292SN/A        }
9712292SN/A
9722292SN/A        if (rxList.empty())
9732292SN/A            panic("Not idle, but nothing to do!");
9742292SN/A
9752292SN/A        assert(!rxFifo.empty());
9762292SN/A
9772292SN/A        rxActive = rxList.front();
9782292SN/A        rxList.pop_front();
9792292SN/A        vnic = &virtualRegs[rxActive];
9802292SN/A
9812292SN/A        DPRINTF(EthernetSM,
9822329SN/A                "processing new packet for vnic %d (rxunique %d)\n",
9832329SN/A                rxActive, vnic->rxUnique);
9842329SN/A
9852329SN/A        // Grab a new packet from the fifo.
9862329SN/A        vnic->rxIndex = rxFifoPtr++;
9872329SN/A        vnic->rxIndex->priv = rxActive;
9882329SN/A        vnic->rxPacketOffset = 0;
9892329SN/A        vnic->rxPacketBytes = vnic->rxIndex->packet->length;
9902329SN/A        assert(vnic->rxPacketBytes);
9912329SN/A        rxMappedCount++;
9922329SN/A
9932329SN/A        vnic->rxDoneData = 0;
9942329SN/A        /* scope for variables */ {
9952329SN/A            IpPtr ip(vnic->rxIndex->packet);
9962329SN/A            if (ip) {
9972329SN/A                DPRINTF(Ethernet, "ID is %d\n", ip->id());
9982329SN/A                vnic->rxDoneData |= Regs::RxDone_IpPacket;
9992329SN/A                rxIpChecksums++;
10002329SN/A                if (cksum(ip) != 0) {
10012329SN/A                    DPRINTF(EthernetCksum, "Rx IP Checksum Error\n");
10022329SN/A                    vnic->rxDoneData |= Regs::RxDone_IpError;
10032329SN/A                }
10042329SN/A                TcpPtr tcp(ip);
10052329SN/A                UdpPtr udp(ip);
10062329SN/A                if (tcp) {
10072329SN/A                    DPRINTF(Ethernet,
10082329SN/A                            "Src Port=%d, Dest Port=%d, Seq=%d, Ack=%d\n",
10092329SN/A                            tcp->sport(), tcp->dport(), tcp->seq(),
10102329SN/A                            tcp->ack());
10112329SN/A                    vnic->rxDoneData |= Regs::RxDone_TcpPacket;
1012                    rxTcpChecksums++;
1013                    if (cksum(tcp) != 0) {
1014                        DPRINTF(EthernetCksum, "Rx TCP Checksum Error\n");
1015                        vnic->rxDoneData |= Regs::RxDone_TcpError;
1016                    }
1017                } else if (udp) {
1018                    vnic->rxDoneData |= Regs::RxDone_UdpPacket;
1019                    rxUdpChecksums++;
1020                    if (cksum(udp) != 0) {
1021                        DPRINTF(EthernetCksum, "Rx UDP Checksum Error\n");
1022                        vnic->rxDoneData |= Regs::RxDone_UdpError;
1023                    }
1024                }
1025            }
1026        }
1027        rxState = rxBeginCopy;
1028        break;
1029
1030      case rxBeginCopy:
1031        if (dmaPending() || getState() != Running)
1032            goto exit;
1033
1034        rxDmaAddr = params()->platform->pciToDma(
1035                Regs::get_RxData_Addr(vnic->RxData));
1036        rxDmaLen = min<unsigned>(Regs::get_RxData_Len(vnic->RxData),
1037                                 vnic->rxPacketBytes);
1038
1039        /*
1040         * if we're doing zero/delay copy and we're below the fifo
1041         * threshold, see if we should try to do the zero/defer copy
1042         */
1043        if ((Regs::get_Config_ZeroCopy(regs.Config) ||
1044             Regs::get_Config_DelayCopy(regs.Config)) &&
1045            !Regs::get_RxData_NoDelay(vnic->RxData) && rxLow) {
1046            if (rxDmaLen > regs.ZeroCopyMark)
1047                rxDmaLen = regs.ZeroCopySize;
1048        }
1049        rxDmaData = vnic->rxIndex->packet->data + vnic->rxPacketOffset;
1050        rxState = rxCopy;
1051        if (rxDmaAddr == 1LL) {
1052            rxState = rxCopyDone;
1053            break;
1054        }
1055
1056        dmaWrite(rxDmaAddr, rxDmaLen, &rxDmaEvent, rxDmaData);
1057        break;
1058
1059      case rxCopy:
1060        DPRINTF(EthernetSM, "receive machine still copying\n");
1061        goto exit;
1062
1063      case rxCopyDone:
1064        vnic->RxDone = vnic->rxDoneData;
1065        vnic->RxDone |= Regs::RxDone_Complete;
1066        rxBusyCount--;
1067
1068        if (vnic->rxPacketBytes == rxDmaLen) {
1069            if (vnic->rxPacketOffset)
1070                rxDirtyCount--;
1071
1072            // Packet is complete.  Indicate how many bytes were copied
1073            vnic->RxDone = Regs::set_RxDone_CopyLen(vnic->RxDone, rxDmaLen);
1074
1075            DPRINTF(EthernetSM,
1076                    "rxKick: packet complete on vnic %d (rxunique %d)\n",
1077                    rxActive, vnic->rxUnique);
1078            rxFifo.remove(vnic->rxIndex);
1079            vnic->rxIndex = rxFifo.end();
1080            rxMappedCount--;
1081        } else {
1082            if (!vnic->rxPacketOffset)
1083                rxDirtyCount++;
1084
1085            vnic->rxPacketBytes -= rxDmaLen;
1086            vnic->rxPacketOffset += rxDmaLen;
1087            vnic->RxDone |= Regs::RxDone_More;
1088            vnic->RxDone = Regs::set_RxDone_CopyLen(vnic->RxDone,
1089                                                    vnic->rxPacketBytes);
1090            DPRINTF(EthernetSM,
1091                    "rxKick: packet not complete on vnic %d (rxunique %d): "
1092                    "%d bytes left\n",
1093                    rxActive, vnic->rxUnique, vnic->rxPacketBytes);
1094        }
1095
1096        rxActive = -1;
1097        rxState = rxBusy.empty() && rxList.empty() ? rxIdle : rxFifoBlock;
1098
1099        if (rxFifo.empty()) {
1100            devIntrPost(Regs::Intr_RxEmpty);
1101            rxEmpty = true;
1102        }
1103
1104        if (rxFifo.size() < regs.RxFifoLow)
1105            rxLow = true;
1106
1107        if (rxFifo.size() > regs.RxFifoHigh)
1108            rxLow = false;
1109
1110        devIntrPost(Regs::Intr_RxDMA);
1111        break;
1112
1113      default:
1114        panic("Invalid rxState!");
1115    }
1116
1117    DPRINTF(EthernetSM, "entering next rxState=%s\n",
1118            RxStateStrings[rxState]);
1119
1120    goto next;
1121
1122  exit:
1123    /**
1124     * @todo do we want to schedule a future kick?
1125     */
1126    DPRINTF(EthernetSM, "rx state machine exited rxState=%s\n",
1127            RxStateStrings[rxState]);
1128}
1129
1130void
1131Device::txDmaDone()
1132{
1133    assert(txState == txCopy);
1134    txState = txCopyDone;
1135    DPRINTF(EthernetDMA, "tx dma read paddr=%#x len=%d\n",
1136            txDmaAddr, txDmaLen);
1137    DDUMP(EthernetData, txDmaData, txDmaLen);
1138
1139    // If the receive state machine  has a pending DMA, let it go first
1140    if (rxState == rxBeginCopy)
1141        rxKick();
1142
1143    txKick();
1144}
1145
1146void
1147Device::transmit()
1148{
1149    if (txFifo.empty()) {
1150        DPRINTF(Ethernet, "nothing to transmit\n");
1151        return;
1152    }
1153
1154    uint32_t interrupts;
1155    EthPacketPtr packet = txFifo.front();
1156    if (!interface->sendPacket(packet)) {
1157        DPRINTF(Ethernet, "Packet Transmit: failed txFifo available %d\n",
1158                txFifo.avail());
1159        return;
1160    }
1161
1162    txFifo.pop();
1163#if TRACING_ON
1164    if (DTRACE(Ethernet)) {
1165        IpPtr ip(packet);
1166        if (ip) {
1167            DPRINTF(Ethernet, "ID is %d\n", ip->id());
1168            TcpPtr tcp(ip);
1169            if (tcp) {
1170                DPRINTF(Ethernet,
1171                        "Src Port=%d, Dest Port=%d, Seq=%d, Ack=%d\n",
1172                        tcp->sport(), tcp->dport(), tcp->seq(),
1173                        tcp->ack());
1174            }
1175        }
1176    }
1177#endif
1178
1179    DDUMP(EthernetData, packet->data, packet->length);
1180    txBytes += packet->length;
1181    txPackets++;
1182
1183    DPRINTF(Ethernet, "Packet Transmit: successful txFifo Available %d\n",
1184            txFifo.avail());
1185
1186    interrupts = Regs::Intr_TxPacket;
1187    if (txFifo.size() < regs.TxFifoLow)
1188        interrupts |= Regs::Intr_TxLow;
1189    devIntrPost(interrupts);
1190}
1191
1192void
1193Device::txKick()
1194{
1195    VirtualReg *vnic;
1196    DPRINTF(EthernetSM, "txKick: txState=%s (txFifo.size=%d)\n",
1197            TxStateStrings[txState], txFifo.size());
1198
1199    if (txKickTick > curTick) {
1200        DPRINTF(EthernetSM, "txKick: exiting, can't run till %d\n",
1201                txKickTick);
1202        return;
1203    }
1204
1205  next:
1206    if (txState == txIdle)
1207        goto exit;
1208
1209    assert(!txList.empty());
1210    vnic = &virtualRegs[txList.front()];
1211
1212    switch (txState) {
1213      case txFifoBlock:
1214        assert(Regs::get_TxDone_Busy(vnic->TxDone));
1215        if (!txPacket) {
1216            // Grab a new packet from the fifo.
1217            txPacket = new EthPacketData(16384);
1218            txPacketOffset = 0;
1219        }
1220
1221        if (txFifo.avail() - txPacket->length <
1222            Regs::get_TxData_Len(vnic->TxData)) {
1223            DPRINTF(EthernetSM, "transmit fifo full.  Nothing to do.\n");
1224            goto exit;
1225        }
1226
1227        txState = txBeginCopy;
1228        break;
1229
1230      case txBeginCopy:
1231        if (dmaPending() || getState() != Running)
1232            goto exit;
1233
1234        txDmaAddr = params()->platform->pciToDma(
1235                Regs::get_TxData_Addr(vnic->TxData));
1236        txDmaLen = Regs::get_TxData_Len(vnic->TxData);
1237        txDmaData = txPacket->data + txPacketOffset;
1238        txState = txCopy;
1239
1240        dmaRead(txDmaAddr, txDmaLen, &txDmaEvent, txDmaData);
1241        break;
1242
1243      case txCopy:
1244        DPRINTF(EthernetSM, "transmit machine still copying\n");
1245        goto exit;
1246
1247      case txCopyDone:
1248        vnic->TxDone = txDmaLen | Regs::TxDone_Complete;
1249        txPacket->length += txDmaLen;
1250        if ((vnic->TxData & Regs::TxData_More)) {
1251            txPacketOffset += txDmaLen;
1252            txState = txIdle;
1253            devIntrPost(Regs::Intr_TxDMA);
1254            break;
1255        }
1256
1257        assert(txPacket->length <= txFifo.avail());
1258        if ((vnic->TxData & Regs::TxData_Checksum)) {
1259            IpPtr ip(txPacket);
1260            if (ip) {
1261                TcpPtr tcp(ip);
1262                if (tcp) {
1263                    tcp->sum(0);
1264                    tcp->sum(cksum(tcp));
1265                    txTcpChecksums++;
1266                }
1267
1268                UdpPtr udp(ip);
1269                if (udp) {
1270                    udp->sum(0);
1271                    udp->sum(cksum(udp));
1272                    txUdpChecksums++;
1273                }
1274
1275                ip->sum(0);
1276                ip->sum(cksum(ip));
1277                txIpChecksums++;
1278            }
1279        }
1280
1281        txFifo.push(txPacket);
1282        if (txFifo.avail() < regs.TxMaxCopy) {
1283            devIntrPost(Regs::Intr_TxFull);
1284            txFull = true;
1285        }
1286        txPacket = 0;
1287        transmit();
1288        txList.pop_front();
1289        txState = txList.empty() ? txIdle : txFifoBlock;
1290        devIntrPost(Regs::Intr_TxDMA);
1291        break;
1292
1293      default:
1294        panic("Invalid txState!");
1295    }
1296
1297    DPRINTF(EthernetSM, "entering next txState=%s\n",
1298            TxStateStrings[txState]);
1299
1300    goto next;
1301
1302  exit:
1303    /**
1304     * @todo do we want to schedule a future kick?
1305     */
1306    DPRINTF(EthernetSM, "tx state machine exited txState=%s\n",
1307            TxStateStrings[txState]);
1308}
1309
1310void
1311Device::transferDone()
1312{
1313    if (txFifo.empty()) {
1314        DPRINTF(Ethernet, "transfer complete: txFifo empty...nothing to do\n");
1315        return;
1316    }
1317
1318    DPRINTF(Ethernet, "transfer complete: data in txFifo...schedule xmit\n");
1319
1320    reschedule(txEvent, curTick + ticks(1), true);
1321}
1322
1323bool
1324Device::rxFilter(const EthPacketPtr &packet)
1325{
1326    if (!Regs::get_Config_Filter(regs.Config))
1327        return false;
1328
1329    panic("receive filter not implemented\n");
1330    bool drop = true;
1331
1332#if 0
1333    string type;
1334
1335    EthHdr *eth = packet->eth();
1336    if (eth->unicast()) {
1337        // If we're accepting all unicast addresses
1338        if (acceptUnicast)
1339            drop = false;
1340
1341        // If we make a perfect match
1342        if (acceptPerfect && params->eaddr == eth.dst())
1343            drop = false;
1344
1345        if (acceptArp && eth->type() == ETH_TYPE_ARP)
1346            drop = false;
1347
1348    } else if (eth->broadcast()) {
1349        // if we're accepting broadcasts
1350        if (acceptBroadcast)
1351            drop = false;
1352
1353    } else if (eth->multicast()) {
1354        // if we're accepting all multicasts
1355        if (acceptMulticast)
1356            drop = false;
1357
1358    }
1359
1360    if (drop) {
1361        DPRINTF(Ethernet, "rxFilter drop\n");
1362        DDUMP(EthernetData, packet->data, packet->length);
1363    }
1364#endif
1365    return drop;
1366}
1367
1368bool
1369Device::recvPacket(EthPacketPtr packet)
1370{
1371    rxBytes += packet->length;
1372    rxPackets++;
1373
1374    DPRINTF(Ethernet, "Receiving packet from wire, rxFifo Available is %d\n",
1375            rxFifo.avail());
1376
1377    if (!rxEnable) {
1378        DPRINTF(Ethernet, "receive disabled...packet dropped\n");
1379        return true;
1380    }
1381
1382    if (rxFilter(packet)) {
1383        DPRINTF(Ethernet, "packet filtered...dropped\n");
1384        return true;
1385    }
1386
1387    if (rxFifo.size() >= regs.RxFifoHigh)
1388        devIntrPost(Regs::Intr_RxHigh);
1389
1390    if (!rxFifo.push(packet)) {
1391        DPRINTF(Ethernet,
1392                "packet will not fit in receive buffer...packet dropped\n");
1393        return false;
1394    }
1395
1396    // If we were at the last element, back up one ot go to the new
1397    // last element of the list.
1398    if (rxFifoPtr == rxFifo.end())
1399        --rxFifoPtr;
1400
1401    devIntrPost(Regs::Intr_RxPacket);
1402    rxKick();
1403    return true;
1404}
1405
1406void
1407Device::resume()
1408{
1409    SimObject::resume();
1410
1411    // During drain we could have left the state machines in a waiting state and
1412    // they wouldn't get out until some other event occured to kick them.
1413    // This way they'll get out immediately
1414    txKick();
1415    rxKick();
1416}
1417
1418//=====================================================================
1419//
1420//
1421void
1422Base::serialize(std::ostream &os)
1423{
1424    // Serialize the PciDev base class
1425    PciDev::serialize(os);
1426
1427    SERIALIZE_SCALAR(rxEnable);
1428    SERIALIZE_SCALAR(txEnable);
1429    SERIALIZE_SCALAR(cpuIntrEnable);
1430
1431    /*
1432     * Keep track of pending interrupt status.
1433     */
1434    SERIALIZE_SCALAR(intrTick);
1435    SERIALIZE_SCALAR(cpuPendingIntr);
1436    Tick intrEventTick = 0;
1437    if (intrEvent)
1438        intrEventTick = intrEvent->when();
1439    SERIALIZE_SCALAR(intrEventTick);
1440}
1441
1442void
1443Base::unserialize(Checkpoint *cp, const std::string &section)
1444{
1445    // Unserialize the PciDev base class
1446    PciDev::unserialize(cp, section);
1447
1448    UNSERIALIZE_SCALAR(rxEnable);
1449    UNSERIALIZE_SCALAR(txEnable);
1450    UNSERIALIZE_SCALAR(cpuIntrEnable);
1451
1452    /*
1453     * Keep track of pending interrupt status.
1454     */
1455    UNSERIALIZE_SCALAR(intrTick);
1456    UNSERIALIZE_SCALAR(cpuPendingIntr);
1457    Tick intrEventTick;
1458    UNSERIALIZE_SCALAR(intrEventTick);
1459    if (intrEventTick) {
1460        intrEvent = new IntrEvent(this, true);
1461        schedule(intrEvent, intrEventTick);
1462    }
1463}
1464
1465void
1466Device::serialize(std::ostream &os)
1467{
1468    int count;
1469
1470    // Serialize the PciDev base class
1471    Base::serialize(os);
1472
1473    if (rxState == rxCopy)
1474        panic("can't serialize with an in flight dma request rxState=%s",
1475              RxStateStrings[rxState]);
1476
1477    if (txState == txCopy)
1478        panic("can't serialize with an in flight dma request txState=%s",
1479              TxStateStrings[txState]);
1480
1481    /*
1482     * Serialize the device registers that could be modified by the OS.
1483     */
1484    SERIALIZE_SCALAR(regs.Config);
1485    SERIALIZE_SCALAR(regs.IntrStatus);
1486    SERIALIZE_SCALAR(regs.IntrMask);
1487    SERIALIZE_SCALAR(regs.RxData);
1488    SERIALIZE_SCALAR(regs.TxData);
1489
1490    /*
1491     * Serialize the virtual nic state
1492     */
1493    int virtualRegsSize = virtualRegs.size();
1494    SERIALIZE_SCALAR(virtualRegsSize);
1495    for (int i = 0; i < virtualRegsSize; ++i) {
1496        VirtualReg *vnic = &virtualRegs[i];
1497
1498        std::string reg = csprintf("vnic%d", i);
1499        paramOut(os, reg + ".RxData", vnic->RxData);
1500        paramOut(os, reg + ".RxDone", vnic->RxDone);
1501        paramOut(os, reg + ".TxData", vnic->TxData);
1502        paramOut(os, reg + ".TxDone", vnic->TxDone);
1503
1504        bool rxPacketExists = vnic->rxIndex != rxFifo.end();
1505        paramOut(os, reg + ".rxPacketExists", rxPacketExists);
1506        if (rxPacketExists) {
1507            int rxPacket = 0;
1508            PacketFifo::iterator i = rxFifo.begin();
1509            while (i != vnic->rxIndex) {
1510                assert(i != rxFifo.end());
1511                ++i;
1512                ++rxPacket;
1513            }
1514
1515            paramOut(os, reg + ".rxPacket", rxPacket);
1516            paramOut(os, reg + ".rxPacketOffset", vnic->rxPacketOffset);
1517            paramOut(os, reg + ".rxPacketBytes", vnic->rxPacketBytes);
1518        }
1519        paramOut(os, reg + ".rxDoneData", vnic->rxDoneData);
1520    }
1521
1522    int rxFifoPtr = -1;
1523    if (this->rxFifoPtr != rxFifo.end())
1524        rxFifoPtr = rxFifo.countPacketsBefore(this->rxFifoPtr);
1525    SERIALIZE_SCALAR(rxFifoPtr);
1526
1527    SERIALIZE_SCALAR(rxActive);
1528    SERIALIZE_SCALAR(rxBusyCount);
1529    SERIALIZE_SCALAR(rxDirtyCount);
1530    SERIALIZE_SCALAR(rxMappedCount);
1531
1532    VirtualList::iterator i, end;
1533    for (count = 0, i = rxList.begin(), end = rxList.end(); i != end; ++i)
1534        paramOut(os, csprintf("rxList%d", count++), *i);
1535    int rxListSize = count;
1536    SERIALIZE_SCALAR(rxListSize);
1537
1538    for (count = 0, i = rxBusy.begin(), end = rxBusy.end(); i != end; ++i)
1539        paramOut(os, csprintf("rxBusy%d", count++), *i);
1540    int rxBusySize = count;
1541    SERIALIZE_SCALAR(rxBusySize);
1542
1543    for (count = 0, i = txList.begin(), end = txList.end(); i != end; ++i)
1544        paramOut(os, csprintf("txList%d", count++), *i);
1545    int txListSize = count;
1546    SERIALIZE_SCALAR(txListSize);
1547
1548    /*
1549     * Serialize rx state machine
1550     */
1551    int rxState = this->rxState;
1552    SERIALIZE_SCALAR(rxState);
1553    SERIALIZE_SCALAR(rxEmpty);
1554    SERIALIZE_SCALAR(rxLow);
1555    rxFifo.serialize("rxFifo", os);
1556
1557    /*
1558     * Serialize tx state machine
1559     */
1560    int txState = this->txState;
1561    SERIALIZE_SCALAR(txState);
1562    SERIALIZE_SCALAR(txFull);
1563    txFifo.serialize("txFifo", os);
1564    bool txPacketExists = txPacket;
1565    SERIALIZE_SCALAR(txPacketExists);
1566    if (txPacketExists) {
1567        txPacket->serialize("txPacket", os);
1568        SERIALIZE_SCALAR(txPacketOffset);
1569        SERIALIZE_SCALAR(txPacketBytes);
1570    }
1571
1572    /*
1573     * If there's a pending transmit, store the time so we can
1574     * reschedule it later
1575     */
1576    Tick transmitTick = txEvent.scheduled() ? txEvent.when() - curTick : 0;
1577    SERIALIZE_SCALAR(transmitTick);
1578}
1579
1580void
1581Device::unserialize(Checkpoint *cp, const std::string &section)
1582{
1583    // Unserialize the PciDev base class
1584    Base::unserialize(cp, section);
1585
1586    /*
1587     * Unserialize the device registers that may have been written by the OS.
1588     */
1589    UNSERIALIZE_SCALAR(regs.Config);
1590    UNSERIALIZE_SCALAR(regs.IntrStatus);
1591    UNSERIALIZE_SCALAR(regs.IntrMask);
1592    UNSERIALIZE_SCALAR(regs.RxData);
1593    UNSERIALIZE_SCALAR(regs.TxData);
1594
1595    UNSERIALIZE_SCALAR(rxActive);
1596    UNSERIALIZE_SCALAR(rxBusyCount);
1597    UNSERIALIZE_SCALAR(rxDirtyCount);
1598    UNSERIALIZE_SCALAR(rxMappedCount);
1599
1600    int rxListSize;
1601    UNSERIALIZE_SCALAR(rxListSize);
1602    rxList.clear();
1603    for (int i = 0; i < rxListSize; ++i) {
1604        int value;
1605        paramIn(cp, section, csprintf("rxList%d", i), value);
1606        rxList.push_back(value);
1607    }
1608
1609    int rxBusySize;
1610    UNSERIALIZE_SCALAR(rxBusySize);
1611    rxBusy.clear();
1612    for (int i = 0; i < rxBusySize; ++i) {
1613        int value;
1614        paramIn(cp, section, csprintf("rxBusy%d", i), value);
1615        rxBusy.push_back(value);
1616    }
1617
1618    int txListSize;
1619    UNSERIALIZE_SCALAR(txListSize);
1620    txList.clear();
1621    for (int i = 0; i < txListSize; ++i) {
1622        int value;
1623        paramIn(cp, section, csprintf("txList%d", i), value);
1624        txList.push_back(value);
1625    }
1626
1627    /*
1628     * Unserialize rx state machine
1629     */
1630    int rxState;
1631    UNSERIALIZE_SCALAR(rxState);
1632    UNSERIALIZE_SCALAR(rxEmpty);
1633    UNSERIALIZE_SCALAR(rxLow);
1634    this->rxState = (RxState) rxState;
1635    rxFifo.unserialize("rxFifo", cp, section);
1636
1637    int rxFifoPtr;
1638    UNSERIALIZE_SCALAR(rxFifoPtr);
1639    if (rxFifoPtr >= 0) {
1640        this->rxFifoPtr = rxFifo.begin();
1641        for (int i = 0; i < rxFifoPtr; ++i)
1642            ++this->rxFifoPtr;
1643    } else {
1644        this->rxFifoPtr = rxFifo.end();
1645    }
1646
1647    /*
1648     * Unserialize tx state machine
1649     */
1650    int txState;
1651    UNSERIALIZE_SCALAR(txState);
1652    UNSERIALIZE_SCALAR(txFull);
1653    this->txState = (TxState) txState;
1654    txFifo.unserialize("txFifo", cp, section);
1655    bool txPacketExists;
1656    UNSERIALIZE_SCALAR(txPacketExists);
1657    txPacket = 0;
1658    if (txPacketExists) {
1659        txPacket = new EthPacketData(16384);
1660        txPacket->unserialize("txPacket", cp, section);
1661        UNSERIALIZE_SCALAR(txPacketOffset);
1662        UNSERIALIZE_SCALAR(txPacketBytes);
1663    }
1664
1665    /*
1666     * unserialize the virtual nic registers/state
1667     *
1668     * this must be done after the unserialization of the rxFifo
1669     * because the packet iterators depend on the fifo being populated
1670     */
1671    int virtualRegsSize;
1672    UNSERIALIZE_SCALAR(virtualRegsSize);
1673    virtualRegs.clear();
1674    virtualRegs.resize(virtualRegsSize);
1675    for (int i = 0; i < virtualRegsSize; ++i) {
1676        VirtualReg *vnic = &virtualRegs[i];
1677        std::string reg = csprintf("vnic%d", i);
1678
1679        paramIn(cp, section, reg + ".RxData", vnic->RxData);
1680        paramIn(cp, section, reg + ".RxDone", vnic->RxDone);
1681        paramIn(cp, section, reg + ".TxData", vnic->TxData);
1682        paramIn(cp, section, reg + ".TxDone", vnic->TxDone);
1683
1684        vnic->rxUnique = rxUnique++;
1685        vnic->txUnique = txUnique++;
1686
1687        bool rxPacketExists;
1688        paramIn(cp, section, reg + ".rxPacketExists", rxPacketExists);
1689        if (rxPacketExists) {
1690            int rxPacket;
1691            paramIn(cp, section, reg + ".rxPacket", rxPacket);
1692            vnic->rxIndex = rxFifo.begin();
1693            while (rxPacket--)
1694                ++vnic->rxIndex;
1695
1696            paramIn(cp, section, reg + ".rxPacketOffset",
1697                    vnic->rxPacketOffset);
1698            paramIn(cp, section, reg + ".rxPacketBytes", vnic->rxPacketBytes);
1699        } else {
1700            vnic->rxIndex = rxFifo.end();
1701        }
1702        paramIn(cp, section, reg + ".rxDoneData", vnic->rxDoneData);
1703    }
1704
1705    /*
1706     * If there's a pending transmit, reschedule it now
1707     */
1708    Tick transmitTick;
1709    UNSERIALIZE_SCALAR(transmitTick);
1710    if (transmitTick)
1711        schedule(txEvent, curTick + transmitTick);
1712
1713    pioPort->sendStatusChange(Port::RangeChange);
1714
1715}
1716
1717/* namespace Sinic */ }
1718
1719Sinic::Device *
1720SinicParams::create()
1721{
1722    return new Sinic::Device(this);
1723}
1724