sinic.cc revision 2279
12SN/A/* 29448SAndreas.Sandberg@ARM.com * Copyright (c) 2004-2005 The Regents of The University of Michigan 39920Syasuko.eckert@amd.com * All rights reserved. 47338SAli.Saidi@ARM.com * 57338SAli.Saidi@ARM.com * Redistribution and use in source and binary forms, with or without 67338SAli.Saidi@ARM.com * modification, are permitted provided that the following conditions are 77338SAli.Saidi@ARM.com * met: redistributions of source code must retain the above copyright 87338SAli.Saidi@ARM.com * notice, this list of conditions and the following disclaimer; 97338SAli.Saidi@ARM.com * redistributions in binary form must reproduce the above copyright 107338SAli.Saidi@ARM.com * notice, this list of conditions and the following disclaimer in the 117338SAli.Saidi@ARM.com * documentation and/or other materials provided with the distribution; 127338SAli.Saidi@ARM.com * neither the name of the copyright holders nor the names of its 137338SAli.Saidi@ARM.com * contributors may be used to endorse or promote products derived from 147338SAli.Saidi@ARM.com * this software without specific prior written permission. 151762SN/A * 162SN/A * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 172SN/A * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 182SN/A * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR 192SN/A * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT 202SN/A * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 212SN/A * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT 222SN/A * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 232SN/A * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 242SN/A * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 252SN/A * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 262SN/A * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 272SN/A */ 282SN/A 292SN/A#include <cstdio> 302SN/A#include <deque> 312SN/A#include <string> 322SN/A 332SN/A#include "base/inet.hh" 342SN/A#include "cpu/exec_context.hh" 352SN/A#include "cpu/intr_control.hh" 362SN/A#include "dev/etherlink.hh" 372SN/A#include "dev/sinic.hh" 382SN/A#include "dev/pciconfigall.hh" 392SN/A#include "mem/bus/bus.hh" 402665Ssaidi@eecs.umich.edu#include "mem/bus/dma_interface.hh" 412665Ssaidi@eecs.umich.edu#include "mem/bus/pio_interface.hh" 422SN/A#include "mem/bus/pio_interface_impl.hh" 432SN/A#include "mem/functional/memory_control.hh" 448779Sgblack@eecs.umich.edu#include "mem/functional/physical.hh" 458779Sgblack@eecs.umich.edu#include "sim/builder.hh" 468779Sgblack@eecs.umich.edu#include "sim/debug.hh" 472439SN/A#include "sim/eventq.hh" 488779Sgblack@eecs.umich.edu#include "sim/host.hh" 498229Snate@binkert.org#include "sim/stats.hh" 506216Snate@binkert.org#include "arch/vtophys.hh" 51146SN/A 52146SN/Ausing namespace Net; 53146SN/Ausing namespace TheISA; 54146SN/A 55146SN/Anamespace Sinic { 566216Snate@binkert.org 576658Snate@binkert.orgconst char *RxStateStrings[] = 588229Snate@binkert.org{ 591717SN/A "rxIdle", 608887Sgeoffrey.blake@arm.com "rxFifoBlock", 618887Sgeoffrey.blake@arm.com "rxBeginCopy", 62146SN/A "rxCopy", 6310061Sandreas@sandberg.pp.se "rxCopyDone" 641977SN/A}; 652683Sktlim@umich.edu 661717SN/Aconst char *TxStateStrings[] = 67146SN/A{ 682683Sktlim@umich.edu "txIdle", 698232Snate@binkert.org "txFifoBlock", 708232Snate@binkert.org "txBeginCopy", 718232Snate@binkert.org "txCopy", 728779Sgblack@eecs.umich.edu "txCopyDone" 733348Sbinkertn@umich.edu}; 746105Ssteve.reinhardt@amd.com 756216Snate@binkert.org 762036SN/A/////////////////////////////////////////////////////////////////////// 77146SN/A// 788817Sgblack@eecs.umich.edu// Sinic PCI Device 798793Sgblack@eecs.umich.edu// 8056SN/ABase::Base(Params *p) 8156SN/A : PciDev(p), rxEnable(false), txEnable(false), clock(p->clock), 82695SN/A intrDelay(p->intr_delay), intrTick(0), cpuIntrEnable(false), 832901Ssaidi@eecs.umich.edu cpuPendingIntr(false), intrEvent(0), interface(NULL) 842SN/A{ 852SN/A} 862449SN/A 871355SN/ADevice::Device(Params *p) 885529Snate@binkert.org : Base(p), plat(p->plat), physmem(p->physmem), 8910061Sandreas@sandberg.pp.se rxFifo(p->rx_fifo_size), txFifo(p->tx_fifo_size), 9010061Sandreas@sandberg.pp.se rxKickTick(0), txKickTick(0), 9110537Sandreas.hansson@arm.com txEvent(this), rxDmaEvent(this), txDmaEvent(this), 9210537Sandreas.hansson@arm.com dmaReadDelay(p->dma_read_delay), dmaReadFactor(p->dma_read_factor), 93224SN/A dmaWriteDelay(p->dma_write_delay), dmaWriteFactor(p->dma_write_factor) 948793Sgblack@eecs.umich.edu{ 959384SAndreas.Sandberg@arm.com reset(); 969384SAndreas.Sandberg@arm.com 978793Sgblack@eecs.umich.edu if (p->pio_bus) { 988820Sgblack@eecs.umich.edu pioInterface = newPioInterface(p->name + ".pio", p->hier, p->pio_bus, 999384SAndreas.Sandberg@arm.com this, &Device::cacheAccess); 1002SN/A pioLatency = p->pio_latency * p->pio_bus->clockRate; 1016029Ssteve.reinhardt@amd.com } 1022672Sktlim@umich.edu 1032683Sktlim@umich.edu if (p->header_bus) { 1042SN/A if (p->payload_bus) 1058733Sgeoffrey.blake@arm.com dmaInterface = new DMAInterface<Bus>(p->name + ".dma", 1068733Sgeoffrey.blake@arm.com p->header_bus, 1078733Sgeoffrey.blake@arm.com p->payload_bus, 1, 1088733Sgeoffrey.blake@arm.com p->dma_no_allocate); 1098733Sgeoffrey.blake@arm.com else 1108733Sgeoffrey.blake@arm.com dmaInterface = new DMAInterface<Bus>(p->name + ".dma", 1118733Sgeoffrey.blake@arm.com p->header_bus, 1128733Sgeoffrey.blake@arm.com p->header_bus, 1, 1138733Sgeoffrey.blake@arm.com p->dma_no_allocate); 1148733Sgeoffrey.blake@arm.com } else if (p->payload_bus) 1158733Sgeoffrey.blake@arm.com panic("must define a header bus if defining a payload bus"); 1162SN/A} 117334SN/A 1188834Satgutier@umich.eduDevice::~Device() 1198834Satgutier@umich.edu{} 120140SN/A 121334SN/Avoid 1222SN/ADevice::regStats() 1232SN/A{ 1242SN/A rxBytes 1252680Sktlim@umich.edu .name(name() + ".rxBytes") 1264377Sgblack@eecs.umich.edu .desc("Bytes Received") 1275169Ssaidi@eecs.umich.edu .prereq(rxBytes) 1284377Sgblack@eecs.umich.edu ; 1294377Sgblack@eecs.umich.edu 1302SN/A rxBandwidth 1312SN/A .name(name() + ".rxBandwidth") 1322623SN/A .desc("Receive Bandwidth (bits/s)") 1332SN/A .precision(0) 1342SN/A .prereq(rxBytes) 1352SN/A ; 136180SN/A 1378737Skoansin.tan@gmail.com rxPackets 138393SN/A .name(name() + ".rxPackets") 139393SN/A .desc("Number of Packets Received") 140393SN/A .prereq(rxBytes) 141393SN/A ; 142384SN/A 143189SN/A rxPacketRate 144189SN/A .name(name() + ".rxPPS") 1452623SN/A .desc("Packet Reception Rate (packets/s)") 1462SN/A .precision(0) 147729SN/A .prereq(rxBytes) 148334SN/A ; 1492SN/A 1502SN/A rxIpPackets 1512SN/A .name(name() + ".rxIpPackets") 1528834Satgutier@umich.edu .desc("Number of IP Packets Received") 1538834Satgutier@umich.edu .prereq(rxBytes) 1548834Satgutier@umich.edu ; 1558834Satgutier@umich.edu 1568834Satgutier@umich.edu rxTcpPackets 1578834Satgutier@umich.edu .name(name() + ".rxTcpPackets") 1588834Satgutier@umich.edu .desc("Number of Packets Received") 1592SN/A .prereq(rxBytes) 1602SN/A ; 1617897Shestness@cs.utexas.edu 1627897Shestness@cs.utexas.edu rxUdpPackets 1637897Shestness@cs.utexas.edu .name(name() + ".rxUdpPackets") 1647897Shestness@cs.utexas.edu .desc("Number of UDP Packets Received") 1657897Shestness@cs.utexas.edu .prereq(rxBytes) 1667897Shestness@cs.utexas.edu ; 1677897Shestness@cs.utexas.edu 1687897Shestness@cs.utexas.edu rxIpChecksums 1697897Shestness@cs.utexas.edu .name(name() + ".rxIpChecksums") 1707897Shestness@cs.utexas.edu .desc("Number of rx IP Checksums done by device") 1717897Shestness@cs.utexas.edu .precision(0) 1727897Shestness@cs.utexas.edu .prereq(rxBytes) 1737897Shestness@cs.utexas.edu ; 1747897Shestness@cs.utexas.edu 1757897Shestness@cs.utexas.edu rxTcpChecksums 1767897Shestness@cs.utexas.edu .name(name() + ".rxTcpChecksums") 1777897Shestness@cs.utexas.edu .desc("Number of rx TCP Checksums done by device") 1787897Shestness@cs.utexas.edu .precision(0) 1797897Shestness@cs.utexas.edu .prereq(rxBytes) 1807897Shestness@cs.utexas.edu ; 1817897Shestness@cs.utexas.edu 1827897Shestness@cs.utexas.edu rxUdpChecksums 1837897Shestness@cs.utexas.edu .name(name() + ".rxUdpChecksums") 1847897Shestness@cs.utexas.edu .desc("Number of rx UDP Checksums done by device") 1857897Shestness@cs.utexas.edu .precision(0) 1867897Shestness@cs.utexas.edu .prereq(rxBytes) 1877897Shestness@cs.utexas.edu ; 1887897Shestness@cs.utexas.edu 1897897Shestness@cs.utexas.edu totBandwidth 1907897Shestness@cs.utexas.edu .name(name() + ".totBandwidth") 1917897Shestness@cs.utexas.edu .desc("Total Bandwidth (bits/s)") 1927897Shestness@cs.utexas.edu .precision(0) 1937897Shestness@cs.utexas.edu .prereq(totBytes) 1947897Shestness@cs.utexas.edu ; 1957897Shestness@cs.utexas.edu 1967897Shestness@cs.utexas.edu totPackets 1977897Shestness@cs.utexas.edu .name(name() + ".totPackets") 1987897Shestness@cs.utexas.edu .desc("Total Packets") 1997897Shestness@cs.utexas.edu .precision(0) 2007897Shestness@cs.utexas.edu .prereq(totBytes) 2017897Shestness@cs.utexas.edu ; 2027897Shestness@cs.utexas.edu 2037897Shestness@cs.utexas.edu totBytes 2047897Shestness@cs.utexas.edu .name(name() + ".totBytes") 2057897Shestness@cs.utexas.edu .desc("Total Bytes") 2067897Shestness@cs.utexas.edu .precision(0) 2077897Shestness@cs.utexas.edu .prereq(totBytes) 2087897Shestness@cs.utexas.edu ; 2097897Shestness@cs.utexas.edu 2107897Shestness@cs.utexas.edu totPacketRate 2119920Syasuko.eckert@amd.com .name(name() + ".totPPS") 2129920Syasuko.eckert@amd.com .desc("Total Tranmission Rate (packets/s)") 2139920Syasuko.eckert@amd.com .precision(0) 2149920Syasuko.eckert@amd.com .prereq(totBytes) 2159920Syasuko.eckert@amd.com ; 2169920Syasuko.eckert@amd.com 2179920Syasuko.eckert@amd.com txBytes 2189920Syasuko.eckert@amd.com .name(name() + ".txBytes") 2199920Syasuko.eckert@amd.com .desc("Bytes Transmitted") 2209920Syasuko.eckert@amd.com .prereq(txBytes) 2219920Syasuko.eckert@amd.com ; 2229920Syasuko.eckert@amd.com 2232SN/A txBandwidth 2247897Shestness@cs.utexas.edu .name(name() + ".txBandwidth") 2257897Shestness@cs.utexas.edu .desc("Transmit Bandwidth (bits/s)") 2267897Shestness@cs.utexas.edu .precision(0) 2277897Shestness@cs.utexas.edu .prereq(txBytes) 2287897Shestness@cs.utexas.edu ; 2297897Shestness@cs.utexas.edu 2307897Shestness@cs.utexas.edu txPackets 2317897Shestness@cs.utexas.edu .name(name() + ".txPackets") 2327897Shestness@cs.utexas.edu .desc("Number of Packets Transmitted") 2337897Shestness@cs.utexas.edu .prereq(txBytes) 2347897Shestness@cs.utexas.edu ; 2357897Shestness@cs.utexas.edu 2362SN/A txPacketRate 2372SN/A .name(name() + ".txPPS") 2381001SN/A .desc("Packet Tranmission Rate (packets/s)") 2391001SN/A .precision(0) 2401001SN/A .prereq(txBytes) 2411001SN/A ; 2421001SN/A 2432SN/A txIpPackets 2442SN/A .name(name() + ".txIpPackets") 2452SN/A .desc("Number of IP Packets Transmitted") 2462SN/A .prereq(txBytes) 2472SN/A ; 2487897Shestness@cs.utexas.edu 2497897Shestness@cs.utexas.edu txTcpPackets 2507897Shestness@cs.utexas.edu .name(name() + ".txTcpPackets") 2517897Shestness@cs.utexas.edu .desc("Number of TCP Packets Transmitted") 2527897Shestness@cs.utexas.edu .prereq(txBytes) 2537897Shestness@cs.utexas.edu ; 2547897Shestness@cs.utexas.edu 2557897Shestness@cs.utexas.edu txUdpPackets 2567897Shestness@cs.utexas.edu .name(name() + ".txUdpPackets") 2577897Shestness@cs.utexas.edu .desc("Number of Packets Transmitted") 2582SN/A .prereq(txBytes) 2592SN/A ; 2602SN/A 2612SN/A txIpChecksums 2622SN/A .name(name() + ".txIpChecksums") 2632SN/A .desc("Number of tx IP Checksums done by device") 2642SN/A .precision(0) 2652SN/A .prereq(txBytes) 2662SN/A ; 2672SN/A 2682SN/A txTcpChecksums 2692SN/A .name(name() + ".txTcpChecksums") 27010193SCurtis.Dunham@arm.com .desc("Number of tx TCP Checksums done by device") 27110193SCurtis.Dunham@arm.com .precision(0) 27210193SCurtis.Dunham@arm.com .prereq(txBytes) 27310193SCurtis.Dunham@arm.com ; 27410193SCurtis.Dunham@arm.com 27510193SCurtis.Dunham@arm.com txUdpChecksums 27610193SCurtis.Dunham@arm.com .name(name() + ".txUdpChecksums") 27710193SCurtis.Dunham@arm.com .desc("Number of tx UDP Checksums done by device") 27810193SCurtis.Dunham@arm.com .precision(0) 27910193SCurtis.Dunham@arm.com .prereq(txBytes) 280385SN/A ; 2817897Shestness@cs.utexas.edu 2827897Shestness@cs.utexas.edu txBandwidth = txBytes * Stats::constant(8) / simSeconds; 28310061Sandreas@sandberg.pp.se rxBandwidth = rxBytes * Stats::constant(8) / simSeconds; 28410061Sandreas@sandberg.pp.se totBandwidth = txBandwidth + rxBandwidth; 28510061Sandreas@sandberg.pp.se totBytes = txBytes + rxBytes; 28610061Sandreas@sandberg.pp.se totPackets = txPackets + rxPackets; 28710061Sandreas@sandberg.pp.se txPacketRate = txPackets / simSeconds; 28810061Sandreas@sandberg.pp.se rxPacketRate = rxPackets / simSeconds; 28910061Sandreas@sandberg.pp.se} 29010061Sandreas@sandberg.pp.se 29110061Sandreas@sandberg.pp.se/** 29210061Sandreas@sandberg.pp.se * This is to write to the PCI general configuration registers 29310061Sandreas@sandberg.pp.se */ 29410061Sandreas@sandberg.pp.sevoid 29510061Sandreas@sandberg.pp.seDevice::writeConfig(int offset, int size, const uint8_t *data) 29610061Sandreas@sandberg.pp.se{ 29710061Sandreas@sandberg.pp.se switch (offset) { 2982SN/A case PCI0_BASE_ADDR0: 2992SN/A // Need to catch writes to BARs to update the PIO interface 3002SN/A PciDev::writeConfig(offset, size, data); 3012623SN/A if (BARAddrs[0] != 0) { 302334SN/A if (pioInterface) 3032361SN/A pioInterface->addAddrRange(RangeSize(BARAddrs[0], BARSize[0])); 3045496Ssaidi@eecs.umich.edu 305334SN/A BARAddrs[0] &= EV5::PAddrUncachedMask; 306334SN/A } 307334SN/A break; 30810905Sandreas.sandberg@arm.com 3092SN/A default: 3109448SAndreas.Sandberg@ARM.com PciDev::writeConfig(offset, size, data); 3119448SAndreas.Sandberg@ARM.com } 3129448SAndreas.Sandberg@ARM.com} 31310905Sandreas.sandberg@arm.com 3142SN/Avoid 3152SN/ADevice::prepareIO(int cpu, int index) 3162SN/A{ 31710905Sandreas.sandberg@arm.com int size = virtualRegs.size(); 3182SN/A if (index < size) 3199448SAndreas.Sandberg@ARM.com return; 3209448SAndreas.Sandberg@ARM.com 32110905Sandreas.sandberg@arm.com virtualRegs.resize(index + 1); 3222SN/A for (int i = size; i <= index; ++i) 3232SN/A virtualRegs[i].rxPacket = rxFifo.end(); 3242SN/A} 3256221Snate@binkert.org 3262SN/Avoid 3272SN/ADevice::prepareRead(int cpu, int index) 3282SN/A{ 3292SN/A using namespace Regs; 3302623SN/A prepareIO(cpu, index); 3312SN/A 3322680Sktlim@umich.edu VirtualReg &vnic = virtualRegs[index]; 3332SN/A 3342SN/A // update rx registers 3352SN/A uint64_t rxdone = vnic.RxDone; 3365807Snate@binkert.org rxdone = set_RxDone_Packets(rxdone, rxFifo.packets()); 3372SN/A regs.RxData = vnic.RxData; 33810529Smorr@cs.wisc.edu regs.RxDone = rxdone; 33910529Smorr@cs.wisc.edu regs.RxWait = rxdone; 3405807Snate@binkert.org 3415807Snate@binkert.org // update tx regsiters 3422SN/A uint64_t txdone = vnic.TxDone; 3435807Snate@binkert.org txdone = set_TxDone_Packets(txdone, txFifo.packets()); 3445807Snate@binkert.org txdone = set_TxDone_Full(txdone, txFifo.avail() < regs.TxMaxCopy); 3452SN/A txdone = set_TxDone_Low(txdone, txFifo.size() < regs.TxFifoMark); 3462SN/A regs.TxData = vnic.TxData; 3472SN/A regs.TxDone = txdone; 3482623SN/A regs.TxWait = txdone; 3492SN/A} 3505704Snate@binkert.org 3515647Sgblack@eecs.umich.eduvoid 3522SN/ADevice::prepareWrite(int cpu, int index) 3533520Sgblack@eecs.umich.edu{ 3547338SAli.Saidi@ARM.com prepareIO(cpu, index); 3555647Sgblack@eecs.umich.edu} 3563520Sgblack@eecs.umich.edu 3579023Sgblack@eecs.umich.edu/** 3582SN/A * I/O read of device register 3592SN/A */ 3602623SN/AFault 3612SN/ADevice::read(MemReqPtr &req, uint8_t *data) 3622623SN/A{ 3635894Sgblack@eecs.umich.edu assert(config.command & PCI_CMD_MSE); 3642662Sstever@eecs.umich.edu Fault fault = readBar(req, data); 3652623SN/A 3667720Sgblack@eecs.umich.edu if (fault && fault->isMachineCheckFault()) { 3674495Sacolyte@umich.edu panic("address does not map to a BAR pa=%#x va=%#x size=%d", 3682623SN/A req->paddr, req->vaddr, req->size); 3697720Sgblack@eecs.umich.edu 3702623SN/A return genMachineCheckFault(); 3717720Sgblack@eecs.umich.edu } 3728832SAli.Saidi@ARM.com 3738832SAli.Saidi@ARM.com return fault; 3742623SN/A} 3752623SN/A 3762623SN/AFault 3772623SN/ADevice::readBar0(MemReqPtr &req, Addr daddr, uint8_t *data) 3782623SN/A{ 3792623SN/A int cpu = (req->xc->readMiscReg(TheISA::IPR_PALtemp16) >> 8) & 0xff; 3802SN/A Addr index = daddr >> Regs::VirtualShift; 3812683Sktlim@umich.edu Addr raddr = daddr & Regs::VirtualMask; 3822427SN/A 3832683Sktlim@umich.edu if (!regValid(raddr)) 3842427SN/A panic("invalid register: cpu=%d vnic=%d da=%#x pa=%#x va=%#x size=%d", 3852SN/A cpu, index, daddr, req->paddr, req->vaddr, req->size); 3862623SN/A 3872623SN/A const Regs::Info &info = regInfo(raddr); 3887897Shestness@cs.utexas.edu if (!info.read) 3892SN/A panic("read %s (write only): " 3902623SN/A "cpu=%d vnic=%d da=%#x pa=%#x va=%#x size=%d", 3912623SN/A info.name, cpu, index, daddr, req->paddr, req->vaddr, req->size); 3924377Sgblack@eecs.umich.edu 3937720Sgblack@eecs.umich.edu if (req->size != info.size) 3944377Sgblack@eecs.umich.edu panic("read %s (invalid size): " 3957720Sgblack@eecs.umich.edu "cpu=%d vnic=%d da=%#x pa=%#x va=%#x size=%d", 3965665Sgblack@eecs.umich.edu info.name, cpu, index, daddr, req->paddr, req->vaddr, req->size); 3977720Sgblack@eecs.umich.edu 3987720Sgblack@eecs.umich.edu prepareRead(cpu, index); 3995665Sgblack@eecs.umich.edu 4005665Sgblack@eecs.umich.edu uint64_t value = 0; 4014181Sgblack@eecs.umich.edu if (req->size == 4) { 4024181Sgblack@eecs.umich.edu uint32_t ® = *(uint32_t *)data; 4039023Sgblack@eecs.umich.edu reg = regData32(raddr); 4049023Sgblack@eecs.umich.edu value = reg; 4054181Sgblack@eecs.umich.edu } 4064182Sgblack@eecs.umich.edu 4077720Sgblack@eecs.umich.edu if (req->size == 8) { 4089023Sgblack@eecs.umich.edu uint64_t ® = *(uint64_t *)data; 4099023Sgblack@eecs.umich.edu reg = regData64(raddr); 4104593Sgblack@eecs.umich.edu value = reg; 4119023Sgblack@eecs.umich.edu } 4124377Sgblack@eecs.umich.edu 4139023Sgblack@eecs.umich.edu DPRINTF(EthernetPIO, 4144377Sgblack@eecs.umich.edu "read %s: cpu=%d vnic=%d da=%#x pa=%#x va=%#x size=%d val=%#x\n", 4159023Sgblack@eecs.umich.edu info.name, cpu, index, daddr, req->paddr, req->vaddr, req->size, 4169023Sgblack@eecs.umich.edu value); 4174377Sgblack@eecs.umich.edu 4187720Sgblack@eecs.umich.edu // reading the interrupt status register has the side effect of 4194377Sgblack@eecs.umich.edu // clearing it 4204377Sgblack@eecs.umich.edu if (raddr == Regs::IntrStatus) 4214377Sgblack@eecs.umich.edu devIntrClear(); 4224377Sgblack@eecs.umich.edu 4234181Sgblack@eecs.umich.edu return NoFault; 4244181Sgblack@eecs.umich.edu} 4254181Sgblack@eecs.umich.edu 4264539Sgblack@eecs.umich.edu/** 4273276Sgblack@eecs.umich.edu * IPR read of device register 4287720Sgblack@eecs.umich.edu */ 4293280Sgblack@eecs.umich.eduFault 4303280Sgblack@eecs.umich.eduDevice::iprRead(Addr daddr, int cpu, uint64_t &result) 4313276Sgblack@eecs.umich.edu{ 4323276Sgblack@eecs.umich.edu if (!regValid(daddr)) 4333276Sgblack@eecs.umich.edu panic("invalid address: da=%#x", daddr); 4347720Sgblack@eecs.umich.edu 4353276Sgblack@eecs.umich.edu const Regs::Info &info = regInfo(daddr); 4363276Sgblack@eecs.umich.edu if (!info.read) 4374181Sgblack@eecs.umich.edu panic("reading %s (write only): cpu=%d da=%#x", info.name, cpu, daddr); 4388955Sgblack@eecs.umich.edu 4394522Ssaidi@eecs.umich.edu DPRINTF(EthernetPIO, "IPR read %s: cpu=%d da=%#x\n", 4407823Ssteve.reinhardt@amd.com info.name, cpu, daddr); 4417720Sgblack@eecs.umich.edu 4422470SN/A prepareRead(cpu, 0); 4438955Sgblack@eecs.umich.edu 4444181Sgblack@eecs.umich.edu if (info.size == 4) 4454522Ssaidi@eecs.umich.edu result = regData32(daddr); 4464181Sgblack@eecs.umich.edu 44710061Sandreas@sandberg.pp.se if (info.size == 8) 44810061Sandreas@sandberg.pp.se result = regData64(daddr); 44910061Sandreas@sandberg.pp.se 45010061Sandreas@sandberg.pp.se DPRINTF(EthernetPIO, "IPR read %s: cpu=%s da=%#x val=%#x\n", 45110061Sandreas@sandberg.pp.se info.name, cpu, result); 45210061Sandreas@sandberg.pp.se 45310061Sandreas@sandberg.pp.se return NoFault; 45410061Sandreas@sandberg.pp.se} 45510061Sandreas@sandberg.pp.se 45610061Sandreas@sandberg.pp.se/** 45710061Sandreas@sandberg.pp.se * I/O write of device register 45810061Sandreas@sandberg.pp.se */ 45910061Sandreas@sandberg.pp.seFault 4602623SN/ADevice::write(MemReqPtr &req, const uint8_t *data) 4612623SN/A{ 4622623SN/A assert(config.command & PCI_CMD_MSE); 4632623SN/A Fault fault = writeBar(req, data); 4642623SN/A 4657720Sgblack@eecs.umich.edu if (fault && fault->isMachineCheckFault()) { 4667720Sgblack@eecs.umich.edu panic("address does not map to a BAR pa=%#x va=%#x size=%d", 4677720Sgblack@eecs.umich.edu req->paddr, req->vaddr, req->size); 4687720Sgblack@eecs.umich.edu 4698780Sgblack@eecs.umich.edu return genMachineCheckFault(); 4703577Sgblack@eecs.umich.edu } 4717720Sgblack@eecs.umich.edu 4725086Sgblack@eecs.umich.edu return fault; 4732623SN/A} 4742683Sktlim@umich.edu 4752623SN/AFault 4762SN/ADevice::writeBar0(MemReqPtr &req, Addr daddr, const uint8_t *data) 4772623SN/A{ 4782623SN/A int cpu = (req->xc->readMiscReg(TheISA::IPR_PALtemp16) >> 8) & 0xff; 4792SN/A Addr index = daddr >> Regs::VirtualShift; 4802SN/A Addr raddr = daddr & Regs::VirtualMask; 4812623SN/A 4822623SN/A if (!regValid(raddr)) 4832623SN/A panic("invalid address: cpu=%d da=%#x pa=%#x va=%#x size=%d", 4842623SN/A cpu, daddr, req->paddr, req->vaddr, req->size); 4852SN/A 4865953Ssaidi@eecs.umich.edu const Regs::Info &info = regInfo(raddr); 4877720Sgblack@eecs.umich.edu if (!info.write) 4885953Ssaidi@eecs.umich.edu panic("write %s (read only): " 4895953Ssaidi@eecs.umich.edu "cpu=%d vnic=%d da=%#x pa=%#x va=%#x size=%d", 49010061Sandreas@sandberg.pp.se info.name, cpu, index, daddr, req->paddr, req->vaddr, req->size); 49110061Sandreas@sandberg.pp.se 49210061Sandreas@sandberg.pp.se if (req->size != info.size) 49310061Sandreas@sandberg.pp.se panic("write %s (invalid size): " 4947897Shestness@cs.utexas.edu "cpu=%d vnic=%d da=%#x pa=%#x va=%#x size=%d", 4957897Shestness@cs.utexas.edu info.name, cpu, index, daddr, req->paddr, req->vaddr, req->size); 4967897Shestness@cs.utexas.edu 4977897Shestness@cs.utexas.edu uint32_t reg32 = *(uint32_t *)data; 4987897Shestness@cs.utexas.edu uint64_t reg64 = *(uint64_t *)data; 4997897Shestness@cs.utexas.edu VirtualReg &vnic = virtualRegs[index]; 5007897Shestness@cs.utexas.edu 5017897Shestness@cs.utexas.edu DPRINTF(EthernetPIO, 5027897Shestness@cs.utexas.edu "write %s vnic %d: cpu=%d val=%#x da=%#x pa=%#x va=%#x size=%d\n", 5037897Shestness@cs.utexas.edu info.name, index, cpu, info.size == 4 ? reg32 : reg64, daddr, 5047897Shestness@cs.utexas.edu req->paddr, req->vaddr, req->size); 5057897Shestness@cs.utexas.edu 5067897Shestness@cs.utexas.edu prepareWrite(cpu, index); 5077897Shestness@cs.utexas.edu 5087897Shestness@cs.utexas.edu switch (raddr) { 5097897Shestness@cs.utexas.edu case Regs::Config: 5107897Shestness@cs.utexas.edu changeConfig(reg32); 5117897Shestness@cs.utexas.edu break; 5127897Shestness@cs.utexas.edu 5137897Shestness@cs.utexas.edu case Regs::Command: 5147897Shestness@cs.utexas.edu command(reg32); 5157897Shestness@cs.utexas.edu break; 5167897Shestness@cs.utexas.edu 5177897Shestness@cs.utexas.edu case Regs::IntrStatus: 5187897Shestness@cs.utexas.edu devIntrClear(regs.IntrStatus & reg32); 5197897Shestness@cs.utexas.edu break; 5207897Shestness@cs.utexas.edu 5217897Shestness@cs.utexas.edu case Regs::IntrMask: 5227897Shestness@cs.utexas.edu devIntrChangeMask(reg32); 5237897Shestness@cs.utexas.edu break; 5247897Shestness@cs.utexas.edu 5257897Shestness@cs.utexas.edu case Regs::RxData: 5267897Shestness@cs.utexas.edu if (Regs::get_RxDone_Busy(vnic.RxDone)) 52710193SCurtis.Dunham@arm.com panic("receive machine busy with another request! rxState=%s", 52810193SCurtis.Dunham@arm.com RxStateStrings[rxState]); 5298780Sgblack@eecs.umich.edu 5308780Sgblack@eecs.umich.edu vnic.RxDone = Regs::RxDone_Busy; 5312644Sstever@eecs.umich.edu vnic.RxData = reg64; 5322644Sstever@eecs.umich.edu rxList.push_back(index); 5334046Sbinkertn@umich.edu if (rxEnable && rxState == rxIdle) { 5344046Sbinkertn@umich.edu rxState = rxFifoBlock; 5354046Sbinkertn@umich.edu rxKick(); 5362644Sstever@eecs.umich.edu } 53710464SAndreas.Sandberg@ARM.com break; 53810464SAndreas.Sandberg@ARM.com 53910464SAndreas.Sandberg@ARM.com case Regs::TxData: 5402623SN/A if (Regs::get_TxDone_Busy(vnic.TxDone)) 5412SN/A panic("transmit machine busy with another request! txState=%s", 5422623SN/A TxStateStrings[txState]); 54310379Sandreas.hansson@arm.com 5442623SN/A vnic.TxDone = Regs::TxDone_Busy; 54510061Sandreas@sandberg.pp.se vnic.TxData = reg64; 54610061Sandreas@sandberg.pp.se if (txList.empty() || txList.front() != index) 5474377Sgblack@eecs.umich.edu txList.push_back(index); 5484377Sgblack@eecs.umich.edu if (txEnable && txState == txIdle && txList.front() == index) { 5492090SN/A txState = txFifoBlock; 5503905Ssaidi@eecs.umich.edu txKick(); 5517678Sgblack@eecs.umich.edu } 5529023Sgblack@eecs.umich.edu break; 5534377Sgblack@eecs.umich.edu } 5547720Sgblack@eecs.umich.edu 5557720Sgblack@eecs.umich.edu return NoFault; 5567720Sgblack@eecs.umich.edu} 5577720Sgblack@eecs.umich.edu 5587720Sgblack@eecs.umich.eduvoid 5597720Sgblack@eecs.umich.eduDevice::devIntrPost(uint32_t interrupts) 5603276Sgblack@eecs.umich.edu{ 5612SN/A if ((interrupts & Regs::Intr_Res)) 56210061Sandreas@sandberg.pp.se panic("Cannot set a reserved interrupt"); 56310061Sandreas@sandberg.pp.se 56410061Sandreas@sandberg.pp.se regs.IntrStatus |= interrupts; 56510061Sandreas@sandberg.pp.se 56610061Sandreas@sandberg.pp.se DPRINTF(EthernetIntr, 56710061Sandreas@sandberg.pp.se "interrupt written to intStatus: intr=%#x status=%#x mask=%#x\n", 56810061Sandreas@sandberg.pp.se interrupts, regs.IntrStatus, regs.IntrMask); 56910061Sandreas@sandberg.pp.se 57010061Sandreas@sandberg.pp.se interrupts = regs.IntrStatus & regs.IntrMask; 57110061Sandreas@sandberg.pp.se 57210061Sandreas@sandberg.pp.se // Intr_RxHigh is special, we only signal it if we've emptied the fifo 57310061Sandreas@sandberg.pp.se // and then filled it above the high watermark 57410061Sandreas@sandberg.pp.se if (rxEmpty) 57510061Sandreas@sandberg.pp.se rxEmpty = false; 57610061Sandreas@sandberg.pp.se else 57710061Sandreas@sandberg.pp.se interrupts &= ~Regs::Intr_RxHigh; 57810061Sandreas@sandberg.pp.se 5792SN/A // Intr_TxLow is special, we only signal it if we've filled up the fifo 5802SN/A // and then dropped below the low watermark 5819461Snilay@cs.wisc.edu if (txFull) 5829461Snilay@cs.wisc.edu txFull = false; 5839461Snilay@cs.wisc.edu else 5849461Snilay@cs.wisc.edu interrupts &= ~Regs::Intr_TxLow; 5859461Snilay@cs.wisc.edu 5869461Snilay@cs.wisc.edu if (interrupts) { 587 Tick when = curTick; 588 if ((interrupts & Regs::Intr_NoDelay) == 0) 589 when += intrDelay; 590 cpuIntrPost(when); 591 } 592} 593 594void 595Device::devIntrClear(uint32_t interrupts) 596{ 597 if ((interrupts & Regs::Intr_Res)) 598 panic("Cannot clear a reserved interrupt"); 599 600 regs.IntrStatus &= ~interrupts; 601 602 DPRINTF(EthernetIntr, 603 "interrupt cleared from intStatus: intr=%x status=%x mask=%x\n", 604 interrupts, regs.IntrStatus, regs.IntrMask); 605 606 if (!(regs.IntrStatus & regs.IntrMask)) 607 cpuIntrClear(); 608} 609 610void 611Device::devIntrChangeMask(uint32_t newmask) 612{ 613 if (regs.IntrMask == newmask) 614 return; 615 616 regs.IntrMask = newmask; 617 618 DPRINTF(EthernetIntr, 619 "interrupt mask changed: intStatus=%x intMask=%x masked=%x\n", 620 regs.IntrStatus, regs.IntrMask, regs.IntrStatus & regs.IntrMask); 621 622 if (regs.IntrStatus & regs.IntrMask) 623 cpuIntrPost(curTick); 624 else 625 cpuIntrClear(); 626} 627 628void 629Base::cpuIntrPost(Tick when) 630{ 631 // If the interrupt you want to post is later than an interrupt 632 // already scheduled, just let it post in the coming one and don't 633 // schedule another. 634 // HOWEVER, must be sure that the scheduled intrTick is in the 635 // future (this was formerly the source of a bug) 636 /** 637 * @todo this warning should be removed and the intrTick code should 638 * be fixed. 639 */ 640 assert(when >= curTick); 641 assert(intrTick >= curTick || intrTick == 0); 642 if (!cpuIntrEnable) { 643 DPRINTF(EthernetIntr, "interrupts not enabled.\n", 644 intrTick); 645 return; 646 } 647 648 if (when > intrTick && intrTick != 0) { 649 DPRINTF(EthernetIntr, "don't need to schedule event...intrTick=%d\n", 650 intrTick); 651 return; 652 } 653 654 intrTick = when; 655 if (intrTick < curTick) { 656 debug_break(); 657 intrTick = curTick; 658 } 659 660 DPRINTF(EthernetIntr, "going to schedule an interrupt for intrTick=%d\n", 661 intrTick); 662 663 if (intrEvent) 664 intrEvent->squash(); 665 intrEvent = new IntrEvent(this, true); 666 intrEvent->schedule(intrTick); 667} 668 669void 670Base::cpuInterrupt() 671{ 672 assert(intrTick == curTick); 673 674 // Whether or not there's a pending interrupt, we don't care about 675 // it anymore 676 intrEvent = 0; 677 intrTick = 0; 678 679 // Don't send an interrupt if there's already one 680 if (cpuPendingIntr) { 681 DPRINTF(EthernetIntr, 682 "would send an interrupt now, but there's already pending\n"); 683 } else { 684 // Send interrupt 685 cpuPendingIntr = true; 686 687 DPRINTF(EthernetIntr, "posting interrupt\n"); 688 intrPost(); 689 } 690} 691 692void 693Base::cpuIntrClear() 694{ 695 if (!cpuPendingIntr) 696 return; 697 698 if (intrEvent) { 699 intrEvent->squash(); 700 intrEvent = 0; 701 } 702 703 intrTick = 0; 704 705 cpuPendingIntr = false; 706 707 DPRINTF(EthernetIntr, "clearing cchip interrupt\n"); 708 intrClear(); 709} 710 711bool 712Base::cpuIntrPending() const 713{ return cpuPendingIntr; } 714 715void 716Device::changeConfig(uint32_t newconf) 717{ 718 uint32_t changed = regs.Config ^ newconf; 719 if (!changed) 720 return; 721 722 regs.Config = newconf; 723 724 if ((changed & Regs::Config_IntEn)) { 725 cpuIntrEnable = regs.Config & Regs::Config_IntEn; 726 if (cpuIntrEnable) { 727 if (regs.IntrStatus & regs.IntrMask) 728 cpuIntrPost(curTick); 729 } else { 730 cpuIntrClear(); 731 } 732 } 733 734 if ((changed & Regs::Config_TxEn)) { 735 txEnable = regs.Config & Regs::Config_TxEn; 736 if (txEnable) 737 txKick(); 738 } 739 740 if ((changed & Regs::Config_RxEn)) { 741 rxEnable = regs.Config & Regs::Config_RxEn; 742 if (rxEnable) 743 rxKick(); 744 } 745} 746 747void 748Device::command(uint32_t command) 749{ 750 if (command & Regs::Command_Intr) 751 devIntrPost(Regs::Intr_Soft); 752 753 if (command & Regs::Command_Reset) 754 reset(); 755} 756 757void 758Device::reset() 759{ 760 using namespace Regs; 761 762 memset(®s, 0, sizeof(regs)); 763 764 regs.Config = 0; 765 if (params()->rx_thread) 766 regs.Config |= Config_RxThread; 767 if (params()->tx_thread) 768 regs.Config |= Config_TxThread; 769 if (params()->rss) 770 regs.Config |= Config_RSS; 771 regs.IntrMask = Intr_Soft | Intr_RxHigh | Intr_RxPacket | Intr_TxLow; 772 regs.RxMaxCopy = params()->rx_max_copy; 773 regs.TxMaxCopy = params()->tx_max_copy; 774 regs.RxMaxIntr = params()->rx_max_intr; 775 regs.RxFifoSize = params()->rx_fifo_size; 776 regs.TxFifoSize = params()->tx_fifo_size; 777 regs.RxFifoMark = params()->rx_fifo_threshold; 778 regs.TxFifoMark = params()->tx_fifo_threshold; 779 regs.HwAddr = params()->eaddr; 780 781 rxList.clear(); 782 txList.clear(); 783 784 rxState = rxIdle; 785 txState = txIdle; 786 787 rxFifo.clear(); 788 rxFifoPtr = rxFifo.end(); 789 txFifo.clear(); 790 rxEmpty = false; 791 txFull = false; 792 793 int size = virtualRegs.size(); 794 virtualRegs.clear(); 795 virtualRegs.resize(size); 796 for (int i = 0; i < size; ++i) 797 virtualRegs[i].rxPacket = rxFifo.end(); 798} 799 800void 801Device::rxDmaCopy() 802{ 803 assert(rxState == rxCopy); 804 rxState = rxCopyDone; 805 physmem->dma_write(rxDmaAddr, (uint8_t *)rxDmaData, rxDmaLen); 806 DPRINTF(EthernetDMA, "rx dma write paddr=%#x len=%d\n", 807 rxDmaAddr, rxDmaLen); 808 DDUMP(EthernetData, rxDmaData, rxDmaLen); 809} 810 811void 812Device::rxDmaDone() 813{ 814 rxDmaCopy(); 815 816 // If the transmit state machine has a pending DMA, let it go first 817 if (txState == txBeginCopy) 818 txKick(); 819 820 rxKick(); 821} 822 823void 824Device::rxKick() 825{ 826 VirtualReg *vnic; 827 828 DPRINTF(EthernetSM, "rxKick: rxState=%s (rxFifo.size=%d)\n", 829 RxStateStrings[rxState], rxFifo.size()); 830 831 if (rxKickTick > curTick) { 832 DPRINTF(EthernetSM, "rxKick: exiting, can't run till %d\n", 833 rxKickTick); 834 return; 835 } 836 837 next: 838 if (rxState == rxIdle) 839 goto exit; 840 841 assert(!rxList.empty()); 842 vnic = &virtualRegs[rxList.front()]; 843 844 DPRINTF(EthernetSM, "processing rxState=%s for virtual nic %d\n", 845 RxStateStrings[rxState], rxList.front()); 846 847 switch (rxState) { 848 case rxFifoBlock: 849 if (vnic->rxPacket != rxFifo.end()) { 850 rxState = rxBeginCopy; 851 break; 852 } 853 854 if (rxFifoPtr == rxFifo.end()) { 855 DPRINTF(EthernetSM, "receive waiting for data. Nothing to do.\n"); 856 goto exit; 857 } 858 859 assert(!rxFifo.empty()); 860 861 // Grab a new packet from the fifo. 862 vnic->rxPacket = rxFifoPtr++; 863 vnic->rxPacketOffset = 0; 864 vnic->rxPacketBytes = (*vnic->rxPacket)->length; 865 assert(vnic->rxPacketBytes); 866 867 vnic->rxDoneData = 0; 868 /* scope for variables */ { 869 IpPtr ip(*vnic->rxPacket); 870 if (ip) { 871 vnic->rxDoneData |= Regs::RxDone_IpPacket; 872 rxIpChecksums++; 873 if (cksum(ip) != 0) { 874 DPRINTF(EthernetCksum, "Rx IP Checksum Error\n"); 875 vnic->rxDoneData |= Regs::RxDone_IpError; 876 } 877 TcpPtr tcp(ip); 878 UdpPtr udp(ip); 879 if (tcp) { 880 DPRINTF(Ethernet, 881 "Src Port=%d, Dest Port=%d, Seq=%d, Ack=%d\n", 882 tcp->sport(), tcp->dport(), tcp->seq(), 883 tcp->ack()); 884 vnic->rxDoneData |= Regs::RxDone_TcpPacket; 885 rxTcpChecksums++; 886 if (cksum(tcp) != 0) { 887 DPRINTF(EthernetCksum, "Rx TCP Checksum Error\n"); 888 vnic->rxDoneData |= Regs::RxDone_TcpError; 889 } 890 } else if (udp) { 891 vnic->rxDoneData |= Regs::RxDone_UdpPacket; 892 rxUdpChecksums++; 893 if (cksum(udp) != 0) { 894 DPRINTF(EthernetCksum, "Rx UDP Checksum Error\n"); 895 vnic->rxDoneData |= Regs::RxDone_UdpError; 896 } 897 } 898 } 899 } 900 rxState = rxBeginCopy; 901 break; 902 903 case rxBeginCopy: 904 if (dmaInterface && dmaInterface->busy()) 905 goto exit; 906 907 rxDmaAddr = plat->pciToDma(Regs::get_RxData_Addr(vnic->RxData)); 908 rxDmaLen = min<int>(Regs::get_RxData_Len(vnic->RxData), 909 vnic->rxPacketBytes); 910 rxDmaData = (*vnic->rxPacket)->data + vnic->rxPacketOffset; 911 rxState = rxCopy; 912 913 if (dmaInterface) { 914 dmaInterface->doDMA(WriteInvalidate, rxDmaAddr, rxDmaLen, 915 curTick, &rxDmaEvent, true); 916 goto exit; 917 } 918 919 if (dmaWriteDelay != 0 || dmaWriteFactor != 0) { 920 Tick factor = ((rxDmaLen + ULL(63)) >> ULL(6)) * dmaWriteFactor; 921 Tick start = curTick + dmaWriteDelay + factor; 922 rxDmaEvent.schedule(start); 923 goto exit; 924 } 925 926 rxDmaCopy(); 927 break; 928 929 case rxCopy: 930 DPRINTF(EthernetSM, "receive machine still copying\n"); 931 goto exit; 932 933 case rxCopyDone: 934 vnic->RxDone = vnic->rxDoneData | rxDmaLen; 935 vnic->RxDone |= Regs::RxDone_Complete; 936 937 if (vnic->rxPacketBytes == rxDmaLen) { 938 DPRINTF(EthernetSM, "rxKick: packet complete on vnic %d\n", 939 rxList.front()); 940 rxFifo.remove(vnic->rxPacket); 941 vnic->rxPacket = rxFifo.end(); 942 } else { 943 vnic->RxDone |= Regs::RxDone_More; 944 vnic->rxPacketBytes -= rxDmaLen; 945 vnic->rxPacketOffset += rxDmaLen; 946 DPRINTF(EthernetSM, 947 "rxKick: packet not complete on vnic %d: %d bytes left\n", 948 rxList.front(), vnic->rxPacketBytes); 949 } 950 951 rxList.pop_front(); 952 rxState = rxList.empty() ? rxIdle : rxFifoBlock; 953 954 if (rxFifo.empty()) { 955 devIntrPost(Regs::Intr_RxEmpty); 956 rxEmpty = true; 957 } 958 959 devIntrPost(Regs::Intr_RxDMA); 960 break; 961 962 default: 963 panic("Invalid rxState!"); 964 } 965 966 DPRINTF(EthernetSM, "entering next rxState=%s\n", 967 RxStateStrings[rxState]); 968 969 goto next; 970 971 exit: 972 /** 973 * @todo do we want to schedule a future kick? 974 */ 975 DPRINTF(EthernetSM, "rx state machine exited rxState=%s\n", 976 RxStateStrings[rxState]); 977} 978 979void 980Device::txDmaCopy() 981{ 982 assert(txState == txCopy); 983 txState = txCopyDone; 984 physmem->dma_read((uint8_t *)txDmaData, txDmaAddr, txDmaLen); 985 DPRINTF(EthernetDMA, "tx dma read paddr=%#x len=%d\n", 986 txDmaAddr, txDmaLen); 987 DDUMP(EthernetData, txDmaData, txDmaLen); 988} 989 990void 991Device::txDmaDone() 992{ 993 txDmaCopy(); 994 995 // If the receive state machine has a pending DMA, let it go first 996 if (rxState == rxBeginCopy) 997 rxKick(); 998 999 txKick(); 1000} 1001 1002void 1003Device::transmit() 1004{ 1005 if (txFifo.empty()) { 1006 DPRINTF(Ethernet, "nothing to transmit\n"); 1007 return; 1008 } 1009 1010 uint32_t interrupts; 1011 PacketPtr packet = txFifo.front(); 1012 if (!interface->sendPacket(packet)) { 1013 DPRINTF(Ethernet, "Packet Transmit: failed txFifo available %d\n", 1014 txFifo.avail()); 1015 goto reschedule; 1016 } 1017 1018 txFifo.pop(); 1019#if TRACING_ON 1020 if (DTRACE(Ethernet)) { 1021 IpPtr ip(packet); 1022 if (ip) { 1023 DPRINTF(Ethernet, "ID is %d\n", ip->id()); 1024 TcpPtr tcp(ip); 1025 if (tcp) { 1026 DPRINTF(Ethernet, "Src Port=%d, Dest Port=%d\n", 1027 tcp->sport(), tcp->dport()); 1028 } 1029 } 1030 } 1031#endif 1032 1033 DDUMP(EthernetData, packet->data, packet->length); 1034 txBytes += packet->length; 1035 txPackets++; 1036 1037 DPRINTF(Ethernet, "Packet Transmit: successful txFifo Available %d\n", 1038 txFifo.avail()); 1039 1040 interrupts = Regs::Intr_TxPacket; 1041 if (txFifo.size() < regs.TxFifoMark) 1042 interrupts |= Regs::Intr_TxLow; 1043 devIntrPost(interrupts); 1044 1045 reschedule: 1046 if (!txFifo.empty() && !txEvent.scheduled()) { 1047 DPRINTF(Ethernet, "reschedule transmit\n"); 1048 txEvent.schedule(curTick + retryTime); 1049 } 1050} 1051 1052void 1053Device::txKick() 1054{ 1055 VirtualReg *vnic; 1056 DPRINTF(EthernetSM, "txKick: txState=%s (txFifo.size=%d)\n", 1057 TxStateStrings[txState], txFifo.size()); 1058 1059 if (txKickTick > curTick) { 1060 DPRINTF(EthernetSM, "txKick: exiting, can't run till %d\n", 1061 txKickTick); 1062 return; 1063 } 1064 1065 next: 1066 if (txState == txIdle) 1067 goto exit; 1068 1069 assert(!txList.empty()); 1070 vnic = &virtualRegs[txList.front()]; 1071 1072 switch (txState) { 1073 case txFifoBlock: 1074 assert(Regs::get_TxDone_Busy(vnic->TxData)); 1075 if (!txPacket) { 1076 // Grab a new packet from the fifo. 1077 txPacket = new PacketData(16384); 1078 txPacketOffset = 0; 1079 } 1080 1081 if (txFifo.avail() - txPacket->length < 1082 Regs::get_TxData_Len(vnic->TxData)) { 1083 DPRINTF(EthernetSM, "transmit fifo full. Nothing to do.\n"); 1084 goto exit; 1085 } 1086 1087 txState = txBeginCopy; 1088 break; 1089 1090 case txBeginCopy: 1091 if (dmaInterface && dmaInterface->busy()) 1092 goto exit; 1093 1094 txDmaAddr = plat->pciToDma(Regs::get_TxData_Addr(vnic->TxData)); 1095 txDmaLen = Regs::get_TxData_Len(vnic->TxData); 1096 txDmaData = txPacket->data + txPacketOffset; 1097 txState = txCopy; 1098 1099 if (dmaInterface) { 1100 dmaInterface->doDMA(Read, txDmaAddr, txDmaLen, 1101 curTick, &txDmaEvent, true); 1102 goto exit; 1103 } 1104 1105 if (dmaReadDelay != 0 || dmaReadFactor != 0) { 1106 Tick factor = ((txDmaLen + ULL(63)) >> ULL(6)) * dmaReadFactor; 1107 Tick start = curTick + dmaReadDelay + factor; 1108 txDmaEvent.schedule(start); 1109 goto exit; 1110 } 1111 1112 txDmaCopy(); 1113 break; 1114 1115 case txCopy: 1116 DPRINTF(EthernetSM, "transmit machine still copying\n"); 1117 goto exit; 1118 1119 case txCopyDone: 1120 vnic->TxDone = txDmaLen | Regs::TxDone_Complete; 1121 txPacket->length += txDmaLen; 1122 if ((vnic->TxData & Regs::TxData_More)) { 1123 txPacketOffset += txDmaLen; 1124 txState = txIdle; 1125 devIntrPost(Regs::Intr_TxDMA); 1126 break; 1127 } 1128 1129 assert(txPacket->length <= txFifo.avail()); 1130 if ((vnic->TxData & Regs::TxData_Checksum)) { 1131 IpPtr ip(txPacket); 1132 if (ip) { 1133 TcpPtr tcp(ip); 1134 if (tcp) { 1135 tcp->sum(0); 1136 tcp->sum(cksum(tcp)); 1137 txTcpChecksums++; 1138 } 1139 1140 UdpPtr udp(ip); 1141 if (udp) { 1142 udp->sum(0); 1143 udp->sum(cksum(udp)); 1144 txUdpChecksums++; 1145 } 1146 1147 ip->sum(0); 1148 ip->sum(cksum(ip)); 1149 txIpChecksums++; 1150 } 1151 } 1152 1153 txFifo.push(txPacket); 1154 if (txFifo.avail() < regs.TxMaxCopy) { 1155 devIntrPost(Regs::Intr_TxFull); 1156 txFull = true; 1157 } 1158 txPacket = 0; 1159 transmit(); 1160 txList.pop_front(); 1161 txState = txList.empty() ? txIdle : txFifoBlock; 1162 devIntrPost(Regs::Intr_TxDMA); 1163 break; 1164 1165 default: 1166 panic("Invalid txState!"); 1167 } 1168 1169 DPRINTF(EthernetSM, "entering next txState=%s\n", 1170 TxStateStrings[txState]); 1171 1172 goto next; 1173 1174 exit: 1175 /** 1176 * @todo do we want to schedule a future kick? 1177 */ 1178 DPRINTF(EthernetSM, "tx state machine exited txState=%s\n", 1179 TxStateStrings[txState]); 1180} 1181 1182void 1183Device::transferDone() 1184{ 1185 if (txFifo.empty()) { 1186 DPRINTF(Ethernet, "transfer complete: txFifo empty...nothing to do\n"); 1187 return; 1188 } 1189 1190 DPRINTF(Ethernet, "transfer complete: data in txFifo...schedule xmit\n"); 1191 1192 if (txEvent.scheduled()) 1193 txEvent.reschedule(curTick + cycles(1)); 1194 else 1195 txEvent.schedule(curTick + cycles(1)); 1196} 1197 1198bool 1199Device::rxFilter(const PacketPtr &packet) 1200{ 1201 if (!Regs::get_Config_Filter(regs.Config)) 1202 return false; 1203 1204 panic("receive filter not implemented\n"); 1205 bool drop = true; 1206 1207#if 0 1208 string type; 1209 1210 EthHdr *eth = packet->eth(); 1211 if (eth->unicast()) { 1212 // If we're accepting all unicast addresses 1213 if (acceptUnicast) 1214 drop = false; 1215 1216 // If we make a perfect match 1217 if (acceptPerfect && params->eaddr == eth.dst()) 1218 drop = false; 1219 1220 if (acceptArp && eth->type() == ETH_TYPE_ARP) 1221 drop = false; 1222 1223 } else if (eth->broadcast()) { 1224 // if we're accepting broadcasts 1225 if (acceptBroadcast) 1226 drop = false; 1227 1228 } else if (eth->multicast()) { 1229 // if we're accepting all multicasts 1230 if (acceptMulticast) 1231 drop = false; 1232 1233 } 1234 1235 if (drop) { 1236 DPRINTF(Ethernet, "rxFilter drop\n"); 1237 DDUMP(EthernetData, packet->data, packet->length); 1238 } 1239#endif 1240 return drop; 1241} 1242 1243bool 1244Device::recvPacket(PacketPtr packet) 1245{ 1246 rxBytes += packet->length; 1247 rxPackets++; 1248 1249 DPRINTF(Ethernet, "Receiving packet from wire, rxFifo Available is %d\n", 1250 rxFifo.avail()); 1251 1252 if (!rxEnable) { 1253 DPRINTF(Ethernet, "receive disabled...packet dropped\n"); 1254 return true; 1255 } 1256 1257 if (rxFilter(packet)) { 1258 DPRINTF(Ethernet, "packet filtered...dropped\n"); 1259 return true; 1260 } 1261 1262 if (rxFifo.size() >= regs.RxFifoMark) 1263 devIntrPost(Regs::Intr_RxHigh); 1264 1265 if (!rxFifo.push(packet)) { 1266 DPRINTF(Ethernet, 1267 "packet will not fit in receive buffer...packet dropped\n"); 1268 return false; 1269 } 1270 1271 // If we were at the last element, back up one ot go to the new 1272 // last element of the list. 1273 if (rxFifoPtr == rxFifo.end()) 1274 --rxFifoPtr; 1275 1276 devIntrPost(Regs::Intr_RxPacket); 1277 rxKick(); 1278 return true; 1279} 1280 1281//===================================================================== 1282// 1283// 1284void 1285Base::serialize(ostream &os) 1286{ 1287 // Serialize the PciDev base class 1288 PciDev::serialize(os); 1289 1290 SERIALIZE_SCALAR(rxEnable); 1291 SERIALIZE_SCALAR(txEnable); 1292 SERIALIZE_SCALAR(cpuIntrEnable); 1293 1294 /* 1295 * Keep track of pending interrupt status. 1296 */ 1297 SERIALIZE_SCALAR(intrTick); 1298 SERIALIZE_SCALAR(cpuPendingIntr); 1299 Tick intrEventTick = 0; 1300 if (intrEvent) 1301 intrEventTick = intrEvent->when(); 1302 SERIALIZE_SCALAR(intrEventTick); 1303} 1304 1305void 1306Base::unserialize(Checkpoint *cp, const std::string §ion) 1307{ 1308 // Unserialize the PciDev base class 1309 PciDev::unserialize(cp, section); 1310 1311 UNSERIALIZE_SCALAR(rxEnable); 1312 UNSERIALIZE_SCALAR(txEnable); 1313 UNSERIALIZE_SCALAR(cpuIntrEnable); 1314 1315 /* 1316 * Keep track of pending interrupt status. 1317 */ 1318 UNSERIALIZE_SCALAR(intrTick); 1319 UNSERIALIZE_SCALAR(cpuPendingIntr); 1320 Tick intrEventTick; 1321 UNSERIALIZE_SCALAR(intrEventTick); 1322 if (intrEventTick) { 1323 intrEvent = new IntrEvent(this, true); 1324 intrEvent->schedule(intrEventTick); 1325 } 1326} 1327 1328void 1329Device::serialize(ostream &os) 1330{ 1331 // Serialize the PciDev base class 1332 Base::serialize(os); 1333 1334 if (rxState == rxCopy) 1335 panic("can't serialize with an in flight dma request rxState=%s", 1336 RxStateStrings[rxState]); 1337 1338 if (txState == txCopy) 1339 panic("can't serialize with an in flight dma request txState=%s", 1340 TxStateStrings[txState]); 1341 1342 /* 1343 * Serialize the device registers 1344 */ 1345 SERIALIZE_SCALAR(regs.Config); 1346 SERIALIZE_SCALAR(regs.IntrStatus); 1347 SERIALIZE_SCALAR(regs.IntrMask); 1348 SERIALIZE_SCALAR(regs.RxMaxCopy); 1349 SERIALIZE_SCALAR(regs.TxMaxCopy); 1350 SERIALIZE_SCALAR(regs.RxMaxIntr); 1351 SERIALIZE_SCALAR(regs.RxData); 1352 SERIALIZE_SCALAR(regs.RxDone); 1353 SERIALIZE_SCALAR(regs.TxData); 1354 SERIALIZE_SCALAR(regs.TxDone); 1355 1356 /* 1357 * Serialize the virtual nic state 1358 */ 1359 int virtualRegsSize = virtualRegs.size(); 1360 SERIALIZE_SCALAR(virtualRegsSize); 1361 for (int i = 0; i < virtualRegsSize; ++i) { 1362 VirtualReg *vnic = &virtualRegs[i]; 1363 1364 string reg = csprintf("vnic%d", i); 1365 paramOut(os, reg + ".RxData", vnic->RxData); 1366 paramOut(os, reg + ".RxDone", vnic->RxDone); 1367 paramOut(os, reg + ".TxData", vnic->TxData); 1368 paramOut(os, reg + ".TxDone", vnic->TxDone); 1369 1370 PacketFifo::iterator rxFifoPtr; 1371 1372 bool rxPacketExists = vnic->rxPacket != rxFifo.end(); 1373 paramOut(os, reg + ".rxPacketExists", rxPacketExists); 1374 if (rxPacketExists) { 1375 int rxPacket = 0; 1376 PacketFifo::iterator i = rxFifo.begin(); 1377 while (i != vnic->rxPacket) { 1378 assert(i != rxFifo.end()); 1379 ++i; 1380 ++rxPacket; 1381 } 1382 1383 paramOut(os, reg + ".rxPacket", rxPacket); 1384 paramOut(os, reg + ".rxPacketOffset", vnic->rxPacketOffset); 1385 paramOut(os, reg + ".rxPacketBytes", vnic->rxPacketBytes); 1386 } 1387 paramOut(os, reg + ".rxDoneData", vnic->rxDoneData); 1388 } 1389 1390 VirtualList::iterator i, end; 1391 int count; 1392 1393 int rxListSize = rxList.size(); 1394 SERIALIZE_SCALAR(rxListSize); 1395 for (count = 0, i = rxList.begin(), end = rxList.end(); i != end; ++i) 1396 paramOut(os, csprintf("rxList%d", count++), *i); 1397 1398 int txListSize = txList.size(); 1399 SERIALIZE_SCALAR(txListSize); 1400 for (count = 0, i = txList.begin(), end = txList.end(); i != end; ++i) 1401 paramOut(os, csprintf("txList%d", count++), *i); 1402 1403 /* 1404 * Serialize rx state machine 1405 */ 1406 int rxState = this->rxState; 1407 SERIALIZE_SCALAR(rxState); 1408 SERIALIZE_SCALAR(rxEmpty); 1409 rxFifo.serialize("rxFifo", os); 1410 1411 /* 1412 * Serialize tx state machine 1413 */ 1414 int txState = this->txState; 1415 SERIALIZE_SCALAR(txState); 1416 SERIALIZE_SCALAR(txFull); 1417 txFifo.serialize("txFifo", os); 1418 bool txPacketExists = txPacket; 1419 SERIALIZE_SCALAR(txPacketExists); 1420 if (txPacketExists) { 1421 txPacket->serialize("txPacket", os); 1422 SERIALIZE_SCALAR(txPacketOffset); 1423 SERIALIZE_SCALAR(txPacketBytes); 1424 } 1425 1426 /* 1427 * If there's a pending transmit, store the time so we can 1428 * reschedule it later 1429 */ 1430 Tick transmitTick = txEvent.scheduled() ? txEvent.when() - curTick : 0; 1431 SERIALIZE_SCALAR(transmitTick); 1432} 1433 1434void 1435Device::unserialize(Checkpoint *cp, const std::string §ion) 1436{ 1437 // Unserialize the PciDev base class 1438 Base::unserialize(cp, section); 1439 1440 /* 1441 * Unserialize the device registers 1442 */ 1443 UNSERIALIZE_SCALAR(regs.Config); 1444 UNSERIALIZE_SCALAR(regs.IntrStatus); 1445 UNSERIALIZE_SCALAR(regs.IntrMask); 1446 UNSERIALIZE_SCALAR(regs.RxMaxCopy); 1447 UNSERIALIZE_SCALAR(regs.TxMaxCopy); 1448 UNSERIALIZE_SCALAR(regs.RxMaxIntr); 1449 UNSERIALIZE_SCALAR(regs.RxData); 1450 UNSERIALIZE_SCALAR(regs.RxDone); 1451 UNSERIALIZE_SCALAR(regs.TxData); 1452 UNSERIALIZE_SCALAR(regs.TxDone); 1453 1454 int rxListSize; 1455 UNSERIALIZE_SCALAR(rxListSize); 1456 rxList.clear(); 1457 for (int i = 0; i < rxListSize; ++i) { 1458 int value; 1459 paramIn(cp, section, csprintf("rxList%d", i), value); 1460 rxList.push_back(value); 1461 } 1462 1463 int txListSize; 1464 UNSERIALIZE_SCALAR(txListSize); 1465 txList.clear(); 1466 for (int i = 0; i < txListSize; ++i) { 1467 int value; 1468 paramIn(cp, section, csprintf("txList%d", i), value); 1469 txList.push_back(value); 1470 } 1471 1472 /* 1473 * Unserialize rx state machine 1474 */ 1475 int rxState; 1476 UNSERIALIZE_SCALAR(rxState); 1477 UNSERIALIZE_SCALAR(rxEmpty); 1478 this->rxState = (RxState) rxState; 1479 rxFifo.unserialize("rxFifo", cp, section); 1480 1481 /* 1482 * Unserialize tx state machine 1483 */ 1484 int txState; 1485 UNSERIALIZE_SCALAR(txState); 1486 UNSERIALIZE_SCALAR(txFull); 1487 this->txState = (TxState) txState; 1488 txFifo.unserialize("txFifo", cp, section); 1489 bool txPacketExists; 1490 UNSERIALIZE_SCALAR(txPacketExists); 1491 txPacket = 0; 1492 if (txPacketExists) { 1493 txPacket = new PacketData(16384); 1494 txPacket->unserialize("txPacket", cp, section); 1495 UNSERIALIZE_SCALAR(txPacketOffset); 1496 UNSERIALIZE_SCALAR(txPacketBytes); 1497 } 1498 1499 /* 1500 * unserialize the virtual nic registers/state 1501 * 1502 * this must be done after the unserialization of the rxFifo 1503 * because the packet iterators depend on the fifo being populated 1504 */ 1505 int virtualRegsSize; 1506 UNSERIALIZE_SCALAR(virtualRegsSize); 1507 virtualRegs.clear(); 1508 virtualRegs.resize(virtualRegsSize); 1509 for (int i = 0; i < virtualRegsSize; ++i) { 1510 VirtualReg *vnic = &virtualRegs[i]; 1511 string reg = csprintf("vnic%d", i); 1512 1513 paramIn(cp, section, reg + ".RxData", vnic->RxData); 1514 paramIn(cp, section, reg + ".RxDone", vnic->RxDone); 1515 paramIn(cp, section, reg + ".TxData", vnic->TxData); 1516 paramIn(cp, section, reg + ".TxDone", vnic->TxDone); 1517 1518 bool rxPacketExists; 1519 paramIn(cp, section, reg + ".rxPacketExists", rxPacketExists); 1520 if (rxPacketExists) { 1521 int rxPacket; 1522 paramIn(cp, section, reg + ".rxPacket", rxPacket); 1523 vnic->rxPacket = rxFifo.begin(); 1524 while (rxPacket--) 1525 ++vnic->rxPacket; 1526 1527 paramIn(cp, section, reg + ".rxPacketOffset", 1528 vnic->rxPacketOffset); 1529 paramIn(cp, section, reg + ".rxPacketBytes", vnic->rxPacketBytes); 1530 } else { 1531 vnic->rxPacket = rxFifo.end(); 1532 } 1533 paramIn(cp, section, reg + ".rxDoneData", vnic->rxDoneData); 1534 } 1535 1536 /* 1537 * If there's a pending transmit, reschedule it now 1538 */ 1539 Tick transmitTick; 1540 UNSERIALIZE_SCALAR(transmitTick); 1541 if (transmitTick) 1542 txEvent.schedule(curTick + transmitTick); 1543 1544 /* 1545 * re-add addrRanges to bus bridges 1546 */ 1547 if (pioInterface) { 1548 pioInterface->addAddrRange(RangeSize(BARAddrs[0], BARSize[0])); 1549 pioInterface->addAddrRange(RangeSize(BARAddrs[1], BARSize[1])); 1550 } 1551} 1552 1553Tick 1554Device::cacheAccess(MemReqPtr &req) 1555{ 1556 Addr daddr; 1557 int bar; 1558 if (!getBAR(req->paddr, daddr, bar)) 1559 panic("address does not map to a BAR pa=%#x va=%#x size=%d", 1560 req->paddr, req->vaddr, req->size); 1561 1562 DPRINTF(EthernetPIO, "timing %s to paddr=%#x bar=%d daddr=%#x\n", 1563 req->cmd.toString(), req->paddr, bar, daddr); 1564 1565 return curTick + pioLatency; 1566} 1567 1568BEGIN_DECLARE_SIM_OBJECT_PARAMS(Interface) 1569 1570 SimObjectParam<EtherInt *> peer; 1571 SimObjectParam<Device *> device; 1572 1573END_DECLARE_SIM_OBJECT_PARAMS(Interface) 1574 1575BEGIN_INIT_SIM_OBJECT_PARAMS(Interface) 1576 1577 INIT_PARAM_DFLT(peer, "peer interface", NULL), 1578 INIT_PARAM(device, "Ethernet device of this interface") 1579 1580END_INIT_SIM_OBJECT_PARAMS(Interface) 1581 1582CREATE_SIM_OBJECT(Interface) 1583{ 1584 Interface *dev_int = new Interface(getInstanceName(), device); 1585 1586 EtherInt *p = (EtherInt *)peer; 1587 if (p) { 1588 dev_int->setPeer(p); 1589 p->setPeer(dev_int); 1590 } 1591 1592 return dev_int; 1593} 1594 1595REGISTER_SIM_OBJECT("SinicInt", Interface) 1596 1597 1598BEGIN_DECLARE_SIM_OBJECT_PARAMS(Device) 1599 1600 Param<Tick> clock; 1601 1602 Param<Addr> addr; 1603 SimObjectParam<MemoryController *> mmu; 1604 SimObjectParam<PhysicalMemory *> physmem; 1605 SimObjectParam<PciConfigAll *> configspace; 1606 SimObjectParam<PciConfigData *> configdata; 1607 SimObjectParam<Platform *> platform; 1608 Param<uint32_t> pci_bus; 1609 Param<uint32_t> pci_dev; 1610 Param<uint32_t> pci_func; 1611 1612 SimObjectParam<HierParams *> hier; 1613 SimObjectParam<Bus*> pio_bus; 1614 SimObjectParam<Bus*> dma_bus; 1615 SimObjectParam<Bus*> payload_bus; 1616 Param<Tick> dma_read_delay; 1617 Param<Tick> dma_read_factor; 1618 Param<Tick> dma_write_delay; 1619 Param<Tick> dma_write_factor; 1620 Param<bool> dma_no_allocate; 1621 Param<Tick> pio_latency; 1622 Param<Tick> intr_delay; 1623 1624 Param<Tick> rx_delay; 1625 Param<Tick> tx_delay; 1626 Param<uint32_t> rx_max_copy; 1627 Param<uint32_t> tx_max_copy; 1628 Param<uint32_t> rx_max_intr; 1629 Param<uint32_t> rx_fifo_size; 1630 Param<uint32_t> tx_fifo_size; 1631 Param<uint32_t> rx_fifo_threshold; 1632 Param<uint32_t> tx_fifo_threshold; 1633 1634 Param<bool> rx_filter; 1635 Param<string> hardware_address; 1636 Param<bool> rx_thread; 1637 Param<bool> tx_thread; 1638 Param<bool> rss; 1639 1640END_DECLARE_SIM_OBJECT_PARAMS(Device) 1641 1642BEGIN_INIT_SIM_OBJECT_PARAMS(Device) 1643 1644 INIT_PARAM(clock, "State machine cycle time"), 1645 1646 INIT_PARAM(addr, "Device Address"), 1647 INIT_PARAM(mmu, "Memory Controller"), 1648 INIT_PARAM(physmem, "Physical Memory"), 1649 INIT_PARAM(configspace, "PCI Configspace"), 1650 INIT_PARAM(configdata, "PCI Config data"), 1651 INIT_PARAM(platform, "Platform"), 1652 INIT_PARAM(pci_bus, "PCI bus"), 1653 INIT_PARAM(pci_dev, "PCI device number"), 1654 INIT_PARAM(pci_func, "PCI function code"), 1655 1656 INIT_PARAM(hier, "Hierarchy global variables"), 1657 INIT_PARAM(pio_bus, ""), 1658 INIT_PARAM(dma_bus, ""), 1659 INIT_PARAM(payload_bus, "The IO Bus to attach to for payload"), 1660 INIT_PARAM(dma_read_delay, "fixed delay for dma reads"), 1661 INIT_PARAM(dma_read_factor, "multiplier for dma reads"), 1662 INIT_PARAM(dma_write_delay, "fixed delay for dma writes"), 1663 INIT_PARAM(dma_write_factor, "multiplier for dma writes"), 1664 INIT_PARAM(dma_no_allocate, "Should we allocat on read in cache"), 1665 INIT_PARAM(pio_latency, "Programmed IO latency in bus cycles"), 1666 INIT_PARAM(intr_delay, "Interrupt Delay"), 1667 1668 INIT_PARAM(rx_delay, "Receive Delay"), 1669 INIT_PARAM(tx_delay, "Transmit Delay"), 1670 INIT_PARAM(rx_max_copy, "rx max copy"), 1671 INIT_PARAM(tx_max_copy, "rx max copy"), 1672 INIT_PARAM(rx_max_intr, "rx max intr"), 1673 INIT_PARAM(rx_fifo_size, "max size in bytes of rxFifo"), 1674 INIT_PARAM(tx_fifo_size, "max size in bytes of txFifo"), 1675 INIT_PARAM(rx_fifo_threshold, "max size in bytes of rxFifo"), 1676 INIT_PARAM(tx_fifo_threshold, "max size in bytes of txFifo"), 1677 1678 INIT_PARAM(rx_filter, "Enable Receive Filter"), 1679 INIT_PARAM(hardware_address, "Ethernet Hardware Address"), 1680 INIT_PARAM(rx_thread, ""), 1681 INIT_PARAM(tx_thread, ""), 1682 INIT_PARAM(rss, "") 1683 1684END_INIT_SIM_OBJECT_PARAMS(Device) 1685 1686 1687CREATE_SIM_OBJECT(Device) 1688{ 1689 Device::Params *params = new Device::Params; 1690 1691 params->name = getInstanceName(); 1692 1693 params->clock = clock; 1694 1695 params->mmu = mmu; 1696 params->physmem = physmem; 1697 params->configSpace = configspace; 1698 params->configData = configdata; 1699 params->plat = platform; 1700 params->busNum = pci_bus; 1701 params->deviceNum = pci_dev; 1702 params->functionNum = pci_func; 1703 1704 params->hier = hier; 1705 params->pio_bus = pio_bus; 1706 params->header_bus = dma_bus; 1707 params->payload_bus = payload_bus; 1708 params->dma_read_delay = dma_read_delay; 1709 params->dma_read_factor = dma_read_factor; 1710 params->dma_write_delay = dma_write_delay; 1711 params->dma_write_factor = dma_write_factor; 1712 params->dma_no_allocate = dma_no_allocate; 1713 params->pio_latency = pio_latency; 1714 params->intr_delay = intr_delay; 1715 1716 params->tx_delay = tx_delay; 1717 params->rx_delay = rx_delay; 1718 params->rx_max_copy = rx_max_copy; 1719 params->tx_max_copy = tx_max_copy; 1720 params->rx_max_intr = rx_max_intr; 1721 params->rx_fifo_size = rx_fifo_size; 1722 params->tx_fifo_size = tx_fifo_size; 1723 params->rx_fifo_threshold = rx_fifo_threshold; 1724 params->tx_fifo_threshold = tx_fifo_threshold; 1725 1726 params->rx_filter = rx_filter; 1727 params->eaddr = hardware_address; 1728 params->rx_thread = rx_thread; 1729 params->tx_thread = tx_thread; 1730 params->rss = rss; 1731 1732 return new Device(params); 1733} 1734 1735REGISTER_SIM_OBJECT("Sinic", Device) 1736 1737/* namespace Sinic */ } 1738