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