sinic.cc revision 10469
19814Sandreas.hansson@arm.com/*
22292SN/A * Copyright (c) 2004-2005 The Regents of The University of Michigan
312216Snikos.nikoleris@arm.com * All rights reserved.
410239Sbinhpham@cs.rutgers.edu *
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
147597Sminkyu.jeong@arm.com * this software without specific prior written permission.
157597Sminkyu.jeong@arm.com *
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#ifdef SINIC_VTOPHYS
362292SN/A#include "arch/vtophys.hh"
372292SN/A#endif
382292SN/A#include "base/compiler.hh"
392292SN/A#include "base/debug.hh"
402292SN/A#include "base/inet.hh"
412689Sktlim@umich.edu#include "base/types.hh"
422689Sktlim@umich.edu#include "config/the_isa.hh"
432689Sktlim@umich.edu#include "debug/EthernetAll.hh"
442292SN/A#include "dev/etherlink.hh"
452292SN/A#include "dev/sinic.hh"
469944Smatt.horsnell@ARM.com#include "mem/packet.hh"
479944Smatt.horsnell@ARM.com#include "mem/packet_access.hh"
489944Smatt.horsnell@ARM.com#include "sim/eventq.hh"
498591Sgblack@eecs.umich.edu#include "sim/stats.hh"
503326Sktlim@umich.edu
518229Snate@binkert.orgusing namespace std;
526658Snate@binkert.orgusing namespace Net;
538887Sgeoffrey.blake@arm.comusing namespace TheISA;
542907Sktlim@umich.edu
552292SN/Anamespace Sinic {
568232Snate@binkert.org
578232Snate@binkert.orgconst char *RxStateStrings[] =
588232Snate@binkert.org{
599527SMatt.Horsnell@arm.com    "rxIdle",
602722Sktlim@umich.edu    "rxFifoBlock",
612669Sktlim@umich.edu    "rxBeginCopy",
622292SN/A    "rxCopy",
632669Sktlim@umich.edu    "rxCopyDone"
642678Sktlim@umich.edu};
652678Sktlim@umich.edu
668581Ssteve.reinhardt@amd.comconst char *TxStateStrings[] =
678581Ssteve.reinhardt@amd.com{
682292SN/A    "txIdle",
692292SN/A    "txFifoBlock",
702292SN/A    "txBeginCopy",
712669Sktlim@umich.edu    "txCopy",
722292SN/A    "txCopyDone"
732678Sktlim@umich.edu};
742292SN/A
759444SAndreas.Sandberg@ARM.com
769444SAndreas.Sandberg@ARM.com///////////////////////////////////////////////////////////////////////
779444SAndreas.Sandberg@ARM.com//
784319Sktlim@umich.edu// Sinic PCI Device
794319Sktlim@umich.edu//
804319Sktlim@umich.eduBase::Base(const Params *p)
814319Sktlim@umich.edu    : EtherDevBase(p), rxEnable(false), txEnable(false),
822678Sktlim@umich.edu      intrDelay(p->intr_delay), intrTick(0), cpuIntrEnable(false),
832678Sktlim@umich.edu      cpuPendingIntr(false), intrEvent(0), interface(NULL)
842292SN/A{
852678Sktlim@umich.edu}
862678Sktlim@umich.edu
875336Shines@cs.fsu.eduDevice::Device(const Params *p)
882678Sktlim@umich.edu    : Base(p), rxUnique(0), txUnique(0),
894873Sstever@eecs.umich.edu      virtualRegs(p->virtual_count < 1 ? 1 : p->virtual_count),
902678Sktlim@umich.edu      rxFifo(p->rx_fifo_size), txFifo(p->tx_fifo_size),
912292SN/A      rxKickTick(0), txKickTick(0),
922678Sktlim@umich.edu      txEvent(this), rxDmaEvent(this), txDmaEvent(this),
932678Sktlim@umich.edu      dmaReadDelay(p->dma_read_delay), dmaReadFactor(p->dma_read_factor),
942678Sktlim@umich.edu      dmaWriteDelay(p->dma_write_delay), dmaWriteFactor(p->dma_write_factor)
952678Sktlim@umich.edu{
962678Sktlim@umich.edu    interface = new Interface(name() + ".int0", this);
972678Sktlim@umich.edu    reset();
987852SMatt.Horsnell@arm.com
997852SMatt.Horsnell@arm.com}
1002344SN/A
10110333Smitch.hayenga@arm.comDevice::~Device()
10210333Smitch.hayenga@arm.com{}
10310333Smitch.hayenga@arm.com
10410333Smitch.hayenga@arm.comvoid
10510333Smitch.hayenga@arm.comDevice::regStats()
10610333Smitch.hayenga@arm.com{
10710333Smitch.hayenga@arm.com    Base::regStats();
10810333Smitch.hayenga@arm.com
1092678Sktlim@umich.edu    _maxVnicDistance = 0;
1106974Stjones1@inf.ed.ac.uk
1116974Stjones1@inf.ed.ac.uk    maxVnicDistance
1126974Stjones1@inf.ed.ac.uk        .name(name() + ".maxVnicDistance")
1136974Stjones1@inf.ed.ac.uk        .desc("maximum vnic distance")
1146974Stjones1@inf.ed.ac.uk        ;
1159444SAndreas.Sandberg@ARM.com
11610327Smitch.hayenga@arm.com    totalVnicDistance
1172678Sktlim@umich.edu        .name(name() + ".totalVnicDistance")
11812216Snikos.nikoleris@arm.com        .desc("total vnic distance")
11912216Snikos.nikoleris@arm.com        ;
12012216Snikos.nikoleris@arm.com    numVnicDistance
1216974Stjones1@inf.ed.ac.uk        .name(name() + ".numVnicDistance")
1226974Stjones1@inf.ed.ac.uk        .desc("number of vnic distance measurements")
1236974Stjones1@inf.ed.ac.uk        ;
1246974Stjones1@inf.ed.ac.uk
1256974Stjones1@inf.ed.ac.uk    avgVnicDistance
1266974Stjones1@inf.ed.ac.uk        .name(name() + ".avgVnicDistance")
1272678Sktlim@umich.edu        .desc("average vnic distance")
1282678Sktlim@umich.edu        ;
1292678Sktlim@umich.edu
1302678Sktlim@umich.edu    avgVnicDistance = totalVnicDistance / numVnicDistance;
1312678Sktlim@umich.edu}
1322344SN/A
1332307SN/Avoid
1346974Stjones1@inf.ed.ac.ukDevice::resetStats()
1356974Stjones1@inf.ed.ac.uk{
1366974Stjones1@inf.ed.ac.uk    Base::resetStats();
13710020Smatt.horsnell@ARM.com
13810020Smatt.horsnell@ARM.com    _maxVnicDistance = 0;
13910023Smatt.horsnell@ARM.com}
14010023Smatt.horsnell@ARM.com
1412678Sktlim@umich.eduEtherInt*
1422292SN/ADevice::getEthPort(const std::string &if_name, int idx)
1432292SN/A{
1442292SN/A    if (if_name == "interface") {
1452292SN/A        if (interface->getPeer())
1468545Ssaidi@eecs.umich.edu            panic("interface already connected to\n");
14711243Spau.cabre@metempsy.com
14811243Spau.cabre@metempsy.com        return interface;
1492292SN/A    }
1502292SN/A    return NULL;
1512292SN/A}
1522292SN/A
1532292SN/A
1545529Snate@binkert.orgvoid
1555529Snate@binkert.orgDevice::prepareIO(int cpu, int index)
1565529Snate@binkert.org{
1572292SN/A    int size = virtualRegs.size();
1584329Sktlim@umich.edu    if (index > size)
1594329Sktlim@umich.edu        panic("Trying to access a vnic that doesn't exist %d > %d\n",
1604329Sktlim@umich.edu              index, size);
1612907Sktlim@umich.edu}
1622907Sktlim@umich.edu
1632292SN/A//add stats for head of line blocking
1642292SN/A//add stats for average fifo length
16510175SMitch.Hayenga@ARM.com//add stats for average number of vnics busy
16610175SMitch.Hayenga@ARM.com
1672329SN/Avoid
1682329SN/ADevice::prepareRead(int cpu, int index)
1692329SN/A{
1702292SN/A    using namespace Regs;
1719936SFaissal.Sleiman@arm.com    prepareIO(cpu, index);
1729936SFaissal.Sleiman@arm.com
1739936SFaissal.Sleiman@arm.com    VirtualReg &vnic = virtualRegs[index];
1749936SFaissal.Sleiman@arm.com
1752292SN/A    // update rx registers
1762292SN/A    uint64_t rxdone = vnic.RxDone;
1772292SN/A    rxdone = set_RxDone_Packets(rxdone, rxFifo.countPacketsAfter(rxFifoPtr));
1788199SAli.Saidi@ARM.com    rxdone = set_RxDone_Empty(rxdone, rxFifo.empty());
1798199SAli.Saidi@ARM.com    rxdone = set_RxDone_High(rxdone, rxFifo.size() > regs.RxFifoHigh);
18011780Sarthur.perais@inria.fr    rxdone = set_RxDone_NotHigh(rxdone, rxLow);
1819444SAndreas.Sandberg@ARM.com    regs.RxData = vnic.RxData;
1829444SAndreas.Sandberg@ARM.com    regs.RxDone = rxdone;
1839444SAndreas.Sandberg@ARM.com    regs.RxWait = rxdone;
1849444SAndreas.Sandberg@ARM.com
1859444SAndreas.Sandberg@ARM.com    // update tx regsiters
1869444SAndreas.Sandberg@ARM.com    uint64_t txdone = vnic.TxDone;
1879444SAndreas.Sandberg@ARM.com    txdone = set_TxDone_Packets(txdone, txFifo.packets());
1889444SAndreas.Sandberg@ARM.com    txdone = set_TxDone_Full(txdone, txFifo.avail() < regs.TxMaxCopy);
1899444SAndreas.Sandberg@ARM.com    txdone = set_TxDone_Low(txdone, txFifo.size() < regs.TxFifoLow);
1909444SAndreas.Sandberg@ARM.com    regs.TxData = vnic.TxData;
1919444SAndreas.Sandberg@ARM.com    regs.TxDone = txdone;
1928199SAli.Saidi@ARM.com    regs.TxWait = txdone;
1932292SN/A
1942292SN/A    int head = 0xffff;
1952292SN/A
1962292SN/A    if (!rxFifo.empty()) {
19711780Sarthur.perais@inria.fr        int vnic = rxFifo.begin()->priv;
1982292SN/A        if (vnic != -1 && virtualRegs[vnic].rxPacketOffset > 0)
1993492Sktlim@umich.edu            head = vnic;
2002329SN/A    }
2012292SN/A
2029444SAndreas.Sandberg@ARM.com    regs.RxStatus = set_RxStatus_Head(regs.RxStatus, head);
2039444SAndreas.Sandberg@ARM.com    regs.RxStatus = set_RxStatus_Busy(regs.RxStatus, rxBusyCount);
2049814Sandreas.hansson@arm.com    regs.RxStatus = set_RxStatus_Mapped(regs.RxStatus, rxMappedCount);
2052292SN/A    regs.RxStatus = set_RxStatus_Dirty(regs.RxStatus, rxDirtyCount);
2062292SN/A}
2072292SN/A
2082292SN/Avoid
2092292SN/ADevice::prepareWrite(int cpu, int index)
2102292SN/A{
2112292SN/A    prepareIO(cpu, index);
2122292SN/A}
2132292SN/A
21410386Sandreas.hansson@arm.com/**
2152292SN/A * I/O read of device register
2162292SN/A */
2172292SN/ATick
2182292SN/ADevice::read(PacketPtr pkt)
2192292SN/A{
2202727Sktlim@umich.edu    assert(config.command & PCI_CMD_MSE);
2212727Sktlim@umich.edu    assert(pkt->getAddr() >= BARAddrs[0] && pkt->getSize() < BARSize[0]);
2222727Sktlim@umich.edu
2232727Sktlim@umich.edu    int cpu = pkt->req->contextId();
2242727Sktlim@umich.edu    Addr daddr = pkt->getAddr() - BARAddrs[0];
2252727Sktlim@umich.edu    Addr index = daddr >> Regs::VirtualShift;
2262727Sktlim@umich.edu    Addr raddr = daddr & Regs::VirtualMask;
2272727Sktlim@umich.edu
2282727Sktlim@umich.edu    pkt->allocate();
2292727Sktlim@umich.edu
2302727Sktlim@umich.edu    if (!regValid(raddr))
2312727Sktlim@umich.edu        panic("invalid register: cpu=%d vnic=%d da=%#x pa=%#x size=%d",
2322727Sktlim@umich.edu              cpu, index, daddr, pkt->getAddr(), pkt->getSize());
2332727Sktlim@umich.edu
2342727Sktlim@umich.edu    const Regs::Info &info = regInfo(raddr);
2352727Sktlim@umich.edu    if (!info.read)
2362727Sktlim@umich.edu        panic("read %s (write only): "
2372727Sktlim@umich.edu              "cpu=%d vnic=%d da=%#x pa=%#x size=%d",
2382361SN/A              info.name, cpu, index, daddr, pkt->getAddr(), pkt->getSize());
2392361SN/A
2402361SN/A        panic("read %s (invalid size): "
2412361SN/A              "cpu=%d vnic=%d da=%#x pa=%#x size=%d",
2422727Sktlim@umich.edu              info.name, cpu, index, daddr, pkt->getAddr(), pkt->getSize());
2432727Sktlim@umich.edu
2442727Sktlim@umich.edu    prepareRead(cpu, index);
2452727Sktlim@umich.edu
2462727Sktlim@umich.edu    uint64_t value M5_VAR_USED = 0;
2472727Sktlim@umich.edu    if (pkt->getSize() == 4) {
2482727Sktlim@umich.edu        uint32_t reg = regData32(raddr);
2492727Sktlim@umich.edu        pkt->set(reg);
2502727Sktlim@umich.edu        value = reg;
2512727Sktlim@umich.edu    }
2522727Sktlim@umich.edu
2532727Sktlim@umich.edu    if (pkt->getSize() == 8) {
2542727Sktlim@umich.edu        uint64_t reg = regData64(raddr);
2552727Sktlim@umich.edu        pkt->set(reg);
2562727Sktlim@umich.edu        value = reg;
2572727Sktlim@umich.edu    }
2582727Sktlim@umich.edu
2592727Sktlim@umich.edu    DPRINTF(EthernetPIO,
2602727Sktlim@umich.edu            "read %s: cpu=%d vnic=%d da=%#x pa=%#x size=%d val=%#x\n",
2612727Sktlim@umich.edu            info.name, cpu, index, daddr, pkt->getAddr(), pkt->getSize(), value);
2622727Sktlim@umich.edu
2632727Sktlim@umich.edu    // reading the interrupt status register has the side effect of
2642727Sktlim@umich.edu    // clearing it
2658922Swilliam.wang@arm.com    if (raddr == Regs::IntrStatus)
2664329Sktlim@umich.edu        devIntrClear();
2674329Sktlim@umich.edu
2684329Sktlim@umich.edu    return pioDelay;
2694329Sktlim@umich.edu}
2704329Sktlim@umich.edu
2714329Sktlim@umich.edu/**
2722292SN/A * IPR read of device register
2732292SN/A
2742292SN/A    Fault
2752292SN/ADevice::iprRead(Addr daddr, int cpu, uint64_t &result)
2762292SN/A{
2772292SN/A    if (!regValid(daddr))
2782292SN/A        panic("invalid address: da=%#x", daddr);
2792292SN/A
2802292SN/A    const Regs::Info &info = regInfo(daddr);
2812292SN/A    if (!info.read)
2822292SN/A        panic("reading %s (write only): cpu=%d da=%#x", info.name, cpu, daddr);
2832292SN/A
2842292SN/A    DPRINTF(EthernetPIO, "IPR read %s: cpu=%d da=%#x\n",
2852292SN/A            info.name, cpu, daddr);
2869444SAndreas.Sandberg@ARM.com
2872307SN/A    prepareRead(cpu, 0);
2889444SAndreas.Sandberg@ARM.com
2892367SN/A    if (info.size == 4)
2902307SN/A        result = regData32(daddr);
2912329SN/A
2929444SAndreas.Sandberg@ARM.com    if (info.size == 8)
2932307SN/A        result = regData64(daddr);
2942307SN/A
2952307SN/A    DPRINTF(EthernetPIO, "IPR read %s: cpu=%s da=%#x val=%#x\n",
2962307SN/A            info.name, cpu, result);
2972307SN/A
2982307SN/A    return NoFault;
2999444SAndreas.Sandberg@ARM.com}
3002307SN/A*/
3012307SN/A/**
3022307SN/A * I/O write of device register
3032307SN/A */
3042292SN/ATick
3052292SN/ADevice::write(PacketPtr pkt)
3062329SN/A{
3072329SN/A    assert(config.command & PCI_CMD_MSE);
3082292SN/A    assert(pkt->getAddr() >= BARAddrs[0] && pkt->getSize() < BARSize[0]);
3092329SN/A
3102329SN/A    int cpu = pkt->req->contextId();
3112292SN/A    Addr daddr = pkt->getAddr() - BARAddrs[0];
3122292SN/A    Addr index = daddr >> Regs::VirtualShift;
3132292SN/A    Addr raddr = daddr & Regs::VirtualMask;
3142292SN/A
3152292SN/A    if (!regValid(raddr))
3162329SN/A        panic("invalid register: cpu=%d, da=%#x pa=%#x size=%d",
3172292SN/A                cpu, daddr, pkt->getAddr(), pkt->getSize());
3182292SN/A
3199936SFaissal.Sleiman@arm.com    const Regs::Info &info = regInfo(raddr);
3202292SN/A    if (!info.write)
3212292SN/A        panic("write %s (read only): "
3222292SN/A              "cpu=%d vnic=%d da=%#x pa=%#x size=%d",
3232292SN/A              info.name, cpu, index, daddr, pkt->getAddr(), pkt->getSize());
3242292SN/A
3252292SN/A    if (pkt->getSize() != info.size)
3262329SN/A        panic("write %s (invalid size): "
3272329SN/A              "cpu=%d vnic=%d da=%#x pa=%#x size=%d",
3282329SN/A              info.name, cpu, index, daddr, pkt->getAddr(), pkt->getSize());
3292292SN/A
3302292SN/A    VirtualReg &vnic = virtualRegs[index];
3312292SN/A
3322292SN/A    DPRINTF(EthernetPIO,
3332292SN/A            "write %s vnic %d: cpu=%d val=%#x da=%#x pa=%#x size=%d\n",
3342329SN/A            info.name, index, cpu, info.size == 4 ? pkt->get<uint32_t>() :
3352292SN/A            pkt->get<uint64_t>(), daddr, pkt->getAddr(), pkt->getSize());
3369936SFaissal.Sleiman@arm.com
3379936SFaissal.Sleiman@arm.com    prepareWrite(cpu, index);
3382292SN/A
3392292SN/A    switch (raddr) {
3402292SN/A      case Regs::Config:
3412292SN/A        changeConfig(pkt->get<uint32_t>());
3422292SN/A        break;
3432292SN/A
3442292SN/A      case Regs::Command:
3452292SN/A        command(pkt->get<uint32_t>());
3462292SN/A        break;
3472292SN/A
3482292SN/A      case Regs::IntrStatus:
3492292SN/A        devIntrClear(regs.IntrStatus & pkt->get<uint32_t>());
3502292SN/A        break;
3512292SN/A
3522292SN/A      case Regs::IntrMask:
3532292SN/A        devIntrChangeMask(pkt->get<uint32_t>());
3542292SN/A        break;
3552292SN/A
3562292SN/A      case Regs::RxData:
3572292SN/A        if (Regs::get_RxDone_Busy(vnic.RxDone))
3582292SN/A            panic("receive machine busy with another request! rxState=%s",
3592292SN/A                  RxStateStrings[rxState]);
3602292SN/A
3612329SN/A        vnic.rxUnique = rxUnique++;
3622329SN/A        vnic.RxDone = Regs::RxDone_Busy;
3632292SN/A        vnic.RxData = pkt->get<uint64_t>();
3647720Sgblack@eecs.umich.edu        rxBusyCount++;
3657720Sgblack@eecs.umich.edu
3662292SN/A        if (Regs::get_RxData_Vaddr(pkt->get<uint64_t>())) {
3672292SN/A            panic("vtophys not implemented in newmem");
3682292SN/A#ifdef SINIC_VTOPHYS
3692292SN/A            Addr vaddr = Regs::get_RxData_Addr(reg64);
3702292SN/A            Addr paddr = vtophys(req->xc, vaddr);
3712292SN/A            DPRINTF(EthernetPIO, "write RxData vnic %d (rxunique %d): "
3722292SN/A                    "vaddr=%#x, paddr=%#x\n",
3732292SN/A                    index, vnic.rxUnique, vaddr, paddr);
3742292SN/A
3752292SN/A            vnic.RxData = Regs::set_RxData_Addr(vnic.RxData, paddr);
3762292SN/A#endif
3772292SN/A        } else {
3782292SN/A            DPRINTF(EthernetPIO, "write RxData vnic %d (rxunique %d)\n",
3792292SN/A                    index, vnic.rxUnique);
3802292SN/A        }
3812292SN/A
3822292SN/A        if (vnic.rxIndex == rxFifo.end()) {
3832292SN/A            DPRINTF(EthernetPIO, "request new packet...appending to rxList\n");
3842292SN/A            rxList.push_back(index);
3852292SN/A        } else {
3862292SN/A            DPRINTF(EthernetPIO, "packet exists...appending to rxBusy\n");
3872292SN/A            rxBusy.push_back(index);
3882292SN/A        }
3892292SN/A
3907720Sgblack@eecs.umich.edu        if (rxEnable && (rxState == rxIdle || rxState == rxFifoBlock)) {
3917720Sgblack@eecs.umich.edu            rxState = rxFifoBlock;
3922292SN/A            rxKick();
3932292SN/A        }
3942292SN/A        break;
3952292SN/A
3962292SN/A      case Regs::TxData:
3972292SN/A        if (Regs::get_TxDone_Busy(vnic.TxDone))
3982292SN/A            panic("transmit machine busy with another request! txState=%s",
3992292SN/A                  TxStateStrings[txState]);
4002292SN/A
4012292SN/A        vnic.txUnique = txUnique++;
4022292SN/A        vnic.TxDone = Regs::TxDone_Busy;
4032292SN/A
4042292SN/A        if (Regs::get_TxData_Vaddr(pkt->get<uint64_t>())) {
4052292SN/A            panic("vtophys won't work here in newmem.\n");
4062292SN/A#ifdef SINIC_VTOPHYS
4072292SN/A            Addr vaddr = Regs::get_TxData_Addr(reg64);
4082292SN/A            Addr paddr = vtophys(req->xc, vaddr);
4092292SN/A            DPRINTF(EthernetPIO, "write TxData vnic %d (txunique %d): "
4102292SN/A                    "vaddr=%#x, paddr=%#x\n",
4112292SN/A                    index, vnic.txUnique, vaddr, paddr);
4122292SN/A
4132292SN/A            vnic.TxData = Regs::set_TxData_Addr(vnic.TxData, paddr);
4142292SN/A#endif
4152292SN/A        } else {
41610239Sbinhpham@cs.rutgers.edu            DPRINTF(EthernetPIO, "write TxData vnic %d (txunique %d)\n",
4172292SN/A                    index, vnic.txUnique);
41810239Sbinhpham@cs.rutgers.edu        }
41910239Sbinhpham@cs.rutgers.edu
42010239Sbinhpham@cs.rutgers.edu        if (txList.empty() || txList.front() != index)
42110239Sbinhpham@cs.rutgers.edu            txList.push_back(index);
42210239Sbinhpham@cs.rutgers.edu        if (txEnable && txState == txIdle && txList.front() == index) {
4232292SN/A            txState = txFifoBlock;
42410239Sbinhpham@cs.rutgers.edu            txKick();
42510239Sbinhpham@cs.rutgers.edu        }
42610239Sbinhpham@cs.rutgers.edu        break;
42710239Sbinhpham@cs.rutgers.edu    }
42810239Sbinhpham@cs.rutgers.edu
42910239Sbinhpham@cs.rutgers.edu    return pioDelay;
43010239Sbinhpham@cs.rutgers.edu}
43110239Sbinhpham@cs.rutgers.edu
43210239Sbinhpham@cs.rutgers.eduvoid
43310239Sbinhpham@cs.rutgers.eduDevice::devIntrPost(uint32_t interrupts)
4342292SN/A{
4352292SN/A    if ((interrupts & Regs::Intr_Res))
4368545Ssaidi@eecs.umich.edu        panic("Cannot set a reserved interrupt");
4378545Ssaidi@eecs.umich.edu
4388545Ssaidi@eecs.umich.edu    regs.IntrStatus |= interrupts;
43911357Sstephan.diestelhorst@arm.com
44011357Sstephan.diestelhorst@arm.com    DPRINTF(EthernetIntr,
44111357Sstephan.diestelhorst@arm.com            "interrupt written to intStatus: intr=%#x status=%#x mask=%#x\n",
4428545Ssaidi@eecs.umich.edu            interrupts, regs.IntrStatus, regs.IntrMask);
44310030SAli.Saidi@ARM.com
4448545Ssaidi@eecs.umich.edu    interrupts = regs.IntrStatus & regs.IntrMask;
44511356Skrinat01@arm.com
44611356Skrinat01@arm.com    // Intr_RxHigh is special, we only signal it if we've emptied the fifo
44710030SAli.Saidi@ARM.com    // and then filled it above the high watermark
4489383SAli.Saidi@ARM.com    if (rxEmpty)
4499383SAli.Saidi@ARM.com        rxEmpty = false;
4509383SAli.Saidi@ARM.com    else
4519383SAli.Saidi@ARM.com        interrupts &= ~Regs::Intr_RxHigh;
4529383SAli.Saidi@ARM.com
4539383SAli.Saidi@ARM.com    // Intr_TxLow is special, we only signal it if we've filled up the fifo
4549383SAli.Saidi@ARM.com    // and then dropped below the low watermark
45510030SAli.Saidi@ARM.com    if (txFull)
45610030SAli.Saidi@ARM.com        txFull = false;
45710030SAli.Saidi@ARM.com    else
45810030SAli.Saidi@ARM.com        interrupts &= ~Regs::Intr_TxLow;
45911097Songal@cs.wisc.edu
46011097Songal@cs.wisc.edu    if (interrupts) {
46111097Songal@cs.wisc.edu        Tick when = curTick();
46210030SAli.Saidi@ARM.com        if ((interrupts & Regs::Intr_NoDelay) == 0)
46311097Songal@cs.wisc.edu            when += intrDelay;
46411097Songal@cs.wisc.edu        cpuIntrPost(when);
46511097Songal@cs.wisc.edu    }
46610030SAli.Saidi@ARM.com}
46710030SAli.Saidi@ARM.com
46810030SAli.Saidi@ARM.comvoid
4698545Ssaidi@eecs.umich.eduDevice::devIntrClear(uint32_t interrupts)
4708545Ssaidi@eecs.umich.edu{
4718545Ssaidi@eecs.umich.edu    if ((interrupts & Regs::Intr_Res))
47210030SAli.Saidi@ARM.com        panic("Cannot clear a reserved interrupt");
4738545Ssaidi@eecs.umich.edu
4748545Ssaidi@eecs.umich.edu    regs.IntrStatus &= ~interrupts;
47510149Smarco.elver@ed.ac.uk
47610149Smarco.elver@ed.ac.uk    DPRINTF(EthernetIntr,
4778545Ssaidi@eecs.umich.edu            "interrupt cleared from intStatus: intr=%x status=%x mask=%x\n",
4788545Ssaidi@eecs.umich.edu            interrupts, regs.IntrStatus, regs.IntrMask);
4798545Ssaidi@eecs.umich.edu
48010824SAndreas.Sandberg@ARM.com    if (!(regs.IntrStatus & regs.IntrMask))
4818545Ssaidi@eecs.umich.edu        cpuIntrClear();
4828545Ssaidi@eecs.umich.edu}
4838545Ssaidi@eecs.umich.edu
4848545Ssaidi@eecs.umich.eduvoid
48511097Songal@cs.wisc.eduDevice::devIntrChangeMask(uint32_t newmask)
48611097Songal@cs.wisc.edu{
48711097Songal@cs.wisc.edu    if (regs.IntrMask == newmask)
4888545Ssaidi@eecs.umich.edu        return;
48911097Songal@cs.wisc.edu
4908545Ssaidi@eecs.umich.edu    regs.IntrMask = newmask;
49111097Songal@cs.wisc.edu
49211097Songal@cs.wisc.edu    DPRINTF(EthernetIntr,
49310149Smarco.elver@ed.ac.uk            "interrupt mask changed: intStatus=%x intMask=%x masked=%x\n",
49410149Smarco.elver@ed.ac.uk            regs.IntrStatus, regs.IntrMask, regs.IntrStatus & regs.IntrMask);
49510149Smarco.elver@ed.ac.uk
49610149Smarco.elver@ed.ac.uk    if (regs.IntrStatus & regs.IntrMask)
49710149Smarco.elver@ed.ac.uk        cpuIntrPost(curTick());
49810149Smarco.elver@ed.ac.uk    else
49910149Smarco.elver@ed.ac.uk        cpuIntrClear();
5008545Ssaidi@eecs.umich.edu}
50110030SAli.Saidi@ARM.com
5028545Ssaidi@eecs.umich.eduvoid
5038545Ssaidi@eecs.umich.eduBase::cpuIntrPost(Tick when)
50410474Sandreas.hansson@arm.com{
5058545Ssaidi@eecs.umich.edu    // If the interrupt you want to post is later than an interrupt
50610030SAli.Saidi@ARM.com    // already scheduled, just let it post in the coming one and don't
50710030SAli.Saidi@ARM.com    // schedule another.
50810030SAli.Saidi@ARM.com    // HOWEVER, must be sure that the scheduled intrTick is in the
50910030SAli.Saidi@ARM.com    // future (this was formerly the source of a bug)
51010030SAli.Saidi@ARM.com    /**
51110030SAli.Saidi@ARM.com     * @todo this warning should be removed and the intrTick code should
51210030SAli.Saidi@ARM.com     * be fixed.
51310030SAli.Saidi@ARM.com     */
51410030SAli.Saidi@ARM.com    assert(when >= curTick());
5158545Ssaidi@eecs.umich.edu    assert(intrTick >= curTick() || intrTick == 0);
5168545Ssaidi@eecs.umich.edu    if (!cpuIntrEnable) {
5178545Ssaidi@eecs.umich.edu        DPRINTF(EthernetIntr, "interrupts not enabled.\n",
5189046SAli.Saidi@ARM.com                intrTick);
5198545Ssaidi@eecs.umich.edu        return;
5208545Ssaidi@eecs.umich.edu    }
5218545Ssaidi@eecs.umich.edu
5228545Ssaidi@eecs.umich.edu    if (when > intrTick && intrTick != 0) {
5238545Ssaidi@eecs.umich.edu        DPRINTF(EthernetIntr, "don't need to schedule event...intrTick=%d\n",
5248545Ssaidi@eecs.umich.edu                intrTick);
5258545Ssaidi@eecs.umich.edu        return;
5268545Ssaidi@eecs.umich.edu    }
5272292SN/A
5288199SAli.Saidi@ARM.com    intrTick = when;
5298199SAli.Saidi@ARM.com    if (intrTick < curTick()) {
5308199SAli.Saidi@ARM.com        Debug::breakpoint();
5318199SAli.Saidi@ARM.com        intrTick = curTick();
5328199SAli.Saidi@ARM.com    }
5338199SAli.Saidi@ARM.com
5348199SAli.Saidi@ARM.com    DPRINTF(EthernetIntr, "going to schedule an interrupt for intrTick=%d\n",
5358199SAli.Saidi@ARM.com            intrTick);
5368199SAli.Saidi@ARM.com
5378199SAli.Saidi@ARM.com    if (intrEvent)
5388199SAli.Saidi@ARM.com        intrEvent->squash();
5398199SAli.Saidi@ARM.com    intrEvent = new IntrEvent(this, true);
54010824SAndreas.Sandberg@ARM.com    schedule(intrEvent, intrTick);
5418199SAli.Saidi@ARM.com}
5428199SAli.Saidi@ARM.com
5438199SAli.Saidi@ARM.comvoid
5448199SAli.Saidi@ARM.comBase::cpuInterrupt()
5458199SAli.Saidi@ARM.com{
5468199SAli.Saidi@ARM.com    assert(intrTick == curTick());
5478199SAli.Saidi@ARM.com
5488199SAli.Saidi@ARM.com    // Whether or not there's a pending interrupt, we don't care about
5498272SAli.Saidi@ARM.com    // it anymore
5508545Ssaidi@eecs.umich.edu    intrEvent = 0;
5518545Ssaidi@eecs.umich.edu    intrTick = 0;
5528545Ssaidi@eecs.umich.edu
5538545Ssaidi@eecs.umich.edu    // Don't send an interrupt if there's already one
5549046SAli.Saidi@ARM.com    if (cpuPendingIntr) {
5558545Ssaidi@eecs.umich.edu        DPRINTF(EthernetIntr,
5568545Ssaidi@eecs.umich.edu                "would send an interrupt now, but there's already pending\n");
5578545Ssaidi@eecs.umich.edu    } else {
5588592Sgblack@eecs.umich.edu        // Send interrupt
5598592Sgblack@eecs.umich.edu        cpuPendingIntr = true;
5608545Ssaidi@eecs.umich.edu
5618199SAli.Saidi@ARM.com        DPRINTF(EthernetIntr, "posting interrupt\n");
5628545Ssaidi@eecs.umich.edu        intrPost();
5638199SAli.Saidi@ARM.com    }
56410474Sandreas.hansson@arm.com}
56510474Sandreas.hansson@arm.com
56610474Sandreas.hansson@arm.comvoid
56710474Sandreas.hansson@arm.comBase::cpuIntrClear()
5688545Ssaidi@eecs.umich.edu{
5698545Ssaidi@eecs.umich.edu    if (!cpuPendingIntr)
5708199SAli.Saidi@ARM.com        return;
5718545Ssaidi@eecs.umich.edu
5728545Ssaidi@eecs.umich.edu    if (intrEvent) {
5739046SAli.Saidi@ARM.com        intrEvent->squash();
57410575SMarco.Elver@ARM.com        intrEvent = 0;
5758545Ssaidi@eecs.umich.edu    }
5768545Ssaidi@eecs.umich.edu
5778545Ssaidi@eecs.umich.edu    intrTick = 0;
5788545Ssaidi@eecs.umich.edu
5798545Ssaidi@eecs.umich.edu    cpuPendingIntr = false;
5808545Ssaidi@eecs.umich.edu
5818545Ssaidi@eecs.umich.edu    DPRINTF(EthernetIntr, "clearing cchip interrupt\n");
5828545Ssaidi@eecs.umich.edu    intrClear();
5838545Ssaidi@eecs.umich.edu}
5848592Sgblack@eecs.umich.edu
5858592Sgblack@eecs.umich.edubool
5868592Sgblack@eecs.umich.eduBase::cpuIntrPending() const
5878545Ssaidi@eecs.umich.edu{ return cpuPendingIntr; }
5888545Ssaidi@eecs.umich.edu
5898545Ssaidi@eecs.umich.eduvoid
5908545Ssaidi@eecs.umich.eduDevice::changeConfig(uint32_t newconf)
59110474Sandreas.hansson@arm.com{
59210474Sandreas.hansson@arm.com    uint32_t changed = regs.Config ^ newconf;
59310474Sandreas.hansson@arm.com    if (!changed)
59410474Sandreas.hansson@arm.com        return;
5958545Ssaidi@eecs.umich.edu
5968199SAli.Saidi@ARM.com    regs.Config = newconf;
5978199SAli.Saidi@ARM.com
5988199SAli.Saidi@ARM.com    if ((changed & Regs::Config_IntEn)) {
5998199SAli.Saidi@ARM.com        cpuIntrEnable = regs.Config & Regs::Config_IntEn;
6008199SAli.Saidi@ARM.com        if (cpuIntrEnable) {
6018199SAli.Saidi@ARM.com            if (regs.IntrStatus & regs.IntrMask)
6028199SAli.Saidi@ARM.com                cpuIntrPost(curTick());
6038199SAli.Saidi@ARM.com        } else {
6048199SAli.Saidi@ARM.com            cpuIntrClear();
6058199SAli.Saidi@ARM.com        }
6068199SAli.Saidi@ARM.com    }
6078199SAli.Saidi@ARM.com
6082292SN/A    if ((changed & Regs::Config_TxEn)) {
6092292SN/A        txEnable = regs.Config & Regs::Config_TxEn;
6104032Sktlim@umich.edu        if (txEnable)
6112292SN/A            txKick();
6122292SN/A    }
6132292SN/A
6147720Sgblack@eecs.umich.edu    if ((changed & Regs::Config_RxEn)) {
6157944SGiacomo.Gabrielli@arm.com        rxEnable = regs.Config & Regs::Config_RxEn;
6162292SN/A        if (rxEnable)
6174032Sktlim@umich.edu            rxKick();
6184032Sktlim@umich.edu    }
6192669Sktlim@umich.edu}
6202292SN/A
6217944SGiacomo.Gabrielli@arm.comvoid
6227944SGiacomo.Gabrielli@arm.comDevice::command(uint32_t command)
6237944SGiacomo.Gabrielli@arm.com{
6247944SGiacomo.Gabrielli@arm.com    if (command & Regs::Command_Intr)
6257597Sminkyu.jeong@arm.com        devIntrPost(Regs::Intr_Soft);
6267597Sminkyu.jeong@arm.com
62710231Ssteve.reinhardt@amd.com    if (command & Regs::Command_Reset)
6282329SN/A        reset();
62910824SAndreas.Sandberg@ARM.com}
63010824SAndreas.Sandberg@ARM.com
63110824SAndreas.Sandberg@ARM.comvoid
63210231Ssteve.reinhardt@amd.comDevice::reset()
6337848SAli.Saidi@ARM.com{
6347600Sminkyu.jeong@arm.com    using namespace Regs;
6357600Sminkyu.jeong@arm.com
6367600Sminkyu.jeong@arm.com    memset(&regs, 0, sizeof(regs));
63710824SAndreas.Sandberg@ARM.com
6383731Sktlim@umich.edu    regs.Config = 0;
6392367SN/A    if (params()->rx_thread)
6402367SN/A        regs.Config |= Config_RxThread;
6412292SN/A    if (params()->tx_thread)
6422292SN/A        regs.Config |= Config_TxThread;
64310333Smitch.hayenga@arm.com    if (params()->rss)
6449046SAli.Saidi@ARM.com        regs.Config |= Config_RSS;
6454032Sktlim@umich.edu    if (params()->zero_copy)
6464032Sktlim@umich.edu        regs.Config |= Config_ZeroCopy;
6474032Sktlim@umich.edu    if (params()->delay_copy)
6488199SAli.Saidi@ARM.com        regs.Config |= Config_DelayCopy;
6498199SAli.Saidi@ARM.com    if (params()->virtual_addr)
6502292SN/A        regs.Config |= Config_Vaddr;
6512292SN/A
6522292SN/A    if (params()->delay_copy && params()->zero_copy)
6532292SN/A        panic("Can't delay copy and zero copy");
6542292SN/A
6552292SN/A    regs.IntrMask = Intr_Soft | Intr_RxHigh | Intr_RxPacket | Intr_TxLow;
6562292SN/A    regs.RxMaxCopy = params()->rx_max_copy;
6572292SN/A    regs.TxMaxCopy = params()->tx_max_copy;
6582292SN/A    regs.ZeroCopySize = params()->zero_copy_size;
6592292SN/A    regs.ZeroCopyMark = params()->zero_copy_threshold;
6602292SN/A    regs.VirtualCount = params()->virtual_count;
6612292SN/A    regs.RxMaxIntr = params()->rx_max_intr;
6622292SN/A    regs.RxFifoSize = params()->rx_fifo_size;
6632292SN/A    regs.TxFifoSize = params()->tx_fifo_size;
6642292SN/A    regs.RxFifoLow = params()->rx_fifo_low_mark;
6657720Sgblack@eecs.umich.edu    regs.TxFifoLow = params()->tx_fifo_threshold;
6667720Sgblack@eecs.umich.edu    regs.RxFifoHigh = params()->rx_fifo_threshold;
6672292SN/A    regs.TxFifoHigh = params()->tx_fifo_high_mark;
6684032Sktlim@umich.edu    regs.HwAddr = params()->hardware_address;
6694032Sktlim@umich.edu
6702292SN/A    if (regs.RxMaxCopy < regs.ZeroCopyMark)
6712292SN/A        panic("Must be able to copy at least as many bytes as the threshold");
6722292SN/A
6732292SN/A    if (regs.ZeroCopySize >= regs.ZeroCopyMark)
6742292SN/A        panic("The number of bytes to copy must be less than the threshold");
6752292SN/A
6767944SGiacomo.Gabrielli@arm.com    rxList.clear();
6777944SGiacomo.Gabrielli@arm.com    rxBusy.clear();
6787944SGiacomo.Gabrielli@arm.com    rxActive = -1;
6797944SGiacomo.Gabrielli@arm.com    txList.clear();
68012217Snikos.nikoleris@arm.com    rxBusyCount = 0;
68112217Snikos.nikoleris@arm.com    rxDirtyCount = 0;
68212217Snikos.nikoleris@arm.com    rxMappedCount = 0;
6837848SAli.Saidi@ARM.com
68412217Snikos.nikoleris@arm.com    rxState = rxIdle;
68512217Snikos.nikoleris@arm.com    txState = txIdle;
6867848SAli.Saidi@ARM.com
6872329SN/A    rxFifo.clear();
6887782Sminkyu.jeong@arm.com    rxFifoPtr = rxFifo.end();
6897720Sgblack@eecs.umich.edu    txFifo.clear();
6902292SN/A    rxEmpty = false;
6912292SN/A    rxLow = true;
6922292SN/A    txFull = false;
6932292SN/A
6942292SN/A    int size = virtualRegs.size();
6952292SN/A    virtualRegs.clear();
6962336SN/A    virtualRegs.resize(size);
6972336SN/A    for (int i = 0; i < size; ++i)
6982336SN/A        virtualRegs[i].rxIndex = rxFifo.end();
6992329SN/A}
7002292SN/A
7012329SN/Avoid
7022292SN/ADevice::rxDmaDone()
7032292SN/A{
7048199SAli.Saidi@ARM.com    assert(rxState == rxCopy);
7052292SN/A    rxState = rxCopyDone;
7062292SN/A    DPRINTF(EthernetDMA, "end rx dma write paddr=%#x len=%d\n",
7072292SN/A            rxDmaAddr, rxDmaLen);
7082292SN/A    DDUMP(EthernetData, rxDmaData, rxDmaLen);
7092292SN/A
7102292SN/A    // If the transmit state machine  has a pending DMA, let it go first
7112292SN/A    if (txState == txBeginCopy)
7122292SN/A        txKick();
7132292SN/A
7147720Sgblack@eecs.umich.edu    rxKick();
7157720Sgblack@eecs.umich.edu}
7162292SN/A
7172292SN/Avoid
7182292SN/ADevice::rxKick()
7192292SN/A{
7202292SN/A    VirtualReg *vnic = NULL;
7212292SN/A
7222292SN/A    DPRINTF(EthernetSM, "rxKick: rxState=%s (rxFifo.size=%d)\n",
7232292SN/A            RxStateStrings[rxState], rxFifo.size());
7242292SN/A
7252292SN/A    if (rxKickTick > curTick()) {
7262292SN/A        DPRINTF(EthernetSM, "rxKick: exiting, can't run till %d\n",
7272292SN/A                rxKickTick);
7282292SN/A        return;
7292292SN/A    }
7302292SN/A
7312292SN/A  next:
7322292SN/A    rxFifo.check();
7332292SN/A    if (rxState == rxIdle)
7342292SN/A        goto exit;
7352292SN/A
7362292SN/A    if (rxActive == -1) {
7372292SN/A        if (rxState != rxFifoBlock)
7382292SN/A            panic("no active vnic while in state %s", RxStateStrings[rxState]);
7392292SN/A
7402292SN/A        DPRINTF(EthernetSM, "processing rxState=%s\n",
7412292SN/A                RxStateStrings[rxState]);
7422292SN/A    } else {
7432292SN/A        vnic = &virtualRegs[rxActive];
7442292SN/A        DPRINTF(EthernetSM,
7452329SN/A                "processing rxState=%s for vnic %d (rxunique %d)\n",
7462329SN/A                RxStateStrings[rxState], rxActive, vnic->rxUnique);
7472292SN/A    }
7482292SN/A
7492292SN/A    switch (rxState) {
7502292SN/A      case rxFifoBlock:
7512292SN/A        if (DTRACE(EthernetSM)) {
7527720Sgblack@eecs.umich.edu            PacketFifo::iterator end = rxFifo.end();
7537720Sgblack@eecs.umich.edu            int size = virtualRegs.size();
7542292SN/A            for (int i = 0; i < size; ++i) {
7552292SN/A                VirtualReg *vn = &virtualRegs[i];
7562292SN/A                bool busy = Regs::get_RxDone_Busy(vn->RxDone);
7572292SN/A                if (vn->rxIndex != end) {
7582292SN/A#ifndef NDEBUG
7592292SN/A                    bool dirty = vn->rxPacketOffset > 0;
7602292SN/A                    const char *status;
7612292SN/A
7622292SN/A                    if (busy && dirty)
7632292SN/A                        status = "busy,dirty";
7642292SN/A                    else if (busy)
7652292SN/A                        status = "busy";
7662292SN/A                    else if (dirty)
7676974Stjones1@inf.ed.ac.uk                        status = "dirty";
7686974Stjones1@inf.ed.ac.uk                    else
7696974Stjones1@inf.ed.ac.uk                        status = "mapped";
7706974Stjones1@inf.ed.ac.uk
7716974Stjones1@inf.ed.ac.uk                    DPRINTF(EthernetSM,
7726974Stjones1@inf.ed.ac.uk                            "vnic %d %s (rxunique %d), packet %d, slack %d\n",
7736974Stjones1@inf.ed.ac.uk                            i, status, vn->rxUnique,
7746974Stjones1@inf.ed.ac.uk                            rxFifo.countPacketsBefore(vn->rxIndex),
7756974Stjones1@inf.ed.ac.uk                            vn->rxIndex->slack);
7766974Stjones1@inf.ed.ac.uk#endif
7776974Stjones1@inf.ed.ac.uk                } else if (busy) {
7786974Stjones1@inf.ed.ac.uk                    DPRINTF(EthernetSM, "vnic %d unmapped (rxunique %d)\n",
7796974Stjones1@inf.ed.ac.uk                            i, vn->rxUnique);
7806974Stjones1@inf.ed.ac.uk                }
7816974Stjones1@inf.ed.ac.uk            }
7826974Stjones1@inf.ed.ac.uk        }
7832292SN/A
7842292SN/A        if (!rxBusy.empty()) {
7856974Stjones1@inf.ed.ac.uk            rxActive = rxBusy.front();
7866974Stjones1@inf.ed.ac.uk            rxBusy.pop_front();
7876974Stjones1@inf.ed.ac.uk            vnic = &virtualRegs[rxActive];
7886974Stjones1@inf.ed.ac.uk
7896974Stjones1@inf.ed.ac.uk            if (vnic->rxIndex == rxFifo.end())
7906974Stjones1@inf.ed.ac.uk                panic("continuing vnic without packet\n");
7912292SN/A
7922292SN/A            DPRINTF(EthernetSM,
7932292SN/A                    "continue processing for vnic %d (rxunique %d)\n",
7942292SN/A                    rxActive, vnic->rxUnique);
7958727Snilay@cs.wisc.edu
79611780Sarthur.perais@inria.fr            rxState = rxBeginCopy;
7972292SN/A
79810333Smitch.hayenga@arm.com            int vnic_distance = rxFifo.countPacketsBefore(vnic->rxIndex);
7992678Sktlim@umich.edu            totalVnicDistance += vnic_distance;
8002678Sktlim@umich.edu            numVnicDistance += 1;
8012678Sktlim@umich.edu            if (vnic_distance > _maxVnicDistance) {
8022678Sktlim@umich.edu                maxVnicDistance = vnic_distance;
8032678Sktlim@umich.edu                _maxVnicDistance = vnic_distance;
8042329SN/A            }
8052329SN/A
8062292SN/A            break;
8072292SN/A        }
8082292SN/A
8092292SN/A        if (rxFifoPtr == rxFifo.end()) {
8102292SN/A            DPRINTF(EthernetSM, "receive waiting for data.  Nothing to do.\n");
8112292SN/A            goto exit;
8122292SN/A        }
8132678Sktlim@umich.edu
81411780Sarthur.perais@inria.fr        if (rxList.empty())
8152292SN/A            panic("Not idle, but nothing to do!");
8162292SN/A
8172292SN/A        assert(!rxFifo.empty());
8182292SN/A
8192292SN/A        rxActive = rxList.front();
8202292SN/A        rxList.pop_front();
8212292SN/A        vnic = &virtualRegs[rxActive];
8222292SN/A
8232292SN/A        DPRINTF(EthernetSM,
8242292SN/A                "processing new packet for vnic %d (rxunique %d)\n",
8256974Stjones1@inf.ed.ac.uk                rxActive, vnic->rxUnique);
8266974Stjones1@inf.ed.ac.uk
8276974Stjones1@inf.ed.ac.uk        // Grab a new packet from the fifo.
8286974Stjones1@inf.ed.ac.uk        vnic->rxIndex = rxFifoPtr++;
8296974Stjones1@inf.ed.ac.uk        vnic->rxIndex->priv = rxActive;
8302669Sktlim@umich.edu        vnic->rxPacketOffset = 0;
8312669Sktlim@umich.edu        vnic->rxPacketBytes = vnic->rxIndex->packet->length;
83212749Sgiacomo.travaglini@arm.com        assert(vnic->rxPacketBytes);
83312749Sgiacomo.travaglini@arm.com        rxMappedCount++;
83412749Sgiacomo.travaglini@arm.com
8358481Sgblack@eecs.umich.edu        vnic->rxDoneData = 0;
8362292SN/A        /* scope for variables */ {
8372292SN/A            IpPtr ip(vnic->rxIndex->packet);
8382669Sktlim@umich.edu            if (ip) {
83910031SAli.Saidi@ARM.com                DPRINTF(Ethernet, "ID is %d\n", ip->id());
8403772Sgblack@eecs.umich.edu                vnic->rxDoneData |= Regs::RxDone_IpPacket;
84110031SAli.Saidi@ARM.com                rxIpChecksums++;
84210031SAli.Saidi@ARM.com                if (cksum(ip) != 0) {
84310031SAli.Saidi@ARM.com                    DPRINTF(EthernetCksum, "Rx IP Checksum Error\n");
84410031SAli.Saidi@ARM.com                    vnic->rxDoneData |= Regs::RxDone_IpError;
8452669Sktlim@umich.edu                }
8466974Stjones1@inf.ed.ac.uk                TcpPtr tcp(ip);
8476974Stjones1@inf.ed.ac.uk                UdpPtr udp(ip);
8482292SN/A                if (tcp) {
8492678Sktlim@umich.edu                    DPRINTF(Ethernet,
8502678Sktlim@umich.edu                            "Src Port=%d, Dest Port=%d, Seq=%d, Ack=%d\n",
8512678Sktlim@umich.edu                            tcp->sport(), tcp->dport(), tcp->seq(),
8522678Sktlim@umich.edu                            tcp->ack());
8536974Stjones1@inf.ed.ac.uk                    vnic->rxDoneData |= Regs::RxDone_TcpPacket;
8546974Stjones1@inf.ed.ac.uk                    rxTcpChecksums++;
8556974Stjones1@inf.ed.ac.uk                    if (cksum(tcp) != 0) {
8566974Stjones1@inf.ed.ac.uk                        DPRINTF(EthernetCksum, "Rx TCP Checksum Error\n");
85710342SCurtis.Dunham@arm.com                        vnic->rxDoneData |= Regs::RxDone_TcpError;
8586974Stjones1@inf.ed.ac.uk                    }
8596974Stjones1@inf.ed.ac.uk                } else if (udp) {
8606974Stjones1@inf.ed.ac.uk                    vnic->rxDoneData |= Regs::RxDone_UdpPacket;
8616974Stjones1@inf.ed.ac.uk                    rxUdpChecksums++;
86210342SCurtis.Dunham@arm.com                    if (cksum(udp) != 0) {
86310342SCurtis.Dunham@arm.com                        DPRINTF(EthernetCksum, "Rx UDP Checksum Error\n");
8646974Stjones1@inf.ed.ac.uk                        vnic->rxDoneData |= Regs::RxDone_UdpError;
8656974Stjones1@inf.ed.ac.uk                    }
8666974Stjones1@inf.ed.ac.uk                }
8676974Stjones1@inf.ed.ac.uk            }
8686974Stjones1@inf.ed.ac.uk        }
8696974Stjones1@inf.ed.ac.uk        rxState = rxBeginCopy;
8706974Stjones1@inf.ed.ac.uk        break;
8716974Stjones1@inf.ed.ac.uk
8726974Stjones1@inf.ed.ac.uk      case rxBeginCopy:
8736974Stjones1@inf.ed.ac.uk        if (dmaPending() || getDrainState() != Drainable::Running)
8746974Stjones1@inf.ed.ac.uk            goto exit;
8756974Stjones1@inf.ed.ac.uk
8766974Stjones1@inf.ed.ac.uk        rxDmaAddr = params()->platform->pciToDma(
8772678Sktlim@umich.edu                Regs::get_RxData_Addr(vnic->RxData));
8787720Sgblack@eecs.umich.edu        rxDmaLen = min<unsigned>(Regs::get_RxData_Len(vnic->RxData),
8792292SN/A                                 vnic->rxPacketBytes);
8807720Sgblack@eecs.umich.edu
8813797Sgblack@eecs.umich.edu        /*
8823221Sktlim@umich.edu         * if we're doing zero/delay copy and we're below the fifo
8832292SN/A         * threshold, see if we should try to do the zero/defer copy
8842693Sktlim@umich.edu         */
8854350Sgblack@eecs.umich.edu        if ((Regs::get_Config_ZeroCopy(regs.Config) ||
8866974Stjones1@inf.ed.ac.uk             Regs::get_Config_DelayCopy(regs.Config)) &&
8873326Sktlim@umich.edu            !Regs::get_RxData_NoDelay(vnic->RxData) && rxLow) {
8883326Sktlim@umich.edu            if (rxDmaLen > regs.ZeroCopyMark)
8893326Sktlim@umich.edu                rxDmaLen = regs.ZeroCopySize;
8909046SAli.Saidi@ARM.com        }
89110030SAli.Saidi@ARM.com        rxDmaData = vnic->rxIndex->packet->data + vnic->rxPacketOffset;
8929046SAli.Saidi@ARM.com        rxState = rxCopy;
8933326Sktlim@umich.edu        if (rxDmaAddr == 1LL) {
8943326Sktlim@umich.edu            rxState = rxCopyDone;
8953326Sktlim@umich.edu            break;
8963326Sktlim@umich.edu        }
8973326Sktlim@umich.edu
8983326Sktlim@umich.edu        dmaWrite(rxDmaAddr, rxDmaLen, &rxDmaEvent, rxDmaData);
8993326Sktlim@umich.edu        break;
9007823Ssteve.reinhardt@amd.com
9013326Sktlim@umich.edu      case rxCopy:
9023326Sktlim@umich.edu        DPRINTF(EthernetSM, "receive machine still copying\n");
9033326Sktlim@umich.edu        goto exit;
9042693Sktlim@umich.edu
9052693Sktlim@umich.edu      case rxCopyDone:
9062693Sktlim@umich.edu        vnic->RxDone = vnic->rxDoneData;
9072693Sktlim@umich.edu        vnic->RxDone |= Regs::RxDone_Complete;
9082693Sktlim@umich.edu        rxBusyCount--;
9092693Sktlim@umich.edu
9108481Sgblack@eecs.umich.edu        if (vnic->rxPacketBytes == rxDmaLen) {
9118481Sgblack@eecs.umich.edu            if (vnic->rxPacketOffset)
9128481Sgblack@eecs.umich.edu                rxDirtyCount--;
9138481Sgblack@eecs.umich.edu
9148481Sgblack@eecs.umich.edu            // Packet is complete.  Indicate how many bytes were copied
9158481Sgblack@eecs.umich.edu            vnic->RxDone = Regs::set_RxDone_CopyLen(vnic->RxDone, rxDmaLen);
9168481Sgblack@eecs.umich.edu
9178481Sgblack@eecs.umich.edu            DPRINTF(EthernetSM,
9188481Sgblack@eecs.umich.edu                    "rxKick: packet complete on vnic %d (rxunique %d)\n",
9198481Sgblack@eecs.umich.edu                    rxActive, vnic->rxUnique);
9208481Sgblack@eecs.umich.edu            rxFifo.remove(vnic->rxIndex);
9218481Sgblack@eecs.umich.edu            vnic->rxIndex = rxFifo.end();
9228481Sgblack@eecs.umich.edu            rxMappedCount--;
9238481Sgblack@eecs.umich.edu        } else {
9248481Sgblack@eecs.umich.edu            if (!vnic->rxPacketOffset)
9258481Sgblack@eecs.umich.edu                rxDirtyCount++;
9268481Sgblack@eecs.umich.edu
9278481Sgblack@eecs.umich.edu            vnic->rxPacketBytes -= rxDmaLen;
9284032Sktlim@umich.edu            vnic->rxPacketOffset += rxDmaLen;
9293221Sktlim@umich.edu            vnic->RxDone |= Regs::RxDone_More;
9303221Sktlim@umich.edu            vnic->RxDone = Regs::set_RxDone_CopyLen(vnic->RxDone,
9316974Stjones1@inf.ed.ac.uk                                                    vnic->rxPacketBytes);
9326974Stjones1@inf.ed.ac.uk            DPRINTF(EthernetSM,
9338481Sgblack@eecs.umich.edu                    "rxKick: packet not complete on vnic %d (rxunique %d): "
9346974Stjones1@inf.ed.ac.uk                    "%d bytes left\n",
9356974Stjones1@inf.ed.ac.uk                    rxActive, vnic->rxUnique, vnic->rxPacketBytes);
9366974Stjones1@inf.ed.ac.uk        }
9372669Sktlim@umich.edu
9386974Stjones1@inf.ed.ac.uk        rxActive = -1;
9396974Stjones1@inf.ed.ac.uk        rxState = rxBusy.empty() && rxList.empty() ? rxIdle : rxFifoBlock;
9408481Sgblack@eecs.umich.edu
9416974Stjones1@inf.ed.ac.uk        if (rxFifo.empty()) {
9426974Stjones1@inf.ed.ac.uk            devIntrPost(Regs::Intr_RxEmpty);
9436974Stjones1@inf.ed.ac.uk            rxEmpty = true;
94411780Sarthur.perais@inria.fr        }
94511780Sarthur.perais@inria.fr
9466974Stjones1@inf.ed.ac.uk        if (rxFifo.size() < regs.RxFifoLow)
9476974Stjones1@inf.ed.ac.uk            rxLow = true;
9486974Stjones1@inf.ed.ac.uk
9496974Stjones1@inf.ed.ac.uk        if (rxFifo.size() > regs.RxFifoHigh)
9506974Stjones1@inf.ed.ac.uk            rxLow = false;
9516974Stjones1@inf.ed.ac.uk
9526974Stjones1@inf.ed.ac.uk        devIntrPost(Regs::Intr_RxDMA);
9536974Stjones1@inf.ed.ac.uk        break;
9546974Stjones1@inf.ed.ac.uk
9556974Stjones1@inf.ed.ac.uk      default:
9566974Stjones1@inf.ed.ac.uk        panic("Invalid rxState!");
9576974Stjones1@inf.ed.ac.uk    }
9586974Stjones1@inf.ed.ac.uk
9596974Stjones1@inf.ed.ac.uk    DPRINTF(EthernetSM, "entering next rxState=%s\n",
9606974Stjones1@inf.ed.ac.uk            RxStateStrings[rxState]);
9616974Stjones1@inf.ed.ac.uk
9626974Stjones1@inf.ed.ac.uk    goto next;
9636974Stjones1@inf.ed.ac.uk
9646974Stjones1@inf.ed.ac.uk  exit:
9652292SN/A    /**
9662292SN/A     * @todo do we want to schedule a future kick?
9672292SN/A     */
9682292SN/A    DPRINTF(EthernetSM, "rx state machine exited rxState=%s\n",
96911780Sarthur.perais@inria.fr            RxStateStrings[rxState]);
9702292SN/A}
9712292SN/A
9722292SN/Avoid
9732292SN/ADevice::txDmaDone()
9742292SN/A{
9752292SN/A    assert(txState == txCopy);
9762292SN/A    txState = txCopyDone;
9772292SN/A    DPRINTF(EthernetDMA, "tx dma read paddr=%#x len=%d\n",
9782292SN/A            txDmaAddr, txDmaLen);
9792292SN/A    DDUMP(EthernetData, txDmaData, txDmaLen);
9802292SN/A
9812292SN/A    // If the receive state machine  has a pending DMA, let it go first
9822292SN/A    if (rxState == rxBeginCopy)
9832292SN/A        rxKick();
9842292SN/A
9852292SN/A    txKick();
9862292SN/A}
9872292SN/A
9882292SN/Avoid
9892292SN/ADevice::transmit()
9902292SN/A{
9912292SN/A    if (txFifo.empty()) {
9922292SN/A        DPRINTF(Ethernet, "nothing to transmit\n");
9932329SN/A        return;
9942292SN/A    }
9952292SN/A
9962292SN/A    uint32_t interrupts;
9972292SN/A    EthPacketPtr packet = txFifo.front();
9982292SN/A    if (!interface->sendPacket(packet)) {
9997720Sgblack@eecs.umich.edu        DPRINTF(Ethernet, "Packet Transmit: failed txFifo available %d\n",
10002292SN/A                txFifo.avail());
10017720Sgblack@eecs.umich.edu        return;
10022292SN/A    }
10032292SN/A
10042292SN/A    txFifo.pop();
10052292SN/A#if TRACING_ON
10062292SN/A    if (DTRACE(Ethernet)) {
10072292SN/A        IpPtr ip(packet);
10082292SN/A        if (ip) {
10092292SN/A            DPRINTF(Ethernet, "ID is %d\n", ip->id());
10102329SN/A            TcpPtr tcp(ip);
10112731Sktlim@umich.edu            if (tcp) {
10122292SN/A                DPRINTF(Ethernet,
10132292SN/A                        "Src Port=%d, Dest Port=%d, Seq=%d, Ack=%d\n",
10142292SN/A                        tcp->sport(), tcp->dport(), tcp->seq(),
10152292SN/A                        tcp->ack());
10162292SN/A            }
10172292SN/A        }
10182292SN/A    }
10192727Sktlim@umich.edu#endif
10202292SN/A
10212292SN/A    DDUMP(EthernetData, packet->data, packet->length);
10224032Sktlim@umich.edu    txBytes += packet->length;
10234032Sktlim@umich.edu    txPackets++;
10244032Sktlim@umich.edu
10254032Sktlim@umich.edu    DPRINTF(Ethernet, "Packet Transmit: successful txFifo Available %d\n",
10262292SN/A            txFifo.avail());
10272292SN/A
10282292SN/A    interrupts = Regs::Intr_TxPacket;
10292292SN/A    if (txFifo.size() < regs.TxFifoLow)
10302292SN/A        interrupts |= Regs::Intr_TxLow;
10312329SN/A    devIntrPost(interrupts);
10322292SN/A}
10332292SN/A
10342292SN/Avoid
10352292SN/ADevice::txKick()
10367720Sgblack@eecs.umich.edu{
10372292SN/A    VirtualReg *vnic;
10387720Sgblack@eecs.umich.edu    DPRINTF(EthernetSM, "txKick: txState=%s (txFifo.size=%d)\n",
10392292SN/A            TxStateStrings[txState], txFifo.size());
10402292SN/A
10412329SN/A    if (txKickTick > curTick()) {
10422329SN/A        DPRINTF(EthernetSM, "txKick: exiting, can't run till %d\n",
10432292SN/A                txKickTick);
10442292SN/A        return;
10452292SN/A    }
10462292SN/A
10472292SN/A  next:
10482292SN/A    if (txState == txIdle)
10492292SN/A        goto exit;
10502329SN/A
10512731Sktlim@umich.edu    assert(!txList.empty());
10522292SN/A    vnic = &virtualRegs[txList.front()];
10532292SN/A
10542292SN/A    switch (txState) {
10554032Sktlim@umich.edu      case txFifoBlock:
10564032Sktlim@umich.edu        assert(Regs::get_TxDone_Busy(vnic->TxDone));
10574032Sktlim@umich.edu        if (!txPacket) {
105812749Sgiacomo.travaglini@arm.com            // Grab a new packet from the fifo.
10596974Stjones1@inf.ed.ac.uk            txPacket = make_shared<EthPacketData>(16384);
106012749Sgiacomo.travaglini@arm.com            txPacketOffset = 0;
106112749Sgiacomo.travaglini@arm.com        }
10626974Stjones1@inf.ed.ac.uk
10634032Sktlim@umich.edu        if (txFifo.avail() - txPacket->length <
10642292SN/A            Regs::get_TxData_Len(vnic->TxData)) {
10652292SN/A            DPRINTF(EthernetSM, "transmit fifo full.  Nothing to do.\n");
10662292SN/A            goto exit;
10672292SN/A        }
10682292SN/A
10692292SN/A        txState = txBeginCopy;
10702727Sktlim@umich.edu        break;
10712292SN/A
10722292SN/A      case txBeginCopy:
10732292SN/A        if (dmaPending() || getDrainState() != Drainable::Running)
10742292SN/A            goto exit;
10752292SN/A
10763349Sbinkertn@umich.edu        txDmaAddr = params()->platform->pciToDma(
10772693Sktlim@umich.edu                Regs::get_TxData_Addr(vnic->TxData));
10782693Sktlim@umich.edu        txDmaLen = Regs::get_TxData_Len(vnic->TxData);
10792693Sktlim@umich.edu        txDmaData = txPacket->data + txPacketOffset;
10802693Sktlim@umich.edu        txState = txCopy;
10812693Sktlim@umich.edu
10822693Sktlim@umich.edu        dmaRead(txDmaAddr, txDmaLen, &txDmaEvent, txDmaData);
10832693Sktlim@umich.edu        break;
10842693Sktlim@umich.edu
10852693Sktlim@umich.edu      case txCopy:
10862693Sktlim@umich.edu        DPRINTF(EthernetSM, "transmit machine still copying\n");
10872693Sktlim@umich.edu        goto exit;
10882693Sktlim@umich.edu
10892693Sktlim@umich.edu      case txCopyDone:
10902693Sktlim@umich.edu        vnic->TxDone = txDmaLen | Regs::TxDone_Complete;
10912693Sktlim@umich.edu        txPacket->length += txDmaLen;
10922693Sktlim@umich.edu        if ((vnic->TxData & Regs::TxData_More)) {
10938887Sgeoffrey.blake@arm.com            txPacketOffset += txDmaLen;
10942693Sktlim@umich.edu            txState = txIdle;
10952732Sktlim@umich.edu            devIntrPost(Regs::Intr_TxDMA);
10962693Sktlim@umich.edu            break;
10972693Sktlim@umich.edu        }
10982693Sktlim@umich.edu
10998727Snilay@cs.wisc.edu        assert(txPacket->length <= txFifo.avail());
11008727Snilay@cs.wisc.edu        if ((vnic->TxData & Regs::TxData_Checksum)) {
11018727Snilay@cs.wisc.edu            IpPtr ip(txPacket);
11028727Snilay@cs.wisc.edu            if (ip) {
11032693Sktlim@umich.edu                TcpPtr tcp(ip);
11042693Sktlim@umich.edu                if (tcp) {
11052693Sktlim@umich.edu                    tcp->sum(0);
11062693Sktlim@umich.edu                    tcp->sum(cksum(tcp));
11072693Sktlim@umich.edu                    txTcpChecksums++;
11082678Sktlim@umich.edu                }
11092678Sktlim@umich.edu
11102678Sktlim@umich.edu                UdpPtr udp(ip);
11112678Sktlim@umich.edu                if (udp) {
11122678Sktlim@umich.edu                    udp->sum(0);
11132678Sktlim@umich.edu                    udp->sum(cksum(udp));
11142678Sktlim@umich.edu                    txUdpChecksums++;
11152727Sktlim@umich.edu                }
11162678Sktlim@umich.edu
11172678Sktlim@umich.edu                ip->sum(0);
11182678Sktlim@umich.edu                ip->sum(cksum(ip));
11192678Sktlim@umich.edu                txIpChecksums++;
11202678Sktlim@umich.edu            }
11212678Sktlim@umich.edu        }
112210575SMarco.Elver@ARM.com
112310575SMarco.Elver@ARM.com        txFifo.push(txPacket);
112410575SMarco.Elver@ARM.com        if (txFifo.avail() < regs.TxMaxCopy) {
112510575SMarco.Elver@ARM.com            devIntrPost(Regs::Intr_TxFull);
112610575SMarco.Elver@ARM.com            txFull = true;
112710575SMarco.Elver@ARM.com        }
112810575SMarco.Elver@ARM.com        txPacket = 0;
112910575SMarco.Elver@ARM.com        transmit();
113010575SMarco.Elver@ARM.com        txList.pop_front();
113110575SMarco.Elver@ARM.com        txState = txList.empty() ? txIdle : txFifoBlock;
113210575SMarco.Elver@ARM.com        devIntrPost(Regs::Intr_TxDMA);
113310575SMarco.Elver@ARM.com        break;
113410575SMarco.Elver@ARM.com
113510575SMarco.Elver@ARM.com      default:
11362678Sktlim@umich.edu        panic("Invalid txState!");
11372678Sktlim@umich.edu    }
11382678Sktlim@umich.edu
11392678Sktlim@umich.edu    DPRINTF(EthernetSM, "entering next txState=%s\n",
11402678Sktlim@umich.edu            TxStateStrings[txState]);
11412678Sktlim@umich.edu
11427598Sminkyu.jeong@arm.com    goto next;
11437598Sminkyu.jeong@arm.com
11447598Sminkyu.jeong@arm.com  exit:
11452678Sktlim@umich.edu    /**
11462678Sktlim@umich.edu     * @todo do we want to schedule a future kick?
11472678Sktlim@umich.edu     */
11482678Sktlim@umich.edu    DPRINTF(EthernetSM, "tx state machine exited txState=%s\n",
11492292SN/A            TxStateStrings[txState]);
11502292SN/A}
11512292SN/A
11522292SN/Avoid
11532292SN/ADevice::transferDone()
11542292SN/A{
11552292SN/A    if (txFifo.empty()) {
11562292SN/A        DPRINTF(Ethernet, "transfer complete: txFifo empty...nothing to do\n");
11573126Sktlim@umich.edu        return;
11582292SN/A    }
11592292SN/A
11602292SN/A    DPRINTF(Ethernet, "transfer complete: data in txFifo...schedule xmit\n");
11612292SN/A
11622292SN/A    reschedule(txEvent, clockEdge(Cycles(1)), true);
11632292SN/A}
11642292SN/A
11652292SN/Abool
11662292SN/ADevice::rxFilter(const EthPacketPtr &packet)
11672292SN/A{
11682292SN/A    if (!Regs::get_Config_Filter(regs.Config))
11692292SN/A        return false;
11702292SN/A
11712329SN/A    panic("receive filter not implemented\n");
11722329SN/A    bool drop = true;
11732329SN/A
11742292SN/A#if 0
11759527SMatt.Horsnell@arm.com    string type;
11769527SMatt.Horsnell@arm.com
11779527SMatt.Horsnell@arm.com    EthHdr *eth = packet->eth();
11789527SMatt.Horsnell@arm.com    if (eth->unicast()) {
11799527SMatt.Horsnell@arm.com        // If we're accepting all unicast addresses
11809527SMatt.Horsnell@arm.com        if (acceptUnicast)
11819527SMatt.Horsnell@arm.com            drop = false;
11822292SN/A
11832292SN/A        // If we make a perfect match
11842292SN/A        if (acceptPerfect && params->eaddr == eth.dst())
11852292SN/A            drop = false;
11862292SN/A
11872292SN/A        if (acceptArp && eth->type() == ETH_TYPE_ARP)
11882292SN/A            drop = false;
11892292SN/A
11902292SN/A    } else if (eth->broadcast()) {
11912316SN/A        // if we're accepting broadcasts
11922316SN/A        if (acceptBroadcast)
11932329SN/A            drop = false;
11948727Snilay@cs.wisc.edu
11958727Snilay@cs.wisc.edu    } else if (eth->multicast()) {
11968727Snilay@cs.wisc.edu        // if we're accepting all multicasts
11978727Snilay@cs.wisc.edu        if (acceptMulticast)
11982329SN/A            drop = false;
11992329SN/A
12002329SN/A    }
120112216Snikos.nikoleris@arm.com
120212216Snikos.nikoleris@arm.com    if (drop) {
120312216Snikos.nikoleris@arm.com        DPRINTF(Ethernet, "rxFilter drop\n");
120412216Snikos.nikoleris@arm.com        DDUMP(EthernetData, packet->data, packet->length);
120512216Snikos.nikoleris@arm.com    }
12062732Sktlim@umich.edu#endif
12072316SN/A    return drop;
12082292SN/A}
12092292SN/A
12102292SN/Abool
12116974Stjones1@inf.ed.ac.ukDevice::recvPacket(EthPacketPtr packet)
12126974Stjones1@inf.ed.ac.uk{
12136974Stjones1@inf.ed.ac.uk    rxBytes += packet->length;
12148975Sandreas.hansson@arm.com    rxPackets++;
12156974Stjones1@inf.ed.ac.uk
12166974Stjones1@inf.ed.ac.uk    DPRINTF(Ethernet, "Receiving packet from wire, rxFifo Available is %d\n",
12176974Stjones1@inf.ed.ac.uk            rxFifo.avail());
12186974Stjones1@inf.ed.ac.uk
12196974Stjones1@inf.ed.ac.uk    if (!rxEnable) {
12206974Stjones1@inf.ed.ac.uk        DPRINTF(Ethernet, "receive disabled...packet dropped\n");
12216974Stjones1@inf.ed.ac.uk        return true;
12226974Stjones1@inf.ed.ac.uk    }
12236974Stjones1@inf.ed.ac.uk
12246974Stjones1@inf.ed.ac.uk    if (rxFilter(packet)) {
12256974Stjones1@inf.ed.ac.uk        DPRINTF(Ethernet, "packet filtered...dropped\n");
12262693Sktlim@umich.edu        return true;
12272693Sktlim@umich.edu    }
12282693Sktlim@umich.edu
12292698Sktlim@umich.edu    if (rxFifo.size() >= regs.RxFifoHigh)
12304985Sktlim@umich.edu        devIntrPost(Regs::Intr_RxHigh);
12312698Sktlim@umich.edu
12322693Sktlim@umich.edu    if (!rxFifo.push(packet)) {
12338587Snilay@cs.wisc.edu        DPRINTF(Ethernet,
12348587Snilay@cs.wisc.edu                "packet will not fit in receive buffer...packet dropped\n");
12358587Snilay@cs.wisc.edu        return false;
12368975Sandreas.hansson@arm.com    }
12376974Stjones1@inf.ed.ac.uk
12388133SAli.Saidi@ARM.com    // If we were at the last element, back up one ot go to the new
12398133SAli.Saidi@ARM.com    // last element of the list.
12408133SAli.Saidi@ARM.com    if (rxFifoPtr == rxFifo.end())
12416974Stjones1@inf.ed.ac.uk        --rxFifoPtr;
12426974Stjones1@inf.ed.ac.uk
12432699Sktlim@umich.edu    devIntrPost(Regs::Intr_RxPacket);
12442693Sktlim@umich.edu    rxKick();
12456974Stjones1@inf.ed.ac.uk    return true;
12466974Stjones1@inf.ed.ac.uk}
12476974Stjones1@inf.ed.ac.uk
12486974Stjones1@inf.ed.ac.ukvoid
12496974Stjones1@inf.ed.ac.ukDevice::drainResume()
12506974Stjones1@inf.ed.ac.uk{
12516974Stjones1@inf.ed.ac.uk    Drainable::drainResume();
12526974Stjones1@inf.ed.ac.uk
12532693Sktlim@umich.edu    // During drain we could have left the state machines in a waiting state and
12542693Sktlim@umich.edu    // they wouldn't get out until some other event occured to kick them.
12552727Sktlim@umich.edu    // This way they'll get out immediately
12562693Sktlim@umich.edu    txKick();
12572693Sktlim@umich.edu    rxKick();
12582693Sktlim@umich.edu}
12592693Sktlim@umich.edu
12602693Sktlim@umich.edu//=====================================================================
12612292SN/A//
12629440SAndreas.Sandberg@ARM.com//
12632292SN/Avoid
12642292SN/ABase::serialize(std::ostream &os)
12652292SN/A{
12662292SN/A    // Serialize the PciDevice base class
12672292SN/A    PciDevice::serialize(os);
12682292SN/A
12692292SN/A    SERIALIZE_SCALAR(rxEnable);
12709440SAndreas.Sandberg@ARM.com    SERIALIZE_SCALAR(txEnable);
12712292SN/A    SERIALIZE_SCALAR(cpuIntrEnable);
12722292SN/A
12732292SN/A    /*
12742292SN/A     * Keep track of pending interrupt status.
12752292SN/A     */
12762292SN/A    SERIALIZE_SCALAR(intrTick);
12772292SN/A    SERIALIZE_SCALAR(cpuPendingIntr);
12789440SAndreas.Sandberg@ARM.com    Tick intrEventTick = 0;
12792292SN/A    if (intrEvent)
12802292SN/A        intrEventTick = intrEvent->when();
12812292SN/A    SERIALIZE_SCALAR(intrEventTick);
12822292SN/A}
12832292SN/A
12842292SN/Avoid
12852292SN/ABase::unserialize(Checkpoint *cp, const std::string &section)
12869440SAndreas.Sandberg@ARM.com{
12872292SN/A    // Unserialize the PciDevice base class
12882292SN/A    PciDevice::unserialize(cp, section);
12892292SN/A
12902292SN/A    UNSERIALIZE_SCALAR(rxEnable);
12912329SN/A    UNSERIALIZE_SCALAR(txEnable);
12922329SN/A    UNSERIALIZE_SCALAR(cpuIntrEnable);
12932329SN/A
12949440SAndreas.Sandberg@ARM.com    /*
12952329SN/A     * Keep track of pending interrupt status.
12962329SN/A     */
12972329SN/A    UNSERIALIZE_SCALAR(intrTick);
12982329SN/A    UNSERIALIZE_SCALAR(cpuPendingIntr);
12992329SN/A    Tick intrEventTick;
13002329SN/A    UNSERIALIZE_SCALAR(intrEventTick);
13012329SN/A    if (intrEventTick) {
13022329SN/A        intrEvent = new IntrEvent(this, true);
13039440SAndreas.Sandberg@ARM.com        schedule(intrEvent, intrEventTick);
13049440SAndreas.Sandberg@ARM.com    }
13052329SN/A}
13062329SN/A
13072329SN/Avoid
13089440SAndreas.Sandberg@ARM.comDevice::serialize(std::ostream &os)
13092329SN/A{
13102329SN/A    int count;
13112329SN/A
13122329SN/A    // Serialize the PciDevice base class
13132329SN/A    Base::serialize(os);
13142329SN/A
13152329SN/A    if (rxState == rxCopy)
13169440SAndreas.Sandberg@ARM.com        panic("can't serialize with an in flight dma request rxState=%s",
13179440SAndreas.Sandberg@ARM.com              RxStateStrings[rxState]);
13182329SN/A
13192329SN/A    if (txState == txCopy)
13202329SN/A        panic("can't serialize with an in flight dma request txState=%s",
13212329SN/A              TxStateStrings[txState]);
13222329SN/A
13232329SN/A    /*
13249944Smatt.horsnell@ARM.com     * Serialize the device registers that could be modified by the OS.
13259944Smatt.horsnell@ARM.com     */
1326    SERIALIZE_SCALAR(regs.Config);
1327    SERIALIZE_SCALAR(regs.IntrStatus);
1328    SERIALIZE_SCALAR(regs.IntrMask);
1329    SERIALIZE_SCALAR(regs.RxData);
1330    SERIALIZE_SCALAR(regs.TxData);
1331
1332    /*
1333     * Serialize the virtual nic state
1334     */
1335    int virtualRegsSize = virtualRegs.size();
1336    SERIALIZE_SCALAR(virtualRegsSize);
1337    for (int i = 0; i < virtualRegsSize; ++i) {
1338        VirtualReg *vnic = &virtualRegs[i];
1339
1340        std::string reg = csprintf("vnic%d", i);
1341        paramOut(os, reg + ".RxData", vnic->RxData);
1342        paramOut(os, reg + ".RxDone", vnic->RxDone);
1343        paramOut(os, reg + ".TxData", vnic->TxData);
1344        paramOut(os, reg + ".TxDone", vnic->TxDone);
1345
1346        bool rxPacketExists = vnic->rxIndex != rxFifo.end();
1347        paramOut(os, reg + ".rxPacketExists", rxPacketExists);
1348        if (rxPacketExists) {
1349            int rxPacket = 0;
1350            PacketFifo::iterator i = rxFifo.begin();
1351            while (i != vnic->rxIndex) {
1352                assert(i != rxFifo.end());
1353                ++i;
1354                ++rxPacket;
1355            }
1356
1357            paramOut(os, reg + ".rxPacket", rxPacket);
1358            paramOut(os, reg + ".rxPacketOffset", vnic->rxPacketOffset);
1359            paramOut(os, reg + ".rxPacketBytes", vnic->rxPacketBytes);
1360        }
1361        paramOut(os, reg + ".rxDoneData", vnic->rxDoneData);
1362    }
1363
1364    int rxFifoPtr = -1;
1365    if (this->rxFifoPtr != rxFifo.end())
1366        rxFifoPtr = rxFifo.countPacketsBefore(this->rxFifoPtr);
1367    SERIALIZE_SCALAR(rxFifoPtr);
1368
1369    SERIALIZE_SCALAR(rxActive);
1370    SERIALIZE_SCALAR(rxBusyCount);
1371    SERIALIZE_SCALAR(rxDirtyCount);
1372    SERIALIZE_SCALAR(rxMappedCount);
1373
1374    VirtualList::iterator i, end;
1375    for (count = 0, i = rxList.begin(), end = rxList.end(); i != end; ++i)
1376        paramOut(os, csprintf("rxList%d", count++), *i);
1377    int rxListSize = count;
1378    SERIALIZE_SCALAR(rxListSize);
1379
1380    for (count = 0, i = rxBusy.begin(), end = rxBusy.end(); i != end; ++i)
1381        paramOut(os, csprintf("rxBusy%d", count++), *i);
1382    int rxBusySize = count;
1383    SERIALIZE_SCALAR(rxBusySize);
1384
1385    for (count = 0, i = txList.begin(), end = txList.end(); i != end; ++i)
1386        paramOut(os, csprintf("txList%d", count++), *i);
1387    int txListSize = count;
1388    SERIALIZE_SCALAR(txListSize);
1389
1390    /*
1391     * Serialize rx state machine
1392     */
1393    int rxState = this->rxState;
1394    SERIALIZE_SCALAR(rxState);
1395    SERIALIZE_SCALAR(rxEmpty);
1396    SERIALIZE_SCALAR(rxLow);
1397    rxFifo.serialize("rxFifo", os);
1398
1399    /*
1400     * Serialize tx state machine
1401     */
1402    int txState = this->txState;
1403    SERIALIZE_SCALAR(txState);
1404    SERIALIZE_SCALAR(txFull);
1405    txFifo.serialize("txFifo", os);
1406    bool txPacketExists = txPacket != nullptr;
1407    SERIALIZE_SCALAR(txPacketExists);
1408    if (txPacketExists) {
1409        txPacket->serialize("txPacket", os);
1410        SERIALIZE_SCALAR(txPacketOffset);
1411        SERIALIZE_SCALAR(txPacketBytes);
1412    }
1413
1414    /*
1415     * If there's a pending transmit, store the time so we can
1416     * reschedule it later
1417     */
1418    Tick transmitTick = txEvent.scheduled() ? txEvent.when() - curTick() : 0;
1419    SERIALIZE_SCALAR(transmitTick);
1420}
1421
1422void
1423Device::unserialize(Checkpoint *cp, const std::string &section)
1424{
1425    // Unserialize the PciDevice base class
1426    Base::unserialize(cp, section);
1427
1428    /*
1429     * Unserialize the device registers that may have been written by the OS.
1430     */
1431    UNSERIALIZE_SCALAR(regs.Config);
1432    UNSERIALIZE_SCALAR(regs.IntrStatus);
1433    UNSERIALIZE_SCALAR(regs.IntrMask);
1434    UNSERIALIZE_SCALAR(regs.RxData);
1435    UNSERIALIZE_SCALAR(regs.TxData);
1436
1437    UNSERIALIZE_SCALAR(rxActive);
1438    UNSERIALIZE_SCALAR(rxBusyCount);
1439    UNSERIALIZE_SCALAR(rxDirtyCount);
1440    UNSERIALIZE_SCALAR(rxMappedCount);
1441
1442    int rxListSize;
1443    UNSERIALIZE_SCALAR(rxListSize);
1444    rxList.clear();
1445    for (int i = 0; i < rxListSize; ++i) {
1446        int value;
1447        paramIn(cp, section, csprintf("rxList%d", i), value);
1448        rxList.push_back(value);
1449    }
1450
1451    int rxBusySize;
1452    UNSERIALIZE_SCALAR(rxBusySize);
1453    rxBusy.clear();
1454    for (int i = 0; i < rxBusySize; ++i) {
1455        int value;
1456        paramIn(cp, section, csprintf("rxBusy%d", i), value);
1457        rxBusy.push_back(value);
1458    }
1459
1460    int txListSize;
1461    UNSERIALIZE_SCALAR(txListSize);
1462    txList.clear();
1463    for (int i = 0; i < txListSize; ++i) {
1464        int value;
1465        paramIn(cp, section, csprintf("txList%d", i), value);
1466        txList.push_back(value);
1467    }
1468
1469    /*
1470     * Unserialize rx state machine
1471     */
1472    int rxState;
1473    UNSERIALIZE_SCALAR(rxState);
1474    UNSERIALIZE_SCALAR(rxEmpty);
1475    UNSERIALIZE_SCALAR(rxLow);
1476    this->rxState = (RxState) rxState;
1477    rxFifo.unserialize("rxFifo", cp, section);
1478
1479    int rxFifoPtr;
1480    UNSERIALIZE_SCALAR(rxFifoPtr);
1481    if (rxFifoPtr >= 0) {
1482        this->rxFifoPtr = rxFifo.begin();
1483        for (int i = 0; i < rxFifoPtr; ++i)
1484            ++this->rxFifoPtr;
1485    } else {
1486        this->rxFifoPtr = rxFifo.end();
1487    }
1488
1489    /*
1490     * Unserialize tx state machine
1491     */
1492    int txState;
1493    UNSERIALIZE_SCALAR(txState);
1494    UNSERIALIZE_SCALAR(txFull);
1495    this->txState = (TxState) txState;
1496    txFifo.unserialize("txFifo", cp, section);
1497    bool txPacketExists;
1498    UNSERIALIZE_SCALAR(txPacketExists);
1499    txPacket = 0;
1500    if (txPacketExists) {
1501        txPacket = make_shared<EthPacketData>(16384);
1502        txPacket->unserialize("txPacket", cp, section);
1503        UNSERIALIZE_SCALAR(txPacketOffset);
1504        UNSERIALIZE_SCALAR(txPacketBytes);
1505    }
1506
1507    /*
1508     * unserialize the virtual nic registers/state
1509     *
1510     * this must be done after the unserialization of the rxFifo
1511     * because the packet iterators depend on the fifo being populated
1512     */
1513    int virtualRegsSize;
1514    UNSERIALIZE_SCALAR(virtualRegsSize);
1515    virtualRegs.clear();
1516    virtualRegs.resize(virtualRegsSize);
1517    for (int i = 0; i < virtualRegsSize; ++i) {
1518        VirtualReg *vnic = &virtualRegs[i];
1519        std::string reg = csprintf("vnic%d", i);
1520
1521        paramIn(cp, section, reg + ".RxData", vnic->RxData);
1522        paramIn(cp, section, reg + ".RxDone", vnic->RxDone);
1523        paramIn(cp, section, reg + ".TxData", vnic->TxData);
1524        paramIn(cp, section, reg + ".TxDone", vnic->TxDone);
1525
1526        vnic->rxUnique = rxUnique++;
1527        vnic->txUnique = txUnique++;
1528
1529        bool rxPacketExists;
1530        paramIn(cp, section, reg + ".rxPacketExists", rxPacketExists);
1531        if (rxPacketExists) {
1532            int rxPacket;
1533            paramIn(cp, section, reg + ".rxPacket", rxPacket);
1534            vnic->rxIndex = rxFifo.begin();
1535            while (rxPacket--)
1536                ++vnic->rxIndex;
1537
1538            paramIn(cp, section, reg + ".rxPacketOffset",
1539                    vnic->rxPacketOffset);
1540            paramIn(cp, section, reg + ".rxPacketBytes", vnic->rxPacketBytes);
1541        } else {
1542            vnic->rxIndex = rxFifo.end();
1543        }
1544        paramIn(cp, section, reg + ".rxDoneData", vnic->rxDoneData);
1545    }
1546
1547    /*
1548     * If there's a pending transmit, reschedule it now
1549     */
1550    Tick transmitTick;
1551    UNSERIALIZE_SCALAR(transmitTick);
1552    if (transmitTick)
1553        schedule(txEvent, curTick() + transmitTick);
1554
1555    pioPort.sendRangeChange();
1556
1557}
1558
1559} // namespace Sinic
1560
1561Sinic::Device *
1562SinicParams::create()
1563{
1564    return new Sinic::Device(this);
1565}
1566