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