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(®s, 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 §ion) 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 §ion) 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