sinic.cc revision 2566
113606Sciro.santilli@arm.com/* 27586SAli.Saidi@arm.com * Copyright (c) 2004-2005 The Regents of The University of Michigan 37586SAli.Saidi@arm.com * All rights reserved. 47586SAli.Saidi@arm.com * 57586SAli.Saidi@arm.com * Redistribution and use in source and binary forms, with or without 67586SAli.Saidi@arm.com * modification, are permitted provided that the following conditions are 77586SAli.Saidi@arm.com * met: redistributions of source code must retain the above copyright 87586SAli.Saidi@arm.com * notice, this list of conditions and the following disclaimer; 97586SAli.Saidi@arm.com * redistributions in binary form must reproduce the above copyright 107586SAli.Saidi@arm.com * notice, this list of conditions and the following disclaimer in the 117586SAli.Saidi@arm.com * documentation and/or other materials provided with the distribution; 127586SAli.Saidi@arm.com * neither the name of the copyright holders nor the names of its 1310118Snilay@cs.wisc.edu * contributors may be used to endorse or promote products derived from 1410118Snilay@cs.wisc.edu * this software without specific prior written permission. 153970Sgblack@eecs.umich.edu * 163005Sstever@eecs.umich.edu * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 173005Sstever@eecs.umich.edu * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 183005Sstever@eecs.umich.edu * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR 193005Sstever@eecs.umich.edu * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT 203005Sstever@eecs.umich.edu * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 213005Sstever@eecs.umich.edu * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT 223005Sstever@eecs.umich.edu * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 233005Sstever@eecs.umich.edu * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 243005Sstever@eecs.umich.edu * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 253005Sstever@eecs.umich.edu * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 263005Sstever@eecs.umich.edu * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 273005Sstever@eecs.umich.edu */ 283005Sstever@eecs.umich.edu 293005Sstever@eecs.umich.edu#include <cstdio> 303005Sstever@eecs.umich.edu#include <deque> 313005Sstever@eecs.umich.edu#include <limits> 323005Sstever@eecs.umich.edu#include <string> 333005Sstever@eecs.umich.edu 343005Sstever@eecs.umich.edu#include "base/inet.hh" 353005Sstever@eecs.umich.edu#include "cpu/exec_context.hh" 363005Sstever@eecs.umich.edu#include "cpu/intr_control.hh" 373005Sstever@eecs.umich.edu#include "dev/etherlink.hh" 383005Sstever@eecs.umich.edu#include "dev/sinic.hh" 393005Sstever@eecs.umich.edu#include "dev/pciconfigall.hh" 403005Sstever@eecs.umich.edu#include "mem/packet.hh" 413005Sstever@eecs.umich.edu#include "sim/builder.hh" 4210118Snilay@cs.wisc.edu#include "sim/debug.hh" 433005Sstever@eecs.umich.edu#include "sim/eventq.hh" 4412564Sgabeblack@google.com#include "sim/host.hh" 4513774Sandreas.sandberg@arm.com#include "sim/stats.hh" 4612564Sgabeblack@google.com#include "arch/vtophys.hh" 476654Snate@binkert.org 486654Snate@binkert.orgusing namespace Net; 492889SN/Ausing namespace TheISA; 502710SN/A 516654Snate@binkert.orgnamespace Sinic { 526654Snate@binkert.org 5312395Sswapnilster@gmail.comconst char *RxStateStrings[] = 5412475Sglenn.bergmans@arm.com{ 555457Ssaidi@eecs.umich.edu "rxIdle", 5611670Sandreas.hansson@arm.com "rxFifoBlock", 5710118Snilay@cs.wisc.edu "rxBeginCopy", 5811670Sandreas.hansson@arm.com "rxCopy", 596654Snate@binkert.org "rxCopyDone" 6011682Sandreas.hansson@arm.com}; 6111682Sandreas.hansson@arm.com 6211682Sandreas.hansson@arm.comconst char *TxStateStrings[] = 6311682Sandreas.hansson@arm.com{ 6411682Sandreas.hansson@arm.com "txIdle", 6511682Sandreas.hansson@arm.com "txFifoBlock", 6611790Sjungma@eit.uni-kl.de "txBeginCopy", 6713432Spau.cabre@metempsy.com "txCopy", 6811682Sandreas.hansson@arm.com "txCopyDone" 6911682Sandreas.hansson@arm.com}; 703444Sktlim@umich.edu 7110594Sgabeblack@google.com 7210594Sgabeblack@google.com/////////////////////////////////////////////////////////////////////// 7312564Sgabeblack@google.com// 7412564Sgabeblack@google.com// Sinic PCI Device 7510594Sgabeblack@google.com// 7610594Sgabeblack@google.comBase::Base(Params *p) 7710594Sgabeblack@google.com : PciDev(p), rxEnable(false), txEnable(false), clock(p->clock), 7810594Sgabeblack@google.com intrDelay(p->intr_delay), intrTick(0), cpuIntrEnable(false), 7910594Sgabeblack@google.com cpuPendingIntr(false), intrEvent(0), interface(NULL) 8010594Sgabeblack@google.com{ 8110594Sgabeblack@google.com} 8210119Snilay@cs.wisc.edu 8310594Sgabeblack@google.comDevice::Device(Params *p) 8410119Snilay@cs.wisc.edu : Base(p), rxFifo(p->rx_fifo_size), txFifo(p->tx_fifo_size), 8510594Sgabeblack@google.com rxKickTick(0), txKickTick(0), 8610594Sgabeblack@google.com txEvent(this), rxDmaEvent(this), txDmaEvent(this), 8710119Snilay@cs.wisc.edu dmaReadDelay(p->dma_read_delay), dmaReadFactor(p->dma_read_factor), 8810594Sgabeblack@google.com dmaWriteDelay(p->dma_write_delay), dmaWriteFactor(p->dma_write_factor) 8910119Snilay@cs.wisc.edu{ 9010594Sgabeblack@google.com reset(); 9110119Snilay@cs.wisc.edu 9213864Ssupohaosu@gmail.com} 9313864Ssupohaosu@gmail.com 9410119Snilay@cs.wisc.eduDevice::~Device() 9513864Ssupohaosu@gmail.com{} 9613864Ssupohaosu@gmail.com 9710594Sgabeblack@google.comvoid 9810780SCurtis.Dunham@arm.comDevice::regStats() 9912475Sglenn.bergmans@arm.com{ 10012475Sglenn.bergmans@arm.com rxBytes 10112079Sgedare@rtems.org .name(name() + ".rxBytes") 10212079Sgedare@rtems.org .desc("Bytes Received") 10310119Snilay@cs.wisc.edu .prereq(rxBytes) 10410119Snilay@cs.wisc.edu ; 10510119Snilay@cs.wisc.edu 10610119Snilay@cs.wisc.edu rxBandwidth 1072566SN/A .name(name() + ".rxBandwidth") 10810119Snilay@cs.wisc.edu .desc("Receive Bandwidth (bits/s)") 10910119Snilay@cs.wisc.edu .precision(0) 1109665Sandreas.hansson@arm.com .prereq(rxBytes) 11110119Snilay@cs.wisc.edu ; 11210119Snilay@cs.wisc.edu 11310119Snilay@cs.wisc.edu rxPackets 11410119Snilay@cs.wisc.edu .name(name() + ".rxPackets") 11510119Snilay@cs.wisc.edu .desc("Number of Packets Received") 11610119Snilay@cs.wisc.edu .prereq(rxBytes) 11710119Snilay@cs.wisc.edu ; 11810119Snilay@cs.wisc.edu 11910119Snilay@cs.wisc.edu rxPacketRate 12010119Snilay@cs.wisc.edu .name(name() + ".rxPPS") 12110119Snilay@cs.wisc.edu .desc("Packet Reception Rate (packets/s)") 12210119Snilay@cs.wisc.edu .precision(0) 12310119Snilay@cs.wisc.edu .prereq(rxBytes) 12410119Snilay@cs.wisc.edu ; 12510119Snilay@cs.wisc.edu 12610119Snilay@cs.wisc.edu rxIpPackets 12710119Snilay@cs.wisc.edu .name(name() + ".rxIpPackets") 12813803Sodanrc@yahoo.com.br .desc("Number of IP Packets Received") 12913803Sodanrc@yahoo.com.br .prereq(rxBytes) 13013803Sodanrc@yahoo.com.br ; 13110119Snilay@cs.wisc.edu 13210119Snilay@cs.wisc.edu rxTcpPackets 13310119Snilay@cs.wisc.edu .name(name() + ".rxTcpPackets") 13410119Snilay@cs.wisc.edu .desc("Number of Packets Received") 13510119Snilay@cs.wisc.edu .prereq(rxBytes) 13610119Snilay@cs.wisc.edu ; 13710119Snilay@cs.wisc.edu 13810119Snilay@cs.wisc.edu rxUdpPackets 13910119Snilay@cs.wisc.edu .name(name() + ".rxUdpPackets") 14010119Snilay@cs.wisc.edu .desc("Number of UDP Packets Received") 14110119Snilay@cs.wisc.edu .prereq(rxBytes) 14210119Snilay@cs.wisc.edu ; 14310119Snilay@cs.wisc.edu 14410119Snilay@cs.wisc.edu rxIpChecksums 14513731Sandreas.sandberg@arm.com .name(name() + ".rxIpChecksums") 14610119Snilay@cs.wisc.edu .desc("Number of rx IP Checksums done by device") 14712941Sandreas.sandberg@arm.com .precision(0) 14811839SCurtis.Dunham@arm.com .prereq(rxBytes) 14910119Snilay@cs.wisc.edu ; 15010119Snilay@cs.wisc.edu 15112598Snikos.nikoleris@arm.com rxTcpChecksums 15210519Snilay@cs.wisc.edu .name(name() + ".rxTcpChecksums") 15312598Snikos.nikoleris@arm.com .desc("Number of rx TCP Checksums done by device") 15410119Snilay@cs.wisc.edu .precision(0) 15510119Snilay@cs.wisc.edu .prereq(rxBytes) 15610119Snilay@cs.wisc.edu ; 15710119Snilay@cs.wisc.edu 15810119Snilay@cs.wisc.edu rxUdpChecksums 15910547Snilay@cs.wisc.edu .name(name() + ".rxUdpChecksums") 16010547Snilay@cs.wisc.edu .desc("Number of rx UDP Checksums done by device") 16110547Snilay@cs.wisc.edu .precision(0) 16210547Snilay@cs.wisc.edu .prereq(rxBytes) 16310119Snilay@cs.wisc.edu ; 16410119Snilay@cs.wisc.edu 16510119Snilay@cs.wisc.edu totBandwidth 16610119Snilay@cs.wisc.edu .name(name() + ".totBandwidth") 16710119Snilay@cs.wisc.edu .desc("Total Bandwidth (bits/s)") 16810119Snilay@cs.wisc.edu .precision(0) 16910119Snilay@cs.wisc.edu .prereq(totBytes) 17010119Snilay@cs.wisc.edu ; 17110120Snilay@cs.wisc.edu 17210120Snilay@cs.wisc.edu totPackets 17310119Snilay@cs.wisc.edu .name(name() + ".totPackets") 17411598Sandreas.sandberg@arm.com .desc("Total Packets") 17510120Snilay@cs.wisc.edu .precision(0) 17610120Snilay@cs.wisc.edu .prereq(totBytes) 17710119Snilay@cs.wisc.edu ; 17811598Sandreas.sandberg@arm.com 17911150Smitch.hayenga@arm.com totBytes 18011150Smitch.hayenga@arm.com .name(name() + ".totBytes") 18111150Smitch.hayenga@arm.com .desc("Total Bytes") 18210119Snilay@cs.wisc.edu .precision(0) 1832995SN/A .prereq(totBytes) 18410119Snilay@cs.wisc.edu ; 18510119Snilay@cs.wisc.edu 18610119Snilay@cs.wisc.edu totPacketRate 18710119Snilay@cs.wisc.edu .name(name() + ".totPPS") 18810119Snilay@cs.wisc.edu .desc("Total Tranmission Rate (packets/s)") 18910780SCurtis.Dunham@arm.com .precision(0) 19010119Snilay@cs.wisc.edu .prereq(totBytes) 19110119Snilay@cs.wisc.edu ; 19210119Snilay@cs.wisc.edu 1933304Sstever@eecs.umich.edu txBytes 19410119Snilay@cs.wisc.edu .name(name() + ".txBytes") 19510608Sdam.sunwoo@arm.com .desc("Bytes Transmitted") 19613684Sgiacomo.travaglini@arm.com .prereq(txBytes) 19713012Sandreas.sandberg@arm.com ; 19810608Sdam.sunwoo@arm.com 19910608Sdam.sunwoo@arm.com txBandwidth 20010608Sdam.sunwoo@arm.com .name(name() + ".txBandwidth") 20113731Sandreas.sandberg@arm.com .desc("Transmit Bandwidth (bits/s)") 20210608Sdam.sunwoo@arm.com .precision(0) 20310608Sdam.sunwoo@arm.com .prereq(txBytes) 20410119Snilay@cs.wisc.edu ; 20510119Snilay@cs.wisc.edu 20613432Spau.cabre@metempsy.com txPackets 20713432Spau.cabre@metempsy.com .name(name() + ".txPackets") 20813432Spau.cabre@metempsy.com .desc("Number of Packets Transmitted") 20913958Sjairo.balart@metempsy.com .prereq(txBytes) 21013958Sjairo.balart@metempsy.com ; 21113958Sjairo.balart@metempsy.com 21213958Sjairo.balart@metempsy.com txPacketRate 21313958Sjairo.balart@metempsy.com .name(name() + ".txPPS") 21410119Snilay@cs.wisc.edu .desc("Packet Tranmission Rate (packets/s)") 2153819Shsul@eecs.umich.edu .precision(0) 21611251Sradhika.jagtap@ARM.com .prereq(txBytes) 21711251Sradhika.jagtap@ARM.com ; 21811251Sradhika.jagtap@ARM.com 21911251Sradhika.jagtap@ARM.com txIpPackets 22011251Sradhika.jagtap@ARM.com .name(name() + ".txIpPackets") 22111251Sradhika.jagtap@ARM.com .desc("Number of IP Packets Transmitted") 22211251Sradhika.jagtap@ARM.com .prereq(txBytes) 22311251Sradhika.jagtap@ARM.com ; 22411251Sradhika.jagtap@ARM.com 22511251Sradhika.jagtap@ARM.com txTcpPackets 22611251Sradhika.jagtap@ARM.com .name(name() + ".txTcpPackets") 22710119Snilay@cs.wisc.edu .desc("Number of TCP Packets Transmitted") 22811183Serfan.azarkhish@unibo.it .prereq(txBytes) 22910119Snilay@cs.wisc.edu ; 23010118Snilay@cs.wisc.edu 23110119Snilay@cs.wisc.edu txUdpPackets 2329827Sakash.bagdia@arm.com .name(name() + ".txUdpPackets") 23310119Snilay@cs.wisc.edu .desc("Number of Packets Transmitted") 23410119Snilay@cs.wisc.edu .prereq(txBytes) 23510119Snilay@cs.wisc.edu ; 23610119Snilay@cs.wisc.edu 23710119Snilay@cs.wisc.edu txIpChecksums 23810119Snilay@cs.wisc.edu .name(name() + ".txIpChecksums") 2399827Sakash.bagdia@arm.com .desc("Number of tx IP Checksums done by device") 24010594Sgabeblack@google.com .precision(0) 2416654Snate@binkert.org .prereq(txBytes) 24213803Sodanrc@yahoo.com.br ; 24313803Sodanrc@yahoo.com.br 2446654Snate@binkert.org txTcpChecksums 24510594Sgabeblack@google.com .name(name() + ".txTcpChecksums") 2466654Snate@binkert.org .desc("Number of tx TCP Checksums done by device") 24710594Sgabeblack@google.com .precision(0) 2486654Snate@binkert.org .prereq(txBytes) 24910594Sgabeblack@google.com ; 25010594Sgabeblack@google.com 2517586SAli.Saidi@arm.com txUdpChecksums 25210635Satgutier@umich.edu .name(name() + ".txUdpChecksums") 25313606Sciro.santilli@arm.com .desc("Number of tx UDP Checksums done by device") 2548661SAli.Saidi@ARM.com .precision(0) 2559827Sakash.bagdia@arm.com .prereq(txBytes) 2569827Sakash.bagdia@arm.com ; 2579827Sakash.bagdia@arm.com 2589793Sakash.bagdia@arm.com txBandwidth = txBytes * Stats::constant(8) / simSeconds; 25910119Snilay@cs.wisc.edu rxBandwidth = rxBytes * Stats::constant(8) / simSeconds; 26010119Snilay@cs.wisc.edu totBandwidth = txBandwidth + rxBandwidth; 2619790Sakash.bagdia@arm.com totBytes = txBytes + rxBytes; 2629827Sakash.bagdia@arm.com totPackets = txPackets + rxPackets; 2639827Sakash.bagdia@arm.com txPacketRate = txPackets / simSeconds; 2649827Sakash.bagdia@arm.com rxPacketRate = rxPackets / simSeconds; 2659793Sakash.bagdia@arm.com} 2669827Sakash.bagdia@arm.com 2679827Sakash.bagdia@arm.comvoid 2689827Sakash.bagdia@arm.comDevice::prepareIO(int cpu, int index) 2699793Sakash.bagdia@arm.com{ 2709793Sakash.bagdia@arm.com int size = virtualRegs.size(); 2719793Sakash.bagdia@arm.com if (index < size) 2729384SAndreas.Sandberg@arm.com return; 2738863Snilay@cs.wisc.edu 2747876Sgblack@eecs.umich.edu virtualRegs.resize(index + 1); 2754837Ssaidi@eecs.umich.edu for (int i = size; i <= index; ++i) 2764837Ssaidi@eecs.umich.edu virtualRegs[i].rxPacket = rxFifo.end(); 27713803Sodanrc@yahoo.com.br} 27813803Sodanrc@yahoo.com.br 27913803Sodanrc@yahoo.com.brvoid 2809408Sandreas.hansson@arm.comDevice::prepareRead(int cpu, int index) 28112941Sandreas.sandberg@arm.com{ 28211839SCurtis.Dunham@arm.com using namespace Regs; 2839653SAndreas.Sandberg@ARM.com prepareIO(cpu, index); 2849164Sandreas.hansson@arm.com 2859408Sandreas.hansson@arm.com VirtualReg &vnic = virtualRegs[index]; 2868845Sandreas.hansson@arm.com 2878845Sandreas.hansson@arm.com // update rx registers 2884837Ssaidi@eecs.umich.edu uint64_t rxdone = vnic.RxDone; 2899826Sandreas.hansson@arm.com rxdone = set_RxDone_Packets(rxdone, rxFifo.packets()); 2909826Sandreas.hansson@arm.com regs.RxData = vnic.RxData; 2919835Sandreas.hansson@arm.com regs.RxDone = rxdone; 2929826Sandreas.hansson@arm.com regs.RxWait = rxdone; 29313731Sandreas.sandberg@arm.com 2949826Sandreas.hansson@arm.com // update tx regsiters 2959826Sandreas.hansson@arm.com uint64_t txdone = vnic.TxDone; 2968659SAli.Saidi@ARM.com txdone = set_TxDone_Packets(txdone, txFifo.packets()); 29710119Snilay@cs.wisc.edu txdone = set_TxDone_Full(txdone, txFifo.avail() < regs.TxMaxCopy); 29810119Snilay@cs.wisc.edu txdone = set_TxDone_Low(txdone, txFifo.size() < regs.TxFifoMark); 29910119Snilay@cs.wisc.edu regs.TxData = vnic.TxData; 30010119Snilay@cs.wisc.edu regs.TxDone = txdone; 30110119Snilay@cs.wisc.edu regs.TxWait = txdone; 30210119Snilay@cs.wisc.edu} 30310119Snilay@cs.wisc.edu 30410119Snilay@cs.wisc.eduvoid 30510119Snilay@cs.wisc.eduDevice::prepareWrite(int cpu, int index) 30610119Snilay@cs.wisc.edu{ 30710119Snilay@cs.wisc.edu prepareIO(cpu, index); 30810119Snilay@cs.wisc.edu} 30910119Snilay@cs.wisc.edu 31010119Snilay@cs.wisc.edu/** 31110119Snilay@cs.wisc.edu * I/O read of device register 31212564Sgabeblack@google.com */ 31310119Snilay@cs.wisc.eduTick 31410119Snilay@cs.wisc.eduDevice::read(Packet &pkt) 31510119Snilay@cs.wisc.edu{ 31610119Snilay@cs.wisc.edu assert(config.command & PCI_CMD_MSE); 31710119Snilay@cs.wisc.edu assert(pkt.addr >= BARAddrs[0] && pkt.size < BARSize[0]); 31810119Snilay@cs.wisc.edu 31910119Snilay@cs.wisc.edu int cpu = pkt.req->getCpuNum(); 32010119Snilay@cs.wisc.edu Addr daddr = pkt.addr - BARAddrs[0]; 32110119Snilay@cs.wisc.edu Addr index = daddr >> Regs::VirtualShift; 32210119Snilay@cs.wisc.edu Addr raddr = daddr & Regs::VirtualMask; 32310119Snilay@cs.wisc.edu 32410119Snilay@cs.wisc.edu pkt.time = curTick + pioDelay; 32512564Sgabeblack@google.com pkt.allocate(); 32612564Sgabeblack@google.com 32710119Snilay@cs.wisc.edu if (!regValid(raddr)) 32810119Snilay@cs.wisc.edu panic("invalid register: cpu=%d, da=%#x pa=%#x size=%d", 32910119Snilay@cs.wisc.edu cpu, daddr, pkt.addr, pkt.size); 33010697SCurtis.Dunham@arm.com 33110747SChris.Emmons@arm.com const Regs::Info &info = regInfo(raddr); 33210697SCurtis.Dunham@arm.com if (!info.read) 33310747SChris.Emmons@arm.com panic("reading %s (write only): cpu=%d da=%#x pa=%#x size=%d", 33410119Snilay@cs.wisc.edu info.name, cpu, daddr, pkt.addr, pkt.size); 33510697SCurtis.Dunham@arm.com 33610747SChris.Emmons@arm.com if (pkt.size != info.size) 33710119Snilay@cs.wisc.edu panic("invalid size for reg %s: cpu=%d da=%#x pa=%#x size=%d", 33810119Snilay@cs.wisc.edu info.name, cpu, daddr, pkt.addr, pkt.size); 33910119Snilay@cs.wisc.edu 34010119Snilay@cs.wisc.edu prepareRead(cpu, index); 34110119Snilay@cs.wisc.edu 34210119Snilay@cs.wisc.edu uint64_t value = 0; 3438801Sgblack@eecs.umich.edu if (pkt.size == 4) { 34411291Sgabor.dozsa@arm.com uint32_t reg = regData32(raddr); 34511291Sgabor.dozsa@arm.com pkt.set(reg); 34611291Sgabor.dozsa@arm.com value = reg; 34711291Sgabor.dozsa@arm.com } 34811291Sgabor.dozsa@arm.com 34911291Sgabor.dozsa@arm.com if (pkt.size == 8) { 35011291Sgabor.dozsa@arm.com uint64_t reg = regData64(raddr); 35111291Sgabor.dozsa@arm.com pkt.set(reg); 35211291Sgabor.dozsa@arm.com value = reg; 35311291Sgabor.dozsa@arm.com } 35411291Sgabor.dozsa@arm.com 35511291Sgabor.dozsa@arm.com DPRINTF(EthernetPIO, 3563005Sstever@eecs.umich.edu "read %s cpu=%d da=%#x pa=%#x size=%d val=%#x\n", 3578801Sgblack@eecs.umich.edu info.name, cpu, daddr, pkt.addr, pkt.size, value); 3583005Sstever@eecs.umich.edu 35912564Sgabeblack@google.com // reading the interrupt status register has the side effect of 3603005Sstever@eecs.umich.edu // clearing it 3612566SN/A if (raddr == Regs::IntrStatus) 3627861Sgblack@eecs.umich.edu devIntrClear(); 3637861Sgblack@eecs.umich.edu 3647861Sgblack@eecs.umich.edu return pioDelay; 3658635Schris.emmons@arm.com} 3668635Schris.emmons@arm.com 3678635Schris.emmons@arm.com/** 36813606Sciro.santilli@arm.com * IPR read of device register 36913606Sciro.santilli@arm.com 37012475Sglenn.bergmans@arm.com Fault 37112475Sglenn.bergmans@arm.comDevice::iprRead(Addr daddr, int cpu, uint64_t &result) 37212475Sglenn.bergmans@arm.com{ 37312475Sglenn.bergmans@arm.com if (!regValid(daddr)) 37412475Sglenn.bergmans@arm.com panic("invalid address: da=%#x", daddr); 37512475Sglenn.bergmans@arm.com 37612475Sglenn.bergmans@arm.com const Regs::Info &info = regInfo(daddr); 37712475Sglenn.bergmans@arm.com if (!info.read) 37812475Sglenn.bergmans@arm.com panic("reading %s (write only): cpu=%d da=%#x", info.name, cpu, daddr); 37913608Sgiacomo.travaglini@arm.com 38012475Sglenn.bergmans@arm.com DPRINTF(EthernetPIO, "IPR read %s: cpu=%d da=%#x\n", 3819061Snilay@cs.wisc.edu info.name, cpu, daddr); 3823481Shsul@eecs.umich.edu 383 prepareRead(cpu, 0); 384 385 if (info.size == 4) 386 result = regData32(daddr); 387 388 if (info.size == 8) 389 result = regData64(daddr); 390 391 DPRINTF(EthernetPIO, "IPR read %s: cpu=%s da=%#x val=%#x\n", 392 info.name, cpu, result); 393 394 return NoFault; 395} 396*/ 397/** 398 * I/O write of device register 399 */ 400Tick 401Device::write(Packet &pkt) 402{ 403 assert(config.command & PCI_CMD_MSE); 404 assert(pkt.addr >= BARAddrs[0] && pkt.size < BARSize[0]); 405 406 int cpu = pkt.req->getCpuNum(); 407 Addr daddr = pkt.addr - BARAddrs[0]; 408 Addr index = daddr >> Regs::VirtualShift; 409 Addr raddr = daddr & Regs::VirtualMask; 410 411 pkt.time = curTick + pioDelay; 412 413 if (!regValid(raddr)) 414 panic("invalid register: cpu=%d, da=%#x pa=%#x size=%d", 415 cpu, daddr, pkt.addr, pkt.size); 416 417 const Regs::Info &info = regInfo(raddr); 418 if (!info.write) 419 panic("write %s (read only): cpu=%d da=%#x pa=%#x size=%d", 420 info.name, cpu, daddr, pkt.addr, pkt.size); 421 422 if (pkt.size != info.size) 423 panic("invalid size for reg %s: cpu=%d da=%#x pa=%#x size=%d", 424 info.name, cpu, daddr, pkt.addr, pkt.size); 425 426 VirtualReg &vnic = virtualRegs[index]; 427 428 DPRINTF(EthernetPIO, 429 "write %s: cpu=%d val=%#x da=%#x pa=%#x size=%d\n", 430 info.name, cpu, info.size == 4 ? pkt.get<uint32_t>() : 431 pkt.get<uint64_t>(), daddr, pkt.addr, pkt.size); 432 433 prepareWrite(cpu, index); 434 435 switch (raddr) { 436 case Regs::Config: 437 changeConfig(pkt.get<uint32_t>()); 438 break; 439 440 case Regs::Command: 441 command(pkt.get<uint32_t>()); 442 break; 443 444 case Regs::IntrStatus: 445 devIntrClear(regs.IntrStatus & pkt.get<uint32_t>()); 446 break; 447 448 case Regs::IntrMask: 449 devIntrChangeMask(pkt.get<uint32_t>()); 450 break; 451 452 case Regs::RxData: 453 if (Regs::get_RxDone_Busy(vnic.RxDone)) 454 panic("receive machine busy with another request! rxState=%s", 455 RxStateStrings[rxState]); 456 457 vnic.RxDone = Regs::RxDone_Busy; 458 vnic.RxData = pkt.get<uint64_t>(); 459 rxList.push_back(index); 460 if (rxEnable && rxState == rxIdle) { 461 rxState = rxFifoBlock; 462 rxKick(); 463 } 464 break; 465 466 case Regs::TxData: 467 if (Regs::get_TxDone_Busy(vnic.TxDone)) 468 panic("transmit machine busy with another request! txState=%s", 469 TxStateStrings[txState]); 470 471 vnic.TxDone = Regs::TxDone_Busy; 472 vnic.TxData = pkt.get<uint64_t>(); 473 if (txList.empty() || txList.front() != index) 474 txList.push_back(index); 475 if (txEnable && txState == txIdle && txList.front() == index) { 476 txState = txFifoBlock; 477 txKick(); 478 } 479 break; 480 } 481 482 return pioDelay; 483} 484 485void 486Device::devIntrPost(uint32_t interrupts) 487{ 488 if ((interrupts & Regs::Intr_Res)) 489 panic("Cannot set a reserved interrupt"); 490 491 regs.IntrStatus |= interrupts; 492 493 DPRINTF(EthernetIntr, 494 "interrupt written to intStatus: intr=%#x status=%#x mask=%#x\n", 495 interrupts, regs.IntrStatus, regs.IntrMask); 496 497 interrupts = regs.IntrStatus & regs.IntrMask; 498 499 // Intr_RxHigh is special, we only signal it if we've emptied the fifo 500 // and then filled it above the high watermark 501 if (rxEmpty) 502 rxEmpty = false; 503 else 504 interrupts &= ~Regs::Intr_RxHigh; 505 506 // Intr_TxLow is special, we only signal it if we've filled up the fifo 507 // and then dropped below the low watermark 508 if (txFull) 509 txFull = false; 510 else 511 interrupts &= ~Regs::Intr_TxLow; 512 513 if (interrupts) { 514 Tick when = curTick; 515 if ((interrupts & Regs::Intr_NoDelay) == 0) 516 when += intrDelay; 517 cpuIntrPost(when); 518 } 519} 520 521void 522Device::devIntrClear(uint32_t interrupts) 523{ 524 if ((interrupts & Regs::Intr_Res)) 525 panic("Cannot clear a reserved interrupt"); 526 527 regs.IntrStatus &= ~interrupts; 528 529 DPRINTF(EthernetIntr, 530 "interrupt cleared from intStatus: intr=%x status=%x mask=%x\n", 531 interrupts, regs.IntrStatus, regs.IntrMask); 532 533 if (!(regs.IntrStatus & regs.IntrMask)) 534 cpuIntrClear(); 535} 536 537void 538Device::devIntrChangeMask(uint32_t newmask) 539{ 540 if (regs.IntrMask == newmask) 541 return; 542 543 regs.IntrMask = newmask; 544 545 DPRINTF(EthernetIntr, 546 "interrupt mask changed: intStatus=%x intMask=%x masked=%x\n", 547 regs.IntrStatus, regs.IntrMask, regs.IntrStatus & regs.IntrMask); 548 549 if (regs.IntrStatus & regs.IntrMask) 550 cpuIntrPost(curTick); 551 else 552 cpuIntrClear(); 553} 554 555void 556Base::cpuIntrPost(Tick when) 557{ 558 // If the interrupt you want to post is later than an interrupt 559 // already scheduled, just let it post in the coming one and don't 560 // schedule another. 561 // HOWEVER, must be sure that the scheduled intrTick is in the 562 // future (this was formerly the source of a bug) 563 /** 564 * @todo this warning should be removed and the intrTick code should 565 * be fixed. 566 */ 567 assert(when >= curTick); 568 assert(intrTick >= curTick || intrTick == 0); 569 if (!cpuIntrEnable) { 570 DPRINTF(EthernetIntr, "interrupts not enabled.\n", 571 intrTick); 572 return; 573 } 574 575 if (when > intrTick && intrTick != 0) { 576 DPRINTF(EthernetIntr, "don't need to schedule event...intrTick=%d\n", 577 intrTick); 578 return; 579 } 580 581 intrTick = when; 582 if (intrTick < curTick) { 583 debug_break(); 584 intrTick = curTick; 585 } 586 587 DPRINTF(EthernetIntr, "going to schedule an interrupt for intrTick=%d\n", 588 intrTick); 589 590 if (intrEvent) 591 intrEvent->squash(); 592 intrEvent = new IntrEvent(this, true); 593 intrEvent->schedule(intrTick); 594} 595 596void 597Base::cpuInterrupt() 598{ 599 assert(intrTick == curTick); 600 601 // Whether or not there's a pending interrupt, we don't care about 602 // it anymore 603 intrEvent = 0; 604 intrTick = 0; 605 606 // Don't send an interrupt if there's already one 607 if (cpuPendingIntr) { 608 DPRINTF(EthernetIntr, 609 "would send an interrupt now, but there's already pending\n"); 610 } else { 611 // Send interrupt 612 cpuPendingIntr = true; 613 614 DPRINTF(EthernetIntr, "posting interrupt\n"); 615 intrPost(); 616 } 617} 618 619void 620Base::cpuIntrClear() 621{ 622 if (!cpuPendingIntr) 623 return; 624 625 if (intrEvent) { 626 intrEvent->squash(); 627 intrEvent = 0; 628 } 629 630 intrTick = 0; 631 632 cpuPendingIntr = false; 633 634 DPRINTF(EthernetIntr, "clearing cchip interrupt\n"); 635 intrClear(); 636} 637 638bool 639Base::cpuIntrPending() const 640{ return cpuPendingIntr; } 641 642void 643Device::changeConfig(uint32_t newconf) 644{ 645 uint32_t changed = regs.Config ^ newconf; 646 if (!changed) 647 return; 648 649 regs.Config = newconf; 650 651 if ((changed & Regs::Config_IntEn)) { 652 cpuIntrEnable = regs.Config & Regs::Config_IntEn; 653 if (cpuIntrEnable) { 654 if (regs.IntrStatus & regs.IntrMask) 655 cpuIntrPost(curTick); 656 } else { 657 cpuIntrClear(); 658 } 659 } 660 661 if ((changed & Regs::Config_TxEn)) { 662 txEnable = regs.Config & Regs::Config_TxEn; 663 if (txEnable) 664 txKick(); 665 } 666 667 if ((changed & Regs::Config_RxEn)) { 668 rxEnable = regs.Config & Regs::Config_RxEn; 669 if (rxEnable) 670 rxKick(); 671 } 672} 673 674void 675Device::command(uint32_t command) 676{ 677 if (command & Regs::Command_Intr) 678 devIntrPost(Regs::Intr_Soft); 679 680 if (command & Regs::Command_Reset) 681 reset(); 682} 683 684void 685Device::reset() 686{ 687 using namespace Regs; 688 689 memset(®s, 0, sizeof(regs)); 690 691 regs.Config = 0; 692 if (params()->rx_thread) 693 regs.Config |= Config_RxThread; 694 if (params()->tx_thread) 695 regs.Config |= Config_TxThread; 696 if (params()->rss) 697 regs.Config |= Config_RSS; 698 regs.IntrMask = Intr_Soft | Intr_RxHigh | Intr_RxPacket | Intr_TxLow; 699 regs.RxMaxCopy = params()->rx_max_copy; 700 regs.TxMaxCopy = params()->tx_max_copy; 701 regs.RxMaxIntr = params()->rx_max_intr; 702 regs.RxFifoSize = params()->rx_fifo_size; 703 regs.TxFifoSize = params()->tx_fifo_size; 704 regs.RxFifoMark = params()->rx_fifo_threshold; 705 regs.TxFifoMark = params()->tx_fifo_threshold; 706 regs.HwAddr = params()->eaddr; 707 708 rxList.clear(); 709 txList.clear(); 710 711 rxState = rxIdle; 712 txState = txIdle; 713 714 rxFifo.clear(); 715 rxFifoPtr = rxFifo.end(); 716 txFifo.clear(); 717 rxEmpty = false; 718 txFull = false; 719 720 int size = virtualRegs.size(); 721 virtualRegs.clear(); 722 virtualRegs.resize(size); 723 for (int i = 0; i < size; ++i) 724 virtualRegs[i].rxPacket = rxFifo.end(); 725} 726 727void 728Device::rxDmaDone() 729{ 730 assert(rxState == rxCopy); 731 rxState = rxCopyDone; 732 DPRINTF(EthernetDMA, "rx dma write paddr=%#x len=%d\n", 733 rxDmaAddr, rxDmaLen); 734 DDUMP(EthernetData, rxDmaData, rxDmaLen); 735 736 // If the transmit state machine has a pending DMA, let it go first 737 if (txState == txBeginCopy) 738 txKick(); 739 740 rxKick(); 741} 742 743void 744Device::rxKick() 745{ 746 VirtualReg *vnic; 747 748 DPRINTF(EthernetSM, "receive kick rxState=%s (rxFifo.size=%d)\n", 749 RxStateStrings[rxState], rxFifo.size()); 750 751 if (rxKickTick > curTick) { 752 DPRINTF(EthernetSM, "receive kick exiting, can't run till %d\n", 753 rxKickTick); 754 return; 755 } 756 757 next: 758 if (rxState == rxIdle) 759 goto exit; 760 761 assert(!rxList.empty()); 762 vnic = &virtualRegs[rxList.front()]; 763 764 DPRINTF(EthernetSM, "processing rxState=%s for virtual nic %d\n", 765 RxStateStrings[rxState], rxList.front()); 766 767 switch (rxState) { 768 case rxFifoBlock: 769 if (vnic->rxPacket != rxFifo.end()) { 770 rxState = rxBeginCopy; 771 break; 772 } 773 774 if (rxFifoPtr == rxFifo.end()) { 775 DPRINTF(EthernetSM, "receive waiting for data. Nothing to do.\n"); 776 goto exit; 777 } 778 779 assert(!rxFifo.empty()); 780 781 // Grab a new packet from the fifo. 782 vnic->rxPacket = rxFifoPtr++; 783 vnic->rxPacketOffset = 0; 784 vnic->rxPacketBytes = (*vnic->rxPacket)->length; 785 assert(vnic->rxPacketBytes); 786 787 vnic->rxDoneData = 0; 788 /* scope for variables */ { 789 IpPtr ip(*vnic->rxPacket); 790 if (ip) { 791 vnic->rxDoneData |= Regs::RxDone_IpPacket; 792 rxIpChecksums++; 793 if (cksum(ip) != 0) { 794 DPRINTF(EthernetCksum, "Rx IP Checksum Error\n"); 795 vnic->rxDoneData |= Regs::RxDone_IpError; 796 } 797 TcpPtr tcp(ip); 798 UdpPtr udp(ip); 799 if (tcp) { 800 vnic->rxDoneData |= Regs::RxDone_TcpPacket; 801 rxTcpChecksums++; 802 if (cksum(tcp) != 0) { 803 DPRINTF(EthernetCksum, "Rx TCP Checksum Error\n"); 804 vnic->rxDoneData |= Regs::RxDone_TcpError; 805 } 806 } else if (udp) { 807 vnic->rxDoneData |= Regs::RxDone_UdpPacket; 808 rxUdpChecksums++; 809 if (cksum(udp) != 0) { 810 DPRINTF(EthernetCksum, "Rx UDP Checksum Error\n"); 811 vnic->rxDoneData |= Regs::RxDone_UdpError; 812 } 813 } 814 } 815 } 816 rxState = rxBeginCopy; 817 break; 818 819 case rxBeginCopy: 820 if (dmaPending()) 821 goto exit; 822 823 rxDmaAddr = params()->platform->pciToDma( 824 Regs::get_RxData_Addr(vnic->RxData)); 825 rxDmaLen = std::min<int>(Regs::get_RxData_Len(vnic->RxData), 826 vnic->rxPacketBytes); 827 rxDmaData = (*vnic->rxPacket)->data + vnic->rxPacketOffset; 828 rxState = rxCopy; 829 830 dmaWrite(rxDmaAddr, rxDmaLen, &rxDmaEvent, rxDmaData); 831 break; 832 833 case rxCopy: 834 DPRINTF(EthernetSM, "receive machine still copying\n"); 835 goto exit; 836 837 case rxCopyDone: 838 vnic->RxDone = vnic->rxDoneData | rxDmaLen; 839 vnic->RxDone |= Regs::RxDone_Complete; 840 841 if (vnic->rxPacketBytes == rxDmaLen) { 842 DPRINTF(EthernetSM, "rxKick: packet complete on vnic %d\n", 843 rxList.front()); 844 rxFifo.remove(vnic->rxPacket); 845 vnic->rxPacket = rxFifo.end(); 846 } else { 847 vnic->RxDone |= Regs::RxDone_More; 848 vnic->rxPacketBytes -= rxDmaLen; 849 vnic->rxPacketOffset += rxDmaLen; 850 DPRINTF(EthernetSM, 851 "rxKick: packet not complete on vnic %d: %d bytes left\n", 852 rxList.front(), vnic->rxPacketBytes); 853 } 854 855 rxList.pop_front(); 856 rxState = rxList.empty() ? rxIdle : rxFifoBlock; 857 858 if (rxFifo.empty()) { 859 devIntrPost(Regs::Intr_RxEmpty); 860 rxEmpty = true; 861 } 862 863 devIntrPost(Regs::Intr_RxDMA); 864 break; 865 866 default: 867 panic("Invalid rxState!"); 868 } 869 870 DPRINTF(EthernetSM, "entering next rxState=%s\n", 871 RxStateStrings[rxState]); 872 873 goto next; 874 875 exit: 876 /** 877 * @todo do we want to schedule a future kick? 878 */ 879 DPRINTF(EthernetSM, "rx state machine exited rxState=%s\n", 880 RxStateStrings[rxState]); 881} 882 883void 884Device::txDmaDone() 885{ 886 assert(txState == txCopy); 887 txState = txCopyDone; 888 DPRINTF(EthernetDMA, "tx dma read paddr=%#x len=%d\n", 889 txDmaAddr, txDmaLen); 890 DDUMP(EthernetData, txDmaData, txDmaLen); 891 892 // If the receive state machine has a pending DMA, let it go first 893 if (rxState == rxBeginCopy) 894 rxKick(); 895 896 txKick(); 897} 898 899void 900Device::transmit() 901{ 902 if (txFifo.empty()) { 903 DPRINTF(Ethernet, "nothing to transmit\n"); 904 return; 905 } 906 907 uint32_t interrupts; 908 EthPacketPtr packet = txFifo.front(); 909 if (!interface->sendPacket(packet)) { 910 DPRINTF(Ethernet, "Packet Transmit: failed txFifo available %d\n", 911 txFifo.avail()); 912 goto reschedule; 913 } 914 915 txFifo.pop(); 916#if TRACING_ON 917 if (DTRACE(Ethernet)) { 918 IpPtr ip(packet); 919 if (ip) { 920 DPRINTF(Ethernet, "ID is %d\n", ip->id()); 921 TcpPtr tcp(ip); 922 if (tcp) { 923 DPRINTF(Ethernet, "Src Port=%d, Dest Port=%d\n", 924 tcp->sport(), tcp->dport()); 925 } 926 } 927 } 928#endif 929 930 DDUMP(EthernetData, packet->data, packet->length); 931 txBytes += packet->length; 932 txPackets++; 933 934 DPRINTF(Ethernet, "Packet Transmit: successful txFifo Available %d\n", 935 txFifo.avail()); 936 937 interrupts = Regs::Intr_TxPacket; 938 if (txFifo.size() < regs.TxFifoMark) 939 interrupts |= Regs::Intr_TxLow; 940 devIntrPost(interrupts); 941 942 reschedule: 943 if (!txFifo.empty() && !txEvent.scheduled()) { 944 DPRINTF(Ethernet, "reschedule transmit\n"); 945 txEvent.schedule(curTick + retryTime); 946 } 947} 948 949void 950Device::txKick() 951{ 952 VirtualReg *vnic; 953 DPRINTF(EthernetSM, "transmit kick txState=%s (txFifo.size=%d)\n", 954 TxStateStrings[txState], txFifo.size()); 955 956 if (txKickTick > curTick) { 957 DPRINTF(EthernetSM, "transmit kick exiting, can't run till %d\n", 958 txKickTick); 959 return; 960 } 961 962 next: 963 if (txState == txIdle) 964 goto exit; 965 966 assert(!txList.empty()); 967 vnic = &virtualRegs[txList.front()]; 968 969 switch (txState) { 970 case txFifoBlock: 971 assert(Regs::get_TxDone_Busy(vnic->TxData)); 972 if (!txPacket) { 973 // Grab a new packet from the fifo. 974 txPacket = new EthPacketData(16384); 975 txPacketOffset = 0; 976 } 977 978 if (txFifo.avail() - txPacket->length < 979 Regs::get_TxData_Len(vnic->TxData)) { 980 DPRINTF(EthernetSM, "transmit fifo full. Nothing to do.\n"); 981 goto exit; 982 } 983 984 txState = txBeginCopy; 985 break; 986 987 case txBeginCopy: 988 if (dmaPending()) 989 goto exit; 990 991 txDmaAddr = params()->platform->pciToDma( 992 Regs::get_TxData_Addr(vnic->TxData)); 993 txDmaLen = Regs::get_TxData_Len(vnic->TxData); 994 txDmaData = txPacket->data + txPacketOffset; 995 txState = txCopy; 996 997 dmaRead(txDmaAddr, txDmaLen, &txDmaEvent, txDmaData); 998 break; 999 1000 case txCopy: 1001 DPRINTF(EthernetSM, "transmit machine still copying\n"); 1002 goto exit; 1003 1004 case txCopyDone: 1005 vnic->TxDone = txDmaLen | Regs::TxDone_Complete; 1006 txPacket->length += txDmaLen; 1007 if ((vnic->TxData & Regs::TxData_More)) { 1008 txPacketOffset += txDmaLen; 1009 txState = txIdle; 1010 devIntrPost(Regs::Intr_TxDMA); 1011 break; 1012 } 1013 1014 assert(txPacket->length <= txFifo.avail()); 1015 if ((vnic->TxData & Regs::TxData_Checksum)) { 1016 IpPtr ip(txPacket); 1017 if (ip) { 1018 TcpPtr tcp(ip); 1019 if (tcp) { 1020 tcp->sum(0); 1021 tcp->sum(cksum(tcp)); 1022 txTcpChecksums++; 1023 } 1024 1025 UdpPtr udp(ip); 1026 if (udp) { 1027 udp->sum(0); 1028 udp->sum(cksum(udp)); 1029 txUdpChecksums++; 1030 } 1031 1032 ip->sum(0); 1033 ip->sum(cksum(ip)); 1034 txIpChecksums++; 1035 } 1036 } 1037 1038 txFifo.push(txPacket); 1039 if (txFifo.avail() < regs.TxMaxCopy) { 1040 devIntrPost(Regs::Intr_TxFull); 1041 txFull = true; 1042 } 1043 txPacket = 0; 1044 transmit(); 1045 txList.pop_front(); 1046 txState = txList.empty() ? txIdle : txFifoBlock; 1047 devIntrPost(Regs::Intr_TxDMA); 1048 break; 1049 1050 default: 1051 panic("Invalid txState!"); 1052 } 1053 1054 DPRINTF(EthernetSM, "entering next txState=%s\n", 1055 TxStateStrings[txState]); 1056 1057 goto next; 1058 1059 exit: 1060 /** 1061 * @todo do we want to schedule a future kick? 1062 */ 1063 DPRINTF(EthernetSM, "tx state machine exited txState=%s\n", 1064 TxStateStrings[txState]); 1065} 1066 1067void 1068Device::transferDone() 1069{ 1070 if (txFifo.empty()) { 1071 DPRINTF(Ethernet, "transfer complete: txFifo empty...nothing to do\n"); 1072 return; 1073 } 1074 1075 DPRINTF(Ethernet, "transfer complete: data in txFifo...schedule xmit\n"); 1076 1077 if (txEvent.scheduled()) 1078 txEvent.reschedule(curTick + cycles(1)); 1079 else 1080 txEvent.schedule(curTick + cycles(1)); 1081} 1082 1083bool 1084Device::rxFilter(const EthPacketPtr &packet) 1085{ 1086 if (!Regs::get_Config_Filter(regs.Config)) 1087 return false; 1088 1089 panic("receive filter not implemented\n"); 1090 bool drop = true; 1091 1092#if 0 1093 string type; 1094 1095 EthHdr *eth = packet->eth(); 1096 if (eth->unicast()) { 1097 // If we're accepting all unicast addresses 1098 if (acceptUnicast) 1099 drop = false; 1100 1101 // If we make a perfect match 1102 if (acceptPerfect && params->eaddr == eth.dst()) 1103 drop = false; 1104 1105 if (acceptArp && eth->type() == ETH_TYPE_ARP) 1106 drop = false; 1107 1108 } else if (eth->broadcast()) { 1109 // if we're accepting broadcasts 1110 if (acceptBroadcast) 1111 drop = false; 1112 1113 } else if (eth->multicast()) { 1114 // if we're accepting all multicasts 1115 if (acceptMulticast) 1116 drop = false; 1117 1118 } 1119 1120 if (drop) { 1121 DPRINTF(Ethernet, "rxFilter drop\n"); 1122 DDUMP(EthernetData, packet->data, packet->length); 1123 } 1124#endif 1125 return drop; 1126} 1127 1128bool 1129Device::recvPacket(EthPacketPtr packet) 1130{ 1131 rxBytes += packet->length; 1132 rxPackets++; 1133 1134 DPRINTF(Ethernet, "Receiving packet from wire, rxFifo Available is %d\n", 1135 rxFifo.avail()); 1136 1137 if (!rxEnable) { 1138 DPRINTF(Ethernet, "receive disabled...packet dropped\n"); 1139 return true; 1140 } 1141 1142 if (rxFilter(packet)) { 1143 DPRINTF(Ethernet, "packet filtered...dropped\n"); 1144 return true; 1145 } 1146 1147 if (rxFifo.size() >= regs.RxFifoMark) 1148 devIntrPost(Regs::Intr_RxHigh); 1149 1150 if (!rxFifo.push(packet)) { 1151 DPRINTF(Ethernet, 1152 "packet will not fit in receive buffer...packet dropped\n"); 1153 return false; 1154 } 1155 1156 // If we were at the last element, back up one ot go to the new 1157 // last element of the list. 1158 if (rxFifoPtr == rxFifo.end()) 1159 --rxFifoPtr; 1160 1161 devIntrPost(Regs::Intr_RxPacket); 1162 rxKick(); 1163 return true; 1164} 1165 1166//===================================================================== 1167// 1168// 1169void 1170Base::serialize(std::ostream &os) 1171{ 1172 // Serialize the PciDev base class 1173 PciDev::serialize(os); 1174 1175 SERIALIZE_SCALAR(rxEnable); 1176 SERIALIZE_SCALAR(txEnable); 1177 SERIALIZE_SCALAR(cpuIntrEnable); 1178 1179 /* 1180 * Keep track of pending interrupt status. 1181 */ 1182 SERIALIZE_SCALAR(intrTick); 1183 SERIALIZE_SCALAR(cpuPendingIntr); 1184 Tick intrEventTick = 0; 1185 if (intrEvent) 1186 intrEventTick = intrEvent->when(); 1187 SERIALIZE_SCALAR(intrEventTick); 1188} 1189 1190void 1191Base::unserialize(Checkpoint *cp, const std::string §ion) 1192{ 1193 // Unserialize the PciDev base class 1194 PciDev::unserialize(cp, section); 1195 1196 UNSERIALIZE_SCALAR(rxEnable); 1197 UNSERIALIZE_SCALAR(txEnable); 1198 UNSERIALIZE_SCALAR(cpuIntrEnable); 1199 1200 /* 1201 * Keep track of pending interrupt status. 1202 */ 1203 UNSERIALIZE_SCALAR(intrTick); 1204 UNSERIALIZE_SCALAR(cpuPendingIntr); 1205 Tick intrEventTick; 1206 UNSERIALIZE_SCALAR(intrEventTick); 1207 if (intrEventTick) { 1208 intrEvent = new IntrEvent(this, true); 1209 intrEvent->schedule(intrEventTick); 1210 } 1211} 1212 1213void 1214Device::serialize(std::ostream &os) 1215{ 1216 // Serialize the PciDev base class 1217 Base::serialize(os); 1218 1219 if (rxState == rxCopy) 1220 panic("can't serialize with an in flight dma request rxState=%s", 1221 RxStateStrings[rxState]); 1222 1223 if (txState == txCopy) 1224 panic("can't serialize with an in flight dma request txState=%s", 1225 TxStateStrings[txState]); 1226 1227 /* 1228 * Serialize the device registers 1229 */ 1230 SERIALIZE_SCALAR(regs.Config); 1231 SERIALIZE_SCALAR(regs.IntrStatus); 1232 SERIALIZE_SCALAR(regs.IntrMask); 1233 SERIALIZE_SCALAR(regs.RxMaxCopy); 1234 SERIALIZE_SCALAR(regs.TxMaxCopy); 1235 SERIALIZE_SCALAR(regs.RxMaxIntr); 1236 SERIALIZE_SCALAR(regs.RxData); 1237 SERIALIZE_SCALAR(regs.RxDone); 1238 SERIALIZE_SCALAR(regs.TxData); 1239 SERIALIZE_SCALAR(regs.TxDone); 1240 1241 /* 1242 * Serialize the virtual nic state 1243 */ 1244 int virtualRegsSize = virtualRegs.size(); 1245 SERIALIZE_SCALAR(virtualRegsSize); 1246 for (int i = 0; i < virtualRegsSize; ++i) { 1247 VirtualReg *vnic = &virtualRegs[i]; 1248 1249 std::string reg = csprintf("vnic%d", i); 1250 paramOut(os, reg + ".RxData", vnic->RxData); 1251 paramOut(os, reg + ".RxDone", vnic->RxDone); 1252 paramOut(os, reg + ".TxData", vnic->TxData); 1253 paramOut(os, reg + ".TxDone", vnic->TxDone); 1254 1255 PacketFifo::iterator rxFifoPtr; 1256 1257 bool rxPacketExists = vnic->rxPacket != rxFifo.end(); 1258 paramOut(os, reg + ".rxPacketExists", rxPacketExists); 1259 if (rxPacketExists) { 1260 int rxPacket = 0; 1261 PacketFifo::iterator i = rxFifo.begin(); 1262 while (i != vnic->rxPacket) { 1263 assert(i != rxFifo.end()); 1264 ++i; 1265 ++rxPacket; 1266 } 1267 1268 paramOut(os, reg + ".rxPacket", rxPacket); 1269 paramOut(os, reg + ".rxPacketOffset", vnic->rxPacketOffset); 1270 paramOut(os, reg + ".rxPacketBytes", vnic->rxPacketBytes); 1271 } 1272 paramOut(os, reg + ".rxDoneData", vnic->rxDoneData); 1273 } 1274 1275 VirtualList::iterator i, end; 1276 int count; 1277 1278 int rxListSize = rxList.size(); 1279 SERIALIZE_SCALAR(rxListSize); 1280 for (count = 0, i = rxList.begin(), end = rxList.end(); i != end; ++i) 1281 paramOut(os, csprintf("rxList%d", count++), *i); 1282 1283 int txListSize = txList.size(); 1284 SERIALIZE_SCALAR(txListSize); 1285 for (count = 0, i = txList.begin(), end = txList.end(); i != end; ++i) 1286 paramOut(os, csprintf("txList%d", count++), *i); 1287 1288 /* 1289 * Serialize rx state machine 1290 */ 1291 int rxState = this->rxState; 1292 SERIALIZE_SCALAR(rxState); 1293 SERIALIZE_SCALAR(rxEmpty); 1294 rxFifo.serialize("rxFifo", os); 1295 1296 /* 1297 * Serialize tx state machine 1298 */ 1299 int txState = this->txState; 1300 SERIALIZE_SCALAR(txState); 1301 SERIALIZE_SCALAR(txFull); 1302 txFifo.serialize("txFifo", os); 1303 bool txPacketExists = txPacket; 1304 SERIALIZE_SCALAR(txPacketExists); 1305 if (txPacketExists) { 1306 txPacket->serialize("txPacket", os); 1307 SERIALIZE_SCALAR(txPacketOffset); 1308 SERIALIZE_SCALAR(txPacketBytes); 1309 } 1310 1311 /* 1312 * If there's a pending transmit, store the time so we can 1313 * reschedule it later 1314 */ 1315 Tick transmitTick = txEvent.scheduled() ? txEvent.when() - curTick : 0; 1316 SERIALIZE_SCALAR(transmitTick); 1317} 1318 1319void 1320Device::unserialize(Checkpoint *cp, const std::string §ion) 1321{ 1322 // Unserialize the PciDev base class 1323 Base::unserialize(cp, section); 1324 1325 /* 1326 * Unserialize the device registers 1327 */ 1328 UNSERIALIZE_SCALAR(regs.Config); 1329 UNSERIALIZE_SCALAR(regs.IntrStatus); 1330 UNSERIALIZE_SCALAR(regs.IntrMask); 1331 UNSERIALIZE_SCALAR(regs.RxMaxCopy); 1332 UNSERIALIZE_SCALAR(regs.TxMaxCopy); 1333 UNSERIALIZE_SCALAR(regs.RxMaxIntr); 1334 UNSERIALIZE_SCALAR(regs.RxData); 1335 UNSERIALIZE_SCALAR(regs.RxDone); 1336 UNSERIALIZE_SCALAR(regs.TxData); 1337 UNSERIALIZE_SCALAR(regs.TxDone); 1338 1339 int rxListSize; 1340 UNSERIALIZE_SCALAR(rxListSize); 1341 rxList.clear(); 1342 for (int i = 0; i < rxListSize; ++i) { 1343 int value; 1344 paramIn(cp, section, csprintf("rxList%d", i), value); 1345 rxList.push_back(value); 1346 } 1347 1348 int txListSize; 1349 UNSERIALIZE_SCALAR(txListSize); 1350 txList.clear(); 1351 for (int i = 0; i < txListSize; ++i) { 1352 int value; 1353 paramIn(cp, section, csprintf("txList%d", i), value); 1354 txList.push_back(value); 1355 } 1356 1357 /* 1358 * Unserialize rx state machine 1359 */ 1360 int rxState; 1361 UNSERIALIZE_SCALAR(rxState); 1362 UNSERIALIZE_SCALAR(rxEmpty); 1363 this->rxState = (RxState) rxState; 1364 rxFifo.unserialize("rxFifo", cp, section); 1365 1366 /* 1367 * Unserialize tx state machine 1368 */ 1369 int txState; 1370 UNSERIALIZE_SCALAR(txState); 1371 UNSERIALIZE_SCALAR(txFull); 1372 this->txState = (TxState) txState; 1373 txFifo.unserialize("txFifo", cp, section); 1374 bool txPacketExists; 1375 UNSERIALIZE_SCALAR(txPacketExists); 1376 txPacket = 0; 1377 if (txPacketExists) { 1378 txPacket = new EthPacketData(16384); 1379 txPacket->unserialize("txPacket", cp, section); 1380 UNSERIALIZE_SCALAR(txPacketOffset); 1381 UNSERIALIZE_SCALAR(txPacketBytes); 1382 } 1383 1384 /* 1385 * unserialize the virtual nic registers/state 1386 * 1387 * this must be done after the unserialization of the rxFifo 1388 * because the packet iterators depend on the fifo being populated 1389 */ 1390 int virtualRegsSize; 1391 UNSERIALIZE_SCALAR(virtualRegsSize); 1392 virtualRegs.clear(); 1393 virtualRegs.resize(virtualRegsSize); 1394 for (int i = 0; i < virtualRegsSize; ++i) { 1395 VirtualReg *vnic = &virtualRegs[i]; 1396 std::string reg = csprintf("vnic%d", i); 1397 1398 paramIn(cp, section, reg + ".RxData", vnic->RxData); 1399 paramIn(cp, section, reg + ".RxDone", vnic->RxDone); 1400 paramIn(cp, section, reg + ".TxData", vnic->TxData); 1401 paramIn(cp, section, reg + ".TxDone", vnic->TxDone); 1402 1403 bool rxPacketExists; 1404 paramIn(cp, section, reg + ".rxPacketExists", rxPacketExists); 1405 if (rxPacketExists) { 1406 int rxPacket; 1407 paramIn(cp, section, reg + ".rxPacket", rxPacket); 1408 vnic->rxPacket = rxFifo.begin(); 1409 while (rxPacket--) 1410 ++vnic->rxPacket; 1411 1412 paramIn(cp, section, reg + ".rxPacketOffset", 1413 vnic->rxPacketOffset); 1414 paramIn(cp, section, reg + ".rxPacketBytes", vnic->rxPacketBytes); 1415 } else { 1416 vnic->rxPacket = rxFifo.end(); 1417 } 1418 paramIn(cp, section, reg + ".rxDoneData", vnic->rxDoneData); 1419 } 1420 1421 /* 1422 * If there's a pending transmit, reschedule it now 1423 */ 1424 Tick transmitTick; 1425 UNSERIALIZE_SCALAR(transmitTick); 1426 if (transmitTick) 1427 txEvent.schedule(curTick + transmitTick); 1428 1429 pioPort->sendStatusChange(Port::RangeChange); 1430 1431} 1432 1433 1434BEGIN_DECLARE_SIM_OBJECT_PARAMS(Interface) 1435 1436 SimObjectParam<EtherInt *> peer; 1437 SimObjectParam<Device *> device; 1438 1439END_DECLARE_SIM_OBJECT_PARAMS(Interface) 1440 1441BEGIN_INIT_SIM_OBJECT_PARAMS(Interface) 1442 1443 INIT_PARAM_DFLT(peer, "peer interface", NULL), 1444 INIT_PARAM(device, "Ethernet device of this interface") 1445 1446END_INIT_SIM_OBJECT_PARAMS(Interface) 1447 1448CREATE_SIM_OBJECT(Interface) 1449{ 1450 Interface *dev_int = new Interface(getInstanceName(), device); 1451 1452 EtherInt *p = (EtherInt *)peer; 1453 if (p) { 1454 dev_int->setPeer(p); 1455 p->setPeer(dev_int); 1456 } 1457 1458 return dev_int; 1459} 1460 1461REGISTER_SIM_OBJECT("SinicInt", Interface) 1462 1463 1464BEGIN_DECLARE_SIM_OBJECT_PARAMS(Device) 1465 1466 1467 SimObjectParam<System *> system; 1468 SimObjectParam<Platform *> platform; 1469 SimObjectParam<PciConfigAll *> configspace; 1470 SimObjectParam<PciConfigData *> configdata; 1471 Param<uint32_t> pci_bus; 1472 Param<uint32_t> pci_dev; 1473 Param<uint32_t> pci_func; 1474 Param<Tick> pio_latency; 1475 Param<Tick> intr_delay; 1476 1477 Param<Tick> clock; 1478 Param<Tick> dma_read_delay; 1479 Param<Tick> dma_read_factor; 1480 Param<Tick> dma_write_delay; 1481 Param<Tick> dma_write_factor; 1482 1483 Param<Tick> rx_delay; 1484 Param<Tick> tx_delay; 1485 Param<uint32_t> rx_max_copy; 1486 Param<uint32_t> tx_max_copy; 1487 Param<uint32_t> rx_max_intr; 1488 Param<uint32_t> rx_fifo_size; 1489 Param<uint32_t> tx_fifo_size; 1490 Param<uint32_t> rx_fifo_threshold; 1491 Param<uint32_t> tx_fifo_threshold; 1492 1493 Param<bool> rx_filter; 1494 Param<std::string> hardware_address; 1495 Param<bool> rx_thread; 1496 Param<bool> tx_thread; 1497 Param<bool> rss; 1498 1499END_DECLARE_SIM_OBJECT_PARAMS(Device) 1500 1501BEGIN_INIT_SIM_OBJECT_PARAMS(Device) 1502 1503 1504 INIT_PARAM(system, "System pointer"), 1505 INIT_PARAM(platform, "Platform pointer"), 1506 INIT_PARAM(configspace, "PCI Configspace"), 1507 INIT_PARAM(configdata, "PCI Config data"), 1508 INIT_PARAM(pci_bus, "PCI bus ID"), 1509 INIT_PARAM(pci_dev, "PCI device number"), 1510 INIT_PARAM(pci_func, "PCI function code"), 1511 INIT_PARAM_DFLT(pio_latency, "Programmed IO latency in bus cycles", 1), 1512 INIT_PARAM(intr_delay, "Interrupt Delay"), 1513 INIT_PARAM(clock, "State machine cycle time"), 1514 1515 INIT_PARAM(dma_read_delay, "fixed delay for dma reads"), 1516 INIT_PARAM(dma_read_factor, "multiplier for dma reads"), 1517 INIT_PARAM(dma_write_delay, "fixed delay for dma writes"), 1518 INIT_PARAM(dma_write_factor, "multiplier for dma writes"), 1519 1520 INIT_PARAM(rx_delay, "Receive Delay"), 1521 INIT_PARAM(tx_delay, "Transmit Delay"), 1522 INIT_PARAM(rx_max_copy, "rx max copy"), 1523 INIT_PARAM(tx_max_copy, "rx max copy"), 1524 INIT_PARAM(rx_max_intr, "rx max intr"), 1525 INIT_PARAM(rx_fifo_size, "max size in bytes of rxFifo"), 1526 INIT_PARAM(tx_fifo_size, "max size in bytes of txFifo"), 1527 INIT_PARAM(rx_fifo_threshold, "max size in bytes of rxFifo"), 1528 INIT_PARAM(tx_fifo_threshold, "max size in bytes of txFifo"), 1529 1530 INIT_PARAM(rx_filter, "Enable Receive Filter"), 1531 INIT_PARAM(hardware_address, "Ethernet Hardware Address"), 1532 INIT_PARAM(rx_thread, ""), 1533 INIT_PARAM(tx_thread, ""), 1534 INIT_PARAM(rss, "") 1535 1536END_INIT_SIM_OBJECT_PARAMS(Device) 1537 1538 1539CREATE_SIM_OBJECT(Device) 1540{ 1541 Device::Params *params = new Device::Params; 1542 params->name = getInstanceName(); 1543 params->platform = platform; 1544 params->system = system; 1545 params->configSpace = configspace; 1546 params->configData = configdata; 1547 params->busNum = pci_bus; 1548 params->deviceNum = pci_dev; 1549 params->functionNum = pci_func; 1550 params->pio_delay = pio_latency; 1551 params->intr_delay = intr_delay; 1552 params->clock = clock; 1553 1554 params->dma_read_delay = dma_read_delay; 1555 params->dma_read_factor = dma_read_factor; 1556 params->dma_write_delay = dma_write_delay; 1557 params->dma_write_factor = dma_write_factor; 1558 1559 params->tx_delay = tx_delay; 1560 params->rx_delay = rx_delay; 1561 params->rx_max_copy = rx_max_copy; 1562 params->tx_max_copy = tx_max_copy; 1563 params->rx_max_intr = rx_max_intr; 1564 params->rx_fifo_size = rx_fifo_size; 1565 params->tx_fifo_size = tx_fifo_size; 1566 params->rx_fifo_threshold = rx_fifo_threshold; 1567 params->tx_fifo_threshold = tx_fifo_threshold; 1568 1569 params->rx_filter = rx_filter; 1570 params->eaddr = hardware_address; 1571 params->rx_thread = rx_thread; 1572 params->tx_thread = tx_thread; 1573 params->rss = rss; 1574 1575 return new Device(params); 1576} 1577 1578REGISTER_SIM_OBJECT("Sinic", Device) 1579 1580/* namespace Sinic */ } 1581