sinic.cc revision 5882
12292SN/A/*
27597Sminkyu.jeong@arm.com * Copyright (c) 2004-2005 The Regents of The University of Michigan
37597Sminkyu.jeong@arm.com * All rights reserved.
47597Sminkyu.jeong@arm.com *
57597Sminkyu.jeong@arm.com * Redistribution and use in source and binary forms, with or without
67597Sminkyu.jeong@arm.com * modification, are permitted provided that the following conditions are
77597Sminkyu.jeong@arm.com * met: redistributions of source code must retain the above copyright
87597Sminkyu.jeong@arm.com * notice, this list of conditions and the following disclaimer;
97597Sminkyu.jeong@arm.com * redistributions in binary form must reproduce the above copyright
107597Sminkyu.jeong@arm.com * notice, this list of conditions and the following disclaimer in the
117597Sminkyu.jeong@arm.com * documentation and/or other materials provided with the distribution;
127597Sminkyu.jeong@arm.com * neither the name of the copyright holders nor the names of its
137597Sminkyu.jeong@arm.com * 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.
272292SN/A *
282292SN/A * Authors: Nathan Binkert
292292SN/A */
302292SN/A
312292SN/A#include <deque>
322292SN/A#include <limits>
332292SN/A#include <string>
342292SN/A
352292SN/A#include "arch/vtophys.hh"
362292SN/A#include "base/debug.hh"
372292SN/A#include "base/inet.hh"
382292SN/A#include "cpu/thread_context.hh"
392689Sktlim@umich.edu#include "cpu/intr_control.hh"
402689Sktlim@umich.edu#include "dev/etherlink.hh"
412689Sktlim@umich.edu#include "dev/sinic.hh"
422292SN/A#include "mem/packet.hh"
432292SN/A#include "mem/packet_access.hh"
448591Sgblack@eecs.umich.edu#include "sim/eventq.hh"
453326Sktlim@umich.edu#include "sim/host.hh"
468229Snate@binkert.org#include "sim/stats.hh"
476658Snate@binkert.org
482733Sktlim@umich.eduusing namespace std;
492907Sktlim@umich.eduusing namespace Net;
502292SN/Ausing namespace TheISA;
518232Snate@binkert.org
528232Snate@binkert.orgnamespace Sinic {
538232Snate@binkert.org
542722Sktlim@umich.educonst char *RxStateStrings[] =
552669Sktlim@umich.edu{
562292SN/A    "rxIdle",
572790Sktlim@umich.edu    "rxFifoBlock",
582790Sktlim@umich.edu    "rxBeginCopy",
592790Sktlim@umich.edu    "rxCopy",
602790Sktlim@umich.edu    "rxCopyDone"
612669Sktlim@umich.edu};
622678Sktlim@umich.edu
632678Sktlim@umich.educonst char *TxStateStrings[] =
648581Ssteve.reinhardt@amd.com{
658581Ssteve.reinhardt@amd.com    "txIdle",
662292SN/A    "txFifoBlock",
672292SN/A    "txBeginCopy",
682292SN/A    "txCopy",
692669Sktlim@umich.edu    "txCopyDone"
702292SN/A};
712678Sktlim@umich.edu
722292SN/A
732678Sktlim@umich.edu///////////////////////////////////////////////////////////////////////
742678Sktlim@umich.edu//
752678Sktlim@umich.edu// Sinic PCI Device
764319Sktlim@umich.edu//
774319Sktlim@umich.eduBase::Base(const Params *p)
784319Sktlim@umich.edu    : PciDev(p), rxEnable(false), txEnable(false), clock(p->clock),
794319Sktlim@umich.edu      intrDelay(p->intr_delay), intrTick(0), cpuIntrEnable(false),
804319Sktlim@umich.edu      cpuPendingIntr(false), intrEvent(0), interface(NULL)
812678Sktlim@umich.edu{
822678Sktlim@umich.edu}
832292SN/A
842678Sktlim@umich.eduDevice::Device(const Params *p)
852678Sktlim@umich.edu    : Base(p), rxUnique(0), txUnique(0),
865336Shines@cs.fsu.edu      virtualRegs(p->virtual_count < 1 ? 1 : p->virtual_count),
872678Sktlim@umich.edu      rxFifo(p->rx_fifo_size), txFifo(p->tx_fifo_size),
884873Sstever@eecs.umich.edu      rxKickTick(0), txKickTick(0),
892678Sktlim@umich.edu      txEvent(this), rxDmaEvent(this), txDmaEvent(this),
902292SN/A      dmaReadDelay(p->dma_read_delay), dmaReadFactor(p->dma_read_factor),
912678Sktlim@umich.edu      dmaWriteDelay(p->dma_write_delay), dmaWriteFactor(p->dma_write_factor)
922678Sktlim@umich.edu{
932678Sktlim@umich.edu    interface = new Interface(name() + ".int0", this);
942678Sktlim@umich.edu    reset();
952678Sktlim@umich.edu
962678Sktlim@umich.edu}
977852SMatt.Horsnell@arm.com
987852SMatt.Horsnell@arm.comDevice::~Device()
992344SN/A{}
1002678Sktlim@umich.edu
1012678Sktlim@umich.eduvoid
1024986Ssaidi@eecs.umich.eduDevice::regStats()
1034986Ssaidi@eecs.umich.edu{
1046974Stjones1@inf.ed.ac.uk    rxBytes
1056974Stjones1@inf.ed.ac.uk        .name(name() + ".rxBytes")
1066974Stjones1@inf.ed.ac.uk        .desc("Bytes Received")
1076974Stjones1@inf.ed.ac.uk        .prereq(rxBytes)
1086974Stjones1@inf.ed.ac.uk        ;
1096974Stjones1@inf.ed.ac.uk
1106974Stjones1@inf.ed.ac.uk    rxBandwidth
1112678Sktlim@umich.edu        .name(name() + ".rxBandwidth")
1122820Sktlim@umich.edu        .desc("Receive Bandwidth (bits/s)")
1132678Sktlim@umich.edu        .precision(0)
1142678Sktlim@umich.edu        .prereq(rxBytes)
1156974Stjones1@inf.ed.ac.uk        ;
1166974Stjones1@inf.ed.ac.uk
1176974Stjones1@inf.ed.ac.uk    rxPackets
1186974Stjones1@inf.ed.ac.uk        .name(name() + ".rxPackets")
1196974Stjones1@inf.ed.ac.uk        .desc("Number of Packets Received")
1206974Stjones1@inf.ed.ac.uk        .prereq(rxBytes)
1212678Sktlim@umich.edu        ;
1222678Sktlim@umich.edu
1232678Sktlim@umich.edu    rxPacketRate
1242678Sktlim@umich.edu        .name(name() + ".rxPPS")
1252678Sktlim@umich.edu        .desc("Packet Reception Rate (packets/s)")
1262344SN/A        .precision(0)
1272307SN/A        .prereq(rxBytes)
1286974Stjones1@inf.ed.ac.uk        ;
1296974Stjones1@inf.ed.ac.uk
1306974Stjones1@inf.ed.ac.uk    rxIpPackets
1316974Stjones1@inf.ed.ac.uk        .name(name() + ".rxIpPackets")
1322678Sktlim@umich.edu        .desc("Number of IP Packets Received")
1334032Sktlim@umich.edu        .prereq(rxBytes)
1342678Sktlim@umich.edu        ;
1352292SN/A
1362292SN/A    rxTcpPackets
1372292SN/A        .name(name() + ".rxTcpPackets")
1382292SN/A        .desc("Number of Packets Received")
1398545Ssaidi@eecs.umich.edu        .prereq(rxBytes)
1402678Sktlim@umich.edu        ;
1416974Stjones1@inf.ed.ac.uk
1422292SN/A    rxUdpPackets
1432292SN/A        .name(name() + ".rxUdpPackets")
1442292SN/A        .desc("Number of UDP Packets Received")
1452292SN/A        .prereq(rxBytes)
1462292SN/A        ;
1475529Snate@binkert.org
1485529Snate@binkert.org    rxIpChecksums
1495529Snate@binkert.org        .name(name() + ".rxIpChecksums")
1502292SN/A        .desc("Number of rx IP Checksums done by device")
1514329Sktlim@umich.edu        .precision(0)
1524329Sktlim@umich.edu        .prereq(rxBytes)
1534329Sktlim@umich.edu        ;
1544329Sktlim@umich.edu
1552292SN/A    rxTcpChecksums
1562307SN/A        .name(name() + ".rxTcpChecksums")
1572307SN/A        .desc("Number of rx TCP Checksums done by device")
1588545Ssaidi@eecs.umich.edu        .precision(0)
1598545Ssaidi@eecs.umich.edu        .prereq(rxBytes)
1602907Sktlim@umich.edu        ;
1612907Sktlim@umich.edu
1622292SN/A    rxUdpChecksums
1632292SN/A        .name(name() + ".rxUdpChecksums")
1642329SN/A        .desc("Number of rx UDP Checksums done by device")
1652329SN/A        .precision(0)
1662329SN/A        .prereq(rxBytes)
1672292SN/A        ;
1682292SN/A
1692292SN/A    totBandwidth
1702292SN/A        .name(name() + ".totBandwidth")
1718199SAli.Saidi@ARM.com        .desc("Total Bandwidth (bits/s)")
1728199SAli.Saidi@ARM.com        .precision(0)
1738199SAli.Saidi@ARM.com        .prereq(totBytes)
1742292SN/A        ;
1752292SN/A
1762292SN/A    totPackets
1772292SN/A        .name(name() + ".totPackets")
1782292SN/A        .desc("Total Packets")
1792292SN/A        .precision(0)
1802292SN/A        .prereq(totBytes)
1813492Sktlim@umich.edu        ;
1822329SN/A
1832292SN/A    totBytes
1842292SN/A        .name(name() + ".totBytes")
1852292SN/A        .desc("Total Bytes")
1862292SN/A        .precision(0)
1872292SN/A        .prereq(totBytes)
1882292SN/A        ;
1892292SN/A
1902292SN/A    totPacketRate
1912292SN/A        .name(name() + ".totPPS")
1922292SN/A        .desc("Total Tranmission Rate (packets/s)")
1932292SN/A        .precision(0)
1948247Snate@binkert.org        .prereq(totBytes)
1952292SN/A        ;
1962292SN/A
1972292SN/A    txBytes
1982292SN/A        .name(name() + ".txBytes")
1992292SN/A        .desc("Bytes Transmitted")
2002727Sktlim@umich.edu        .prereq(txBytes)
2012727Sktlim@umich.edu        ;
2022727Sktlim@umich.edu
2032727Sktlim@umich.edu    txBandwidth
2042727Sktlim@umich.edu        .name(name() + ".txBandwidth")
2052727Sktlim@umich.edu        .desc("Transmit Bandwidth (bits/s)")
2062727Sktlim@umich.edu        .precision(0)
2072727Sktlim@umich.edu        .prereq(txBytes)
2082727Sktlim@umich.edu        ;
2092727Sktlim@umich.edu
2102727Sktlim@umich.edu    txPackets
2112727Sktlim@umich.edu        .name(name() + ".txPackets")
2122727Sktlim@umich.edu        .desc("Number of Packets Transmitted")
2132727Sktlim@umich.edu        .prereq(txBytes)
2142727Sktlim@umich.edu        ;
2152727Sktlim@umich.edu
2162727Sktlim@umich.edu    txPacketRate
2172727Sktlim@umich.edu        .name(name() + ".txPPS")
2182361SN/A        .desc("Packet Tranmission Rate (packets/s)")
2192361SN/A        .precision(0)
2202361SN/A        .prereq(txBytes)
2212361SN/A        ;
2222727Sktlim@umich.edu
2232727Sktlim@umich.edu    txIpPackets
2242727Sktlim@umich.edu        .name(name() + ".txIpPackets")
2252727Sktlim@umich.edu        .desc("Number of IP Packets Transmitted")
2262727Sktlim@umich.edu        .prereq(txBytes)
2272727Sktlim@umich.edu        ;
2282727Sktlim@umich.edu
2292727Sktlim@umich.edu    txTcpPackets
2302727Sktlim@umich.edu        .name(name() + ".txTcpPackets")
2312727Sktlim@umich.edu        .desc("Number of TCP Packets Transmitted")
2322727Sktlim@umich.edu        .prereq(txBytes)
2332727Sktlim@umich.edu        ;
2342727Sktlim@umich.edu
2352727Sktlim@umich.edu    txUdpPackets
2362727Sktlim@umich.edu        .name(name() + ".txUdpPackets")
2372727Sktlim@umich.edu        .desc("Number of Packets Transmitted")
2382727Sktlim@umich.edu        .prereq(txBytes)
2392727Sktlim@umich.edu        ;
2402727Sktlim@umich.edu
2412727Sktlim@umich.edu    txIpChecksums
2422727Sktlim@umich.edu        .name(name() + ".txIpChecksums")
2432727Sktlim@umich.edu        .desc("Number of tx IP Checksums done by device")
2442727Sktlim@umich.edu        .precision(0)
2454329Sktlim@umich.edu        .prereq(txBytes)
2464329Sktlim@umich.edu        ;
2474329Sktlim@umich.edu
2484329Sktlim@umich.edu    txTcpChecksums
2494329Sktlim@umich.edu        .name(name() + ".txTcpChecksums")
2504329Sktlim@umich.edu        .desc("Number of tx TCP Checksums done by device")
2514329Sktlim@umich.edu        .precision(0)
2524329Sktlim@umich.edu        .prereq(txBytes)
2534329Sktlim@umich.edu        ;
2544329Sktlim@umich.edu
2554329Sktlim@umich.edu    txUdpChecksums
2564329Sktlim@umich.edu        .name(name() + ".txUdpChecksums")
2574329Sktlim@umich.edu        .desc("Number of tx UDP Checksums done by device")
2582292SN/A        .precision(0)
2592292SN/A        .prereq(txBytes)
2602292SN/A        ;
2612292SN/A
2622292SN/A    txBandwidth = txBytes * Stats::constant(8) / simSeconds;
2632292SN/A    rxBandwidth = rxBytes * Stats::constant(8) / simSeconds;
2642292SN/A    totBandwidth = txBandwidth + rxBandwidth;
2652292SN/A    totBytes = txBytes + rxBytes;
2662292SN/A    totPackets = txPackets + rxPackets;
2672292SN/A    txPacketRate = txPackets / simSeconds;
2682292SN/A    rxPacketRate = rxPackets / simSeconds;
2692292SN/A
2702292SN/A    _maxVnicDistance = 0;
2712292SN/A
2722307SN/A    maxVnicDistance
2732307SN/A        .name(name() + ".maxVnicDistance")
2742307SN/A        .desc("maximum vnic distance")
2752367SN/A        ;
2762367SN/A
2772307SN/A    totalVnicDistance
2782367SN/A        .name(name() + ".totalVnicDistance")
2792307SN/A        .desc("total vnic distance")
2802329SN/A        ;
2812307SN/A    numVnicDistance
2822307SN/A        .name(name() + ".numVnicDistance")
2832307SN/A        .desc("number of vnic distance measurements")
2842307SN/A        ;
2852307SN/A
2862307SN/A    avgVnicDistance
2872307SN/A        .name(name() + ".avgVnicDistance")
2882307SN/A        .desc("average vnic distance")
2892307SN/A        ;
2902307SN/A
2912307SN/A    avgVnicDistance = totalVnicDistance / numVnicDistance;
2922307SN/A}
2932307SN/A
2942307SN/Avoid
2952307SN/ADevice::resetStats()
2962329SN/A{
2972307SN/A    _maxVnicDistance = 0;
2982307SN/A}
2992307SN/A
3002307SN/AEtherInt*
3012307SN/ADevice::getEthPort(const std::string &if_name, int idx)
3022307SN/A{
3038545Ssaidi@eecs.umich.edu    if (if_name == "interface") {
3048545Ssaidi@eecs.umich.edu        if (interface->getPeer())
3058545Ssaidi@eecs.umich.edu            panic("interface already connected to\n");
3062307SN/A
3072307SN/A        return interface;
3082307SN/A    }
3092307SN/A    return NULL;
3102292SN/A}
3112292SN/A
3122329SN/A
3132329SN/Avoid
3142292SN/ADevice::prepareIO(int cpu, int index)
3152329SN/A{
3162329SN/A    int size = virtualRegs.size();
3172292SN/A    if (index > size)
3182292SN/A        panic("Trying to access a vnic that doesn't exist %d > %d\n",
3192292SN/A              index, size);
3202292SN/A}
3212292SN/A
3222329SN/A//add stats for head of line blocking
3232292SN/A//add stats for average fifo length
3242292SN/A//add stats for average number of vnics busy
3252292SN/A
3262292SN/Avoid
3272292SN/ADevice::prepareRead(int cpu, int index)
3282292SN/A{
3292292SN/A    using namespace Regs;
3302292SN/A    prepareIO(cpu, index);
3312329SN/A
3322329SN/A    VirtualReg &vnic = virtualRegs[index];
3332329SN/A
3342292SN/A    // update rx registers
3352292SN/A    uint64_t rxdone = vnic.RxDone;
3362292SN/A    rxdone = set_RxDone_Packets(rxdone, rxFifo.countPacketsAfter(rxFifoPtr));
3372292SN/A    rxdone = set_RxDone_Empty(rxdone, rxFifo.empty());
3382292SN/A    rxdone = set_RxDone_High(rxdone, rxFifo.size() > regs.RxFifoHigh);
3392329SN/A    rxdone = set_RxDone_NotHigh(rxdone, rxLow);
3402292SN/A    regs.RxData = vnic.RxData;
3412292SN/A    regs.RxDone = rxdone;
3422292SN/A    regs.RxWait = rxdone;
3432292SN/A
3442292SN/A    // update tx regsiters
3452292SN/A    uint64_t txdone = vnic.TxDone;
3462292SN/A    txdone = set_TxDone_Packets(txdone, txFifo.packets());
3472292SN/A    txdone = set_TxDone_Full(txdone, txFifo.avail() < regs.TxMaxCopy);
3482292SN/A    txdone = set_TxDone_Low(txdone, txFifo.size() < regs.TxFifoLow);
3492292SN/A    regs.TxData = vnic.TxData;
3502292SN/A    regs.TxDone = txdone;
3512292SN/A    regs.TxWait = txdone;
3522292SN/A
3532292SN/A    int head = 0xffff;
3542292SN/A
3552292SN/A    if (!rxFifo.empty()) {
3562292SN/A        int vnic = rxFifo.begin()->priv;
3572292SN/A        if (vnic != -1 && virtualRegs[vnic].rxPacketOffset > 0)
3582292SN/A            head = vnic;
3592292SN/A    }
3602292SN/A
3612292SN/A    regs.RxStatus = set_RxStatus_Head(regs.RxStatus, head);
3622292SN/A    regs.RxStatus = set_RxStatus_Busy(regs.RxStatus, rxBusyCount);
3632292SN/A    regs.RxStatus = set_RxStatus_Mapped(regs.RxStatus, rxMappedCount);
3642329SN/A    regs.RxStatus = set_RxStatus_Dirty(regs.RxStatus, rxDirtyCount);
3652329SN/A}
3662292SN/A
3677720Sgblack@eecs.umich.eduvoid
3687720Sgblack@eecs.umich.eduDevice::prepareWrite(int cpu, int index)
3692292SN/A{
3702292SN/A    prepareIO(cpu, index);
3712292SN/A}
3722292SN/A
3732292SN/A/**
3742292SN/A * I/O read of device register
3752292SN/A */
3762292SN/ATick
3772292SN/ADevice::read(PacketPtr pkt)
3782292SN/A{
3792292SN/A    assert(config.command & PCI_CMD_MSE);
3802292SN/A    assert(pkt->getAddr() >= BARAddrs[0] && pkt->getSize() < BARSize[0]);
3812292SN/A
3822292SN/A    int cpu = pkt->req->contextId();
3832292SN/A    Addr daddr = pkt->getAddr() - BARAddrs[0];
3842292SN/A    Addr index = daddr >> Regs::VirtualShift;
3852292SN/A    Addr raddr = daddr & Regs::VirtualMask;
3862292SN/A
3872292SN/A    pkt->allocate();
3882292SN/A
3892292SN/A    if (!regValid(raddr))
3902292SN/A        panic("invalid register: cpu=%d vnic=%d da=%#x pa=%#x size=%d",
3912292SN/A              cpu, index, daddr, pkt->getAddr(), pkt->getSize());
3922292SN/A
3937720Sgblack@eecs.umich.edu    const Regs::Info &info = regInfo(raddr);
3947720Sgblack@eecs.umich.edu    if (!info.read)
3952292SN/A        panic("read %s (write only): "
3962292SN/A              "cpu=%d vnic=%d da=%#x pa=%#x size=%d",
3972292SN/A              info.name, cpu, index, daddr, pkt->getAddr(), pkt->getSize());
3982292SN/A
3992292SN/A        panic("read %s (invalid size): "
4002292SN/A              "cpu=%d vnic=%d da=%#x pa=%#x size=%d",
4012292SN/A              info.name, cpu, index, daddr, pkt->getAddr(), pkt->getSize());
4022292SN/A
4032292SN/A    prepareRead(cpu, index);
4042292SN/A
4052292SN/A    uint64_t value = 0;
4062292SN/A    if (pkt->getSize() == 4) {
4072292SN/A        uint32_t reg = regData32(raddr);
4082292SN/A        pkt->set(reg);
4092292SN/A        value = reg;
4102292SN/A    }
4112292SN/A
4122292SN/A    if (pkt->getSize() == 8) {
4132292SN/A        uint64_t reg = regData64(raddr);
4142292SN/A        pkt->set(reg);
4152292SN/A        value = reg;
4162292SN/A    }
4172292SN/A
4182292SN/A    DPRINTF(EthernetPIO,
4192292SN/A            "read %s: cpu=%d vnic=%d da=%#x pa=%#x size=%d val=%#x\n",
4202292SN/A            info.name, cpu, index, daddr, pkt->getAddr(), pkt->getSize(), value);
4212292SN/A
4222292SN/A    // reading the interrupt status register has the side effect of
4232292SN/A    // clearing it
4242292SN/A    if (raddr == Regs::IntrStatus)
4252292SN/A        devIntrClear();
4262292SN/A
4272292SN/A    return pioDelay;
4282292SN/A}
4292292SN/A
4302292SN/A/**
4312292SN/A * IPR read of device register
4322292SN/A
4332292SN/A    Fault
4342292SN/ADevice::iprRead(Addr daddr, int cpu, uint64_t &result)
4352292SN/A{
4362292SN/A    if (!regValid(daddr))
4372292SN/A        panic("invalid address: da=%#x", daddr);
4382292SN/A
4392292SN/A    const Regs::Info &info = regInfo(daddr);
4402292SN/A    if (!info.read)
4412292SN/A        panic("reading %s (write only): cpu=%d da=%#x", info.name, cpu, daddr);
4422292SN/A
4432292SN/A    DPRINTF(EthernetPIO, "IPR read %s: cpu=%d da=%#x\n",
4442292SN/A            info.name, cpu, daddr);
4452292SN/A
4462292SN/A    prepareRead(cpu, 0);
4472292SN/A
4482292SN/A    if (info.size == 4)
4492292SN/A        result = regData32(daddr);
4502292SN/A
4512292SN/A    if (info.size == 8)
4528545Ssaidi@eecs.umich.edu        result = regData64(daddr);
4538545Ssaidi@eecs.umich.edu
4548545Ssaidi@eecs.umich.edu    DPRINTF(EthernetPIO, "IPR read %s: cpu=%s da=%#x val=%#x\n",
4558545Ssaidi@eecs.umich.edu            info.name, cpu, result);
4568545Ssaidi@eecs.umich.edu
4578545Ssaidi@eecs.umich.edu    return NoFault;
4588545Ssaidi@eecs.umich.edu}
4598545Ssaidi@eecs.umich.edu*/
4608545Ssaidi@eecs.umich.edu/**
4618545Ssaidi@eecs.umich.edu * I/O write of device register
4628545Ssaidi@eecs.umich.edu */
4638545Ssaidi@eecs.umich.eduTick
4648545Ssaidi@eecs.umich.eduDevice::write(PacketPtr pkt)
4658545Ssaidi@eecs.umich.edu{
4668545Ssaidi@eecs.umich.edu    assert(config.command & PCI_CMD_MSE);
4678545Ssaidi@eecs.umich.edu    assert(pkt->getAddr() >= BARAddrs[0] && pkt->getSize() < BARSize[0]);
4688545Ssaidi@eecs.umich.edu
4698545Ssaidi@eecs.umich.edu    int cpu = pkt->req->contextId();
4708545Ssaidi@eecs.umich.edu    Addr daddr = pkt->getAddr() - BARAddrs[0];
4718545Ssaidi@eecs.umich.edu    Addr index = daddr >> Regs::VirtualShift;
4728545Ssaidi@eecs.umich.edu    Addr raddr = daddr & Regs::VirtualMask;
4738545Ssaidi@eecs.umich.edu
4748545Ssaidi@eecs.umich.edu    if (!regValid(raddr))
4758545Ssaidi@eecs.umich.edu        panic("invalid register: cpu=%d, da=%#x pa=%#x size=%d",
4768545Ssaidi@eecs.umich.edu                cpu, daddr, pkt->getAddr(), pkt->getSize());
4778545Ssaidi@eecs.umich.edu
4788545Ssaidi@eecs.umich.edu    const Regs::Info &info = regInfo(raddr);
4798545Ssaidi@eecs.umich.edu    if (!info.write)
4808545Ssaidi@eecs.umich.edu        panic("write %s (read only): "
4818545Ssaidi@eecs.umich.edu              "cpu=%d vnic=%d da=%#x pa=%#x size=%d",
4828545Ssaidi@eecs.umich.edu              info.name, cpu, index, daddr, pkt->getAddr(), pkt->getSize());
4838545Ssaidi@eecs.umich.edu
4848545Ssaidi@eecs.umich.edu    if (pkt->getSize() != info.size)
4858545Ssaidi@eecs.umich.edu        panic("write %s (invalid size): "
4868545Ssaidi@eecs.umich.edu              "cpu=%d vnic=%d da=%#x pa=%#x size=%d",
4878545Ssaidi@eecs.umich.edu              info.name, cpu, index, daddr, pkt->getAddr(), pkt->getSize());
4888545Ssaidi@eecs.umich.edu
4898545Ssaidi@eecs.umich.edu    VirtualReg &vnic = virtualRegs[index];
4908545Ssaidi@eecs.umich.edu
4918545Ssaidi@eecs.umich.edu    DPRINTF(EthernetPIO,
4928545Ssaidi@eecs.umich.edu            "write %s vnic %d: cpu=%d val=%#x da=%#x pa=%#x size=%d\n",
4938545Ssaidi@eecs.umich.edu            info.name, index, cpu, info.size == 4 ? pkt->get<uint32_t>() :
4948545Ssaidi@eecs.umich.edu            pkt->get<uint64_t>(), daddr, pkt->getAddr(), pkt->getSize());
4958545Ssaidi@eecs.umich.edu
4968545Ssaidi@eecs.umich.edu    prepareWrite(cpu, index);
4978545Ssaidi@eecs.umich.edu
4988545Ssaidi@eecs.umich.edu    switch (raddr) {
4998545Ssaidi@eecs.umich.edu      case Regs::Config:
5008545Ssaidi@eecs.umich.edu        changeConfig(pkt->get<uint32_t>());
5018545Ssaidi@eecs.umich.edu        break;
5028545Ssaidi@eecs.umich.edu
5038545Ssaidi@eecs.umich.edu      case Regs::Command:
5048545Ssaidi@eecs.umich.edu        command(pkt->get<uint32_t>());
5058545Ssaidi@eecs.umich.edu        break;
5062292SN/A
5078199SAli.Saidi@ARM.com      case Regs::IntrStatus:
5088199SAli.Saidi@ARM.com        devIntrClear(regs.IntrStatus & pkt->get<uint32_t>());
5098199SAli.Saidi@ARM.com        break;
5108199SAli.Saidi@ARM.com
5118199SAli.Saidi@ARM.com      case Regs::IntrMask:
5128199SAli.Saidi@ARM.com        devIntrChangeMask(pkt->get<uint32_t>());
5138199SAli.Saidi@ARM.com        break;
5148199SAli.Saidi@ARM.com
5158199SAli.Saidi@ARM.com      case Regs::RxData:
5168199SAli.Saidi@ARM.com        if (Regs::get_RxDone_Busy(vnic.RxDone))
5178199SAli.Saidi@ARM.com            panic("receive machine busy with another request! rxState=%s",
5188199SAli.Saidi@ARM.com                  RxStateStrings[rxState]);
5198199SAli.Saidi@ARM.com
5208199SAli.Saidi@ARM.com        vnic.rxUnique = rxUnique++;
5218199SAli.Saidi@ARM.com        vnic.RxDone = Regs::RxDone_Busy;
5228199SAli.Saidi@ARM.com        vnic.RxData = pkt->get<uint64_t>();
5238199SAli.Saidi@ARM.com        rxBusyCount++;
5248199SAli.Saidi@ARM.com
5258199SAli.Saidi@ARM.com        if (Regs::get_RxData_Vaddr(pkt->get<uint64_t>())) {
5268199SAli.Saidi@ARM.com            panic("vtophys not implemented in newmem");
5278199SAli.Saidi@ARM.com#ifdef SINIC_VTOPHYS
5288272SAli.Saidi@ARM.com            Addr vaddr = Regs::get_RxData_Addr(reg64);
5298545Ssaidi@eecs.umich.edu            Addr paddr = vtophys(req->xc, vaddr);
5308545Ssaidi@eecs.umich.edu            DPRINTF(EthernetPIO, "write RxData vnic %d (rxunique %d): "
5318545Ssaidi@eecs.umich.edu                    "vaddr=%#x, paddr=%#x\n",
5328545Ssaidi@eecs.umich.edu                    index, vnic.rxUnique, vaddr, paddr);
5338545Ssaidi@eecs.umich.edu
5348545Ssaidi@eecs.umich.edu            vnic.RxData = Regs::set_RxData_Addr(vnic.RxData, paddr);
5358545Ssaidi@eecs.umich.edu#endif
5368545Ssaidi@eecs.umich.edu        } else {
5378545Ssaidi@eecs.umich.edu            DPRINTF(EthernetPIO, "write RxData vnic %d (rxunique %d)\n",
5388545Ssaidi@eecs.umich.edu                    index, vnic.rxUnique);
5398545Ssaidi@eecs.umich.edu        }
5408199SAli.Saidi@ARM.com
5418545Ssaidi@eecs.umich.edu        if (vnic.rxIndex == rxFifo.end()) {
5428199SAli.Saidi@ARM.com            DPRINTF(EthernetPIO, "request new packet...appending to rxList\n");
5438591Sgblack@eecs.umich.edu            rxList.push_back(index);
5448591Sgblack@eecs.umich.edu        } else {
5458591Sgblack@eecs.umich.edu            DPRINTF(EthernetPIO, "packet exists...appending to rxBusy\n");
5468591Sgblack@eecs.umich.edu            rxBusy.push_back(index);
5478545Ssaidi@eecs.umich.edu        }
5488545Ssaidi@eecs.umich.edu
5498199SAli.Saidi@ARM.com        if (rxEnable && (rxState == rxIdle || rxState == rxFifoBlock)) {
5508545Ssaidi@eecs.umich.edu            rxState = rxFifoBlock;
5518545Ssaidi@eecs.umich.edu            rxKick();
5528545Ssaidi@eecs.umich.edu        }
5538545Ssaidi@eecs.umich.edu        break;
5548545Ssaidi@eecs.umich.edu
5558545Ssaidi@eecs.umich.edu      case Regs::TxData:
5568545Ssaidi@eecs.umich.edu        if (Regs::get_TxDone_Busy(vnic.TxDone))
5578545Ssaidi@eecs.umich.edu            panic("transmit machine busy with another request! txState=%s",
5588545Ssaidi@eecs.umich.edu                  TxStateStrings[txState]);
5598545Ssaidi@eecs.umich.edu
5608545Ssaidi@eecs.umich.edu        vnic.txUnique = txUnique++;
5618545Ssaidi@eecs.umich.edu        vnic.TxDone = Regs::TxDone_Busy;
5628545Ssaidi@eecs.umich.edu
5638545Ssaidi@eecs.umich.edu        if (Regs::get_TxData_Vaddr(pkt->get<uint64_t>())) {
5648545Ssaidi@eecs.umich.edu            panic("vtophys won't work here in newmem.\n");
5658545Ssaidi@eecs.umich.edu#ifdef SINIC_VTOPHYS
5668545Ssaidi@eecs.umich.edu            Addr vaddr = Regs::get_TxData_Addr(reg64);
5678545Ssaidi@eecs.umich.edu            Addr paddr = vtophys(req->xc, vaddr);
5688545Ssaidi@eecs.umich.edu            DPRINTF(EthernetPIO, "write TxData vnic %d (txunique %d): "
5698545Ssaidi@eecs.umich.edu                    "vaddr=%#x, paddr=%#x\n",
5708591Sgblack@eecs.umich.edu                    index, vnic.txUnique, vaddr, paddr);
5718591Sgblack@eecs.umich.edu
5728591Sgblack@eecs.umich.edu            vnic.TxData = Regs::set_TxData_Addr(vnic.TxData, paddr);
5738545Ssaidi@eecs.umich.edu#endif
5748199SAli.Saidi@ARM.com        } else {
5758199SAli.Saidi@ARM.com            DPRINTF(EthernetPIO, "write TxData vnic %d (txunique %d)\n",
5768199SAli.Saidi@ARM.com                    index, vnic.txUnique);
5778199SAli.Saidi@ARM.com        }
5788199SAli.Saidi@ARM.com
5798199SAli.Saidi@ARM.com        if (txList.empty() || txList.front() != index)
5808199SAli.Saidi@ARM.com            txList.push_back(index);
5818199SAli.Saidi@ARM.com        if (txEnable && txState == txIdle && txList.front() == index) {
5828199SAli.Saidi@ARM.com            txState = txFifoBlock;
5838199SAli.Saidi@ARM.com            txKick();
5848199SAli.Saidi@ARM.com        }
5858199SAli.Saidi@ARM.com        break;
5862292SN/A    }
5872292SN/A
5884032Sktlim@umich.edu    return pioDelay;
5892292SN/A}
5902292SN/A
5912292SN/Avoid
5927720Sgblack@eecs.umich.eduDevice::devIntrPost(uint32_t interrupts)
5937944SGiacomo.Gabrielli@arm.com{
5942292SN/A    if ((interrupts & Regs::Intr_Res))
5954032Sktlim@umich.edu        panic("Cannot set a reserved interrupt");
5964032Sktlim@umich.edu
5972669Sktlim@umich.edu    regs.IntrStatus |= interrupts;
5982292SN/A
5997944SGiacomo.Gabrielli@arm.com    DPRINTF(EthernetIntr,
6007944SGiacomo.Gabrielli@arm.com            "interrupt written to intStatus: intr=%#x status=%#x mask=%#x\n",
6017944SGiacomo.Gabrielli@arm.com            interrupts, regs.IntrStatus, regs.IntrMask);
6027944SGiacomo.Gabrielli@arm.com
6037597Sminkyu.jeong@arm.com    interrupts = regs.IntrStatus & regs.IntrMask;
6047597Sminkyu.jeong@arm.com
6057597Sminkyu.jeong@arm.com    // Intr_RxHigh is special, we only signal it if we've emptied the fifo
6062329SN/A    // and then filled it above the high watermark
6072329SN/A    if (rxEmpty)
6082367SN/A        rxEmpty = false;
6092367SN/A    else
6107848SAli.Saidi@ARM.com        interrupts &= ~Regs::Intr_RxHigh;
6117848SAli.Saidi@ARM.com
6127600Sminkyu.jeong@arm.com    // Intr_TxLow is special, we only signal it if we've filled up the fifo
6137600Sminkyu.jeong@arm.com    // and then dropped below the low watermark
6147600Sminkyu.jeong@arm.com    if (txFull)
6154032Sktlim@umich.edu        txFull = false;
6163731Sktlim@umich.edu    else
6172367SN/A        interrupts &= ~Regs::Intr_TxLow;
6182367SN/A
6192292SN/A    if (interrupts) {
6202292SN/A        Tick when = curTick;
6214032Sktlim@umich.edu        if ((interrupts & Regs::Intr_NoDelay) == 0)
6224032Sktlim@umich.edu            when += intrDelay;
6234032Sktlim@umich.edu        cpuIntrPost(when);
6244032Sktlim@umich.edu    }
6254032Sktlim@umich.edu}
6268199SAli.Saidi@ARM.com
6278199SAli.Saidi@ARM.comvoid
6282292SN/ADevice::devIntrClear(uint32_t interrupts)
6292292SN/A{
6302292SN/A    if ((interrupts & Regs::Intr_Res))
6312292SN/A        panic("Cannot clear a reserved interrupt");
6322292SN/A
6332292SN/A    regs.IntrStatus &= ~interrupts;
6342292SN/A
6352292SN/A    DPRINTF(EthernetIntr,
6362292SN/A            "interrupt cleared from intStatus: intr=%x status=%x mask=%x\n",
6372292SN/A            interrupts, regs.IntrStatus, regs.IntrMask);
6382292SN/A
6392292SN/A    if (!(regs.IntrStatus & regs.IntrMask))
6402292SN/A        cpuIntrClear();
6412292SN/A}
6422292SN/A
6437720Sgblack@eecs.umich.eduvoid
6447720Sgblack@eecs.umich.eduDevice::devIntrChangeMask(uint32_t newmask)
6452292SN/A{
6464032Sktlim@umich.edu    if (regs.IntrMask == newmask)
6474032Sktlim@umich.edu        return;
6482292SN/A
6492292SN/A    regs.IntrMask = newmask;
6502292SN/A
6512292SN/A    DPRINTF(EthernetIntr,
6522292SN/A            "interrupt mask changed: intStatus=%x intMask=%x masked=%x\n",
6532292SN/A            regs.IntrStatus, regs.IntrMask, regs.IntrStatus & regs.IntrMask);
6547944SGiacomo.Gabrielli@arm.com
6557944SGiacomo.Gabrielli@arm.com    if (regs.IntrStatus & regs.IntrMask)
6567944SGiacomo.Gabrielli@arm.com        cpuIntrPost(curTick);
6577944SGiacomo.Gabrielli@arm.com    else
6587848SAli.Saidi@ARM.com        cpuIntrClear();
6597848SAli.Saidi@ARM.com}
6607848SAli.Saidi@ARM.com
6612329SN/Avoid
6627782Sminkyu.jeong@arm.comBase::cpuIntrPost(Tick when)
6637720Sgblack@eecs.umich.edu{
6642292SN/A    // If the interrupt you want to post is later than an interrupt
6652292SN/A    // already scheduled, just let it post in the coming one and don't
6667782Sminkyu.jeong@arm.com    // schedule another.
6677782Sminkyu.jeong@arm.com    // HOWEVER, must be sure that the scheduled intrTick is in the
6687782Sminkyu.jeong@arm.com    // future (this was formerly the source of a bug)
6697782Sminkyu.jeong@arm.com    /**
6702292SN/A     * @todo this warning should be removed and the intrTick code should
6712292SN/A     * be fixed.
6722292SN/A     */
6732292SN/A    assert(when >= curTick);
6742336SN/A    assert(intrTick >= curTick || intrTick == 0);
6752336SN/A    if (!cpuIntrEnable) {
6762336SN/A        DPRINTF(EthernetIntr, "interrupts not enabled.\n",
6772329SN/A                intrTick);
6782292SN/A        return;
6792329SN/A    }
6802292SN/A
6812292SN/A    if (when > intrTick && intrTick != 0) {
6828199SAli.Saidi@ARM.com        DPRINTF(EthernetIntr, "don't need to schedule event...intrTick=%d\n",
6832292SN/A                intrTick);
6842292SN/A        return;
6852292SN/A    }
6862292SN/A
6872292SN/A    intrTick = when;
6882292SN/A    if (intrTick < curTick) {
6892292SN/A        debug_break();
6902292SN/A        intrTick = curTick;
6912292SN/A    }
6927720Sgblack@eecs.umich.edu
6937720Sgblack@eecs.umich.edu    DPRINTF(EthernetIntr, "going to schedule an interrupt for intrTick=%d\n",
6942292SN/A            intrTick);
6952292SN/A
6962292SN/A    if (intrEvent)
6972292SN/A        intrEvent->squash();
6982292SN/A    intrEvent = new IntrEvent(this, true);
6992292SN/A    schedule(intrEvent, intrTick);
7002292SN/A}
7012292SN/A
7022292SN/Avoid
7032292SN/ABase::cpuInterrupt()
7042292SN/A{
7052292SN/A    assert(intrTick == curTick);
7062292SN/A
7072292SN/A    // Whether or not there's a pending interrupt, we don't care about
7082292SN/A    // it anymore
7092292SN/A    intrEvent = 0;
7102292SN/A    intrTick = 0;
7112292SN/A
7122292SN/A    // Don't send an interrupt if there's already one
7132292SN/A    if (cpuPendingIntr) {
7142292SN/A        DPRINTF(EthernetIntr,
7152292SN/A                "would send an interrupt now, but there's already pending\n");
7162292SN/A    } else {
7172292SN/A        // Send interrupt
7182292SN/A        cpuPendingIntr = true;
7192292SN/A
7202292SN/A        DPRINTF(EthernetIntr, "posting interrupt\n");
7212292SN/A        intrPost();
7222292SN/A    }
7232329SN/A}
7242329SN/A
7252292SN/Avoid
7262292SN/ABase::cpuIntrClear()
7272292SN/A{
7282292SN/A    if (!cpuPendingIntr)
7292292SN/A        return;
7307720Sgblack@eecs.umich.edu
7317720Sgblack@eecs.umich.edu    if (intrEvent) {
7322292SN/A        intrEvent->squash();
7332292SN/A        intrEvent = 0;
7342292SN/A    }
7352292SN/A
7362292SN/A    intrTick = 0;
7372292SN/A
7382292SN/A    cpuPendingIntr = false;
7392292SN/A
7402292SN/A    DPRINTF(EthernetIntr, "clearing cchip interrupt\n");
7412292SN/A    intrClear();
7422292SN/A}
7432292SN/A
7442292SN/Abool
7456974Stjones1@inf.ed.ac.ukBase::cpuIntrPending() const
7466974Stjones1@inf.ed.ac.uk{ return cpuPendingIntr; }
7476974Stjones1@inf.ed.ac.uk
7486974Stjones1@inf.ed.ac.ukvoid
7496974Stjones1@inf.ed.ac.ukDevice::changeConfig(uint32_t newconf)
7506974Stjones1@inf.ed.ac.uk{
7516974Stjones1@inf.ed.ac.uk    uint32_t changed = regs.Config ^ newconf;
7526974Stjones1@inf.ed.ac.uk    if (!changed)
7536974Stjones1@inf.ed.ac.uk        return;
7546974Stjones1@inf.ed.ac.uk
7556974Stjones1@inf.ed.ac.uk    regs.Config = newconf;
7566974Stjones1@inf.ed.ac.uk
7576974Stjones1@inf.ed.ac.uk    if ((changed & Regs::Config_IntEn)) {
7586974Stjones1@inf.ed.ac.uk        cpuIntrEnable = regs.Config & Regs::Config_IntEn;
7596974Stjones1@inf.ed.ac.uk        if (cpuIntrEnable) {
7606974Stjones1@inf.ed.ac.uk            if (regs.IntrStatus & regs.IntrMask)
7612292SN/A                cpuIntrPost(curTick);
7622292SN/A        } else {
7636974Stjones1@inf.ed.ac.uk            cpuIntrClear();
7646974Stjones1@inf.ed.ac.uk        }
7656974Stjones1@inf.ed.ac.uk    }
7666974Stjones1@inf.ed.ac.uk
7676974Stjones1@inf.ed.ac.uk    if ((changed & Regs::Config_TxEn)) {
7686974Stjones1@inf.ed.ac.uk        txEnable = regs.Config & Regs::Config_TxEn;
7692292SN/A        if (txEnable)
7702292SN/A            txKick();
7712292SN/A    }
7722292SN/A
7732292SN/A    if ((changed & Regs::Config_RxEn)) {
7742292SN/A        rxEnable = regs.Config & Regs::Config_RxEn;
7752907Sktlim@umich.edu        if (rxEnable)
7762678Sktlim@umich.edu            rxKick();
7772678Sktlim@umich.edu    }
7782678Sktlim@umich.edu}
7792678Sktlim@umich.edu
7802678Sktlim@umich.eduvoid
7812329SN/ADevice::command(uint32_t command)
7822329SN/A{
7832292SN/A    if (command & Regs::Command_Intr)
7842292SN/A        devIntrPost(Regs::Intr_Soft);
7852292SN/A
7862292SN/A    if (command & Regs::Command_Reset)
7872292SN/A        reset();
7882292SN/A}
7892292SN/A
7902678Sktlim@umich.eduvoid
7912292SN/ADevice::reset()
7922292SN/A{
7932292SN/A    using namespace Regs;
7942292SN/A
7952292SN/A    memset(&regs, 0, sizeof(regs));
7962292SN/A
7972292SN/A    regs.Config = 0;
7982292SN/A    if (params()->rx_thread)
7992292SN/A        regs.Config |= Config_RxThread;
8002292SN/A    if (params()->tx_thread)
8012292SN/A        regs.Config |= Config_TxThread;
8026974Stjones1@inf.ed.ac.uk    if (params()->rss)
8036974Stjones1@inf.ed.ac.uk        regs.Config |= Config_RSS;
8046974Stjones1@inf.ed.ac.uk    if (params()->zero_copy)
8056974Stjones1@inf.ed.ac.uk        regs.Config |= Config_ZeroCopy;
8066974Stjones1@inf.ed.ac.uk    if (params()->delay_copy)
8072669Sktlim@umich.edu        regs.Config |= Config_DelayCopy;
8082669Sktlim@umich.edu    if (params()->virtual_addr)
8092669Sktlim@umich.edu        regs.Config |= Config_Vaddr;
8108481Sgblack@eecs.umich.edu
8118481Sgblack@eecs.umich.edu    if (params()->delay_copy && params()->zero_copy)
8128481Sgblack@eecs.umich.edu        panic("Can't delay copy and zero copy");
8132292SN/A
8142292SN/A    regs.IntrMask = Intr_Soft | Intr_RxHigh | Intr_RxPacket | Intr_TxLow;
8152669Sktlim@umich.edu    regs.RxMaxCopy = params()->rx_max_copy;
8162669Sktlim@umich.edu    regs.TxMaxCopy = params()->tx_max_copy;
8173772Sgblack@eecs.umich.edu    regs.ZeroCopySize = params()->zero_copy_size;
8184326Sgblack@eecs.umich.edu    regs.ZeroCopyMark = params()->zero_copy_threshold;
8192669Sktlim@umich.edu    regs.VirtualCount = params()->virtual_count;
8204878Sstever@eecs.umich.edu    regs.RxMaxIntr = params()->rx_max_intr;
8214878Sstever@eecs.umich.edu    regs.RxFifoSize = params()->rx_fifo_size;
8226102Sgblack@eecs.umich.edu    regs.TxFifoSize = params()->tx_fifo_size;
8236974Stjones1@inf.ed.ac.uk    regs.RxFifoLow = params()->rx_fifo_low_mark;
8246974Stjones1@inf.ed.ac.uk    regs.TxFifoLow = params()->tx_fifo_threshold;
8252292SN/A    regs.RxFifoHigh = params()->rx_fifo_threshold;
8262678Sktlim@umich.edu    regs.TxFifoHigh = params()->tx_fifo_high_mark;
8272678Sktlim@umich.edu    regs.HwAddr = params()->hardware_address;
8282678Sktlim@umich.edu
8292678Sktlim@umich.edu    if (regs.RxMaxCopy < regs.ZeroCopyMark)
8306974Stjones1@inf.ed.ac.uk        panic("Must be able to copy at least as many bytes as the threshold");
8316974Stjones1@inf.ed.ac.uk
8326974Stjones1@inf.ed.ac.uk    if (regs.ZeroCopySize >= regs.ZeroCopyMark)
8336974Stjones1@inf.ed.ac.uk        panic("The number of bytes to copy must be less than the threshold");
8346974Stjones1@inf.ed.ac.uk
8356974Stjones1@inf.ed.ac.uk    rxList.clear();
8366974Stjones1@inf.ed.ac.uk    rxBusy.clear();
8376974Stjones1@inf.ed.ac.uk    rxActive = -1;
8386974Stjones1@inf.ed.ac.uk    txList.clear();
8396974Stjones1@inf.ed.ac.uk    rxBusyCount = 0;
8406974Stjones1@inf.ed.ac.uk    rxDirtyCount = 0;
8416974Stjones1@inf.ed.ac.uk    rxMappedCount = 0;
8426974Stjones1@inf.ed.ac.uk
8436974Stjones1@inf.ed.ac.uk    rxState = rxIdle;
8446974Stjones1@inf.ed.ac.uk    txState = txIdle;
8456974Stjones1@inf.ed.ac.uk
8466974Stjones1@inf.ed.ac.uk    rxFifo.clear();
8476974Stjones1@inf.ed.ac.uk    rxFifoPtr = rxFifo.end();
8486974Stjones1@inf.ed.ac.uk    txFifo.clear();
8496974Stjones1@inf.ed.ac.uk    rxEmpty = false;
8506974Stjones1@inf.ed.ac.uk    rxLow = true;
8516974Stjones1@inf.ed.ac.uk    txFull = false;
8526974Stjones1@inf.ed.ac.uk
8536974Stjones1@inf.ed.ac.uk    int size = virtualRegs.size();
8546974Stjones1@inf.ed.ac.uk    virtualRegs.clear();
8552678Sktlim@umich.edu    virtualRegs.resize(size);
8567720Sgblack@eecs.umich.edu    for (int i = 0; i < size; ++i)
8572292SN/A        virtualRegs[i].rxIndex = rxFifo.end();
8587720Sgblack@eecs.umich.edu}
8593797Sgblack@eecs.umich.edu
8603221Sktlim@umich.eduvoid
8612292SN/ADevice::rxDmaDone()
8622693Sktlim@umich.edu{
8634350Sgblack@eecs.umich.edu    assert(rxState == rxCopy);
8646974Stjones1@inf.ed.ac.uk    rxState = rxCopyDone;
8653326Sktlim@umich.edu    DPRINTF(EthernetDMA, "end rx dma write paddr=%#x len=%d\n",
8663326Sktlim@umich.edu            rxDmaAddr, rxDmaLen);
8673326Sktlim@umich.edu    DDUMP(EthernetData, rxDmaData, rxDmaLen);
8683326Sktlim@umich.edu
8693326Sktlim@umich.edu    // If the transmit state machine  has a pending DMA, let it go first
8703326Sktlim@umich.edu    if (txState == txBeginCopy)
8713326Sktlim@umich.edu        txKick();
8723326Sktlim@umich.edu
8733326Sktlim@umich.edu    rxKick();
8743326Sktlim@umich.edu}
8753326Sktlim@umich.edu
8763326Sktlim@umich.eduvoid
8773326Sktlim@umich.eduDevice::rxKick()
8787823Ssteve.reinhardt@amd.com{
8793326Sktlim@umich.edu    VirtualReg *vnic = NULL;
8803326Sktlim@umich.edu
8813326Sktlim@umich.edu    DPRINTF(EthernetSM, "rxKick: rxState=%s (rxFifo.size=%d)\n",
8822693Sktlim@umich.edu            RxStateStrings[rxState], rxFifo.size());
8832693Sktlim@umich.edu
8842693Sktlim@umich.edu    if (rxKickTick > curTick) {
8852693Sktlim@umich.edu        DPRINTF(EthernetSM, "rxKick: exiting, can't run till %d\n",
8862693Sktlim@umich.edu                rxKickTick);
8872693Sktlim@umich.edu        return;
8888481Sgblack@eecs.umich.edu    }
8898481Sgblack@eecs.umich.edu
8908481Sgblack@eecs.umich.edu  next:
8918481Sgblack@eecs.umich.edu    rxFifo.check();
8928481Sgblack@eecs.umich.edu    if (rxState == rxIdle)
8938481Sgblack@eecs.umich.edu        goto exit;
8948481Sgblack@eecs.umich.edu
8958481Sgblack@eecs.umich.edu    if (rxActive == -1) {
8968481Sgblack@eecs.umich.edu        if (rxState != rxFifoBlock)
8978481Sgblack@eecs.umich.edu            panic("no active vnic while in state %s", RxStateStrings[rxState]);
8988481Sgblack@eecs.umich.edu
8998481Sgblack@eecs.umich.edu        DPRINTF(EthernetSM, "processing rxState=%s\n",
9008481Sgblack@eecs.umich.edu                RxStateStrings[rxState]);
9018481Sgblack@eecs.umich.edu    } else {
9028481Sgblack@eecs.umich.edu        vnic = &virtualRegs[rxActive];
9038481Sgblack@eecs.umich.edu        DPRINTF(EthernetSM,
9048481Sgblack@eecs.umich.edu                "processing rxState=%s for vnic %d (rxunique %d)\n",
9058481Sgblack@eecs.umich.edu                RxStateStrings[rxState], rxActive, vnic->rxUnique);
9068481Sgblack@eecs.umich.edu    }
9078481Sgblack@eecs.umich.edu
9088481Sgblack@eecs.umich.edu    switch (rxState) {
9094032Sktlim@umich.edu      case rxFifoBlock:
9103221Sktlim@umich.edu        if (DTRACE(EthernetSM)) {
9113221Sktlim@umich.edu            PacketFifo::iterator end = rxFifo.end();
9126974Stjones1@inf.ed.ac.uk            int size = virtualRegs.size();
9136974Stjones1@inf.ed.ac.uk            for (int i = 0; i < size; ++i) {
9148481Sgblack@eecs.umich.edu                VirtualReg *vn = &virtualRegs[i];
9156974Stjones1@inf.ed.ac.uk                bool busy = Regs::get_RxDone_Busy(vn->RxDone);
9166974Stjones1@inf.ed.ac.uk                if (vn->rxIndex != end) {
9176974Stjones1@inf.ed.ac.uk                    bool dirty = vn->rxPacketOffset > 0;
9182669Sktlim@umich.edu                    const char *status;
9196974Stjones1@inf.ed.ac.uk
9206974Stjones1@inf.ed.ac.uk                    if (busy && dirty)
9218481Sgblack@eecs.umich.edu                        status = "busy,dirty";
9226974Stjones1@inf.ed.ac.uk                    else if (busy)
9236974Stjones1@inf.ed.ac.uk                        status = "busy";
9246974Stjones1@inf.ed.ac.uk                    else if (dirty)
9256974Stjones1@inf.ed.ac.uk                        status = "dirty";
9266974Stjones1@inf.ed.ac.uk                    else
9276974Stjones1@inf.ed.ac.uk                        status = "mapped";
9286974Stjones1@inf.ed.ac.uk
9296974Stjones1@inf.ed.ac.uk                    DPRINTF(EthernetSM,
9306974Stjones1@inf.ed.ac.uk                            "vnic %d %s (rxunique %d), packet %d, slack %d\n",
9316974Stjones1@inf.ed.ac.uk                            i, status, vn->rxUnique,
9326974Stjones1@inf.ed.ac.uk                            rxFifo.countPacketsBefore(vn->rxIndex),
9336974Stjones1@inf.ed.ac.uk                            vn->rxIndex->slack);
9346974Stjones1@inf.ed.ac.uk                } else if (busy) {
9356974Stjones1@inf.ed.ac.uk                    DPRINTF(EthernetSM, "vnic %d unmapped (rxunique %d)\n",
9366974Stjones1@inf.ed.ac.uk                            i, vn->rxUnique);
9376974Stjones1@inf.ed.ac.uk                }
9386974Stjones1@inf.ed.ac.uk            }
9396974Stjones1@inf.ed.ac.uk        }
9406974Stjones1@inf.ed.ac.uk
9416974Stjones1@inf.ed.ac.uk        if (!rxBusy.empty()) {
9426974Stjones1@inf.ed.ac.uk            rxActive = rxBusy.front();
9436974Stjones1@inf.ed.ac.uk            rxBusy.pop_front();
9446974Stjones1@inf.ed.ac.uk            vnic = &virtualRegs[rxActive];
9456974Stjones1@inf.ed.ac.uk
9462292SN/A            if (vnic->rxIndex == rxFifo.end())
9472292SN/A                panic("continuing vnic without packet\n");
9482292SN/A
9492292SN/A            DPRINTF(EthernetSM,
9502292SN/A                    "continue processing for vnic %d (rxunique %d)\n",
9512292SN/A                    rxActive, vnic->rxUnique);
9522292SN/A
9532292SN/A            rxState = rxBeginCopy;
9542292SN/A
9552292SN/A            int vnic_distance = rxFifo.countPacketsBefore(vnic->rxIndex);
9562292SN/A            totalVnicDistance += vnic_distance;
9572292SN/A            numVnicDistance += 1;
9582292SN/A            if (vnic_distance > _maxVnicDistance) {
9592292SN/A                maxVnicDistance = vnic_distance;
9602292SN/A                _maxVnicDistance = vnic_distance;
9612292SN/A            }
9622292SN/A
9632292SN/A            break;
9642292SN/A        }
9652292SN/A
9662292SN/A        if (rxFifoPtr == rxFifo.end()) {
9672292SN/A            DPRINTF(EthernetSM, "receive waiting for data.  Nothing to do.\n");
9682292SN/A            goto exit;
9692292SN/A        }
9702292SN/A
9712292SN/A        if (rxList.empty())
9722292SN/A            panic("Not idle, but nothing to do!");
9732292SN/A
9742329SN/A        assert(!rxFifo.empty());
9752292SN/A
9762292SN/A        rxActive = rxList.front();
9772292SN/A        rxList.pop_front();
9782292SN/A        vnic = &virtualRegs[rxActive];
9792292SN/A
9807720Sgblack@eecs.umich.edu        DPRINTF(EthernetSM,
9812292SN/A                "processing new packet for vnic %d (rxunique %d)\n",
9827720Sgblack@eecs.umich.edu                rxActive, vnic->rxUnique);
9832292SN/A
9842292SN/A        // Grab a new packet from the fifo.
9852292SN/A        vnic->rxIndex = rxFifoPtr++;
9862292SN/A        vnic->rxIndex->priv = rxActive;
9872292SN/A        vnic->rxPacketOffset = 0;
9882292SN/A        vnic->rxPacketBytes = vnic->rxIndex->packet->length;
9892292SN/A        assert(vnic->rxPacketBytes);
9902292SN/A        rxMappedCount++;
9912329SN/A
9922731Sktlim@umich.edu        vnic->rxDoneData = 0;
9932292SN/A        /* scope for variables */ {
9942292SN/A            IpPtr ip(vnic->rxIndex->packet);
9952292SN/A            if (ip) {
9962292SN/A                DPRINTF(Ethernet, "ID is %d\n", ip->id());
9972292SN/A                vnic->rxDoneData |= Regs::RxDone_IpPacket;
9982292SN/A                rxIpChecksums++;
9992292SN/A                if (cksum(ip) != 0) {
10002727Sktlim@umich.edu                    DPRINTF(EthernetCksum, "Rx IP Checksum Error\n");
10012292SN/A                    vnic->rxDoneData |= Regs::RxDone_IpError;
10022292SN/A                }
10032292SN/A                TcpPtr tcp(ip);
10042292SN/A                UdpPtr udp(ip);
10052292SN/A                if (tcp) {
10062292SN/A                    DPRINTF(Ethernet,
10072292SN/A                            "Src Port=%d, Dest Port=%d, Seq=%d, Ack=%d\n",
10082292SN/A                            tcp->sport(), tcp->dport(), tcp->seq(),
10092292SN/A                            tcp->ack());
10102292SN/A                    vnic->rxDoneData |= Regs::RxDone_TcpPacket;
10114032Sktlim@umich.edu                    rxTcpChecksums++;
10124032Sktlim@umich.edu                    if (cksum(tcp) != 0) {
10134032Sktlim@umich.edu                        DPRINTF(EthernetCksum, "Rx TCP Checksum Error\n");
10144032Sktlim@umich.edu                        vnic->rxDoneData |= Regs::RxDone_TcpError;
10152292SN/A                    }
10162292SN/A                } else if (udp) {
10172292SN/A                    vnic->rxDoneData |= Regs::RxDone_UdpPacket;
10182292SN/A                    rxUdpChecksums++;
10192292SN/A                    if (cksum(udp) != 0) {
10202329SN/A                        DPRINTF(EthernetCksum, "Rx UDP Checksum Error\n");
10212292SN/A                        vnic->rxDoneData |= Regs::RxDone_UdpError;
10222292SN/A                    }
10232292SN/A                }
10242292SN/A            }
10257720Sgblack@eecs.umich.edu        }
10262292SN/A        rxState = rxBeginCopy;
10277720Sgblack@eecs.umich.edu        break;
10282292SN/A
10292292SN/A      case rxBeginCopy:
10302329SN/A        if (dmaPending() || getState() != Running)
10312329SN/A            goto exit;
10322292SN/A
10332292SN/A        rxDmaAddr = params()->platform->pciToDma(
10342292SN/A                Regs::get_RxData_Addr(vnic->RxData));
10352292SN/A        rxDmaLen = min<int>(Regs::get_RxData_Len(vnic->RxData),
10362292SN/A                            vnic->rxPacketBytes);
10372292SN/A
10382292SN/A        /*
10392329SN/A         * if we're doing zero/delay copy and we're below the fifo
10402731Sktlim@umich.edu         * threshold, see if we should try to do the zero/defer copy
10412292SN/A         */
10422292SN/A        if ((Regs::get_Config_ZeroCopy(regs.Config) ||
10432292SN/A             Regs::get_Config_DelayCopy(regs.Config)) &&
10444032Sktlim@umich.edu            !Regs::get_RxData_NoDelay(vnic->RxData) && rxLow) {
10454032Sktlim@umich.edu            if (rxDmaLen > regs.ZeroCopyMark)
10464032Sktlim@umich.edu                rxDmaLen = regs.ZeroCopySize;
10474032Sktlim@umich.edu        }
10486974Stjones1@inf.ed.ac.uk        rxDmaData = vnic->rxIndex->packet->data + vnic->rxPacketOffset;
10496974Stjones1@inf.ed.ac.uk        rxState = rxCopy;
10506974Stjones1@inf.ed.ac.uk        if (rxDmaAddr == 1LL) {
10516974Stjones1@inf.ed.ac.uk            rxState = rxCopyDone;
10526974Stjones1@inf.ed.ac.uk            break;
10536974Stjones1@inf.ed.ac.uk        }
10546974Stjones1@inf.ed.ac.uk
10554032Sktlim@umich.edu        dmaWrite(rxDmaAddr, rxDmaLen, &rxDmaEvent, rxDmaData);
10562292SN/A        break;
10572292SN/A
10582292SN/A      case rxCopy:
10592292SN/A        DPRINTF(EthernetSM, "receive machine still copying\n");
10602292SN/A        goto exit;
10612292SN/A
10622292SN/A      case rxCopyDone:
10632727Sktlim@umich.edu        vnic->RxDone = vnic->rxDoneData;
10642292SN/A        vnic->RxDone |= Regs::RxDone_Complete;
10652292SN/A        rxBusyCount--;
10662292SN/A
10672292SN/A        if (vnic->rxPacketBytes == rxDmaLen) {
10682292SN/A            if (vnic->rxPacketOffset)
10693349Sbinkertn@umich.edu                rxDirtyCount--;
10702693Sktlim@umich.edu
10712693Sktlim@umich.edu            // Packet is complete.  Indicate how many bytes were copied
10722693Sktlim@umich.edu            vnic->RxDone = Regs::set_RxDone_CopyLen(vnic->RxDone, rxDmaLen);
10732693Sktlim@umich.edu
10742693Sktlim@umich.edu            DPRINTF(EthernetSM,
10752693Sktlim@umich.edu                    "rxKick: packet complete on vnic %d (rxunique %d)\n",
10762693Sktlim@umich.edu                    rxActive, vnic->rxUnique);
10772693Sktlim@umich.edu            rxFifo.remove(vnic->rxIndex);
10782693Sktlim@umich.edu            vnic->rxIndex = rxFifo.end();
10792693Sktlim@umich.edu            rxMappedCount--;
10802693Sktlim@umich.edu        } else {
10812693Sktlim@umich.edu            if (!vnic->rxPacketOffset)
10822693Sktlim@umich.edu                rxDirtyCount++;
10832693Sktlim@umich.edu
10842693Sktlim@umich.edu            vnic->rxPacketBytes -= rxDmaLen;
10852693Sktlim@umich.edu            vnic->rxPacketOffset += rxDmaLen;
10862733Sktlim@umich.edu            vnic->RxDone |= Regs::RxDone_More;
10872693Sktlim@umich.edu            vnic->RxDone = Regs::set_RxDone_CopyLen(vnic->RxDone,
10882732Sktlim@umich.edu                                                    vnic->rxPacketBytes);
10892693Sktlim@umich.edu            DPRINTF(EthernetSM,
10902733Sktlim@umich.edu                    "rxKick: packet not complete on vnic %d (rxunique %d): "
10912693Sktlim@umich.edu                    "%d bytes left\n",
10922693Sktlim@umich.edu                    rxActive, vnic->rxUnique, vnic->rxPacketBytes);
10932693Sktlim@umich.edu        }
10942693Sktlim@umich.edu
10952693Sktlim@umich.edu        rxActive = -1;
10962693Sktlim@umich.edu        rxState = rxBusy.empty() && rxList.empty() ? rxIdle : rxFifoBlock;
10972693Sktlim@umich.edu
10982678Sktlim@umich.edu        if (rxFifo.empty()) {
10992678Sktlim@umich.edu            devIntrPost(Regs::Intr_RxEmpty);
11002678Sktlim@umich.edu            rxEmpty = true;
11012678Sktlim@umich.edu        }
11022678Sktlim@umich.edu
11032678Sktlim@umich.edu        if (rxFifo.size() < regs.RxFifoLow)
11042927Sktlim@umich.edu            rxLow = true;
11052678Sktlim@umich.edu
11062727Sktlim@umich.edu        if (rxFifo.size() > regs.RxFifoHigh)
11072678Sktlim@umich.edu            rxLow = false;
11082678Sktlim@umich.edu
11092678Sktlim@umich.edu        devIntrPost(Regs::Intr_RxDMA);
11102678Sktlim@umich.edu        break;
11112678Sktlim@umich.edu
11122678Sktlim@umich.edu      default:
11132678Sktlim@umich.edu        panic("Invalid rxState!");
11142678Sktlim@umich.edu    }
11152678Sktlim@umich.edu
11162678Sktlim@umich.edu    DPRINTF(EthernetSM, "entering next rxState=%s\n",
11172678Sktlim@umich.edu            RxStateStrings[rxState]);
11182678Sktlim@umich.edu
11192678Sktlim@umich.edu    goto next;
11202678Sktlim@umich.edu
11217598Sminkyu.jeong@arm.com  exit:
11227598Sminkyu.jeong@arm.com    /**
11237598Sminkyu.jeong@arm.com     * @todo do we want to schedule a future kick?
11242678Sktlim@umich.edu     */
11252678Sktlim@umich.edu    DPRINTF(EthernetSM, "rx state machine exited rxState=%s\n",
11262678Sktlim@umich.edu            RxStateStrings[rxState]);
11272678Sktlim@umich.edu}
11282292SN/A
11292292SN/Avoid
11302292SN/ADevice::txDmaDone()
11312292SN/A{
11322292SN/A    assert(txState == txCopy);
11332292SN/A    txState = txCopyDone;
11342292SN/A    DPRINTF(EthernetDMA, "tx dma read paddr=%#x len=%d\n",
11352292SN/A            txDmaAddr, txDmaLen);
11363126Sktlim@umich.edu    DDUMP(EthernetData, txDmaData, txDmaLen);
11372292SN/A
11382292SN/A    // If the receive state machine  has a pending DMA, let it go first
11392292SN/A    if (rxState == rxBeginCopy)
11402292SN/A        rxKick();
11412292SN/A
11422292SN/A    txKick();
11432292SN/A}
11442292SN/A
11452292SN/Avoid
11462292SN/ADevice::transmit()
11472292SN/A{
11482292SN/A    if (txFifo.empty()) {
11492292SN/A        DPRINTF(Ethernet, "nothing to transmit\n");
11502329SN/A        return;
11512329SN/A    }
11522329SN/A
11532292SN/A    uint32_t interrupts;
11542292SN/A    EthPacketPtr packet = txFifo.front();
11552292SN/A    if (!interface->sendPacket(packet)) {
11562292SN/A        DPRINTF(Ethernet, "Packet Transmit: failed txFifo available %d\n",
11572292SN/A                txFifo.avail());
11582292SN/A        return;
11592292SN/A    }
11602292SN/A
11612292SN/A    txFifo.pop();
11622292SN/A#if TRACING_ON
11632316SN/A    if (DTRACE(Ethernet)) {
11642316SN/A        IpPtr ip(packet);
11652329SN/A        if (ip) {
11662329SN/A            DPRINTF(Ethernet, "ID is %d\n", ip->id());
11672329SN/A            TcpPtr tcp(ip);
11682329SN/A            if (tcp) {
11692733Sktlim@umich.edu                DPRINTF(Ethernet,
11702316SN/A                        "Src Port=%d, Dest Port=%d, Seq=%d, Ack=%d\n",
11712732Sktlim@umich.edu                        tcp->sport(), tcp->dport(), tcp->seq(),
11722316SN/A                        tcp->ack());
11732733Sktlim@umich.edu            }
11742292SN/A        }
11752292SN/A    }
11762292SN/A#endif
11776974Stjones1@inf.ed.ac.uk
11786974Stjones1@inf.ed.ac.uk    DDUMP(EthernetData, packet->data, packet->length);
11796974Stjones1@inf.ed.ac.uk    txBytes += packet->length;
11806974Stjones1@inf.ed.ac.uk    txPackets++;
11816974Stjones1@inf.ed.ac.uk
11826974Stjones1@inf.ed.ac.uk    DPRINTF(Ethernet, "Packet Transmit: successful txFifo Available %d\n",
11836974Stjones1@inf.ed.ac.uk            txFifo.avail());
11846974Stjones1@inf.ed.ac.uk
11856974Stjones1@inf.ed.ac.uk    interrupts = Regs::Intr_TxPacket;
11866974Stjones1@inf.ed.ac.uk    if (txFifo.size() < regs.TxFifoLow)
11876974Stjones1@inf.ed.ac.uk        interrupts |= Regs::Intr_TxLow;
11886974Stjones1@inf.ed.ac.uk    devIntrPost(interrupts);
11896974Stjones1@inf.ed.ac.uk}
11906974Stjones1@inf.ed.ac.uk
11916974Stjones1@inf.ed.ac.ukvoid
11926974Stjones1@inf.ed.ac.ukDevice::txKick()
11932693Sktlim@umich.edu{
11942693Sktlim@umich.edu    VirtualReg *vnic;
11952693Sktlim@umich.edu    DPRINTF(EthernetSM, "txKick: txState=%s (txFifo.size=%d)\n",
11962698Sktlim@umich.edu            TxStateStrings[txState], txFifo.size());
11974985Sktlim@umich.edu
11982698Sktlim@umich.edu    if (txKickTick > curTick) {
11992693Sktlim@umich.edu        DPRINTF(EthernetSM, "txKick: exiting, can't run till %d\n",
12008587Snilay@cs.wisc.edu                txKickTick);
12018587Snilay@cs.wisc.edu        return;
12028587Snilay@cs.wisc.edu    }
12032698Sktlim@umich.edu
12046974Stjones1@inf.ed.ac.uk  next:
12058133SAli.Saidi@ARM.com    if (txState == txIdle)
12068133SAli.Saidi@ARM.com        goto exit;
12078133SAli.Saidi@ARM.com
12086974Stjones1@inf.ed.ac.uk    assert(!txList.empty());
12096974Stjones1@inf.ed.ac.uk    vnic = &virtualRegs[txList.front()];
12102699Sktlim@umich.edu
12112693Sktlim@umich.edu    switch (txState) {
12126221Snate@binkert.org      case txFifoBlock:
12136974Stjones1@inf.ed.ac.uk        assert(Regs::get_TxDone_Busy(vnic->TxDone));
12146974Stjones1@inf.ed.ac.uk        if (!txPacket) {
12156974Stjones1@inf.ed.ac.uk            // Grab a new packet from the fifo.
12166974Stjones1@inf.ed.ac.uk            txPacket = new EthPacketData(16384);
12176974Stjones1@inf.ed.ac.uk            txPacketOffset = 0;
12186974Stjones1@inf.ed.ac.uk        }
12196974Stjones1@inf.ed.ac.uk
12206974Stjones1@inf.ed.ac.uk        if (txFifo.avail() - txPacket->length <
12212693Sktlim@umich.edu            Regs::get_TxData_Len(vnic->TxData)) {
12222693Sktlim@umich.edu            DPRINTF(EthernetSM, "transmit fifo full.  Nothing to do.\n");
12232727Sktlim@umich.edu            goto exit;
12242907Sktlim@umich.edu        }
12252693Sktlim@umich.edu
12262693Sktlim@umich.edu        txState = txBeginCopy;
12272693Sktlim@umich.edu        break;
12282693Sktlim@umich.edu
12292693Sktlim@umich.edu      case txBeginCopy:
12302693Sktlim@umich.edu        if (dmaPending() || getState() != Running)
12312693Sktlim@umich.edu            goto exit;
12322693Sktlim@umich.edu
12332693Sktlim@umich.edu        txDmaAddr = params()->platform->pciToDma(
12342693Sktlim@umich.edu                Regs::get_TxData_Addr(vnic->TxData));
12352292SN/A        txDmaLen = Regs::get_TxData_Len(vnic->TxData);
12362292SN/A        txDmaData = txPacket->data + txPacketOffset;
12372292SN/A        txState = txCopy;
12382292SN/A
12392292SN/A        dmaRead(txDmaAddr, txDmaLen, &txDmaEvent, txDmaData);
12402292SN/A        break;
12412292SN/A
12422292SN/A      case txCopy:
12432292SN/A        DPRINTF(EthernetSM, "transmit machine still copying\n");
12442292SN/A        goto exit;
12452292SN/A
12462292SN/A      case txCopyDone:
12472292SN/A        vnic->TxDone = txDmaLen | Regs::TxDone_Complete;
12482292SN/A        txPacket->length += txDmaLen;
12492292SN/A        if ((vnic->TxData & Regs::TxData_More)) {
12502292SN/A            txPacketOffset += txDmaLen;
12512292SN/A            txState = txIdle;
12522292SN/A            devIntrPost(Regs::Intr_TxDMA);
12532292SN/A            break;
12542292SN/A        }
12552292SN/A
12562292SN/A        assert(txPacket->length <= txFifo.avail());
12572292SN/A        if ((vnic->TxData & Regs::TxData_Checksum)) {
12582292SN/A            IpPtr ip(txPacket);
12592292SN/A            if (ip) {
12602292SN/A                TcpPtr tcp(ip);
12612292SN/A                if (tcp) {
12622292SN/A                    tcp->sum(0);
12632292SN/A                    tcp->sum(cksum(tcp));
12642292SN/A                    txTcpChecksums++;
12652329SN/A                }
12662329SN/A
12672329SN/A                UdpPtr udp(ip);
12682329SN/A                if (udp) {
12692329SN/A                    udp->sum(0);
12702329SN/A                    udp->sum(cksum(udp));
12712329SN/A                    txUdpChecksums++;
12722329SN/A                }
12732329SN/A
12742329SN/A                ip->sum(0);
12752329SN/A                ip->sum(cksum(ip));
12762329SN/A                txIpChecksums++;
12777720Sgblack@eecs.umich.edu            }
12782329SN/A        }
12792329SN/A
12802329SN/A        txFifo.push(txPacket);
12812329SN/A        if (txFifo.avail() < regs.TxMaxCopy) {
12822329SN/A            devIntrPost(Regs::Intr_TxFull);
12832329SN/A            txFull = true;
12842329SN/A        }
12852329SN/A        txPacket = 0;
12862329SN/A        transmit();
12872329SN/A        txList.pop_front();
12887720Sgblack@eecs.umich.edu        txState = txList.empty() ? txIdle : txFifoBlock;
12892329SN/A        devIntrPost(Regs::Intr_TxDMA);
12902329SN/A        break;
12912329SN/A
12922329SN/A      default:
12932329SN/A        panic("Invalid txState!");
12942329SN/A    }
1295
1296    DPRINTF(EthernetSM, "entering next txState=%s\n",
1297            TxStateStrings[txState]);
1298
1299    goto next;
1300
1301  exit:
1302    /**
1303     * @todo do we want to schedule a future kick?
1304     */
1305    DPRINTF(EthernetSM, "tx state machine exited txState=%s\n",
1306            TxStateStrings[txState]);
1307}
1308
1309void
1310Device::transferDone()
1311{
1312    if (txFifo.empty()) {
1313        DPRINTF(Ethernet, "transfer complete: txFifo empty...nothing to do\n");
1314        return;
1315    }
1316
1317    DPRINTF(Ethernet, "transfer complete: data in txFifo...schedule xmit\n");
1318
1319    reschedule(txEvent, curTick + ticks(1), true);
1320}
1321
1322bool
1323Device::rxFilter(const EthPacketPtr &packet)
1324{
1325    if (!Regs::get_Config_Filter(regs.Config))
1326        return false;
1327
1328    panic("receive filter not implemented\n");
1329    bool drop = true;
1330
1331#if 0
1332    string type;
1333
1334    EthHdr *eth = packet->eth();
1335    if (eth->unicast()) {
1336        // If we're accepting all unicast addresses
1337        if (acceptUnicast)
1338            drop = false;
1339
1340        // If we make a perfect match
1341        if (acceptPerfect && params->eaddr == eth.dst())
1342            drop = false;
1343
1344        if (acceptArp && eth->type() == ETH_TYPE_ARP)
1345            drop = false;
1346
1347    } else if (eth->broadcast()) {
1348        // if we're accepting broadcasts
1349        if (acceptBroadcast)
1350            drop = false;
1351
1352    } else if (eth->multicast()) {
1353        // if we're accepting all multicasts
1354        if (acceptMulticast)
1355            drop = false;
1356
1357    }
1358
1359    if (drop) {
1360        DPRINTF(Ethernet, "rxFilter drop\n");
1361        DDUMP(EthernetData, packet->data, packet->length);
1362    }
1363#endif
1364    return drop;
1365}
1366
1367bool
1368Device::recvPacket(EthPacketPtr packet)
1369{
1370    rxBytes += packet->length;
1371    rxPackets++;
1372
1373    DPRINTF(Ethernet, "Receiving packet from wire, rxFifo Available is %d\n",
1374            rxFifo.avail());
1375
1376    if (!rxEnable) {
1377        DPRINTF(Ethernet, "receive disabled...packet dropped\n");
1378        return true;
1379    }
1380
1381    if (rxFilter(packet)) {
1382        DPRINTF(Ethernet, "packet filtered...dropped\n");
1383        return true;
1384    }
1385
1386    if (rxFifo.size() >= regs.RxFifoHigh)
1387        devIntrPost(Regs::Intr_RxHigh);
1388
1389    if (!rxFifo.push(packet)) {
1390        DPRINTF(Ethernet,
1391                "packet will not fit in receive buffer...packet dropped\n");
1392        return false;
1393    }
1394
1395    // If we were at the last element, back up one ot go to the new
1396    // last element of the list.
1397    if (rxFifoPtr == rxFifo.end())
1398        --rxFifoPtr;
1399
1400    devIntrPost(Regs::Intr_RxPacket);
1401    rxKick();
1402    return true;
1403}
1404
1405void
1406Device::resume()
1407{
1408    SimObject::resume();
1409
1410    // During drain we could have left the state machines in a waiting state and
1411    // they wouldn't get out until some other event occured to kick them.
1412    // This way they'll get out immediately
1413    txKick();
1414    rxKick();
1415}
1416
1417//=====================================================================
1418//
1419//
1420void
1421Base::serialize(std::ostream &os)
1422{
1423    // Serialize the PciDev base class
1424    PciDev::serialize(os);
1425
1426    SERIALIZE_SCALAR(rxEnable);
1427    SERIALIZE_SCALAR(txEnable);
1428    SERIALIZE_SCALAR(cpuIntrEnable);
1429
1430    /*
1431     * Keep track of pending interrupt status.
1432     */
1433    SERIALIZE_SCALAR(intrTick);
1434    SERIALIZE_SCALAR(cpuPendingIntr);
1435    Tick intrEventTick = 0;
1436    if (intrEvent)
1437        intrEventTick = intrEvent->when();
1438    SERIALIZE_SCALAR(intrEventTick);
1439}
1440
1441void
1442Base::unserialize(Checkpoint *cp, const std::string &section)
1443{
1444    // Unserialize the PciDev base class
1445    PciDev::unserialize(cp, section);
1446
1447    UNSERIALIZE_SCALAR(rxEnable);
1448    UNSERIALIZE_SCALAR(txEnable);
1449    UNSERIALIZE_SCALAR(cpuIntrEnable);
1450
1451    /*
1452     * Keep track of pending interrupt status.
1453     */
1454    UNSERIALIZE_SCALAR(intrTick);
1455    UNSERIALIZE_SCALAR(cpuPendingIntr);
1456    Tick intrEventTick;
1457    UNSERIALIZE_SCALAR(intrEventTick);
1458    if (intrEventTick) {
1459        intrEvent = new IntrEvent(this, true);
1460        schedule(intrEvent, intrEventTick);
1461    }
1462}
1463
1464void
1465Device::serialize(std::ostream &os)
1466{
1467    int count;
1468
1469    // Serialize the PciDev base class
1470    Base::serialize(os);
1471
1472    if (rxState == rxCopy)
1473        panic("can't serialize with an in flight dma request rxState=%s",
1474              RxStateStrings[rxState]);
1475
1476    if (txState == txCopy)
1477        panic("can't serialize with an in flight dma request txState=%s",
1478              TxStateStrings[txState]);
1479
1480    /*
1481     * Serialize the device registers that could be modified by the OS.
1482     */
1483    SERIALIZE_SCALAR(regs.Config);
1484    SERIALIZE_SCALAR(regs.IntrStatus);
1485    SERIALIZE_SCALAR(regs.IntrMask);
1486    SERIALIZE_SCALAR(regs.RxData);
1487    SERIALIZE_SCALAR(regs.TxData);
1488
1489    /*
1490     * Serialize the virtual nic state
1491     */
1492    int virtualRegsSize = virtualRegs.size();
1493    SERIALIZE_SCALAR(virtualRegsSize);
1494    for (int i = 0; i < virtualRegsSize; ++i) {
1495        VirtualReg *vnic = &virtualRegs[i];
1496
1497        std::string reg = csprintf("vnic%d", i);
1498        paramOut(os, reg + ".RxData", vnic->RxData);
1499        paramOut(os, reg + ".RxDone", vnic->RxDone);
1500        paramOut(os, reg + ".TxData", vnic->TxData);
1501        paramOut(os, reg + ".TxDone", vnic->TxDone);
1502
1503        bool rxPacketExists = vnic->rxIndex != rxFifo.end();
1504        paramOut(os, reg + ".rxPacketExists", rxPacketExists);
1505        if (rxPacketExists) {
1506            int rxPacket = 0;
1507            PacketFifo::iterator i = rxFifo.begin();
1508            while (i != vnic->rxIndex) {
1509                assert(i != rxFifo.end());
1510                ++i;
1511                ++rxPacket;
1512            }
1513
1514            paramOut(os, reg + ".rxPacket", rxPacket);
1515            paramOut(os, reg + ".rxPacketOffset", vnic->rxPacketOffset);
1516            paramOut(os, reg + ".rxPacketBytes", vnic->rxPacketBytes);
1517        }
1518        paramOut(os, reg + ".rxDoneData", vnic->rxDoneData);
1519    }
1520
1521    int rxFifoPtr = -1;
1522    if (this->rxFifoPtr != rxFifo.end())
1523        rxFifoPtr = rxFifo.countPacketsBefore(this->rxFifoPtr);
1524    SERIALIZE_SCALAR(rxFifoPtr);
1525
1526    SERIALIZE_SCALAR(rxActive);
1527    SERIALIZE_SCALAR(rxBusyCount);
1528    SERIALIZE_SCALAR(rxDirtyCount);
1529    SERIALIZE_SCALAR(rxMappedCount);
1530
1531    VirtualList::iterator i, end;
1532    for (count = 0, i = rxList.begin(), end = rxList.end(); i != end; ++i)
1533        paramOut(os, csprintf("rxList%d", count++), *i);
1534    int rxListSize = count;
1535    SERIALIZE_SCALAR(rxListSize);
1536
1537    for (count = 0, i = rxBusy.begin(), end = rxBusy.end(); i != end; ++i)
1538        paramOut(os, csprintf("rxBusy%d", count++), *i);
1539    int rxBusySize = count;
1540    SERIALIZE_SCALAR(rxBusySize);
1541
1542    for (count = 0, i = txList.begin(), end = txList.end(); i != end; ++i)
1543        paramOut(os, csprintf("txList%d", count++), *i);
1544    int txListSize = count;
1545    SERIALIZE_SCALAR(txListSize);
1546
1547    /*
1548     * Serialize rx state machine
1549     */
1550    int rxState = this->rxState;
1551    SERIALIZE_SCALAR(rxState);
1552    SERIALIZE_SCALAR(rxEmpty);
1553    SERIALIZE_SCALAR(rxLow);
1554    rxFifo.serialize("rxFifo", os);
1555
1556    /*
1557     * Serialize tx state machine
1558     */
1559    int txState = this->txState;
1560    SERIALIZE_SCALAR(txState);
1561    SERIALIZE_SCALAR(txFull);
1562    txFifo.serialize("txFifo", os);
1563    bool txPacketExists = txPacket;
1564    SERIALIZE_SCALAR(txPacketExists);
1565    if (txPacketExists) {
1566        txPacket->serialize("txPacket", os);
1567        SERIALIZE_SCALAR(txPacketOffset);
1568        SERIALIZE_SCALAR(txPacketBytes);
1569    }
1570
1571    /*
1572     * If there's a pending transmit, store the time so we can
1573     * reschedule it later
1574     */
1575    Tick transmitTick = txEvent.scheduled() ? txEvent.when() - curTick : 0;
1576    SERIALIZE_SCALAR(transmitTick);
1577}
1578
1579void
1580Device::unserialize(Checkpoint *cp, const std::string &section)
1581{
1582    // Unserialize the PciDev base class
1583    Base::unserialize(cp, section);
1584
1585    /*
1586     * Unserialize the device registers that may have been written by the OS.
1587     */
1588    UNSERIALIZE_SCALAR(regs.Config);
1589    UNSERIALIZE_SCALAR(regs.IntrStatus);
1590    UNSERIALIZE_SCALAR(regs.IntrMask);
1591    UNSERIALIZE_SCALAR(regs.RxData);
1592    UNSERIALIZE_SCALAR(regs.TxData);
1593
1594    UNSERIALIZE_SCALAR(rxActive);
1595    UNSERIALIZE_SCALAR(rxBusyCount);
1596    UNSERIALIZE_SCALAR(rxDirtyCount);
1597    UNSERIALIZE_SCALAR(rxMappedCount);
1598
1599    int rxListSize;
1600    UNSERIALIZE_SCALAR(rxListSize);
1601    rxList.clear();
1602    for (int i = 0; i < rxListSize; ++i) {
1603        int value;
1604        paramIn(cp, section, csprintf("rxList%d", i), value);
1605        rxList.push_back(value);
1606    }
1607
1608    int rxBusySize;
1609    UNSERIALIZE_SCALAR(rxBusySize);
1610    rxBusy.clear();
1611    for (int i = 0; i < rxBusySize; ++i) {
1612        int value;
1613        paramIn(cp, section, csprintf("rxBusy%d", i), value);
1614        rxBusy.push_back(value);
1615    }
1616
1617    int txListSize;
1618    UNSERIALIZE_SCALAR(txListSize);
1619    txList.clear();
1620    for (int i = 0; i < txListSize; ++i) {
1621        int value;
1622        paramIn(cp, section, csprintf("txList%d", i), value);
1623        txList.push_back(value);
1624    }
1625
1626    /*
1627     * Unserialize rx state machine
1628     */
1629    int rxState;
1630    UNSERIALIZE_SCALAR(rxState);
1631    UNSERIALIZE_SCALAR(rxEmpty);
1632    UNSERIALIZE_SCALAR(rxLow);
1633    this->rxState = (RxState) rxState;
1634    rxFifo.unserialize("rxFifo", cp, section);
1635
1636    int rxFifoPtr;
1637    UNSERIALIZE_SCALAR(rxFifoPtr);
1638    if (rxFifoPtr >= 0) {
1639        this->rxFifoPtr = rxFifo.begin();
1640        for (int i = 0; i < rxFifoPtr; ++i)
1641            ++this->rxFifoPtr;
1642    } else {
1643        this->rxFifoPtr = rxFifo.end();
1644    }
1645
1646    /*
1647     * Unserialize tx state machine
1648     */
1649    int txState;
1650    UNSERIALIZE_SCALAR(txState);
1651    UNSERIALIZE_SCALAR(txFull);
1652    this->txState = (TxState) txState;
1653    txFifo.unserialize("txFifo", cp, section);
1654    bool txPacketExists;
1655    UNSERIALIZE_SCALAR(txPacketExists);
1656    txPacket = 0;
1657    if (txPacketExists) {
1658        txPacket = new EthPacketData(16384);
1659        txPacket->unserialize("txPacket", cp, section);
1660        UNSERIALIZE_SCALAR(txPacketOffset);
1661        UNSERIALIZE_SCALAR(txPacketBytes);
1662    }
1663
1664    /*
1665     * unserialize the virtual nic registers/state
1666     *
1667     * this must be done after the unserialization of the rxFifo
1668     * because the packet iterators depend on the fifo being populated
1669     */
1670    int virtualRegsSize;
1671    UNSERIALIZE_SCALAR(virtualRegsSize);
1672    virtualRegs.clear();
1673    virtualRegs.resize(virtualRegsSize);
1674    for (int i = 0; i < virtualRegsSize; ++i) {
1675        VirtualReg *vnic = &virtualRegs[i];
1676        std::string reg = csprintf("vnic%d", i);
1677
1678        paramIn(cp, section, reg + ".RxData", vnic->RxData);
1679        paramIn(cp, section, reg + ".RxDone", vnic->RxDone);
1680        paramIn(cp, section, reg + ".TxData", vnic->TxData);
1681        paramIn(cp, section, reg + ".TxDone", vnic->TxDone);
1682
1683        vnic->rxUnique = rxUnique++;
1684        vnic->txUnique = txUnique++;
1685
1686        bool rxPacketExists;
1687        paramIn(cp, section, reg + ".rxPacketExists", rxPacketExists);
1688        if (rxPacketExists) {
1689            int rxPacket;
1690            paramIn(cp, section, reg + ".rxPacket", rxPacket);
1691            vnic->rxIndex = rxFifo.begin();
1692            while (rxPacket--)
1693                ++vnic->rxIndex;
1694
1695            paramIn(cp, section, reg + ".rxPacketOffset",
1696                    vnic->rxPacketOffset);
1697            paramIn(cp, section, reg + ".rxPacketBytes", vnic->rxPacketBytes);
1698        } else {
1699            vnic->rxIndex = rxFifo.end();
1700        }
1701        paramIn(cp, section, reg + ".rxDoneData", vnic->rxDoneData);
1702    }
1703
1704    /*
1705     * If there's a pending transmit, reschedule it now
1706     */
1707    Tick transmitTick;
1708    UNSERIALIZE_SCALAR(transmitTick);
1709    if (transmitTick)
1710        schedule(txEvent, curTick + transmitTick);
1711
1712    pioPort->sendStatusChange(Port::RangeChange);
1713
1714}
1715
1716/* namespace Sinic */ }
1717
1718Sinic::Device *
1719SinicParams::create()
1720{
1721    return new Sinic::Device(this);
1722}
1723