sinic.cc revision 11006
17119Sgblack@eecs.umich.edu/* 27119Sgblack@eecs.umich.edu * Copyright (c) 2004-2005 The Regents of The University of Michigan 37120Sgblack@eecs.umich.edu * All rights reserved. 47120Sgblack@eecs.umich.edu * 57120Sgblack@eecs.umich.edu * Redistribution and use in source and binary forms, with or without 67120Sgblack@eecs.umich.edu * modification, are permitted provided that the following conditions are 77120Sgblack@eecs.umich.edu * met: redistributions of source code must retain the above copyright 87120Sgblack@eecs.umich.edu * notice, this list of conditions and the following disclaimer; 97120Sgblack@eecs.umich.edu * redistributions in binary form must reproduce the above copyright 107120Sgblack@eecs.umich.edu * notice, this list of conditions and the following disclaimer in the 117120Sgblack@eecs.umich.edu * documentation and/or other materials provided with the distribution; 127120Sgblack@eecs.umich.edu * neither the name of the copyright holders nor the names of its 137120Sgblack@eecs.umich.edu * contributors may be used to endorse or promote products derived from 147120Sgblack@eecs.umich.edu * this software without specific prior written permission. 157119Sgblack@eecs.umich.edu * 167119Sgblack@eecs.umich.edu * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 177119Sgblack@eecs.umich.edu * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 187119Sgblack@eecs.umich.edu * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR 197119Sgblack@eecs.umich.edu * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT 207119Sgblack@eecs.umich.edu * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 217119Sgblack@eecs.umich.edu * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT 227119Sgblack@eecs.umich.edu * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 237119Sgblack@eecs.umich.edu * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 247119Sgblack@eecs.umich.edu * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 257119Sgblack@eecs.umich.edu * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 267119Sgblack@eecs.umich.edu * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 277119Sgblack@eecs.umich.edu * 287119Sgblack@eecs.umich.edu * Authors: Nathan Binkert 297119Sgblack@eecs.umich.edu */ 307119Sgblack@eecs.umich.edu 317119Sgblack@eecs.umich.edu#include <deque> 327119Sgblack@eecs.umich.edu#include <limits> 337119Sgblack@eecs.umich.edu#include <string> 347119Sgblack@eecs.umich.edu 357119Sgblack@eecs.umich.edu#ifdef SINIC_VTOPHYS 367119Sgblack@eecs.umich.edu#include "arch/vtophys.hh" 377119Sgblack@eecs.umich.edu#endif 387119Sgblack@eecs.umich.edu#include "base/compiler.hh" 397119Sgblack@eecs.umich.edu#include "base/debug.hh" 407119Sgblack@eecs.umich.edu#include "base/inet.hh" 417119Sgblack@eecs.umich.edu#include "base/types.hh" 427119Sgblack@eecs.umich.edu#include "config/the_isa.hh" 437119Sgblack@eecs.umich.edu#include "debug/EthernetAll.hh" 447646Sgene.wu@arm.com#include "dev/etherlink.hh" 457646Sgene.wu@arm.com#include "dev/sinic.hh" 467646Sgene.wu@arm.com#include "mem/packet.hh" 477646Sgene.wu@arm.com#include "mem/packet_access.hh" 487646Sgene.wu@arm.com#include "sim/eventq.hh" 497646Sgene.wu@arm.com#include "sim/stats.hh" 507646Sgene.wu@arm.com 517646Sgene.wu@arm.comusing namespace std; 527646Sgene.wu@arm.comusing namespace Net; 537646Sgene.wu@arm.comusing namespace TheISA; 547646Sgene.wu@arm.com 557646Sgene.wu@arm.comnamespace Sinic { 567646Sgene.wu@arm.com 577646Sgene.wu@arm.comconst char *RxStateStrings[] = 587646Sgene.wu@arm.com{ 597646Sgene.wu@arm.com "rxIdle", 607646Sgene.wu@arm.com "rxFifoBlock", 617646Sgene.wu@arm.com "rxBeginCopy", 627646Sgene.wu@arm.com "rxCopy", 637646Sgene.wu@arm.com "rxCopyDone" 647646Sgene.wu@arm.com}; 657646Sgene.wu@arm.com 667646Sgene.wu@arm.comconst char *TxStateStrings[] = 677646Sgene.wu@arm.com{ 687646Sgene.wu@arm.com "txIdle", 697646Sgene.wu@arm.com "txFifoBlock", 707646Sgene.wu@arm.com "txBeginCopy", 717646Sgene.wu@arm.com "txCopy", 727646Sgene.wu@arm.com "txCopyDone" 737205Sgblack@eecs.umich.edu}; 747205Sgblack@eecs.umich.edu 757205Sgblack@eecs.umich.edu 767205Sgblack@eecs.umich.edu/////////////////////////////////////////////////////////////////////// 777205Sgblack@eecs.umich.edu// 787205Sgblack@eecs.umich.edu// Sinic PCI Device 797205Sgblack@eecs.umich.edu// 807205Sgblack@eecs.umich.eduBase::Base(const Params *p) 817205Sgblack@eecs.umich.edu : EtherDevBase(p), rxEnable(false), txEnable(false), 827205Sgblack@eecs.umich.edu intrDelay(p->intr_delay), intrTick(0), cpuIntrEnable(false), 837205Sgblack@eecs.umich.edu cpuPendingIntr(false), intrEvent(0), interface(NULL) 847205Sgblack@eecs.umich.edu{ 857205Sgblack@eecs.umich.edu} 867205Sgblack@eecs.umich.edu 877205Sgblack@eecs.umich.eduDevice::Device(const Params *p) 887205Sgblack@eecs.umich.edu : Base(p), rxUnique(0), txUnique(0), 897205Sgblack@eecs.umich.edu virtualRegs(p->virtual_count < 1 ? 1 : p->virtual_count), 907205Sgblack@eecs.umich.edu rxFifo(p->rx_fifo_size), txFifo(p->tx_fifo_size), 917205Sgblack@eecs.umich.edu rxKickTick(0), txKickTick(0), 927205Sgblack@eecs.umich.edu txEvent(this), rxDmaEvent(this), txDmaEvent(this), 937205Sgblack@eecs.umich.edu dmaReadDelay(p->dma_read_delay), dmaReadFactor(p->dma_read_factor), 947205Sgblack@eecs.umich.edu dmaWriteDelay(p->dma_write_delay), dmaWriteFactor(p->dma_write_factor) 957205Sgblack@eecs.umich.edu{ 967205Sgblack@eecs.umich.edu interface = new Interface(name() + ".int0", this); 977205Sgblack@eecs.umich.edu reset(); 987205Sgblack@eecs.umich.edu 997205Sgblack@eecs.umich.edu} 1007205Sgblack@eecs.umich.edu 1017597Sminkyu.jeong@arm.comDevice::~Device() 1027597Sminkyu.jeong@arm.com{} 1037205Sgblack@eecs.umich.edu 1047205Sgblack@eecs.umich.eduvoid 1057646Sgene.wu@arm.comDevice::regStats() 1067646Sgene.wu@arm.com{ 1077408Sgblack@eecs.umich.edu Base::regStats(); 1087408Sgblack@eecs.umich.edu 1097408Sgblack@eecs.umich.edu _maxVnicDistance = 0; 1107205Sgblack@eecs.umich.edu 1117205Sgblack@eecs.umich.edu maxVnicDistance 1127205Sgblack@eecs.umich.edu .name(name() + ".maxVnicDistance") 1137205Sgblack@eecs.umich.edu .desc("maximum vnic distance") 1147205Sgblack@eecs.umich.edu ; 1157205Sgblack@eecs.umich.edu 1167205Sgblack@eecs.umich.edu totalVnicDistance 1177205Sgblack@eecs.umich.edu .name(name() + ".totalVnicDistance") 1187205Sgblack@eecs.umich.edu .desc("total vnic distance") 1197205Sgblack@eecs.umich.edu ; 1207205Sgblack@eecs.umich.edu numVnicDistance 1217205Sgblack@eecs.umich.edu .name(name() + ".numVnicDistance") 1227205Sgblack@eecs.umich.edu .desc("number of vnic distance measurements") 1237205Sgblack@eecs.umich.edu ; 1247205Sgblack@eecs.umich.edu 1257205Sgblack@eecs.umich.edu avgVnicDistance 1267205Sgblack@eecs.umich.edu .name(name() + ".avgVnicDistance") 1277205Sgblack@eecs.umich.edu .desc("average vnic distance") 1287205Sgblack@eecs.umich.edu ; 1297205Sgblack@eecs.umich.edu 1307205Sgblack@eecs.umich.edu avgVnicDistance = totalVnicDistance / numVnicDistance; 1317205Sgblack@eecs.umich.edu} 1327205Sgblack@eecs.umich.edu 1337205Sgblack@eecs.umich.eduvoid 1347597Sminkyu.jeong@arm.comDevice::resetStats() 1357597Sminkyu.jeong@arm.com{ 1367205Sgblack@eecs.umich.edu Base::resetStats(); 1377205Sgblack@eecs.umich.edu 1387646Sgene.wu@arm.com _maxVnicDistance = 0; 1397646Sgene.wu@arm.com} 1407408Sgblack@eecs.umich.edu 1417408Sgblack@eecs.umich.eduEtherInt* 1427408Sgblack@eecs.umich.eduDevice::getEthPort(const std::string &if_name, int idx) 1437205Sgblack@eecs.umich.edu{ 1447205Sgblack@eecs.umich.edu if (if_name == "interface") { 1457205Sgblack@eecs.umich.edu if (interface->getPeer()) 1467205Sgblack@eecs.umich.edu panic("interface already connected to\n"); 1477205Sgblack@eecs.umich.edu 1487205Sgblack@eecs.umich.edu return interface; 1497205Sgblack@eecs.umich.edu } 1507205Sgblack@eecs.umich.edu return NULL; 1517205Sgblack@eecs.umich.edu} 1527205Sgblack@eecs.umich.edu 1537205Sgblack@eecs.umich.edu 1547205Sgblack@eecs.umich.eduvoid 1557205Sgblack@eecs.umich.eduDevice::prepareIO(ContextID cpu, int index) 1567205Sgblack@eecs.umich.edu{ 1577205Sgblack@eecs.umich.edu int size = virtualRegs.size(); 1587205Sgblack@eecs.umich.edu if (index > size) 1597205Sgblack@eecs.umich.edu panic("Trying to access a vnic that doesn't exist %d > %d\n", 1607205Sgblack@eecs.umich.edu index, size); 1617205Sgblack@eecs.umich.edu} 1627205Sgblack@eecs.umich.edu 1637205Sgblack@eecs.umich.edu//add stats for head of line blocking 1647205Sgblack@eecs.umich.edu//add stats for average fifo length 1657205Sgblack@eecs.umich.edu//add stats for average number of vnics busy 1667205Sgblack@eecs.umich.edu 1677205Sgblack@eecs.umich.eduvoid 1687205Sgblack@eecs.umich.eduDevice::prepareRead(ContextID cpu, int index) 1697408Sgblack@eecs.umich.edu{ 1707408Sgblack@eecs.umich.edu using namespace Regs; 1717408Sgblack@eecs.umich.edu prepareIO(cpu, index); 1727408Sgblack@eecs.umich.edu 1737205Sgblack@eecs.umich.edu VirtualReg &vnic = virtualRegs[index]; 1747205Sgblack@eecs.umich.edu 1757205Sgblack@eecs.umich.edu // update rx registers 1767205Sgblack@eecs.umich.edu uint64_t rxdone = vnic.RxDone; 1777119Sgblack@eecs.umich.edu rxdone = set_RxDone_Packets(rxdone, rxFifo.countPacketsAfter(rxFifoPtr)); 1787119Sgblack@eecs.umich.edu rxdone = set_RxDone_Empty(rxdone, rxFifo.empty()); 1797119Sgblack@eecs.umich.edu rxdone = set_RxDone_High(rxdone, rxFifo.size() > regs.RxFifoHigh); 1807119Sgblack@eecs.umich.edu rxdone = set_RxDone_NotHigh(rxdone, rxLow); 1817119Sgblack@eecs.umich.edu regs.RxData = vnic.RxData; 1827119Sgblack@eecs.umich.edu regs.RxDone = rxdone; 1837119Sgblack@eecs.umich.edu regs.RxWait = rxdone; 1847119Sgblack@eecs.umich.edu 1857119Sgblack@eecs.umich.edu // update tx regsiters 1867119Sgblack@eecs.umich.edu uint64_t txdone = vnic.TxDone; 1877119Sgblack@eecs.umich.edu txdone = set_TxDone_Packets(txdone, txFifo.packets()); 1887119Sgblack@eecs.umich.edu txdone = set_TxDone_Full(txdone, txFifo.avail() < regs.TxMaxCopy); 1897119Sgblack@eecs.umich.edu txdone = set_TxDone_Low(txdone, txFifo.size() < regs.TxFifoLow); 1907119Sgblack@eecs.umich.edu regs.TxData = vnic.TxData; 1917119Sgblack@eecs.umich.edu regs.TxDone = txdone; 1927119Sgblack@eecs.umich.edu regs.TxWait = txdone; 1937119Sgblack@eecs.umich.edu 1947119Sgblack@eecs.umich.edu int head = 0xffff; 1957119Sgblack@eecs.umich.edu 1967119Sgblack@eecs.umich.edu if (!rxFifo.empty()) { 1977119Sgblack@eecs.umich.edu int vnic = rxFifo.begin()->priv; 1987597Sminkyu.jeong@arm.com if (vnic != -1 && virtualRegs[vnic].rxPacketOffset > 0) 1997597Sminkyu.jeong@arm.com head = vnic; 2007119Sgblack@eecs.umich.edu } 2017119Sgblack@eecs.umich.edu 2027646Sgene.wu@arm.com regs.RxStatus = set_RxStatus_Head(regs.RxStatus, head); 2037646Sgene.wu@arm.com regs.RxStatus = set_RxStatus_Busy(regs.RxStatus, rxBusyCount); 2047408Sgblack@eecs.umich.edu regs.RxStatus = set_RxStatus_Mapped(regs.RxStatus, rxMappedCount); 2057408Sgblack@eecs.umich.edu regs.RxStatus = set_RxStatus_Dirty(regs.RxStatus, rxDirtyCount); 2067408Sgblack@eecs.umich.edu} 2077119Sgblack@eecs.umich.edu 2087119Sgblack@eecs.umich.eduvoid 2097119Sgblack@eecs.umich.eduDevice::prepareWrite(ContextID cpu, int index) 2107119Sgblack@eecs.umich.edu{ 2117639Sgblack@eecs.umich.edu prepareIO(cpu, index); 2127639Sgblack@eecs.umich.edu} 2137639Sgblack@eecs.umich.edu 2147639Sgblack@eecs.umich.edu/** 2157639Sgblack@eecs.umich.edu * I/O read of device register 2167639Sgblack@eecs.umich.edu */ 2177639Sgblack@eecs.umich.eduTick 2187639Sgblack@eecs.umich.eduDevice::read(PacketPtr pkt) 2197639Sgblack@eecs.umich.edu{ 2207639Sgblack@eecs.umich.edu assert(config.command & PCI_CMD_MSE); 2217639Sgblack@eecs.umich.edu assert(pkt->getAddr() >= BARAddrs[0] && pkt->getSize() < BARSize[0]); 2227639Sgblack@eecs.umich.edu 2237639Sgblack@eecs.umich.edu ContextID cpu = pkt->req->contextId(); 2247639Sgblack@eecs.umich.edu Addr daddr = pkt->getAddr() - BARAddrs[0]; 2257639Sgblack@eecs.umich.edu Addr index = daddr >> Regs::VirtualShift; 2267639Sgblack@eecs.umich.edu Addr raddr = daddr & Regs::VirtualMask; 2277639Sgblack@eecs.umich.edu 2287639Sgblack@eecs.umich.edu if (!regValid(raddr)) 2297639Sgblack@eecs.umich.edu panic("invalid register: cpu=%d vnic=%d da=%#x pa=%#x size=%d", 2307639Sgblack@eecs.umich.edu cpu, index, daddr, pkt->getAddr(), pkt->getSize()); 2317639Sgblack@eecs.umich.edu 2327639Sgblack@eecs.umich.edu const Regs::Info &info = regInfo(raddr); 2337639Sgblack@eecs.umich.edu if (!info.read) 2347639Sgblack@eecs.umich.edu panic("read %s (write only): " 2357639Sgblack@eecs.umich.edu "cpu=%d vnic=%d da=%#x pa=%#x size=%d", 2367639Sgblack@eecs.umich.edu info.name, cpu, index, daddr, pkt->getAddr(), pkt->getSize()); 2378072SGiacomo.Gabrielli@arm.com 2388072SGiacomo.Gabrielli@arm.com panic("read %s (invalid size): " 2397639Sgblack@eecs.umich.edu "cpu=%d vnic=%d da=%#x pa=%#x size=%d", 2407639Sgblack@eecs.umich.edu info.name, cpu, index, daddr, pkt->getAddr(), pkt->getSize()); 2417646Sgene.wu@arm.com 2427646Sgene.wu@arm.com prepareRead(cpu, index); 2437639Sgblack@eecs.umich.edu 2447639Sgblack@eecs.umich.edu uint64_t value M5_VAR_USED = 0; 2457639Sgblack@eecs.umich.edu if (pkt->getSize() == 4) { 2467639Sgblack@eecs.umich.edu uint32_t reg = regData32(raddr); 2477639Sgblack@eecs.umich.edu pkt->set(reg); 2487639Sgblack@eecs.umich.edu value = reg; 2497639Sgblack@eecs.umich.edu } 2507120Sgblack@eecs.umich.edu 2517120Sgblack@eecs.umich.edu if (pkt->getSize() == 8) { 2527120Sgblack@eecs.umich.edu uint64_t reg = regData64(raddr); 2537120Sgblack@eecs.umich.edu pkt->set(reg); 2547120Sgblack@eecs.umich.edu value = reg; 2557120Sgblack@eecs.umich.edu } 2567120Sgblack@eecs.umich.edu 2577120Sgblack@eecs.umich.edu DPRINTF(EthernetPIO, 2587120Sgblack@eecs.umich.edu "read %s: cpu=%d vnic=%d da=%#x pa=%#x size=%d val=%#x\n", 2597120Sgblack@eecs.umich.edu info.name, cpu, index, daddr, pkt->getAddr(), pkt->getSize(), value); 2607120Sgblack@eecs.umich.edu 2617120Sgblack@eecs.umich.edu // reading the interrupt status register has the side effect of 2627120Sgblack@eecs.umich.edu // clearing it 2637120Sgblack@eecs.umich.edu if (raddr == Regs::IntrStatus) 2647120Sgblack@eecs.umich.edu devIntrClear(); 2657120Sgblack@eecs.umich.edu 2667120Sgblack@eecs.umich.edu return pioDelay; 2677120Sgblack@eecs.umich.edu} 2687120Sgblack@eecs.umich.edu 2697120Sgblack@eecs.umich.edu/** 2707120Sgblack@eecs.umich.edu * IPR read of device register 2717120Sgblack@eecs.umich.edu 2727120Sgblack@eecs.umich.edu Fault 2737120Sgblack@eecs.umich.eduDevice::iprRead(Addr daddr, ContextID cpu, uint64_t &result) 2747120Sgblack@eecs.umich.edu{ 2757597Sminkyu.jeong@arm.com if (!regValid(daddr)) 2767597Sminkyu.jeong@arm.com panic("invalid address: da=%#x", daddr); 2777120Sgblack@eecs.umich.edu 2787120Sgblack@eecs.umich.edu const Regs::Info &info = regInfo(daddr); 2797646Sgene.wu@arm.com if (!info.read) 2807646Sgene.wu@arm.com panic("reading %s (write only): cpu=%d da=%#x", info.name, cpu, daddr); 2817408Sgblack@eecs.umich.edu 2827408Sgblack@eecs.umich.edu DPRINTF(EthernetPIO, "IPR read %s: cpu=%d da=%#x\n", 2837408Sgblack@eecs.umich.edu info.name, cpu, daddr); 2847120Sgblack@eecs.umich.edu 2857120Sgblack@eecs.umich.edu prepareRead(cpu, 0); 2867120Sgblack@eecs.umich.edu 2877120Sgblack@eecs.umich.edu if (info.size == 4) 2887639Sgblack@eecs.umich.edu result = regData32(daddr); 2897639Sgblack@eecs.umich.edu 2907639Sgblack@eecs.umich.edu if (info.size == 8) 2917639Sgblack@eecs.umich.edu result = regData64(daddr); 2927639Sgblack@eecs.umich.edu 2937639Sgblack@eecs.umich.edu DPRINTF(EthernetPIO, "IPR read %s: cpu=%s da=%#x val=%#x\n", 2947639Sgblack@eecs.umich.edu info.name, cpu, result); 2957639Sgblack@eecs.umich.edu 2967639Sgblack@eecs.umich.edu return NoFault; 2977639Sgblack@eecs.umich.edu} 2987639Sgblack@eecs.umich.edu*/ 2997639Sgblack@eecs.umich.edu/** 3007639Sgblack@eecs.umich.edu * I/O write of device register 3017639Sgblack@eecs.umich.edu */ 3027639Sgblack@eecs.umich.eduTick 3037639Sgblack@eecs.umich.eduDevice::write(PacketPtr pkt) 3047639Sgblack@eecs.umich.edu{ 3057639Sgblack@eecs.umich.edu assert(config.command & PCI_CMD_MSE); 3067639Sgblack@eecs.umich.edu assert(pkt->getAddr() >= BARAddrs[0] && pkt->getSize() < BARSize[0]); 3077639Sgblack@eecs.umich.edu 3087639Sgblack@eecs.umich.edu ContextID cpu = pkt->req->contextId(); 3097639Sgblack@eecs.umich.edu Addr daddr = pkt->getAddr() - BARAddrs[0]; 3107639Sgblack@eecs.umich.edu Addr index = daddr >> Regs::VirtualShift; 3117639Sgblack@eecs.umich.edu Addr raddr = daddr & Regs::VirtualMask; 3127639Sgblack@eecs.umich.edu 3137639Sgblack@eecs.umich.edu if (!regValid(raddr)) 3147639Sgblack@eecs.umich.edu panic("invalid register: cpu=%d, da=%#x pa=%#x size=%d", 3157639Sgblack@eecs.umich.edu cpu, daddr, pkt->getAddr(), pkt->getSize()); 3167639Sgblack@eecs.umich.edu 3177639Sgblack@eecs.umich.edu const Regs::Info &info = regInfo(raddr); 3188072SGiacomo.Gabrielli@arm.com if (!info.write) 3198072SGiacomo.Gabrielli@arm.com panic("write %s (read only): " 3207639Sgblack@eecs.umich.edu "cpu=%d vnic=%d da=%#x pa=%#x size=%d", 3217639Sgblack@eecs.umich.edu info.name, cpu, index, daddr, pkt->getAddr(), pkt->getSize()); 3227646Sgene.wu@arm.com 3237646Sgene.wu@arm.com if (pkt->getSize() != info.size) 3247639Sgblack@eecs.umich.edu panic("write %s (invalid size): " 3257639Sgblack@eecs.umich.edu "cpu=%d vnic=%d da=%#x pa=%#x size=%d", 3267639Sgblack@eecs.umich.edu info.name, cpu, index, daddr, pkt->getAddr(), pkt->getSize()); 3277639Sgblack@eecs.umich.edu 3287639Sgblack@eecs.umich.edu VirtualReg &vnic = virtualRegs[index]; 3297639Sgblack@eecs.umich.edu 3307639Sgblack@eecs.umich.edu DPRINTF(EthernetPIO, 3317303Sgblack@eecs.umich.edu "write %s vnic %d: cpu=%d val=%#x da=%#x pa=%#x size=%d\n", 3327303Sgblack@eecs.umich.edu info.name, index, cpu, info.size == 4 ? pkt->get<uint32_t>() : 3337303Sgblack@eecs.umich.edu pkt->get<uint64_t>(), daddr, pkt->getAddr(), pkt->getSize()); 3347303Sgblack@eecs.umich.edu 3357303Sgblack@eecs.umich.edu prepareWrite(cpu, index); 3367303Sgblack@eecs.umich.edu 3377303Sgblack@eecs.umich.edu switch (raddr) { 3387303Sgblack@eecs.umich.edu case Regs::Config: 3397303Sgblack@eecs.umich.edu changeConfig(pkt->get<uint32_t>()); 3407303Sgblack@eecs.umich.edu break; 3417303Sgblack@eecs.umich.edu 3427303Sgblack@eecs.umich.edu case Regs::Command: 3437303Sgblack@eecs.umich.edu command(pkt->get<uint32_t>()); 3447303Sgblack@eecs.umich.edu break; 3457303Sgblack@eecs.umich.edu 3467303Sgblack@eecs.umich.edu case Regs::IntrStatus: 3477303Sgblack@eecs.umich.edu devIntrClear(regs.IntrStatus & pkt->get<uint32_t>()); 3487303Sgblack@eecs.umich.edu break; 3497303Sgblack@eecs.umich.edu 3507303Sgblack@eecs.umich.edu case Regs::IntrMask: 3517303Sgblack@eecs.umich.edu devIntrChangeMask(pkt->get<uint32_t>()); 3527303Sgblack@eecs.umich.edu break; 3537303Sgblack@eecs.umich.edu 3547303Sgblack@eecs.umich.edu case Regs::RxData: 3557303Sgblack@eecs.umich.edu if (Regs::get_RxDone_Busy(vnic.RxDone)) 3567303Sgblack@eecs.umich.edu panic("receive machine busy with another request! rxState=%s", 3577303Sgblack@eecs.umich.edu RxStateStrings[rxState]); 3587303Sgblack@eecs.umich.edu 3597303Sgblack@eecs.umich.edu vnic.rxUnique = rxUnique++; 3607303Sgblack@eecs.umich.edu vnic.RxDone = Regs::RxDone_Busy; 3617303Sgblack@eecs.umich.edu vnic.RxData = pkt->get<uint64_t>(); 3627597Sminkyu.jeong@arm.com rxBusyCount++; 3637597Sminkyu.jeong@arm.com 3647303Sgblack@eecs.umich.edu if (Regs::get_RxData_Vaddr(pkt->get<uint64_t>())) { 3657303Sgblack@eecs.umich.edu panic("vtophys not implemented in newmem"); 3667646Sgene.wu@arm.com#ifdef SINIC_VTOPHYS 3677646Sgene.wu@arm.com Addr vaddr = Regs::get_RxData_Addr(reg64); 3687408Sgblack@eecs.umich.edu Addr paddr = vtophys(req->xc, vaddr); 3697408Sgblack@eecs.umich.edu DPRINTF(EthernetPIO, "write RxData vnic %d (rxunique %d): " 3707408Sgblack@eecs.umich.edu "vaddr=%#x, paddr=%#x\n", 3717303Sgblack@eecs.umich.edu index, vnic.rxUnique, vaddr, paddr); 3727303Sgblack@eecs.umich.edu 3737303Sgblack@eecs.umich.edu vnic.RxData = Regs::set_RxData_Addr(vnic.RxData, paddr); 3747303Sgblack@eecs.umich.edu#endif 3757303Sgblack@eecs.umich.edu } else { 3767303Sgblack@eecs.umich.edu DPRINTF(EthernetPIO, "write RxData vnic %d (rxunique %d)\n", 3777303Sgblack@eecs.umich.edu index, vnic.rxUnique); 3787303Sgblack@eecs.umich.edu } 3797303Sgblack@eecs.umich.edu 3807303Sgblack@eecs.umich.edu if (vnic.rxIndex == rxFifo.end()) { 3817303Sgblack@eecs.umich.edu DPRINTF(EthernetPIO, "request new packet...appending to rxList\n"); 3827303Sgblack@eecs.umich.edu rxList.push_back(index); 3837303Sgblack@eecs.umich.edu } else { 3847303Sgblack@eecs.umich.edu DPRINTF(EthernetPIO, "packet exists...appending to rxBusy\n"); 3857303Sgblack@eecs.umich.edu rxBusy.push_back(index); 3867303Sgblack@eecs.umich.edu } 3877303Sgblack@eecs.umich.edu 3887303Sgblack@eecs.umich.edu if (rxEnable && (rxState == rxIdle || rxState == rxFifoBlock)) { 3897303Sgblack@eecs.umich.edu rxState = rxFifoBlock; 3907303Sgblack@eecs.umich.edu rxKick(); 3917303Sgblack@eecs.umich.edu } 3927303Sgblack@eecs.umich.edu break; 3937303Sgblack@eecs.umich.edu 3947303Sgblack@eecs.umich.edu case Regs::TxData: 3957303Sgblack@eecs.umich.edu if (Regs::get_TxDone_Busy(vnic.TxDone)) 3967597Sminkyu.jeong@arm.com panic("transmit machine busy with another request! txState=%s", 3977597Sminkyu.jeong@arm.com TxStateStrings[txState]); 3987303Sgblack@eecs.umich.edu 3997646Sgene.wu@arm.com vnic.txUnique = txUnique++; 4007646Sgene.wu@arm.com vnic.TxDone = Regs::TxDone_Busy; 4017408Sgblack@eecs.umich.edu 4027408Sgblack@eecs.umich.edu if (Regs::get_TxData_Vaddr(pkt->get<uint64_t>())) { 4037408Sgblack@eecs.umich.edu panic("vtophys won't work here in newmem.\n"); 4047303Sgblack@eecs.umich.edu#ifdef SINIC_VTOPHYS 4057303Sgblack@eecs.umich.edu Addr vaddr = Regs::get_TxData_Addr(reg64); 4067303Sgblack@eecs.umich.edu Addr paddr = vtophys(req->xc, vaddr); 4077303Sgblack@eecs.umich.edu DPRINTF(EthernetPIO, "write TxData vnic %d (txunique %d): " 4087120Sgblack@eecs.umich.edu "vaddr=%#x, paddr=%#x\n", 4097120Sgblack@eecs.umich.edu index, vnic.txUnique, vaddr, paddr); 4107120Sgblack@eecs.umich.edu 4117120Sgblack@eecs.umich.edu vnic.TxData = Regs::set_TxData_Addr(vnic.TxData, paddr); 4127120Sgblack@eecs.umich.edu#endif 4137120Sgblack@eecs.umich.edu } else { 4147120Sgblack@eecs.umich.edu DPRINTF(EthernetPIO, "write TxData vnic %d (txunique %d)\n", 4157120Sgblack@eecs.umich.edu index, vnic.txUnique); 4167120Sgblack@eecs.umich.edu } 4177120Sgblack@eecs.umich.edu 4187120Sgblack@eecs.umich.edu if (txList.empty() || txList.front() != index) 4197120Sgblack@eecs.umich.edu txList.push_back(index); 4207120Sgblack@eecs.umich.edu if (txEnable && txState == txIdle && txList.front() == index) { 4217120Sgblack@eecs.umich.edu txState = txFifoBlock; 4227120Sgblack@eecs.umich.edu txKick(); 4237120Sgblack@eecs.umich.edu } 4247120Sgblack@eecs.umich.edu break; 4257120Sgblack@eecs.umich.edu } 4267120Sgblack@eecs.umich.edu 4277120Sgblack@eecs.umich.edu return pioDelay; 4287120Sgblack@eecs.umich.edu} 4297597Sminkyu.jeong@arm.com 4307597Sminkyu.jeong@arm.comvoid 4317120Sgblack@eecs.umich.eduDevice::devIntrPost(uint32_t interrupts) 4327120Sgblack@eecs.umich.edu{ 4337646Sgene.wu@arm.com if ((interrupts & Regs::Intr_Res)) 4347646Sgene.wu@arm.com panic("Cannot set a reserved interrupt"); 4357408Sgblack@eecs.umich.edu 4367408Sgblack@eecs.umich.edu regs.IntrStatus |= interrupts; 4377408Sgblack@eecs.umich.edu 4387120Sgblack@eecs.umich.edu DPRINTF(EthernetIntr, 4397120Sgblack@eecs.umich.edu "interrupt written to intStatus: intr=%#x status=%#x mask=%#x\n", 4407120Sgblack@eecs.umich.edu interrupts, regs.IntrStatus, regs.IntrMask); 4417120Sgblack@eecs.umich.edu 4427639Sgblack@eecs.umich.edu interrupts = regs.IntrStatus & regs.IntrMask; 4437639Sgblack@eecs.umich.edu 4447639Sgblack@eecs.umich.edu // Intr_RxHigh is special, we only signal it if we've emptied the fifo 4457639Sgblack@eecs.umich.edu // and then filled it above the high watermark 4467639Sgblack@eecs.umich.edu if (rxEmpty) 4477639Sgblack@eecs.umich.edu rxEmpty = false; 4487639Sgblack@eecs.umich.edu else 4497639Sgblack@eecs.umich.edu interrupts &= ~Regs::Intr_RxHigh; 4507639Sgblack@eecs.umich.edu 4517639Sgblack@eecs.umich.edu // Intr_TxLow is special, we only signal it if we've filled up the fifo 4527639Sgblack@eecs.umich.edu // and then dropped below the low watermark 4537639Sgblack@eecs.umich.edu if (txFull) 4547639Sgblack@eecs.umich.edu txFull = false; 4557639Sgblack@eecs.umich.edu else 4567639Sgblack@eecs.umich.edu interrupts &= ~Regs::Intr_TxLow; 4577639Sgblack@eecs.umich.edu 4587639Sgblack@eecs.umich.edu if (interrupts) { 4597639Sgblack@eecs.umich.edu Tick when = curTick(); 4607639Sgblack@eecs.umich.edu if ((interrupts & Regs::Intr_NoDelay) == 0) 4617639Sgblack@eecs.umich.edu when += intrDelay; 4627639Sgblack@eecs.umich.edu cpuIntrPost(when); 4637639Sgblack@eecs.umich.edu } 4647639Sgblack@eecs.umich.edu} 4657639Sgblack@eecs.umich.edu 4668072SGiacomo.Gabrielli@arm.comvoid 4678072SGiacomo.Gabrielli@arm.comDevice::devIntrClear(uint32_t interrupts) 4687639Sgblack@eecs.umich.edu{ 4697639Sgblack@eecs.umich.edu if ((interrupts & Regs::Intr_Res)) 4707646Sgene.wu@arm.com panic("Cannot clear a reserved interrupt"); 4717646Sgene.wu@arm.com 4727639Sgblack@eecs.umich.edu regs.IntrStatus &= ~interrupts; 4737639Sgblack@eecs.umich.edu 4747639Sgblack@eecs.umich.edu DPRINTF(EthernetIntr, 4757639Sgblack@eecs.umich.edu "interrupt cleared from intStatus: intr=%x status=%x mask=%x\n", 4767639Sgblack@eecs.umich.edu interrupts, regs.IntrStatus, regs.IntrMask); 4777639Sgblack@eecs.umich.edu 4787639Sgblack@eecs.umich.edu if (!(regs.IntrStatus & regs.IntrMask)) 4797119Sgblack@eecs.umich.edu cpuIntrClear(); 4807119Sgblack@eecs.umich.edu} 4817119Sgblack@eecs.umich.edu 4827119Sgblack@eecs.umich.eduvoid 4837119Sgblack@eecs.umich.eduDevice::devIntrChangeMask(uint32_t newmask) 4847119Sgblack@eecs.umich.edu{ 4857119Sgblack@eecs.umich.edu if (regs.IntrMask == newmask) 4867119Sgblack@eecs.umich.edu return; 4877119Sgblack@eecs.umich.edu 4887119Sgblack@eecs.umich.edu regs.IntrMask = newmask; 4897119Sgblack@eecs.umich.edu 4907119Sgblack@eecs.umich.edu DPRINTF(EthernetIntr, 4917119Sgblack@eecs.umich.edu "interrupt mask changed: intStatus=%x intMask=%x masked=%x\n", 4927119Sgblack@eecs.umich.edu regs.IntrStatus, regs.IntrMask, regs.IntrStatus & regs.IntrMask); 4937119Sgblack@eecs.umich.edu 4947119Sgblack@eecs.umich.edu if (regs.IntrStatus & regs.IntrMask) 4957597Sminkyu.jeong@arm.com cpuIntrPost(curTick()); 4967597Sminkyu.jeong@arm.com else 4977646Sgene.wu@arm.com cpuIntrClear(); 4987646Sgene.wu@arm.com} 4997597Sminkyu.jeong@arm.com 5007597Sminkyu.jeong@arm.comvoid 5017119Sgblack@eecs.umich.eduBase::cpuIntrPost(Tick when) 5027119Sgblack@eecs.umich.edu{ 5037119Sgblack@eecs.umich.edu // If the interrupt you want to post is later than an interrupt 5047119Sgblack@eecs.umich.edu // already scheduled, just let it post in the coming one and don't 5057119Sgblack@eecs.umich.edu // schedule another. 5067119Sgblack@eecs.umich.edu // HOWEVER, must be sure that the scheduled intrTick is in the 5077639Sgblack@eecs.umich.edu // future (this was formerly the source of a bug) 5087639Sgblack@eecs.umich.edu /** 5097639Sgblack@eecs.umich.edu * @todo this warning should be removed and the intrTick code should 5107639Sgblack@eecs.umich.edu * be fixed. 5117639Sgblack@eecs.umich.edu */ 5127639Sgblack@eecs.umich.edu assert(when >= curTick()); 5137639Sgblack@eecs.umich.edu assert(intrTick >= curTick() || intrTick == 0); 5147639Sgblack@eecs.umich.edu if (!cpuIntrEnable) { 5157639Sgblack@eecs.umich.edu DPRINTF(EthernetIntr, "interrupts not enabled.\n", 5167639Sgblack@eecs.umich.edu intrTick); 5177639Sgblack@eecs.umich.edu return; 5187639Sgblack@eecs.umich.edu } 5197639Sgblack@eecs.umich.edu 5207639Sgblack@eecs.umich.edu if (when > intrTick && intrTick != 0) { 5217639Sgblack@eecs.umich.edu DPRINTF(EthernetIntr, "don't need to schedule event...intrTick=%d\n", 5227639Sgblack@eecs.umich.edu intrTick); 5237639Sgblack@eecs.umich.edu return; 5248072SGiacomo.Gabrielli@arm.com } 5258072SGiacomo.Gabrielli@arm.com 5268072SGiacomo.Gabrielli@arm.com intrTick = when; 5278072SGiacomo.Gabrielli@arm.com if (intrTick < curTick()) { 5288072SGiacomo.Gabrielli@arm.com Debug::breakpoint(); 5298072SGiacomo.Gabrielli@arm.com intrTick = curTick(); 5307639Sgblack@eecs.umich.edu } 5317639Sgblack@eecs.umich.edu 5327639Sgblack@eecs.umich.edu DPRINTF(EthernetIntr, "going to schedule an interrupt for intrTick=%d\n", 5337639Sgblack@eecs.umich.edu intrTick); 5347639Sgblack@eecs.umich.edu 5357639Sgblack@eecs.umich.edu if (intrEvent) 5367119Sgblack@eecs.umich.edu intrEvent->squash(); 5377119Sgblack@eecs.umich.edu intrEvent = new IntrEvent(this, true); 5387119Sgblack@eecs.umich.edu schedule(intrEvent, intrTick); 5397119Sgblack@eecs.umich.edu} 5407119Sgblack@eecs.umich.edu 5417119Sgblack@eecs.umich.eduvoid 5427119Sgblack@eecs.umich.eduBase::cpuInterrupt() 5437119Sgblack@eecs.umich.edu{ 5447119Sgblack@eecs.umich.edu assert(intrTick == curTick()); 5457119Sgblack@eecs.umich.edu 5467119Sgblack@eecs.umich.edu // Whether or not there's a pending interrupt, we don't care about 5477119Sgblack@eecs.umich.edu // it anymore 5487119Sgblack@eecs.umich.edu intrEvent = 0; 5497119Sgblack@eecs.umich.edu intrTick = 0; 5507119Sgblack@eecs.umich.edu 5517119Sgblack@eecs.umich.edu // Don't send an interrupt if there's already one 5527119Sgblack@eecs.umich.edu if (cpuPendingIntr) { 5537119Sgblack@eecs.umich.edu DPRINTF(EthernetIntr, 5547119Sgblack@eecs.umich.edu "would send an interrupt now, but there's already pending\n"); 5557119Sgblack@eecs.umich.edu } else { 5567119Sgblack@eecs.umich.edu // Send interrupt 5577119Sgblack@eecs.umich.edu cpuPendingIntr = true; 5587119Sgblack@eecs.umich.edu 5597119Sgblack@eecs.umich.edu DPRINTF(EthernetIntr, "posting interrupt\n"); 5607408Sgblack@eecs.umich.edu intrPost(); 5617408Sgblack@eecs.umich.edu } 5627408Sgblack@eecs.umich.edu} 5637408Sgblack@eecs.umich.edu 5647119Sgblack@eecs.umich.eduvoid 5657119Sgblack@eecs.umich.eduBase::cpuIntrClear() 5667119Sgblack@eecs.umich.edu{ 5677119Sgblack@eecs.umich.edu if (!cpuPendingIntr) 5687639Sgblack@eecs.umich.edu return; 5697639Sgblack@eecs.umich.edu 5707639Sgblack@eecs.umich.edu if (intrEvent) { 5717639Sgblack@eecs.umich.edu intrEvent->squash(); 5727639Sgblack@eecs.umich.edu intrEvent = 0; 5737639Sgblack@eecs.umich.edu } 5747639Sgblack@eecs.umich.edu 5757639Sgblack@eecs.umich.edu intrTick = 0; 5767639Sgblack@eecs.umich.edu 5777639Sgblack@eecs.umich.edu cpuPendingIntr = false; 5787639Sgblack@eecs.umich.edu 5797639Sgblack@eecs.umich.edu DPRINTF(EthernetIntr, "clearing cchip interrupt\n"); 5807639Sgblack@eecs.umich.edu intrClear(); 5817639Sgblack@eecs.umich.edu} 5827639Sgblack@eecs.umich.edu 5837639Sgblack@eecs.umich.edubool 5847639Sgblack@eecs.umich.eduBase::cpuIntrPending() const 5857639Sgblack@eecs.umich.edu{ return cpuPendingIntr; } 5867639Sgblack@eecs.umich.edu 5877639Sgblack@eecs.umich.eduvoid 5887639Sgblack@eecs.umich.eduDevice::changeConfig(uint32_t newconf) 5897639Sgblack@eecs.umich.edu{ 5907639Sgblack@eecs.umich.edu uint32_t changed = regs.Config ^ newconf; 5917639Sgblack@eecs.umich.edu if (!changed) 5927639Sgblack@eecs.umich.edu return; 5937639Sgblack@eecs.umich.edu 5947639Sgblack@eecs.umich.edu regs.Config = newconf; 5957639Sgblack@eecs.umich.edu 5967639Sgblack@eecs.umich.edu if ((changed & Regs::Config_IntEn)) { 5977639Sgblack@eecs.umich.edu cpuIntrEnable = regs.Config & Regs::Config_IntEn; 5987639Sgblack@eecs.umich.edu if (cpuIntrEnable) { 5997639Sgblack@eecs.umich.edu if (regs.IntrStatus & regs.IntrMask) 6007639Sgblack@eecs.umich.edu cpuIntrPost(curTick()); 6017639Sgblack@eecs.umich.edu } else { 6027120Sgblack@eecs.umich.edu cpuIntrClear(); 6037120Sgblack@eecs.umich.edu } 6047120Sgblack@eecs.umich.edu } 6057120Sgblack@eecs.umich.edu 6067120Sgblack@eecs.umich.edu if ((changed & Regs::Config_TxEn)) { 6077712Sgblack@eecs.umich.edu txEnable = regs.Config & Regs::Config_TxEn; 6087712Sgblack@eecs.umich.edu if (txEnable) 6097408Sgblack@eecs.umich.edu txKick(); 6107408Sgblack@eecs.umich.edu } 6117712Sgblack@eecs.umich.edu 6127120Sgblack@eecs.umich.edu if ((changed & Regs::Config_RxEn)) { 6137120Sgblack@eecs.umich.edu rxEnable = regs.Config & Regs::Config_RxEn; 6147120Sgblack@eecs.umich.edu if (rxEnable) 6157639Sgblack@eecs.umich.edu rxKick(); 6167639Sgblack@eecs.umich.edu } 6177639Sgblack@eecs.umich.edu} 6187639Sgblack@eecs.umich.edu 6197639Sgblack@eecs.umich.eduvoid 6207639Sgblack@eecs.umich.eduDevice::command(uint32_t command) 6217712Sgblack@eecs.umich.edu{ 6227712Sgblack@eecs.umich.edu if (command & Regs::Command_Intr) 6237639Sgblack@eecs.umich.edu devIntrPost(Regs::Intr_Soft); 6247639Sgblack@eecs.umich.edu 6257712Sgblack@eecs.umich.edu if (command & Regs::Command_Reset) 6267639Sgblack@eecs.umich.edu reset(); 6277639Sgblack@eecs.umich.edu} 6287639Sgblack@eecs.umich.edu 6297303Sgblack@eecs.umich.eduvoid 6307303Sgblack@eecs.umich.eduDevice::reset() 6317303Sgblack@eecs.umich.edu{ 6327303Sgblack@eecs.umich.edu using namespace Regs; 6337303Sgblack@eecs.umich.edu 6347303Sgblack@eecs.umich.edu memset(®s, 0, sizeof(regs)); 6357303Sgblack@eecs.umich.edu 6367303Sgblack@eecs.umich.edu regs.Config = 0; 6377303Sgblack@eecs.umich.edu if (params()->rx_thread) 6387303Sgblack@eecs.umich.edu regs.Config |= Config_RxThread; 6397303Sgblack@eecs.umich.edu if (params()->tx_thread) 6407303Sgblack@eecs.umich.edu regs.Config |= Config_TxThread; 6417303Sgblack@eecs.umich.edu if (params()->rss) 6427303Sgblack@eecs.umich.edu regs.Config |= Config_RSS; 6437303Sgblack@eecs.umich.edu if (params()->zero_copy) 6447303Sgblack@eecs.umich.edu regs.Config |= Config_ZeroCopy; 6457303Sgblack@eecs.umich.edu if (params()->delay_copy) 6467303Sgblack@eecs.umich.edu regs.Config |= Config_DelayCopy; 6477303Sgblack@eecs.umich.edu if (params()->virtual_addr) 6487303Sgblack@eecs.umich.edu regs.Config |= Config_Vaddr; 6497408Sgblack@eecs.umich.edu 6507408Sgblack@eecs.umich.edu if (params()->delay_copy && params()->zero_copy) 6517408Sgblack@eecs.umich.edu panic("Can't delay copy and zero copy"); 6527408Sgblack@eecs.umich.edu 6537303Sgblack@eecs.umich.edu regs.IntrMask = Intr_Soft | Intr_RxHigh | Intr_RxPacket | Intr_TxLow; 6547303Sgblack@eecs.umich.edu regs.RxMaxCopy = params()->rx_max_copy; 6557303Sgblack@eecs.umich.edu regs.TxMaxCopy = params()->tx_max_copy; 6567303Sgblack@eecs.umich.edu regs.ZeroCopySize = params()->zero_copy_size; 6577291Sgblack@eecs.umich.edu regs.ZeroCopyMark = params()->zero_copy_threshold; 6587291Sgblack@eecs.umich.edu regs.VirtualCount = params()->virtual_count; 6597291Sgblack@eecs.umich.edu regs.RxMaxIntr = params()->rx_max_intr; 6607291Sgblack@eecs.umich.edu regs.RxFifoSize = params()->rx_fifo_size; 6617291Sgblack@eecs.umich.edu regs.TxFifoSize = params()->tx_fifo_size; 6627291Sgblack@eecs.umich.edu regs.RxFifoLow = params()->rx_fifo_low_mark; 6637291Sgblack@eecs.umich.edu regs.TxFifoLow = params()->tx_fifo_threshold; 6647291Sgblack@eecs.umich.edu regs.RxFifoHigh = params()->rx_fifo_threshold; 6657291Sgblack@eecs.umich.edu regs.TxFifoHigh = params()->tx_fifo_high_mark; 6667291Sgblack@eecs.umich.edu regs.HwAddr = params()->hardware_address; 6677291Sgblack@eecs.umich.edu 6687291Sgblack@eecs.umich.edu if (regs.RxMaxCopy < regs.ZeroCopyMark) 6697291Sgblack@eecs.umich.edu panic("Must be able to copy at least as many bytes as the threshold"); 6707291Sgblack@eecs.umich.edu 6717291Sgblack@eecs.umich.edu if (regs.ZeroCopySize >= regs.ZeroCopyMark) 6727291Sgblack@eecs.umich.edu panic("The number of bytes to copy must be less than the threshold"); 6737291Sgblack@eecs.umich.edu 6747291Sgblack@eecs.umich.edu rxList.clear(); 6757291Sgblack@eecs.umich.edu rxBusy.clear(); 6767291Sgblack@eecs.umich.edu rxActive = -1; 6777312Sgblack@eecs.umich.edu txList.clear(); 6787312Sgblack@eecs.umich.edu rxBusyCount = 0; 6797312Sgblack@eecs.umich.edu rxDirtyCount = 0; 6807312Sgblack@eecs.umich.edu rxMappedCount = 0; 6817312Sgblack@eecs.umich.edu 6827312Sgblack@eecs.umich.edu rxState = rxIdle; 6837312Sgblack@eecs.umich.edu txState = txIdle; 6847312Sgblack@eecs.umich.edu 6857312Sgblack@eecs.umich.edu rxFifo.clear(); 6867312Sgblack@eecs.umich.edu rxFifoPtr = rxFifo.end(); 6877312Sgblack@eecs.umich.edu txFifo.clear(); 6887312Sgblack@eecs.umich.edu rxEmpty = false; 6897312Sgblack@eecs.umich.edu rxLow = true; 6907312Sgblack@eecs.umich.edu txFull = false; 6917312Sgblack@eecs.umich.edu 6927312Sgblack@eecs.umich.edu int size = virtualRegs.size(); 6937312Sgblack@eecs.umich.edu virtualRegs.clear(); 6947312Sgblack@eecs.umich.edu virtualRegs.resize(size); 6957312Sgblack@eecs.umich.edu for (int i = 0; i < size; ++i) 6967312Sgblack@eecs.umich.edu virtualRegs[i].rxIndex = rxFifo.end(); 6977205Sgblack@eecs.umich.edu} 6987205Sgblack@eecs.umich.edu 6997205Sgblack@eecs.umich.eduvoid 7007205Sgblack@eecs.umich.eduDevice::rxDmaDone() 7017205Sgblack@eecs.umich.edu{ 7027205Sgblack@eecs.umich.edu assert(rxState == rxCopy); 7037205Sgblack@eecs.umich.edu rxState = rxCopyDone; 7047205Sgblack@eecs.umich.edu DPRINTF(EthernetDMA, "end rx dma write paddr=%#x len=%d\n", 7057205Sgblack@eecs.umich.edu rxDmaAddr, rxDmaLen); 7067205Sgblack@eecs.umich.edu DDUMP(EthernetData, rxDmaData, rxDmaLen); 7077205Sgblack@eecs.umich.edu 7087205Sgblack@eecs.umich.edu // If the transmit state machine has a pending DMA, let it go first 7097205Sgblack@eecs.umich.edu if (txState == txBeginCopy) 7107205Sgblack@eecs.umich.edu txKick(); 7117205Sgblack@eecs.umich.edu 7127205Sgblack@eecs.umich.edu rxKick(); 7137205Sgblack@eecs.umich.edu} 7147205Sgblack@eecs.umich.edu 7157205Sgblack@eecs.umich.eduvoid 7167205Sgblack@eecs.umich.eduDevice::rxKick() 7177279Sgblack@eecs.umich.edu{ 7187279Sgblack@eecs.umich.edu VirtualReg *vnic = NULL; 7197279Sgblack@eecs.umich.edu 7207279Sgblack@eecs.umich.edu DPRINTF(EthernetSM, "rxKick: rxState=%s (rxFifo.size=%d)\n", 7217279Sgblack@eecs.umich.edu RxStateStrings[rxState], rxFifo.size()); 7227279Sgblack@eecs.umich.edu 7237279Sgblack@eecs.umich.edu if (rxKickTick > curTick()) { 7247279Sgblack@eecs.umich.edu DPRINTF(EthernetSM, "rxKick: exiting, can't run till %d\n", 7257279Sgblack@eecs.umich.edu rxKickTick); 7267279Sgblack@eecs.umich.edu return; 7277279Sgblack@eecs.umich.edu } 7287279Sgblack@eecs.umich.edu 7297279Sgblack@eecs.umich.edu next: 7307279Sgblack@eecs.umich.edu rxFifo.check(); 7317279Sgblack@eecs.umich.edu if (rxState == rxIdle) 7327279Sgblack@eecs.umich.edu goto exit; 7337279Sgblack@eecs.umich.edu 7347279Sgblack@eecs.umich.edu if (rxActive == -1) { 7357279Sgblack@eecs.umich.edu if (rxState != rxFifoBlock) 7367279Sgblack@eecs.umich.edu panic("no active vnic while in state %s", RxStateStrings[rxState]); 7377279Sgblack@eecs.umich.edu 7387303Sgblack@eecs.umich.edu DPRINTF(EthernetSM, "processing rxState=%s\n", 7397303Sgblack@eecs.umich.edu RxStateStrings[rxState]); 7407303Sgblack@eecs.umich.edu } else { 7417303Sgblack@eecs.umich.edu vnic = &virtualRegs[rxActive]; 7427303Sgblack@eecs.umich.edu DPRINTF(EthernetSM, 7437303Sgblack@eecs.umich.edu "processing rxState=%s for vnic %d (rxunique %d)\n", 7447303Sgblack@eecs.umich.edu RxStateStrings[rxState], rxActive, vnic->rxUnique); 7457303Sgblack@eecs.umich.edu } 7467303Sgblack@eecs.umich.edu 7477303Sgblack@eecs.umich.edu switch (rxState) { 7487303Sgblack@eecs.umich.edu case rxFifoBlock: 7497303Sgblack@eecs.umich.edu if (DTRACE(EthernetSM)) { 7507303Sgblack@eecs.umich.edu PacketFifo::iterator end = rxFifo.end(); 7517303Sgblack@eecs.umich.edu int size = virtualRegs.size(); 7527303Sgblack@eecs.umich.edu for (int i = 0; i < size; ++i) { 7537303Sgblack@eecs.umich.edu VirtualReg *vn = &virtualRegs[i]; 7547303Sgblack@eecs.umich.edu bool busy = Regs::get_RxDone_Busy(vn->RxDone); 7557303Sgblack@eecs.umich.edu if (vn->rxIndex != end) { 7567303Sgblack@eecs.umich.edu#ifndef NDEBUG 7577303Sgblack@eecs.umich.edu bool dirty = vn->rxPacketOffset > 0; 7587303Sgblack@eecs.umich.edu const char *status; 7597119Sgblack@eecs.umich.edu 7607119Sgblack@eecs.umich.edu if (busy && dirty) 7617119Sgblack@eecs.umich.edu status = "busy,dirty"; 7627119Sgblack@eecs.umich.edu else if (busy) 7637119Sgblack@eecs.umich.edu status = "busy"; 7647119Sgblack@eecs.umich.edu else if (dirty) 7657119Sgblack@eecs.umich.edu status = "dirty"; 7667119Sgblack@eecs.umich.edu else 7677119Sgblack@eecs.umich.edu status = "mapped"; 7687119Sgblack@eecs.umich.edu 7697119Sgblack@eecs.umich.edu DPRINTF(EthernetSM, 7707119Sgblack@eecs.umich.edu "vnic %d %s (rxunique %d), packet %d, slack %d\n", 7717119Sgblack@eecs.umich.edu i, status, vn->rxUnique, 7727119Sgblack@eecs.umich.edu rxFifo.countPacketsBefore(vn->rxIndex), 7737119Sgblack@eecs.umich.edu vn->rxIndex->slack); 7747119Sgblack@eecs.umich.edu#endif 7757119Sgblack@eecs.umich.edu } else if (busy) { 7767119Sgblack@eecs.umich.edu DPRINTF(EthernetSM, "vnic %d unmapped (rxunique %d)\n", 7777119Sgblack@eecs.umich.edu i, vn->rxUnique); 7787119Sgblack@eecs.umich.edu } 7797303Sgblack@eecs.umich.edu } 7807303Sgblack@eecs.umich.edu } 7817303Sgblack@eecs.umich.edu 7827303Sgblack@eecs.umich.edu if (!rxBusy.empty()) { 7837303Sgblack@eecs.umich.edu rxActive = rxBusy.front(); 7847303Sgblack@eecs.umich.edu rxBusy.pop_front(); 7857303Sgblack@eecs.umich.edu vnic = &virtualRegs[rxActive]; 7867303Sgblack@eecs.umich.edu 7877303Sgblack@eecs.umich.edu if (vnic->rxIndex == rxFifo.end()) 7887303Sgblack@eecs.umich.edu panic("continuing vnic without packet\n"); 7897303Sgblack@eecs.umich.edu 7907303Sgblack@eecs.umich.edu DPRINTF(EthernetSM, 7917303Sgblack@eecs.umich.edu "continue processing for vnic %d (rxunique %d)\n", 7927303Sgblack@eecs.umich.edu rxActive, vnic->rxUnique); 7937303Sgblack@eecs.umich.edu 7947303Sgblack@eecs.umich.edu rxState = rxBeginCopy; 7957303Sgblack@eecs.umich.edu 7967303Sgblack@eecs.umich.edu int vnic_distance = rxFifo.countPacketsBefore(vnic->rxIndex); 7977303Sgblack@eecs.umich.edu totalVnicDistance += vnic_distance; 7987303Sgblack@eecs.umich.edu numVnicDistance += 1; 7997303Sgblack@eecs.umich.edu if (vnic_distance > _maxVnicDistance) { 8007646Sgene.wu@arm.com maxVnicDistance = vnic_distance; 8017279Sgblack@eecs.umich.edu _maxVnicDistance = vnic_distance; 8027279Sgblack@eecs.umich.edu } 8037279Sgblack@eecs.umich.edu 8047279Sgblack@eecs.umich.edu break; 8057279Sgblack@eecs.umich.edu } 8067279Sgblack@eecs.umich.edu 8077279Sgblack@eecs.umich.edu if (rxFifoPtr == rxFifo.end()) { 8087279Sgblack@eecs.umich.edu DPRINTF(EthernetSM, "receive waiting for data. Nothing to do.\n"); 8097279Sgblack@eecs.umich.edu goto exit; 8107279Sgblack@eecs.umich.edu } 8117279Sgblack@eecs.umich.edu 8127279Sgblack@eecs.umich.edu if (rxList.empty()) 8137279Sgblack@eecs.umich.edu panic("Not idle, but nothing to do!"); 8147279Sgblack@eecs.umich.edu 8157279Sgblack@eecs.umich.edu assert(!rxFifo.empty()); 8167279Sgblack@eecs.umich.edu 8177279Sgblack@eecs.umich.edu rxActive = rxList.front(); 8187279Sgblack@eecs.umich.edu rxList.pop_front(); 8197279Sgblack@eecs.umich.edu vnic = &virtualRegs[rxActive]; 8207279Sgblack@eecs.umich.edu 8217279Sgblack@eecs.umich.edu DPRINTF(EthernetSM, 8227279Sgblack@eecs.umich.edu "processing new packet for vnic %d (rxunique %d)\n", 8237646Sgene.wu@arm.com rxActive, vnic->rxUnique); 8247119Sgblack@eecs.umich.edu 8257119Sgblack@eecs.umich.edu // Grab a new packet from the fifo. 8267119Sgblack@eecs.umich.edu vnic->rxIndex = rxFifoPtr++; 8277119Sgblack@eecs.umich.edu vnic->rxIndex->priv = rxActive; 8287119Sgblack@eecs.umich.edu vnic->rxPacketOffset = 0; 8297119Sgblack@eecs.umich.edu vnic->rxPacketBytes = vnic->rxIndex->packet->length; 8307119Sgblack@eecs.umich.edu assert(vnic->rxPacketBytes); 8317119Sgblack@eecs.umich.edu rxMappedCount++; 8327119Sgblack@eecs.umich.edu 8337119Sgblack@eecs.umich.edu vnic->rxDoneData = 0; 8347119Sgblack@eecs.umich.edu /* scope for variables */ { 8357119Sgblack@eecs.umich.edu IpPtr ip(vnic->rxIndex->packet); 8367119Sgblack@eecs.umich.edu if (ip) { 8377119Sgblack@eecs.umich.edu DPRINTF(Ethernet, "ID is %d\n", ip->id()); 8387119Sgblack@eecs.umich.edu vnic->rxDoneData |= Regs::RxDone_IpPacket; 8397119Sgblack@eecs.umich.edu rxIpChecksums++; 8407119Sgblack@eecs.umich.edu if (cksum(ip) != 0) { 8417119Sgblack@eecs.umich.edu DPRINTF(EthernetCksum, "Rx IP Checksum Error\n"); 8427119Sgblack@eecs.umich.edu vnic->rxDoneData |= Regs::RxDone_IpError; 8437119Sgblack@eecs.umich.edu } 8447119Sgblack@eecs.umich.edu TcpPtr tcp(ip); 8457646Sgene.wu@arm.com UdpPtr udp(ip); 8467646Sgene.wu@arm.com if (tcp) { 8477646Sgene.wu@arm.com DPRINTF(Ethernet, 8487646Sgene.wu@arm.com "Src Port=%d, Dest Port=%d, Seq=%d, Ack=%d\n", 8497646Sgene.wu@arm.com tcp->sport(), tcp->dport(), tcp->seq(), 8507646Sgene.wu@arm.com tcp->ack()); 8517646Sgene.wu@arm.com vnic->rxDoneData |= Regs::RxDone_TcpPacket; 8527646Sgene.wu@arm.com rxTcpChecksums++; 8537646Sgene.wu@arm.com if (cksum(tcp) != 0) { 8547646Sgene.wu@arm.com DPRINTF(EthernetCksum, "Rx TCP Checksum Error\n"); 8557646Sgene.wu@arm.com vnic->rxDoneData |= Regs::RxDone_TcpError; 8567646Sgene.wu@arm.com } 8577646Sgene.wu@arm.com } else if (udp) { 8587646Sgene.wu@arm.com vnic->rxDoneData |= Regs::RxDone_UdpPacket; 8597646Sgene.wu@arm.com rxUdpChecksums++; 8607646Sgene.wu@arm.com if (cksum(udp) != 0) { 8617646Sgene.wu@arm.com DPRINTF(EthernetCksum, "Rx UDP Checksum Error\n"); 8627646Sgene.wu@arm.com vnic->rxDoneData |= Regs::RxDone_UdpError; 8637646Sgene.wu@arm.com } 8647646Sgene.wu@arm.com } 8657646Sgene.wu@arm.com } 8667646Sgene.wu@arm.com } 8677646Sgene.wu@arm.com rxState = rxBeginCopy; 8687646Sgene.wu@arm.com break; 8697646Sgene.wu@arm.com 8707646Sgene.wu@arm.com case rxBeginCopy: 8717646Sgene.wu@arm.com if (dmaPending() || drainState() != DrainState::Running) 8727646Sgene.wu@arm.com goto exit; 8737646Sgene.wu@arm.com 8747646Sgene.wu@arm.com rxDmaAddr = params()->platform->pciToDma( 8757646Sgene.wu@arm.com Regs::get_RxData_Addr(vnic->RxData)); 8767646Sgene.wu@arm.com rxDmaLen = min<unsigned>(Regs::get_RxData_Len(vnic->RxData), 8777646Sgene.wu@arm.com vnic->rxPacketBytes); 8787646Sgene.wu@arm.com 8797646Sgene.wu@arm.com /* 8807646Sgene.wu@arm.com * if we're doing zero/delay copy and we're below the fifo 8817646Sgene.wu@arm.com * threshold, see if we should try to do the zero/defer copy 8827646Sgene.wu@arm.com */ 8837646Sgene.wu@arm.com if ((Regs::get_Config_ZeroCopy(regs.Config) || 8847646Sgene.wu@arm.com Regs::get_Config_DelayCopy(regs.Config)) && 8857646Sgene.wu@arm.com !Regs::get_RxData_NoDelay(vnic->RxData) && rxLow) { 8867646Sgene.wu@arm.com if (rxDmaLen > regs.ZeroCopyMark) 8877646Sgene.wu@arm.com rxDmaLen = regs.ZeroCopySize; 8887646Sgene.wu@arm.com } 8897646Sgene.wu@arm.com rxDmaData = vnic->rxIndex->packet->data + vnic->rxPacketOffset; 8907646Sgene.wu@arm.com rxState = rxCopy; 8917646Sgene.wu@arm.com if (rxDmaAddr == 1LL) { 8927646Sgene.wu@arm.com rxState = rxCopyDone; 8937646Sgene.wu@arm.com break; 8947646Sgene.wu@arm.com } 8957646Sgene.wu@arm.com 8967646Sgene.wu@arm.com dmaWrite(rxDmaAddr, rxDmaLen, &rxDmaEvent, rxDmaData); 8977646Sgene.wu@arm.com break; 8987646Sgene.wu@arm.com 8997646Sgene.wu@arm.com case rxCopy: 9007646Sgene.wu@arm.com DPRINTF(EthernetSM, "receive machine still copying\n"); 9017646Sgene.wu@arm.com goto exit; 9027646Sgene.wu@arm.com 9037646Sgene.wu@arm.com case rxCopyDone: 9047646Sgene.wu@arm.com vnic->RxDone = vnic->rxDoneData; 9057646Sgene.wu@arm.com vnic->RxDone |= Regs::RxDone_Complete; 9067646Sgene.wu@arm.com rxBusyCount--; 9077646Sgene.wu@arm.com 9087646Sgene.wu@arm.com if (vnic->rxPacketBytes == rxDmaLen) { 9097646Sgene.wu@arm.com if (vnic->rxPacketOffset) 9107119Sgblack@eecs.umich.edu rxDirtyCount--; 9117119Sgblack@eecs.umich.edu 9127119Sgblack@eecs.umich.edu // Packet is complete. Indicate how many bytes were copied 9137119Sgblack@eecs.umich.edu vnic->RxDone = Regs::set_RxDone_CopyLen(vnic->RxDone, rxDmaLen); 9147119Sgblack@eecs.umich.edu 9157119Sgblack@eecs.umich.edu DPRINTF(EthernetSM, 9167119Sgblack@eecs.umich.edu "rxKick: packet complete on vnic %d (rxunique %d)\n", 9177119Sgblack@eecs.umich.edu rxActive, vnic->rxUnique); 9187291Sgblack@eecs.umich.edu rxFifo.remove(vnic->rxIndex); 9197291Sgblack@eecs.umich.edu vnic->rxIndex = rxFifo.end(); 9208140SMatt.Horsnell@arm.com rxMappedCount--; 9218140SMatt.Horsnell@arm.com } else { 9228140SMatt.Horsnell@arm.com if (!vnic->rxPacketOffset) 9237291Sgblack@eecs.umich.edu rxDirtyCount++; 9247291Sgblack@eecs.umich.edu 9257848SAli.Saidi@ARM.com vnic->rxPacketBytes -= rxDmaLen; 9267848SAli.Saidi@ARM.com vnic->rxPacketOffset += rxDmaLen; 9277848SAli.Saidi@ARM.com vnic->RxDone |= Regs::RxDone_More; 9287848SAli.Saidi@ARM.com vnic->RxDone = Regs::set_RxDone_CopyLen(vnic->RxDone, 9297848SAli.Saidi@ARM.com vnic->rxPacketBytes); 9307646Sgene.wu@arm.com DPRINTF(EthernetSM, 9318140SMatt.Horsnell@arm.com "rxKick: packet not complete on vnic %d (rxunique %d): " 9328140SMatt.Horsnell@arm.com "%d bytes left\n", 9338140SMatt.Horsnell@arm.com rxActive, vnic->rxUnique, vnic->rxPacketBytes); 9348140SMatt.Horsnell@arm.com } 9358140SMatt.Horsnell@arm.com 9368140SMatt.Horsnell@arm.com rxActive = -1; 9378140SMatt.Horsnell@arm.com rxState = rxBusy.empty() && rxList.empty() ? rxIdle : rxFifoBlock; 9388140SMatt.Horsnell@arm.com 9398140SMatt.Horsnell@arm.com if (rxFifo.empty()) { 9408140SMatt.Horsnell@arm.com devIntrPost(Regs::Intr_RxEmpty); 9418140SMatt.Horsnell@arm.com rxEmpty = true; 9428140SMatt.Horsnell@arm.com } 9437646Sgene.wu@arm.com 9447291Sgblack@eecs.umich.edu if (rxFifo.size() < regs.RxFifoLow) 9457291Sgblack@eecs.umich.edu rxLow = true; 9467291Sgblack@eecs.umich.edu 9477312Sgblack@eecs.umich.edu if (rxFifo.size() > regs.RxFifoHigh) 9487312Sgblack@eecs.umich.edu rxLow = false; 9497312Sgblack@eecs.umich.edu 9507312Sgblack@eecs.umich.edu devIntrPost(Regs::Intr_RxDMA); 9517312Sgblack@eecs.umich.edu break; 9527312Sgblack@eecs.umich.edu 9537312Sgblack@eecs.umich.edu default: 9547848SAli.Saidi@ARM.com panic("Invalid rxState!"); 9557848SAli.Saidi@ARM.com } 9567848SAli.Saidi@ARM.com 9577848SAli.Saidi@ARM.com DPRINTF(EthernetSM, "entering next rxState=%s\n", 9587848SAli.Saidi@ARM.com RxStateStrings[rxState]); 9597646Sgene.wu@arm.com 9607646Sgene.wu@arm.com goto next; 9617646Sgene.wu@arm.com 9627646Sgene.wu@arm.com exit: 9637724SAli.Saidi@ARM.com /** 9647646Sgene.wu@arm.com * @todo do we want to schedule a future kick? 9657646Sgene.wu@arm.com */ 9667646Sgene.wu@arm.com DPRINTF(EthernetSM, "rx state machine exited rxState=%s\n", 9677312Sgblack@eecs.umich.edu RxStateStrings[rxState]); 9687312Sgblack@eecs.umich.edu} 9697312Sgblack@eecs.umich.edu 9707205Sgblack@eecs.umich.eduvoid 9717205Sgblack@eecs.umich.eduDevice::txDmaDone() 9727205Sgblack@eecs.umich.edu{ 9737205Sgblack@eecs.umich.edu assert(txState == txCopy); 9747205Sgblack@eecs.umich.edu txState = txCopyDone; 9757205Sgblack@eecs.umich.edu DPRINTF(EthernetDMA, "tx dma read paddr=%#x len=%d\n", 9767205Sgblack@eecs.umich.edu txDmaAddr, txDmaLen); 9777848SAli.Saidi@ARM.com DDUMP(EthernetData, txDmaData, txDmaLen); 9787848SAli.Saidi@ARM.com 9797848SAli.Saidi@ARM.com // If the receive state machine has a pending DMA, let it go first 9807848SAli.Saidi@ARM.com if (rxState == rxBeginCopy) 9817848SAli.Saidi@ARM.com rxKick(); 9827205Sgblack@eecs.umich.edu 9837205Sgblack@eecs.umich.edu txKick(); 9847205Sgblack@eecs.umich.edu} 9857279Sgblack@eecs.umich.edu 9867279Sgblack@eecs.umich.eduvoid 9877279Sgblack@eecs.umich.eduDevice::transmit() 9887279Sgblack@eecs.umich.edu{ 9897279Sgblack@eecs.umich.edu if (txFifo.empty()) { 9907279Sgblack@eecs.umich.edu DPRINTF(Ethernet, "nothing to transmit\n"); 9917279Sgblack@eecs.umich.edu return; 9927279Sgblack@eecs.umich.edu } 9937279Sgblack@eecs.umich.edu 9947848SAli.Saidi@ARM.com uint32_t interrupts; 9957848SAli.Saidi@ARM.com EthPacketPtr packet = txFifo.front(); 9967848SAli.Saidi@ARM.com if (!interface->sendPacket(packet)) { 9977848SAli.Saidi@ARM.com DPRINTF(Ethernet, "Packet Transmit: failed txFifo available %d\n", 9987848SAli.Saidi@ARM.com txFifo.avail()); 9997646Sgene.wu@arm.com return; 10007646Sgene.wu@arm.com } 10017646Sgene.wu@arm.com 10027646Sgene.wu@arm.com txFifo.pop(); 10037724SAli.Saidi@ARM.com#if TRACING_ON 10047646Sgene.wu@arm.com if (DTRACE(Ethernet)) { 10057646Sgene.wu@arm.com IpPtr ip(packet); 10067646Sgene.wu@arm.com if (ip) { 10077279Sgblack@eecs.umich.edu DPRINTF(Ethernet, "ID is %d\n", ip->id()); 10087279Sgblack@eecs.umich.edu TcpPtr tcp(ip); 10097279Sgblack@eecs.umich.edu if (tcp) { 10107303Sgblack@eecs.umich.edu DPRINTF(Ethernet, 10117303Sgblack@eecs.umich.edu "Src Port=%d, Dest Port=%d, Seq=%d, Ack=%d\n", 10127303Sgblack@eecs.umich.edu tcp->sport(), tcp->dport(), tcp->seq(), 10137303Sgblack@eecs.umich.edu tcp->ack()); 10147303Sgblack@eecs.umich.edu } 10157303Sgblack@eecs.umich.edu } 10167303Sgblack@eecs.umich.edu } 10177303Sgblack@eecs.umich.edu#endif 10187303Sgblack@eecs.umich.edu 10197303Sgblack@eecs.umich.edu DDUMP(EthernetData, packet->data, packet->length); 10207848SAli.Saidi@ARM.com txBytes += packet->length; 10217848SAli.Saidi@ARM.com txPackets++; 10227848SAli.Saidi@ARM.com 10237848SAli.Saidi@ARM.com DPRINTF(Ethernet, "Packet Transmit: successful txFifo Available %d\n", 10247848SAli.Saidi@ARM.com txFifo.avail()); 10257646Sgene.wu@arm.com 10267646Sgene.wu@arm.com interrupts = Regs::Intr_TxPacket; 10277646Sgene.wu@arm.com if (txFifo.size() < regs.TxFifoLow) 10287646Sgene.wu@arm.com interrupts |= Regs::Intr_TxLow; 10297646Sgene.wu@arm.com devIntrPost(interrupts); 10307724SAli.Saidi@ARM.com} 10317646Sgene.wu@arm.com 10327646Sgene.wu@arm.comvoid 10337646Sgene.wu@arm.comDevice::txKick() 10347303Sgblack@eecs.umich.edu{ 10357303Sgblack@eecs.umich.edu VirtualReg *vnic; 10367303Sgblack@eecs.umich.edu DPRINTF(EthernetSM, "txKick: txState=%s (txFifo.size=%d)\n", 10377119Sgblack@eecs.umich.edu TxStateStrings[txState], txFifo.size()); 10387119Sgblack@eecs.umich.edu 10397119Sgblack@eecs.umich.edu if (txKickTick > curTick()) { 10407119Sgblack@eecs.umich.edu DPRINTF(EthernetSM, "txKick: exiting, can't run till %d\n", 10417119Sgblack@eecs.umich.edu txKickTick); 10427119Sgblack@eecs.umich.edu return; 10437119Sgblack@eecs.umich.edu } 10447848SAli.Saidi@ARM.com 10457848SAli.Saidi@ARM.com next: 10467848SAli.Saidi@ARM.com if (txState == txIdle) 10477848SAli.Saidi@ARM.com goto exit; 10487848SAli.Saidi@ARM.com 10497646Sgene.wu@arm.com assert(!txList.empty()); 10507646Sgene.wu@arm.com vnic = &virtualRegs[txList.front()]; 10517646Sgene.wu@arm.com 10527646Sgene.wu@arm.com switch (txState) { 10537724SAli.Saidi@ARM.com case txFifoBlock: 10547646Sgene.wu@arm.com assert(Regs::get_TxDone_Busy(vnic->TxDone)); 10557646Sgene.wu@arm.com if (!txPacket) { 10567646Sgene.wu@arm.com // Grab a new packet from the fifo. 10577119Sgblack@eecs.umich.edu txPacket = make_shared<EthPacketData>(16384); 10587119Sgblack@eecs.umich.edu txPacketOffset = 0; 10597119Sgblack@eecs.umich.edu } 10607303Sgblack@eecs.umich.edu 10617303Sgblack@eecs.umich.edu if (txFifo.avail() - txPacket->length < 10627303Sgblack@eecs.umich.edu Regs::get_TxData_Len(vnic->TxData)) { 10637303Sgblack@eecs.umich.edu DPRINTF(EthernetSM, "transmit fifo full. Nothing to do.\n"); 10647303Sgblack@eecs.umich.edu goto exit; 10657303Sgblack@eecs.umich.edu } 10667303Sgblack@eecs.umich.edu 10677303Sgblack@eecs.umich.edu txState = txBeginCopy; 10687303Sgblack@eecs.umich.edu break; 10697848SAli.Saidi@ARM.com 10707848SAli.Saidi@ARM.com case txBeginCopy: 10717848SAli.Saidi@ARM.com if (dmaPending() || drainState() != DrainState::Running) 10727848SAli.Saidi@ARM.com goto exit; 10737848SAli.Saidi@ARM.com 10747646Sgene.wu@arm.com txDmaAddr = params()->platform->pciToDma( 10757646Sgene.wu@arm.com Regs::get_TxData_Addr(vnic->TxData)); 10767646Sgene.wu@arm.com txDmaLen = Regs::get_TxData_Len(vnic->TxData); 10777646Sgene.wu@arm.com txDmaData = txPacket->data + txPacketOffset; 10787646Sgene.wu@arm.com txState = txCopy; 10797724SAli.Saidi@ARM.com 10807646Sgene.wu@arm.com dmaRead(txDmaAddr, txDmaLen, &txDmaEvent, txDmaData); 10817646Sgene.wu@arm.com break; 10827646Sgene.wu@arm.com 10837303Sgblack@eecs.umich.edu case txCopy: 10847303Sgblack@eecs.umich.edu DPRINTF(EthernetSM, "transmit machine still copying\n"); 10857303Sgblack@eecs.umich.edu goto exit; 10867646Sgene.wu@arm.com 10877279Sgblack@eecs.umich.edu case txCopyDone: 10887279Sgblack@eecs.umich.edu vnic->TxDone = txDmaLen | Regs::TxDone_Complete; 10897279Sgblack@eecs.umich.edu txPacket->length += txDmaLen; 10907279Sgblack@eecs.umich.edu if ((vnic->TxData & Regs::TxData_More)) { 10917279Sgblack@eecs.umich.edu txPacketOffset += txDmaLen; 10927279Sgblack@eecs.umich.edu txState = txIdle; 10937279Sgblack@eecs.umich.edu devIntrPost(Regs::Intr_TxDMA); 10947279Sgblack@eecs.umich.edu break; 10957279Sgblack@eecs.umich.edu } 10967279Sgblack@eecs.umich.edu 10977848SAli.Saidi@ARM.com assert(txPacket->length <= txFifo.avail()); 10987848SAli.Saidi@ARM.com if ((vnic->TxData & Regs::TxData_Checksum)) { 10997848SAli.Saidi@ARM.com IpPtr ip(txPacket); 11007848SAli.Saidi@ARM.com if (ip) { 11017848SAli.Saidi@ARM.com TcpPtr tcp(ip); 11027646Sgene.wu@arm.com if (tcp) { 11037646Sgene.wu@arm.com tcp->sum(0); 11047646Sgene.wu@arm.com tcp->sum(cksum(tcp)); 11057646Sgene.wu@arm.com txTcpChecksums++; 11067646Sgene.wu@arm.com } 11077724SAli.Saidi@ARM.com 11087646Sgene.wu@arm.com UdpPtr udp(ip); 11097646Sgene.wu@arm.com if (udp) { 11107646Sgene.wu@arm.com udp->sum(0); 11117279Sgblack@eecs.umich.edu udp->sum(cksum(udp)); 11127279Sgblack@eecs.umich.edu txUdpChecksums++; 11137279Sgblack@eecs.umich.edu } 11147646Sgene.wu@arm.com 11157119Sgblack@eecs.umich.edu ip->sum(0); 11167119Sgblack@eecs.umich.edu ip->sum(cksum(ip)); 11177119Sgblack@eecs.umich.edu txIpChecksums++; 11187119Sgblack@eecs.umich.edu } 11197119Sgblack@eecs.umich.edu } 11207119Sgblack@eecs.umich.edu 11217119Sgblack@eecs.umich.edu txFifo.push(txPacket); 11227119Sgblack@eecs.umich.edu if (txFifo.avail() < regs.TxMaxCopy) { 11237119Sgblack@eecs.umich.edu devIntrPost(Regs::Intr_TxFull); 11247848SAli.Saidi@ARM.com txFull = true; 11257848SAli.Saidi@ARM.com } 11267848SAli.Saidi@ARM.com txPacket = 0; 11277848SAli.Saidi@ARM.com transmit(); 11287848SAli.Saidi@ARM.com txList.pop_front(); 11297646Sgene.wu@arm.com txState = txList.empty() ? txIdle : txFifoBlock; 11307646Sgene.wu@arm.com devIntrPost(Regs::Intr_TxDMA); 11317646Sgene.wu@arm.com break; 11327646Sgene.wu@arm.com 11337646Sgene.wu@arm.com default: 11347724SAli.Saidi@ARM.com panic("Invalid txState!"); 11357646Sgene.wu@arm.com } 11367646Sgene.wu@arm.com 11377646Sgene.wu@arm.com DPRINTF(EthernetSM, "entering next txState=%s\n", 11387119Sgblack@eecs.umich.edu TxStateStrings[txState]); 11397119Sgblack@eecs.umich.edu 11407646Sgene.wu@arm.com goto next; 11417646Sgene.wu@arm.com 11427646Sgene.wu@arm.com exit: 11437646Sgene.wu@arm.com /** 11447646Sgene.wu@arm.com * @todo do we want to schedule a future kick? 11457646Sgene.wu@arm.com */ 11467646Sgene.wu@arm.com DPRINTF(EthernetSM, "tx state machine exited txState=%s\n", 11477646Sgene.wu@arm.com TxStateStrings[txState]); 11487646Sgene.wu@arm.com} 11497646Sgene.wu@arm.com 11507646Sgene.wu@arm.comvoid 11517646Sgene.wu@arm.comDevice::transferDone() 11527848SAli.Saidi@ARM.com{ 11537848SAli.Saidi@ARM.com if (txFifo.empty()) { 11547848SAli.Saidi@ARM.com DPRINTF(Ethernet, "transfer complete: txFifo empty...nothing to do\n"); 11557848SAli.Saidi@ARM.com return; 11567848SAli.Saidi@ARM.com } 11577646Sgene.wu@arm.com 11587646Sgene.wu@arm.com DPRINTF(Ethernet, "transfer complete: data in txFifo...schedule xmit\n"); 11597646Sgene.wu@arm.com 11607646Sgene.wu@arm.com reschedule(txEvent, clockEdge(Cycles(1)), true); 11617646Sgene.wu@arm.com} 11627646Sgene.wu@arm.com 11637724SAli.Saidi@ARM.combool 11647646Sgene.wu@arm.comDevice::rxFilter(const EthPacketPtr &packet) 11657646Sgene.wu@arm.com{ 11667724SAli.Saidi@ARM.com if (!Regs::get_Config_Filter(regs.Config)) 11677646Sgene.wu@arm.com return false; 11687646Sgene.wu@arm.com 11697646Sgene.wu@arm.com panic("receive filter not implemented\n"); 11707646Sgene.wu@arm.com bool drop = true; 11717646Sgene.wu@arm.com 11727646Sgene.wu@arm.com#if 0 11737724SAli.Saidi@ARM.com string type; 11747646Sgene.wu@arm.com 11757646Sgene.wu@arm.com EthHdr *eth = packet->eth(); 11767646Sgene.wu@arm.com if (eth->unicast()) { 11777646Sgene.wu@arm.com // If we're accepting all unicast addresses 11787646Sgene.wu@arm.com if (acceptUnicast) 11797646Sgene.wu@arm.com drop = false; 11807646Sgene.wu@arm.com 11817646Sgene.wu@arm.com // If we make a perfect match 11827646Sgene.wu@arm.com if (acceptPerfect && params->eaddr == eth.dst()) 11837646Sgene.wu@arm.com drop = false; 11847646Sgene.wu@arm.com 11857646Sgene.wu@arm.com if (acceptArp && eth->type() == ETH_TYPE_ARP) 11867646Sgene.wu@arm.com drop = false; 11877646Sgene.wu@arm.com 11887646Sgene.wu@arm.com } else if (eth->broadcast()) { 11897646Sgene.wu@arm.com // if we're accepting broadcasts 11907646Sgene.wu@arm.com if (acceptBroadcast) 11917848SAli.Saidi@ARM.com drop = false; 11927848SAli.Saidi@ARM.com 11937848SAli.Saidi@ARM.com } else if (eth->multicast()) { 11947848SAli.Saidi@ARM.com // if we're accepting all multicasts 11957848SAli.Saidi@ARM.com if (acceptMulticast) 11967646Sgene.wu@arm.com drop = false; 11977646Sgene.wu@arm.com 11987646Sgene.wu@arm.com } 11997646Sgene.wu@arm.com 12007646Sgene.wu@arm.com if (drop) { 12017646Sgene.wu@arm.com DPRINTF(Ethernet, "rxFilter drop\n"); 12027646Sgene.wu@arm.com DDUMP(EthernetData, packet->data, packet->length); 12037724SAli.Saidi@ARM.com } 12047646Sgene.wu@arm.com#endif 12057724SAli.Saidi@ARM.com return drop; 12067646Sgene.wu@arm.com} 12077646Sgene.wu@arm.com 12087646Sgene.wu@arm.combool 12097646Sgene.wu@arm.comDevice::recvPacket(EthPacketPtr packet) 12107646Sgene.wu@arm.com{ 12117724SAli.Saidi@ARM.com rxBytes += packet->length; 12127646Sgene.wu@arm.com rxPackets++; 12137646Sgene.wu@arm.com 12147724SAli.Saidi@ARM.com DPRINTF(Ethernet, "Receiving packet from wire, rxFifo Available is %d\n", 12157646Sgene.wu@arm.com rxFifo.avail()); 12167646Sgene.wu@arm.com 12177646Sgene.wu@arm.com if (!rxEnable) { 12187646Sgene.wu@arm.com DPRINTF(Ethernet, "receive disabled...packet dropped\n"); 12197646Sgene.wu@arm.com return true; 12207646Sgene.wu@arm.com } 12217724SAli.Saidi@ARM.com 12227646Sgene.wu@arm.com if (rxFilter(packet)) { 12237646Sgene.wu@arm.com DPRINTF(Ethernet, "packet filtered...dropped\n"); 12247646Sgene.wu@arm.com return true; 12257646Sgene.wu@arm.com } 12267646Sgene.wu@arm.com 12277646Sgene.wu@arm.com if (rxFifo.size() >= regs.RxFifoHigh) 12287646Sgene.wu@arm.com devIntrPost(Regs::Intr_RxHigh); 12297646Sgene.wu@arm.com 12307646Sgene.wu@arm.com if (!rxFifo.push(packet)) { 12317646Sgene.wu@arm.com DPRINTF(Ethernet, 12327646Sgene.wu@arm.com "packet will not fit in receive buffer...packet dropped\n"); 12337646Sgene.wu@arm.com return false; 12347646Sgene.wu@arm.com } 12357646Sgene.wu@arm.com 12367646Sgene.wu@arm.com // If we were at the last element, back up one ot go to the new 12377848SAli.Saidi@ARM.com // last element of the list. 12387848SAli.Saidi@ARM.com if (rxFifoPtr == rxFifo.end()) 12397848SAli.Saidi@ARM.com --rxFifoPtr; 12407848SAli.Saidi@ARM.com 12417848SAli.Saidi@ARM.com devIntrPost(Regs::Intr_RxPacket); 12427646Sgene.wu@arm.com rxKick(); 12437646Sgene.wu@arm.com return true; 12447646Sgene.wu@arm.com} 12457646Sgene.wu@arm.com 12467646Sgene.wu@arm.comvoid 12477646Sgene.wu@arm.comDevice::drainResume() 12487724SAli.Saidi@ARM.com{ 12497646Sgene.wu@arm.com Drainable::drainResume(); 12507724SAli.Saidi@ARM.com 12517646Sgene.wu@arm.com // During drain we could have left the state machines in a waiting state and 12527646Sgene.wu@arm.com // they wouldn't get out until some other event occured to kick them. 12537646Sgene.wu@arm.com // This way they'll get out immediately 12547646Sgene.wu@arm.com txKick(); 12557724SAli.Saidi@ARM.com rxKick(); 12567646Sgene.wu@arm.com} 12577646Sgene.wu@arm.com 12587646Sgene.wu@arm.com//===================================================================== 12597646Sgene.wu@arm.com// 12607646Sgene.wu@arm.com// 12617646Sgene.wu@arm.comvoid 12627646Sgene.wu@arm.comBase::serialize(CheckpointOut &cp) const 1263{ 1264 // Serialize the PciDevice base class 1265 PciDevice::serialize(cp); 1266 1267 SERIALIZE_SCALAR(rxEnable); 1268 SERIALIZE_SCALAR(txEnable); 1269 SERIALIZE_SCALAR(cpuIntrEnable); 1270 1271 /* 1272 * Keep track of pending interrupt status. 1273 */ 1274 SERIALIZE_SCALAR(intrTick); 1275 SERIALIZE_SCALAR(cpuPendingIntr); 1276 Tick intrEventTick = 0; 1277 if (intrEvent) 1278 intrEventTick = intrEvent->when(); 1279 SERIALIZE_SCALAR(intrEventTick); 1280} 1281 1282void 1283Base::unserialize(CheckpointIn &cp) 1284{ 1285 // Unserialize the PciDevice base class 1286 PciDevice::unserialize(cp); 1287 1288 UNSERIALIZE_SCALAR(rxEnable); 1289 UNSERIALIZE_SCALAR(txEnable); 1290 UNSERIALIZE_SCALAR(cpuIntrEnable); 1291 1292 /* 1293 * Keep track of pending interrupt status. 1294 */ 1295 UNSERIALIZE_SCALAR(intrTick); 1296 UNSERIALIZE_SCALAR(cpuPendingIntr); 1297 Tick intrEventTick; 1298 UNSERIALIZE_SCALAR(intrEventTick); 1299 if (intrEventTick) { 1300 intrEvent = new IntrEvent(this, true); 1301 schedule(intrEvent, intrEventTick); 1302 } 1303} 1304 1305void 1306Device::serialize(CheckpointOut &cp) const 1307{ 1308 int count; 1309 1310 // Serialize the PciDevice base class 1311 Base::serialize(cp); 1312 1313 if (rxState == rxCopy) 1314 panic("can't serialize with an in flight dma request rxState=%s", 1315 RxStateStrings[rxState]); 1316 1317 if (txState == txCopy) 1318 panic("can't serialize with an in flight dma request txState=%s", 1319 TxStateStrings[txState]); 1320 1321 /* 1322 * Serialize the device registers that could be modified by the OS. 1323 */ 1324 SERIALIZE_SCALAR(regs.Config); 1325 SERIALIZE_SCALAR(regs.IntrStatus); 1326 SERIALIZE_SCALAR(regs.IntrMask); 1327 SERIALIZE_SCALAR(regs.RxData); 1328 SERIALIZE_SCALAR(regs.TxData); 1329 1330 /* 1331 * Serialize the virtual nic state 1332 */ 1333 int virtualRegsSize = virtualRegs.size(); 1334 SERIALIZE_SCALAR(virtualRegsSize); 1335 for (int i = 0; i < virtualRegsSize; ++i) { 1336 const VirtualReg *vnic = &virtualRegs[i]; 1337 1338 std::string reg = csprintf("vnic%d", i); 1339 paramOut(cp, reg + ".RxData", vnic->RxData); 1340 paramOut(cp, reg + ".RxDone", vnic->RxDone); 1341 paramOut(cp, reg + ".TxData", vnic->TxData); 1342 paramOut(cp, reg + ".TxDone", vnic->TxDone); 1343 1344 bool rxPacketExists = vnic->rxIndex != rxFifo.end(); 1345 paramOut(cp, reg + ".rxPacketExists", rxPacketExists); 1346 if (rxPacketExists) { 1347 int rxPacket = 0; 1348 auto i = rxFifo.begin(); 1349 while (i != vnic->rxIndex) { 1350 assert(i != rxFifo.end()); 1351 ++i; 1352 ++rxPacket; 1353 } 1354 1355 paramOut(cp, reg + ".rxPacket", rxPacket); 1356 paramOut(cp, reg + ".rxPacketOffset", vnic->rxPacketOffset); 1357 paramOut(cp, reg + ".rxPacketBytes", vnic->rxPacketBytes); 1358 } 1359 paramOut(cp, reg + ".rxDoneData", vnic->rxDoneData); 1360 } 1361 1362 int rxFifoPtr = -1; 1363 if (this->rxFifoPtr != rxFifo.end()) 1364 rxFifoPtr = rxFifo.countPacketsBefore(this->rxFifoPtr); 1365 SERIALIZE_SCALAR(rxFifoPtr); 1366 1367 SERIALIZE_SCALAR(rxActive); 1368 SERIALIZE_SCALAR(rxBusyCount); 1369 SERIALIZE_SCALAR(rxDirtyCount); 1370 SERIALIZE_SCALAR(rxMappedCount); 1371 1372 VirtualList::const_iterator i, end; 1373 for (count = 0, i = rxList.begin(), end = rxList.end(); i != end; ++i) 1374 paramOut(cp, csprintf("rxList%d", count++), *i); 1375 int rxListSize = count; 1376 SERIALIZE_SCALAR(rxListSize); 1377 1378 for (count = 0, i = rxBusy.begin(), end = rxBusy.end(); i != end; ++i) 1379 paramOut(cp, csprintf("rxBusy%d", count++), *i); 1380 int rxBusySize = count; 1381 SERIALIZE_SCALAR(rxBusySize); 1382 1383 for (count = 0, i = txList.begin(), end = txList.end(); i != end; ++i) 1384 paramOut(cp, csprintf("txList%d", count++), *i); 1385 int txListSize = count; 1386 SERIALIZE_SCALAR(txListSize); 1387 1388 /* 1389 * Serialize rx state machine 1390 */ 1391 int rxState = this->rxState; 1392 SERIALIZE_SCALAR(rxState); 1393 SERIALIZE_SCALAR(rxEmpty); 1394 SERIALIZE_SCALAR(rxLow); 1395 rxFifo.serialize("rxFifo", cp); 1396 1397 /* 1398 * Serialize tx state machine 1399 */ 1400 int txState = this->txState; 1401 SERIALIZE_SCALAR(txState); 1402 SERIALIZE_SCALAR(txFull); 1403 txFifo.serialize("txFifo", cp); 1404 bool txPacketExists = txPacket != nullptr; 1405 SERIALIZE_SCALAR(txPacketExists); 1406 if (txPacketExists) { 1407 txPacket->serialize("txPacket", cp); 1408 SERIALIZE_SCALAR(txPacketOffset); 1409 SERIALIZE_SCALAR(txPacketBytes); 1410 } 1411 1412 /* 1413 * If there's a pending transmit, store the time so we can 1414 * reschedule it later 1415 */ 1416 Tick transmitTick = txEvent.scheduled() ? txEvent.when() - curTick() : 0; 1417 SERIALIZE_SCALAR(transmitTick); 1418} 1419 1420void 1421Device::unserialize(CheckpointIn &cp) 1422{ 1423 // Unserialize the PciDevice base class 1424 Base::unserialize(cp); 1425 1426 /* 1427 * Unserialize the device registers that may have been written by the OS. 1428 */ 1429 UNSERIALIZE_SCALAR(regs.Config); 1430 UNSERIALIZE_SCALAR(regs.IntrStatus); 1431 UNSERIALIZE_SCALAR(regs.IntrMask); 1432 UNSERIALIZE_SCALAR(regs.RxData); 1433 UNSERIALIZE_SCALAR(regs.TxData); 1434 1435 UNSERIALIZE_SCALAR(rxActive); 1436 UNSERIALIZE_SCALAR(rxBusyCount); 1437 UNSERIALIZE_SCALAR(rxDirtyCount); 1438 UNSERIALIZE_SCALAR(rxMappedCount); 1439 1440 int rxListSize; 1441 UNSERIALIZE_SCALAR(rxListSize); 1442 rxList.clear(); 1443 for (int i = 0; i < rxListSize; ++i) { 1444 int value; 1445 paramIn(cp, csprintf("rxList%d", i), value); 1446 rxList.push_back(value); 1447 } 1448 1449 int rxBusySize; 1450 UNSERIALIZE_SCALAR(rxBusySize); 1451 rxBusy.clear(); 1452 for (int i = 0; i < rxBusySize; ++i) { 1453 int value; 1454 paramIn(cp, csprintf("rxBusy%d", i), value); 1455 rxBusy.push_back(value); 1456 } 1457 1458 int txListSize; 1459 UNSERIALIZE_SCALAR(txListSize); 1460 txList.clear(); 1461 for (int i = 0; i < txListSize; ++i) { 1462 int value; 1463 paramIn(cp, csprintf("txList%d", i), value); 1464 txList.push_back(value); 1465 } 1466 1467 /* 1468 * Unserialize rx state machine 1469 */ 1470 int rxState; 1471 UNSERIALIZE_SCALAR(rxState); 1472 UNSERIALIZE_SCALAR(rxEmpty); 1473 UNSERIALIZE_SCALAR(rxLow); 1474 this->rxState = (RxState) rxState; 1475 rxFifo.unserialize("rxFifo", cp); 1476 1477 int rxFifoPtr; 1478 UNSERIALIZE_SCALAR(rxFifoPtr); 1479 if (rxFifoPtr >= 0) { 1480 this->rxFifoPtr = rxFifo.begin(); 1481 for (int i = 0; i < rxFifoPtr; ++i) 1482 ++this->rxFifoPtr; 1483 } else { 1484 this->rxFifoPtr = rxFifo.end(); 1485 } 1486 1487 /* 1488 * Unserialize tx state machine 1489 */ 1490 int txState; 1491 UNSERIALIZE_SCALAR(txState); 1492 UNSERIALIZE_SCALAR(txFull); 1493 this->txState = (TxState) txState; 1494 txFifo.unserialize("txFifo", cp); 1495 bool txPacketExists; 1496 UNSERIALIZE_SCALAR(txPacketExists); 1497 txPacket = 0; 1498 if (txPacketExists) { 1499 txPacket = make_shared<EthPacketData>(16384); 1500 txPacket->unserialize("txPacket", cp); 1501 UNSERIALIZE_SCALAR(txPacketOffset); 1502 UNSERIALIZE_SCALAR(txPacketBytes); 1503 } 1504 1505 /* 1506 * unserialize the virtual nic registers/state 1507 * 1508 * this must be done after the unserialization of the rxFifo 1509 * because the packet iterators depend on the fifo being populated 1510 */ 1511 int virtualRegsSize; 1512 UNSERIALIZE_SCALAR(virtualRegsSize); 1513 virtualRegs.clear(); 1514 virtualRegs.resize(virtualRegsSize); 1515 for (int i = 0; i < virtualRegsSize; ++i) { 1516 VirtualReg *vnic = &virtualRegs[i]; 1517 std::string reg = csprintf("vnic%d", i); 1518 1519 paramIn(cp, reg + ".RxData", vnic->RxData); 1520 paramIn(cp, reg + ".RxDone", vnic->RxDone); 1521 paramIn(cp, reg + ".TxData", vnic->TxData); 1522 paramIn(cp, reg + ".TxDone", vnic->TxDone); 1523 1524 vnic->rxUnique = rxUnique++; 1525 vnic->txUnique = txUnique++; 1526 1527 bool rxPacketExists; 1528 paramIn(cp, reg + ".rxPacketExists", rxPacketExists); 1529 if (rxPacketExists) { 1530 int rxPacket; 1531 paramIn(cp, reg + ".rxPacket", rxPacket); 1532 vnic->rxIndex = rxFifo.begin(); 1533 while (rxPacket--) 1534 ++vnic->rxIndex; 1535 1536 paramIn(cp, reg + ".rxPacketOffset", 1537 vnic->rxPacketOffset); 1538 paramIn(cp, reg + ".rxPacketBytes", vnic->rxPacketBytes); 1539 } else { 1540 vnic->rxIndex = rxFifo.end(); 1541 } 1542 paramIn(cp, reg + ".rxDoneData", vnic->rxDoneData); 1543 } 1544 1545 /* 1546 * If there's a pending transmit, reschedule it now 1547 */ 1548 Tick transmitTick; 1549 UNSERIALIZE_SCALAR(transmitTick); 1550 if (transmitTick) 1551 schedule(txEvent, curTick() + transmitTick); 1552 1553 pioPort.sendRangeChange(); 1554 1555} 1556 1557} // namespace Sinic 1558 1559Sinic::Device * 1560SinicParams::create() 1561{ 1562 return new Sinic::Device(this); 1563} 1564