sinic.cc revision 1634
16019Shines@cs.fsu.edu/* 26019Shines@cs.fsu.edu * Copyright (c) 2004 The Regents of The University of Michigan 37178Sgblack@eecs.umich.edu * All rights reserved. 47178Sgblack@eecs.umich.edu * 57178Sgblack@eecs.umich.edu * Redistribution and use in source and binary forms, with or without 67178Sgblack@eecs.umich.edu * modification, are permitted provided that the following conditions are 77178Sgblack@eecs.umich.edu * met: redistributions of source code must retain the above copyright 87178Sgblack@eecs.umich.edu * notice, this list of conditions and the following disclaimer; 97178Sgblack@eecs.umich.edu * redistributions in binary form must reproduce the above copyright 107178Sgblack@eecs.umich.edu * notice, this list of conditions and the following disclaimer in the 117178Sgblack@eecs.umich.edu * documentation and/or other materials provided with the distribution; 127178Sgblack@eecs.umich.edu * neither the name of the copyright holders nor the names of its 137178Sgblack@eecs.umich.edu * contributors may be used to endorse or promote products derived from 147178Sgblack@eecs.umich.edu * this software without specific prior written permission. 156019Shines@cs.fsu.edu * 166019Shines@cs.fsu.edu * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 176019Shines@cs.fsu.edu * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 186019Shines@cs.fsu.edu * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR 196019Shines@cs.fsu.edu * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT 206019Shines@cs.fsu.edu * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 216019Shines@cs.fsu.edu * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT 226019Shines@cs.fsu.edu * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 236019Shines@cs.fsu.edu * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 246019Shines@cs.fsu.edu * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 256019Shines@cs.fsu.edu * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 266019Shines@cs.fsu.edu * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 276019Shines@cs.fsu.edu */ 286019Shines@cs.fsu.edu 296019Shines@cs.fsu.edu#include <cstdio> 306019Shines@cs.fsu.edu#include <deque> 316019Shines@cs.fsu.edu#include <string> 326019Shines@cs.fsu.edu 336019Shines@cs.fsu.edu#include "base/inet.hh" 346019Shines@cs.fsu.edu#include "cpu/exec_context.hh" 356019Shines@cs.fsu.edu#include "cpu/intr_control.hh" 366019Shines@cs.fsu.edu#include "dev/dma.hh" 376019Shines@cs.fsu.edu#include "dev/etherlink.hh" 386019Shines@cs.fsu.edu#include "dev/sinic.hh" 396019Shines@cs.fsu.edu#include "dev/pciconfigall.hh" 406019Shines@cs.fsu.edu#include "mem/bus/bus.hh" 416019Shines@cs.fsu.edu#include "mem/bus/dma_interface.hh" 426019Shines@cs.fsu.edu#include "mem/bus/pio_interface.hh" 436019Shines@cs.fsu.edu#include "mem/bus/pio_interface_impl.hh" 446019Shines@cs.fsu.edu#include "mem/functional_mem/memory_control.hh" 456019Shines@cs.fsu.edu#include "mem/functional_mem/physical_memory.hh" 466019Shines@cs.fsu.edu#include "sim/builder.hh" 476019Shines@cs.fsu.edu#include "sim/debug.hh" 486019Shines@cs.fsu.edu#include "sim/eventq.hh" 496019Shines@cs.fsu.edu#include "sim/host.hh" 506019Shines@cs.fsu.edu#include "sim/stats.hh" 516019Shines@cs.fsu.edu#include "targetarch/vtophys.hh" 526019Shines@cs.fsu.edu 536019Shines@cs.fsu.eduusing namespace Net; 546019Shines@cs.fsu.edu 556019Shines@cs.fsu.edunamespace Sinic { 566019Shines@cs.fsu.edu 576019Shines@cs.fsu.educonst char *RxStateStrings[] = 586243Sgblack@eecs.umich.edu{ 596243Sgblack@eecs.umich.edu "rxIdle", 606243Sgblack@eecs.umich.edu "rxFifoBlock", 616243Sgblack@eecs.umich.edu "rxBeginCopy", 626243Sgblack@eecs.umich.edu "rxCopy", 636019Shines@cs.fsu.edu "rxCopyDone" 646019Shines@cs.fsu.edu}; 656019Shines@cs.fsu.edu 666019Shines@cs.fsu.educonst char *TxStateStrings[] = 676019Shines@cs.fsu.edu{ 686019Shines@cs.fsu.edu "txIdle", 696019Shines@cs.fsu.edu "txFifoBlock", 706019Shines@cs.fsu.edu "txBeginCopy", 716019Shines@cs.fsu.edu "txCopy", 726019Shines@cs.fsu.edu "txCopyDone" 736019Shines@cs.fsu.edu}; 746019Shines@cs.fsu.edu 756019Shines@cs.fsu.edu 766019Shines@cs.fsu.edu/////////////////////////////////////////////////////////////////////// 776019Shines@cs.fsu.edu// 786019Shines@cs.fsu.edu// Sinic PCI Device 796019Shines@cs.fsu.edu// 806019Shines@cs.fsu.eduBase::Base(Params *p) 816019Shines@cs.fsu.edu : PciDev(p), rxEnable(false), txEnable(false), cycleTime(p->cycle_time), 826019Shines@cs.fsu.edu intrDelay(p->intr_delay), intrTick(0), cpuIntrEnable(false), 836019Shines@cs.fsu.edu cpuPendingIntr(false), intrEvent(0), interface(NULL) 846019Shines@cs.fsu.edu{ 856019Shines@cs.fsu.edu} 866019Shines@cs.fsu.edu 876019Shines@cs.fsu.eduDevice::Device(Params *p) 886019Shines@cs.fsu.edu : Base(p), plat(p->plat), physmem(p->physmem), 896019Shines@cs.fsu.edu rxFifo(p->rx_fifo_size), txFifo(p->tx_fifo_size), 906019Shines@cs.fsu.edu rxKickTick(0), txKickTick(0), 916019Shines@cs.fsu.edu txEvent(this), rxDmaEvent(this), txDmaEvent(this), 926019Shines@cs.fsu.edu dmaReadDelay(p->dma_read_delay), dmaReadFactor(p->dma_read_factor), 936019Shines@cs.fsu.edu dmaWriteDelay(p->dma_write_delay), dmaWriteFactor(p->dma_write_factor) 946252Sgblack@eecs.umich.edu{ 956243Sgblack@eecs.umich.edu reset(); 966243Sgblack@eecs.umich.edu 976243Sgblack@eecs.umich.edu if (p->header_bus) { 986019Shines@cs.fsu.edu pioInterface = newPioInterface(p->name, p->hier, p->header_bus, this, 996019Shines@cs.fsu.edu &Device::cacheAccess); 1006019Shines@cs.fsu.edu 1016019Shines@cs.fsu.edu pioLatency = p->pio_latency * p->header_bus->clockRatio; 1026019Shines@cs.fsu.edu 1036252Sgblack@eecs.umich.edu if (p->payload_bus) 1046243Sgblack@eecs.umich.edu dmaInterface = new DMAInterface<Bus>(p->name + ".dma", 1056243Sgblack@eecs.umich.edu p->header_bus, p->payload_bus, 1066243Sgblack@eecs.umich.edu 1); 1076019Shines@cs.fsu.edu else 1086019Shines@cs.fsu.edu dmaInterface = new DMAInterface<Bus>(p->name + ".dma", 1096019Shines@cs.fsu.edu p->header_bus, p->header_bus, 1106019Shines@cs.fsu.edu 1); 1116019Shines@cs.fsu.edu } else if (p->payload_bus) { 1126019Shines@cs.fsu.edu pioInterface = newPioInterface(p->name, p->hier, p->payload_bus, this, 1136019Shines@cs.fsu.edu &Device::cacheAccess); 1146252Sgblack@eecs.umich.edu 1156243Sgblack@eecs.umich.edu pioLatency = p->pio_latency * p->payload_bus->clockRatio; 1166243Sgblack@eecs.umich.edu 1176243Sgblack@eecs.umich.edu dmaInterface = new DMAInterface<Bus>(p->name + ".dma", p->payload_bus, 1186019Shines@cs.fsu.edu p->payload_bus, 1); 1196019Shines@cs.fsu.edu } 1206019Shines@cs.fsu.edu} 1216019Shines@cs.fsu.edu 1226019Shines@cs.fsu.eduDevice::~Device() 1236019Shines@cs.fsu.edu{} 1246019Shines@cs.fsu.edu 1256019Shines@cs.fsu.eduvoid 1266019Shines@cs.fsu.eduDevice::regStats() 1276019Shines@cs.fsu.edu{ 1286019Shines@cs.fsu.edu rxBytes 1296019Shines@cs.fsu.edu .name(name() + ".rxBytes") 1306019Shines@cs.fsu.edu .desc("Bytes Received") 1316019Shines@cs.fsu.edu .prereq(rxBytes) 1326019Shines@cs.fsu.edu ; 1336019Shines@cs.fsu.edu 1346724Sgblack@eecs.umich.edu rxBandwidth 1356724Sgblack@eecs.umich.edu .name(name() + ".rxBandwidth") 1366019Shines@cs.fsu.edu .desc("Receive Bandwidth (bits/s)") 1376019Shines@cs.fsu.edu .precision(0) 1386019Shines@cs.fsu.edu .prereq(rxBytes) 1396019Shines@cs.fsu.edu ; 1406019Shines@cs.fsu.edu 1416252Sgblack@eecs.umich.edu rxPackets 1426243Sgblack@eecs.umich.edu .name(name() + ".rxPackets") 1436243Sgblack@eecs.umich.edu .desc("Number of Packets Received") 1446243Sgblack@eecs.umich.edu .prereq(rxBytes) 1456019Shines@cs.fsu.edu ; 1466019Shines@cs.fsu.edu 1476019Shines@cs.fsu.edu rxPacketRate 1486019Shines@cs.fsu.edu .name(name() + ".rxPPS") 1496019Shines@cs.fsu.edu .desc("Packet Reception Rate (packets/s)") 1506019Shines@cs.fsu.edu .precision(0) 1517356Sgblack@eecs.umich.edu .prereq(rxBytes) 1527356Sgblack@eecs.umich.edu ; 1537356Sgblack@eecs.umich.edu 1547356Sgblack@eecs.umich.edu rxIpPackets 1557356Sgblack@eecs.umich.edu .name(name() + ".rxIpPackets") 1567356Sgblack@eecs.umich.edu .desc("Number of IP Packets Received") 1577356Sgblack@eecs.umich.edu .prereq(rxBytes) 1587356Sgblack@eecs.umich.edu ; 1597178Sgblack@eecs.umich.edu 1607178Sgblack@eecs.umich.edu rxTcpPackets 1617178Sgblack@eecs.umich.edu .name(name() + ".rxTcpPackets") 1627337Sgblack@eecs.umich.edu .desc("Number of Packets Received") 1637178Sgblack@eecs.umich.edu .prereq(rxBytes) 1647178Sgblack@eecs.umich.edu ; 1657178Sgblack@eecs.umich.edu 1667178Sgblack@eecs.umich.edu rxUdpPackets 1677178Sgblack@eecs.umich.edu .name(name() + ".rxUdpPackets") 1687178Sgblack@eecs.umich.edu .desc("Number of UDP Packets Received") 1697178Sgblack@eecs.umich.edu .prereq(rxBytes) 1707178Sgblack@eecs.umich.edu ; 1717178Sgblack@eecs.umich.edu 1727178Sgblack@eecs.umich.edu rxIpChecksums 1737178Sgblack@eecs.umich.edu .name(name() + ".rxIpChecksums") 1747335Sgblack@eecs.umich.edu .desc("Number of rx IP Checksums done by device") 1757335Sgblack@eecs.umich.edu .precision(0) 1767335Sgblack@eecs.umich.edu .prereq(rxBytes) 1777335Sgblack@eecs.umich.edu ; 1787335Sgblack@eecs.umich.edu 1797335Sgblack@eecs.umich.edu rxTcpChecksums 1807335Sgblack@eecs.umich.edu .name(name() + ".rxTcpChecksums") 1817335Sgblack@eecs.umich.edu .desc("Number of rx TCP Checksums done by device") 1827335Sgblack@eecs.umich.edu .precision(0) 1837335Sgblack@eecs.umich.edu .prereq(rxBytes) 1847335Sgblack@eecs.umich.edu ; 1857335Sgblack@eecs.umich.edu 1867337Sgblack@eecs.umich.edu rxUdpChecksums 1877335Sgblack@eecs.umich.edu .name(name() + ".rxUdpChecksums") 1887335Sgblack@eecs.umich.edu .desc("Number of rx UDP Checksums done by device") 1897335Sgblack@eecs.umich.edu .precision(0) 1907335Sgblack@eecs.umich.edu .prereq(rxBytes) 1917335Sgblack@eecs.umich.edu ; 1927335Sgblack@eecs.umich.edu 1937335Sgblack@eecs.umich.edu totBandwidth 1947335Sgblack@eecs.umich.edu .name(name() + ".totBandwidth") 1957335Sgblack@eecs.umich.edu .desc("Total Bandwidth (bits/s)") 1967335Sgblack@eecs.umich.edu .precision(0) 1977335Sgblack@eecs.umich.edu .prereq(totBytes) 1987335Sgblack@eecs.umich.edu ; 1997178Sgblack@eecs.umich.edu 2007178Sgblack@eecs.umich.edu totPackets 2017178Sgblack@eecs.umich.edu .name(name() + ".totPackets") 2027178Sgblack@eecs.umich.edu .desc("Total Packets") 2037178Sgblack@eecs.umich.edu .precision(0) 2047178Sgblack@eecs.umich.edu .prereq(totBytes) 2057178Sgblack@eecs.umich.edu ; 2067178Sgblack@eecs.umich.edu 2077178Sgblack@eecs.umich.edu totBytes 2087178Sgblack@eecs.umich.edu .name(name() + ".totBytes") 2097178Sgblack@eecs.umich.edu .desc("Total Bytes") 2107178Sgblack@eecs.umich.edu .precision(0) 2117178Sgblack@eecs.umich.edu .prereq(totBytes) 2127178Sgblack@eecs.umich.edu ; 2137178Sgblack@eecs.umich.edu 2147178Sgblack@eecs.umich.edu totPacketRate 2157178Sgblack@eecs.umich.edu .name(name() + ".totPPS") 2167178Sgblack@eecs.umich.edu .desc("Total Tranmission Rate (packets/s)") 2177178Sgblack@eecs.umich.edu .precision(0) 2187178Sgblack@eecs.umich.edu .prereq(totBytes) 2197178Sgblack@eecs.umich.edu ; 2207178Sgblack@eecs.umich.edu 2217178Sgblack@eecs.umich.edu txBytes 2227178Sgblack@eecs.umich.edu .name(name() + ".txBytes") 2237178Sgblack@eecs.umich.edu .desc("Bytes Transmitted") 2247178Sgblack@eecs.umich.edu .prereq(txBytes) 2257178Sgblack@eecs.umich.edu ; 2267178Sgblack@eecs.umich.edu 2277178Sgblack@eecs.umich.edu txBandwidth 2287346Sgblack@eecs.umich.edu .name(name() + ".txBandwidth") 2297346Sgblack@eecs.umich.edu .desc("Transmit Bandwidth (bits/s)") 2307346Sgblack@eecs.umich.edu .precision(0) 2317346Sgblack@eecs.umich.edu .prereq(txBytes) 2327346Sgblack@eecs.umich.edu ; 2337346Sgblack@eecs.umich.edu 2347346Sgblack@eecs.umich.edu txPackets 2357346Sgblack@eecs.umich.edu .name(name() + ".txPackets") 2367346Sgblack@eecs.umich.edu .desc("Number of Packets Transmitted") 2377346Sgblack@eecs.umich.edu .prereq(txBytes) 2387178Sgblack@eecs.umich.edu ; 2397346Sgblack@eecs.umich.edu 2407346Sgblack@eecs.umich.edu txPacketRate 2417346Sgblack@eecs.umich.edu .name(name() + ".txPPS") 2427346Sgblack@eecs.umich.edu .desc("Packet Tranmission Rate (packets/s)") 2437346Sgblack@eecs.umich.edu .precision(0) 2447346Sgblack@eecs.umich.edu .prereq(txBytes) 2457346Sgblack@eecs.umich.edu ; 2467346Sgblack@eecs.umich.edu 2477346Sgblack@eecs.umich.edu txIpPackets 2487346Sgblack@eecs.umich.edu .name(name() + ".txIpPackets") 2497346Sgblack@eecs.umich.edu .desc("Number of IP Packets Transmitted") 2507346Sgblack@eecs.umich.edu .prereq(txBytes) 2517346Sgblack@eecs.umich.edu ; 2527346Sgblack@eecs.umich.edu 2537346Sgblack@eecs.umich.edu txTcpPackets 2547178Sgblack@eecs.umich.edu .name(name() + ".txTcpPackets") 2557337Sgblack@eecs.umich.edu .desc("Number of TCP Packets Transmitted") 2567337Sgblack@eecs.umich.edu .prereq(txBytes) 2577337Sgblack@eecs.umich.edu ; 2587337Sgblack@eecs.umich.edu 2597337Sgblack@eecs.umich.edu txUdpPackets 2607337Sgblack@eecs.umich.edu .name(name() + ".txUdpPackets") 2617337Sgblack@eecs.umich.edu .desc("Number of Packets Transmitted") 2627337Sgblack@eecs.umich.edu .prereq(txBytes) 2637337Sgblack@eecs.umich.edu ; 2647337Sgblack@eecs.umich.edu 2657337Sgblack@eecs.umich.edu txIpChecksums 2667337Sgblack@eecs.umich.edu .name(name() + ".txIpChecksums") 2677337Sgblack@eecs.umich.edu .desc("Number of tx IP Checksums done by device") 2687337Sgblack@eecs.umich.edu .precision(0) 2697337Sgblack@eecs.umich.edu .prereq(txBytes) 2707178Sgblack@eecs.umich.edu ; 2717178Sgblack@eecs.umich.edu 2727178Sgblack@eecs.umich.edu txTcpChecksums 2737178Sgblack@eecs.umich.edu .name(name() + ".txTcpChecksums") 2747337Sgblack@eecs.umich.edu .desc("Number of tx TCP Checksums done by device") 2757337Sgblack@eecs.umich.edu .precision(0) 2767337Sgblack@eecs.umich.edu .prereq(txBytes) 2777337Sgblack@eecs.umich.edu ; 2787346Sgblack@eecs.umich.edu 2797346Sgblack@eecs.umich.edu txUdpChecksums 2807346Sgblack@eecs.umich.edu .name(name() + ".txUdpChecksums") 2817346Sgblack@eecs.umich.edu .desc("Number of tx UDP Checksums done by device") 2827346Sgblack@eecs.umich.edu .precision(0) 2837337Sgblack@eecs.umich.edu .prereq(txBytes) 2847178Sgblack@eecs.umich.edu ; 2857321Sgblack@eecs.umich.edu 2867356Sgblack@eecs.umich.edu txBandwidth = txBytes * Stats::constant(8) / simSeconds; 2877321Sgblack@eecs.umich.edu rxBandwidth = rxBytes * Stats::constant(8) / simSeconds; 2887356Sgblack@eecs.umich.edu totBandwidth = txBandwidth + rxBandwidth; 2897356Sgblack@eecs.umich.edu totBytes = txBytes + rxBytes; 2907356Sgblack@eecs.umich.edu totPackets = txPackets + rxPackets; 2917356Sgblack@eecs.umich.edu txPacketRate = txPackets / simSeconds; 2927356Sgblack@eecs.umich.edu rxPacketRate = rxPackets / simSeconds; 2937356Sgblack@eecs.umich.edu} 2947356Sgblack@eecs.umich.edu 2957356Sgblack@eecs.umich.edu/** 2967356Sgblack@eecs.umich.edu * This is to write to the PCI general configuration registers 2977356Sgblack@eecs.umich.edu */ 2987356Sgblack@eecs.umich.eduvoid 2997356Sgblack@eecs.umich.eduDevice::WriteConfig(int offset, int size, uint32_t data) 3007321Sgblack@eecs.umich.edu{ 3017321Sgblack@eecs.umich.edu switch (offset) { 3027321Sgblack@eecs.umich.edu case PCI0_BASE_ADDR0: 3037321Sgblack@eecs.umich.edu // Need to catch writes to BARs to update the PIO interface 3047321Sgblack@eecs.umich.edu PciDev::WriteConfig(offset, size, data); 3057321Sgblack@eecs.umich.edu if (BARAddrs[0] != 0) { 3067321Sgblack@eecs.umich.edu if (pioInterface) 3077321Sgblack@eecs.umich.edu pioInterface->addAddrRange(RangeSize(BARAddrs[0], BARSize[0])); 3087321Sgblack@eecs.umich.edu 3097321Sgblack@eecs.umich.edu BARAddrs[0] &= EV5::PAddrUncachedMask; 3107321Sgblack@eecs.umich.edu } 3117335Sgblack@eecs.umich.edu break; 3127335Sgblack@eecs.umich.edu 3137335Sgblack@eecs.umich.edu default: 3147335Sgblack@eecs.umich.edu PciDev::WriteConfig(offset, size, data); 3157335Sgblack@eecs.umich.edu } 3167335Sgblack@eecs.umich.edu} 3177335Sgblack@eecs.umich.edu 3187335Sgblack@eecs.umich.edu/** 3197335Sgblack@eecs.umich.edu * This reads the device registers, which are detailed in the NS83820 3207321Sgblack@eecs.umich.edu * spec sheet 3217323Sgblack@eecs.umich.edu */ 3227323Sgblack@eecs.umich.eduFault 3237323Sgblack@eecs.umich.eduDevice::read(MemReqPtr &req, uint8_t *data) 3247323Sgblack@eecs.umich.edu{ 3257323Sgblack@eecs.umich.edu assert(config.hdr.command & PCI_CMD_MSE); 3267323Sgblack@eecs.umich.edu 3277323Sgblack@eecs.umich.edu //The mask is to give you only the offset into the device register file 3287323Sgblack@eecs.umich.edu Addr daddr = req->paddr & 0xfff; 3297323Sgblack@eecs.umich.edu 3307323Sgblack@eecs.umich.edu if (Regs::regSize(daddr) == 0) 3317323Sgblack@eecs.umich.edu panic("invalid address: da=%#x pa=%#x va=%#x size=%d", 3327323Sgblack@eecs.umich.edu daddr, req->paddr, req->vaddr, req->size); 3337323Sgblack@eecs.umich.edu 3347323Sgblack@eecs.umich.edu if (req->size != Regs::regSize(daddr)) 3357323Sgblack@eecs.umich.edu panic("invalid size for reg %s: da=%#x pa=%#x va=%#x size=%d", 3367323Sgblack@eecs.umich.edu Regs::regName(daddr), daddr, req->paddr, req->vaddr, req->size); 3377323Sgblack@eecs.umich.edu 3387321Sgblack@eecs.umich.edu DPRINTF(EthernetPIO, "read reg=%s da=%#x pa=%#x va=%#x size=%d\n", 3397321Sgblack@eecs.umich.edu Regs::regName(daddr), daddr, req->paddr, req->vaddr, req->size); 3407321Sgblack@eecs.umich.edu 3417335Sgblack@eecs.umich.edu uint32_t ®32 = *(uint32_t *)data; 3427335Sgblack@eecs.umich.edu uint64_t ®64 = *(uint64_t *)data; 3437335Sgblack@eecs.umich.edu 3447335Sgblack@eecs.umich.edu switch (daddr) { 3457335Sgblack@eecs.umich.edu case Regs::Config: 3467335Sgblack@eecs.umich.edu reg32 = regs.Config; 3477335Sgblack@eecs.umich.edu break; 3487335Sgblack@eecs.umich.edu 3497335Sgblack@eecs.umich.edu case Regs::RxMaxCopy: 3507335Sgblack@eecs.umich.edu reg32 = regs.RxMaxCopy; 3517335Sgblack@eecs.umich.edu break; 3527335Sgblack@eecs.umich.edu 3537335Sgblack@eecs.umich.edu case Regs::TxMaxCopy: 3547335Sgblack@eecs.umich.edu reg32 = regs.TxMaxCopy; 3557335Sgblack@eecs.umich.edu break; 3567335Sgblack@eecs.umich.edu 3577335Sgblack@eecs.umich.edu case Regs::RxThreshold: 3587335Sgblack@eecs.umich.edu reg32 = regs.RxThreshold; 3597335Sgblack@eecs.umich.edu break; 3607335Sgblack@eecs.umich.edu 3617335Sgblack@eecs.umich.edu case Regs::TxThreshold: 3627335Sgblack@eecs.umich.edu reg32 = regs.TxThreshold; 3637335Sgblack@eecs.umich.edu break; 3647335Sgblack@eecs.umich.edu 3657335Sgblack@eecs.umich.edu case Regs::IntrStatus: 3667335Sgblack@eecs.umich.edu reg32 = regs.IntrStatus; 3677335Sgblack@eecs.umich.edu devIntrClear(); 3687335Sgblack@eecs.umich.edu break; 3697335Sgblack@eecs.umich.edu 3707335Sgblack@eecs.umich.edu case Regs::IntrMask: 3717335Sgblack@eecs.umich.edu reg32 = regs.IntrMask; 3727335Sgblack@eecs.umich.edu break; 3737335Sgblack@eecs.umich.edu 3747321Sgblack@eecs.umich.edu case Regs::RxData: 3757321Sgblack@eecs.umich.edu reg64 = regs.RxData; 3767321Sgblack@eecs.umich.edu break; 3777321Sgblack@eecs.umich.edu 3787321Sgblack@eecs.umich.edu case Regs::RxDone: 3797321Sgblack@eecs.umich.edu case Regs::RxWait: 3807335Sgblack@eecs.umich.edu reg64 = Regs::set_RxDone_FifoLen(regs.RxDone, 3817335Sgblack@eecs.umich.edu min(rxFifo.packets(), 255)); 3827335Sgblack@eecs.umich.edu break; 3837335Sgblack@eecs.umich.edu 3847335Sgblack@eecs.umich.edu case Regs::TxData: 3857335Sgblack@eecs.umich.edu reg64 = regs.TxData; 3867335Sgblack@eecs.umich.edu break; 3877335Sgblack@eecs.umich.edu 3887335Sgblack@eecs.umich.edu case Regs::TxDone: 3897321Sgblack@eecs.umich.edu case Regs::TxWait: 3907326Sgblack@eecs.umich.edu reg64 = Regs::set_TxDone_FifoLen(regs.TxDone, 3917326Sgblack@eecs.umich.edu min(txFifo.packets(), 255)); 3927326Sgblack@eecs.umich.edu break; 3937326Sgblack@eecs.umich.edu 3947326Sgblack@eecs.umich.edu case Regs::HwAddr: 3957326Sgblack@eecs.umich.edu reg64 = params()->eaddr; 3967326Sgblack@eecs.umich.edu break; 3977326Sgblack@eecs.umich.edu 3987326Sgblack@eecs.umich.edu default: 3997326Sgblack@eecs.umich.edu panic("reading write only register %s: da=%#x pa=%#x va=%#x size=%d", 4007326Sgblack@eecs.umich.edu Regs::regName(daddr), daddr, req->paddr, req->vaddr, req->size); 4017326Sgblack@eecs.umich.edu } 4027326Sgblack@eecs.umich.edu 4037326Sgblack@eecs.umich.edu DPRINTF(EthernetPIO, "read reg=%s done val=%#x\n", Regs::regName(daddr), 4047326Sgblack@eecs.umich.edu Regs::regSize(daddr) == 4 ? reg32 : reg64); 4057326Sgblack@eecs.umich.edu 4067326Sgblack@eecs.umich.edu return No_Fault; 4077326Sgblack@eecs.umich.edu} 4087326Sgblack@eecs.umich.edu 4097326Sgblack@eecs.umich.eduFault 4107326Sgblack@eecs.umich.eduDevice::write(MemReqPtr &req, const uint8_t *data) 4117326Sgblack@eecs.umich.edu{ 4127326Sgblack@eecs.umich.edu assert(config.hdr.command & PCI_CMD_MSE); 4137321Sgblack@eecs.umich.edu Addr daddr = req->paddr & 0xfff; 4147321Sgblack@eecs.umich.edu 4157335Sgblack@eecs.umich.edu if (Regs::regSize(daddr) == 0) 4167335Sgblack@eecs.umich.edu panic("invalid address: da=%#x pa=%#x va=%#x size=%d", 4177335Sgblack@eecs.umich.edu daddr, req->paddr, req->vaddr, req->size); 4187335Sgblack@eecs.umich.edu 4197335Sgblack@eecs.umich.edu if (req->size != Regs::regSize(daddr)) 4207335Sgblack@eecs.umich.edu panic("invalid size: reg=%s da=%#x pa=%#x va=%#x size=%d", 4217335Sgblack@eecs.umich.edu Regs::regName(daddr), daddr, req->paddr, req->vaddr, req->size); 4227335Sgblack@eecs.umich.edu 4237335Sgblack@eecs.umich.edu uint32_t reg32 = *(uint32_t *)data; 4247335Sgblack@eecs.umich.edu uint64_t reg64 = *(uint64_t *)data; 4257335Sgblack@eecs.umich.edu 4267335Sgblack@eecs.umich.edu DPRINTF(EthernetPIO, "write reg=%s val=%#x da=%#x pa=%#x va=%#x size=%d\n", 4277335Sgblack@eecs.umich.edu Regs::regName(daddr), Regs::regSize(daddr) == 4 ? reg32 : reg64, 4287335Sgblack@eecs.umich.edu daddr, req->paddr, req->vaddr, req->size); 4297335Sgblack@eecs.umich.edu 4307335Sgblack@eecs.umich.edu 4317335Sgblack@eecs.umich.edu switch (daddr) { 4327335Sgblack@eecs.umich.edu case Regs::Config: 4337335Sgblack@eecs.umich.edu changeConfig(reg32); 4347335Sgblack@eecs.umich.edu break; 4357335Sgblack@eecs.umich.edu 4367335Sgblack@eecs.umich.edu case Regs::RxThreshold: 4377335Sgblack@eecs.umich.edu regs.RxThreshold = reg32; 4387335Sgblack@eecs.umich.edu break; 4397335Sgblack@eecs.umich.edu 4407335Sgblack@eecs.umich.edu case Regs::TxThreshold: 4417335Sgblack@eecs.umich.edu regs.TxThreshold = reg32; 4427335Sgblack@eecs.umich.edu break; 4437335Sgblack@eecs.umich.edu 4447335Sgblack@eecs.umich.edu case Regs::IntrMask: 4457335Sgblack@eecs.umich.edu devIntrChangeMask(reg32); 4467335Sgblack@eecs.umich.edu break; 4477335Sgblack@eecs.umich.edu 4487335Sgblack@eecs.umich.edu case Regs::RxData: 4497335Sgblack@eecs.umich.edu if (rxState != rxIdle) 4507335Sgblack@eecs.umich.edu panic("receive machine busy with another request!"); 4517335Sgblack@eecs.umich.edu 4527335Sgblack@eecs.umich.edu regs.RxDone = 0; 4537335Sgblack@eecs.umich.edu regs.RxData = reg64; 4547335Sgblack@eecs.umich.edu if (rxEnable) { 4557335Sgblack@eecs.umich.edu rxState = rxFifoBlock; 4567335Sgblack@eecs.umich.edu rxKick(); 4577335Sgblack@eecs.umich.edu } 4587335Sgblack@eecs.umich.edu break; 4597321Sgblack@eecs.umich.edu 4607321Sgblack@eecs.umich.edu case Regs::TxData: 4617321Sgblack@eecs.umich.edu if (txState != txIdle) 4627321Sgblack@eecs.umich.edu panic("transmit machine busy with another request!"); 4637321Sgblack@eecs.umich.edu 4647356Sgblack@eecs.umich.edu regs.TxDone = 0; 4657356Sgblack@eecs.umich.edu regs.TxData = reg64; 4667356Sgblack@eecs.umich.edu if (txEnable) { 4677356Sgblack@eecs.umich.edu txState = txFifoBlock; 4687356Sgblack@eecs.umich.edu txKick(); 4697356Sgblack@eecs.umich.edu } 4707363Sgblack@eecs.umich.edu break; 4717363Sgblack@eecs.umich.edu 4727363Sgblack@eecs.umich.edu default: 4737363Sgblack@eecs.umich.edu panic("writing read only register %s: da=%#x pa=%#x va=%#x size=%d", 4747363Sgblack@eecs.umich.edu Regs::regName(daddr), daddr, req->paddr, req->vaddr, req->size); 4757363Sgblack@eecs.umich.edu } 4767363Sgblack@eecs.umich.edu 4777363Sgblack@eecs.umich.edu return No_Fault; 4787363Sgblack@eecs.umich.edu} 4797363Sgblack@eecs.umich.edu 4807363Sgblack@eecs.umich.eduvoid 4817363Sgblack@eecs.umich.eduDevice::devIntrPost(uint32_t interrupts) 4827363Sgblack@eecs.umich.edu{ 4837363Sgblack@eecs.umich.edu if ((interrupts & Regs::Intr_Res)) 4847363Sgblack@eecs.umich.edu panic("Cannot set a reserved interrupt"); 4857363Sgblack@eecs.umich.edu 4867363Sgblack@eecs.umich.edu regs.IntrStatus |= interrupts; 4877363Sgblack@eecs.umich.edu 4887363Sgblack@eecs.umich.edu DPRINTF(EthernetIntr, 4897364Sgblack@eecs.umich.edu "interrupt written to intStatus: intr=%#x status=%#x mask=%#x\n", 4907364Sgblack@eecs.umich.edu interrupts, regs.IntrStatus, regs.IntrMask); 4917364Sgblack@eecs.umich.edu 4927364Sgblack@eecs.umich.edu if ((regs.IntrStatus & regs.IntrMask)) { 4937364Sgblack@eecs.umich.edu Tick when = curTick; 4947364Sgblack@eecs.umich.edu if ((regs.IntrStatus & regs.IntrMask & Regs::Intr_NoDelay) == 0) 4957364Sgblack@eecs.umich.edu when += intrDelay; 4967364Sgblack@eecs.umich.edu cpuIntrPost(when); 4977364Sgblack@eecs.umich.edu } 4987364Sgblack@eecs.umich.edu} 4997364Sgblack@eecs.umich.edu 5007364Sgblack@eecs.umich.eduvoid 5017364Sgblack@eecs.umich.eduDevice::devIntrClear(uint32_t interrupts) 5027364Sgblack@eecs.umich.edu{ 5037364Sgblack@eecs.umich.edu if ((interrupts & Regs::Intr_Res)) 5047364Sgblack@eecs.umich.edu panic("Cannot clear a reserved interrupt"); 5057364Sgblack@eecs.umich.edu 5067364Sgblack@eecs.umich.edu regs.IntrStatus &= ~interrupts; 5077364Sgblack@eecs.umich.edu 5087363Sgblack@eecs.umich.edu DPRINTF(EthernetIntr, 5097363Sgblack@eecs.umich.edu "interrupt cleared from intStatus: intr=%x status=%x mask=%x\n", 5107363Sgblack@eecs.umich.edu interrupts, regs.IntrStatus, regs.IntrMask); 5117363Sgblack@eecs.umich.edu 5127363Sgblack@eecs.umich.edu if (!(regs.IntrStatus & regs.IntrMask)) 5137367Sgblack@eecs.umich.edu cpuIntrClear(); 5147367Sgblack@eecs.umich.edu} 5157367Sgblack@eecs.umich.edu 5167367Sgblack@eecs.umich.eduvoid 5177367Sgblack@eecs.umich.eduDevice::devIntrChangeMask(uint32_t newmask) 5187367Sgblack@eecs.umich.edu{ 5197367Sgblack@eecs.umich.edu if (regs.IntrMask == newmask) 5207367Sgblack@eecs.umich.edu return; 5217367Sgblack@eecs.umich.edu 5227367Sgblack@eecs.umich.edu regs.IntrMask = newmask; 5237367Sgblack@eecs.umich.edu 5247367Sgblack@eecs.umich.edu DPRINTF(EthernetIntr, 5257367Sgblack@eecs.umich.edu "interrupt mask changed: intStatus=%x intMask=%x masked=%x\n", 5267367Sgblack@eecs.umich.edu regs.IntrStatus, regs.IntrMask, regs.IntrStatus & regs.IntrMask); 5277367Sgblack@eecs.umich.edu 5287367Sgblack@eecs.umich.edu if (regs.IntrStatus & regs.IntrMask) 5297367Sgblack@eecs.umich.edu cpuIntrPost(curTick); 5307367Sgblack@eecs.umich.edu else 5317367Sgblack@eecs.umich.edu cpuIntrClear(); 5327363Sgblack@eecs.umich.edu} 5337368Sgblack@eecs.umich.edu 5347368Sgblack@eecs.umich.eduvoid 5357368Sgblack@eecs.umich.eduBase::cpuIntrPost(Tick when) 5367368Sgblack@eecs.umich.edu{ 5377368Sgblack@eecs.umich.edu // If the interrupt you want to post is later than an interrupt 5387368Sgblack@eecs.umich.edu // already scheduled, just let it post in the coming one and don't 5397368Sgblack@eecs.umich.edu // schedule another. 5407368Sgblack@eecs.umich.edu // HOWEVER, must be sure that the scheduled intrTick is in the 5417368Sgblack@eecs.umich.edu // future (this was formerly the source of a bug) 5427368Sgblack@eecs.umich.edu /** 5437368Sgblack@eecs.umich.edu * @todo this warning should be removed and the intrTick code should 5447368Sgblack@eecs.umich.edu * be fixed. 5457368Sgblack@eecs.umich.edu */ 5467368Sgblack@eecs.umich.edu assert(when >= curTick); 5477368Sgblack@eecs.umich.edu assert(intrTick >= curTick || intrTick == 0); 5487368Sgblack@eecs.umich.edu if (!cpuIntrEnable) { 5497368Sgblack@eecs.umich.edu DPRINTF(EthernetIntr, "interrupts not enabled.\n", 5507368Sgblack@eecs.umich.edu intrTick); 5517368Sgblack@eecs.umich.edu return; 5527363Sgblack@eecs.umich.edu } 5537363Sgblack@eecs.umich.edu 5547363Sgblack@eecs.umich.edu if (when > intrTick && intrTick != 0) { 5557369Sgblack@eecs.umich.edu DPRINTF(EthernetIntr, "don't need to schedule event...intrTick=%d\n", 5567369Sgblack@eecs.umich.edu intrTick); 5577369Sgblack@eecs.umich.edu return; 5587369Sgblack@eecs.umich.edu } 5597369Sgblack@eecs.umich.edu 5607369Sgblack@eecs.umich.edu intrTick = when; 5617369Sgblack@eecs.umich.edu if (intrTick < curTick) { 5627369Sgblack@eecs.umich.edu debug_break(); 5637369Sgblack@eecs.umich.edu intrTick = curTick; 5647369Sgblack@eecs.umich.edu } 5657369Sgblack@eecs.umich.edu 5667369Sgblack@eecs.umich.edu DPRINTF(EthernetIntr, "going to schedule an interrupt for intrTick=%d\n", 5677369Sgblack@eecs.umich.edu intrTick); 5687369Sgblack@eecs.umich.edu 5697369Sgblack@eecs.umich.edu if (intrEvent) 5707369Sgblack@eecs.umich.edu intrEvent->squash(); 5717369Sgblack@eecs.umich.edu intrEvent = new IntrEvent(this, true); 5727369Sgblack@eecs.umich.edu intrEvent->schedule(intrTick); 5737369Sgblack@eecs.umich.edu} 5747363Sgblack@eecs.umich.edu 5757363Sgblack@eecs.umich.eduvoid 5767363Sgblack@eecs.umich.eduBase::cpuInterrupt() 5777363Sgblack@eecs.umich.edu{ 5787363Sgblack@eecs.umich.edu assert(intrTick == curTick); 5797363Sgblack@eecs.umich.edu 5807363Sgblack@eecs.umich.edu // Whether or not there's a pending interrupt, we don't care about 5817363Sgblack@eecs.umich.edu // it anymore 5827363Sgblack@eecs.umich.edu intrEvent = 0; 5837363Sgblack@eecs.umich.edu intrTick = 0; 5847363Sgblack@eecs.umich.edu 5857363Sgblack@eecs.umich.edu // Don't send an interrupt if there's already one 5867363Sgblack@eecs.umich.edu if (cpuPendingIntr) { 5877363Sgblack@eecs.umich.edu DPRINTF(EthernetIntr, 5887363Sgblack@eecs.umich.edu "would send an interrupt now, but there's already pending\n"); 5897363Sgblack@eecs.umich.edu } else { 5907363Sgblack@eecs.umich.edu // Send interrupt 5917363Sgblack@eecs.umich.edu cpuPendingIntr = true; 5927363Sgblack@eecs.umich.edu 5937363Sgblack@eecs.umich.edu DPRINTF(EthernetIntr, "posting interrupt\n"); 5947363Sgblack@eecs.umich.edu intrPost(); 5957363Sgblack@eecs.umich.edu } 5967363Sgblack@eecs.umich.edu} 5977363Sgblack@eecs.umich.edu 5987363Sgblack@eecs.umich.eduvoid 5997363Sgblack@eecs.umich.eduBase::cpuIntrClear() 6007363Sgblack@eecs.umich.edu{ 6017363Sgblack@eecs.umich.edu if (!cpuPendingIntr) 6027363Sgblack@eecs.umich.edu return; 6037363Sgblack@eecs.umich.edu 6047363Sgblack@eecs.umich.edu if (intrEvent) { 6057363Sgblack@eecs.umich.edu intrEvent->squash(); 6067363Sgblack@eecs.umich.edu intrEvent = 0; 6077363Sgblack@eecs.umich.edu } 6087363Sgblack@eecs.umich.edu 6097363Sgblack@eecs.umich.edu intrTick = 0; 6107363Sgblack@eecs.umich.edu 6117366Sgblack@eecs.umich.edu cpuPendingIntr = false; 6127366Sgblack@eecs.umich.edu 6137366Sgblack@eecs.umich.edu DPRINTF(EthernetIntr, "clearing cchip interrupt\n"); 6147366Sgblack@eecs.umich.edu intrClear(); 6157366Sgblack@eecs.umich.edu} 6167366Sgblack@eecs.umich.edu 6177366Sgblack@eecs.umich.edubool 6187366Sgblack@eecs.umich.eduBase::cpuIntrPending() const 6197366Sgblack@eecs.umich.edu{ return cpuPendingIntr; } 6207366Sgblack@eecs.umich.edu 6217366Sgblack@eecs.umich.eduvoid 6227366Sgblack@eecs.umich.eduDevice::changeConfig(uint32_t newconf) 6237366Sgblack@eecs.umich.edu{ 6247366Sgblack@eecs.umich.edu uint32_t changed = regs.Config ^ newconf; 6257366Sgblack@eecs.umich.edu if (!changed) 6267363Sgblack@eecs.umich.edu return; 6277363Sgblack@eecs.umich.edu 6287363Sgblack@eecs.umich.edu regs.Config = newconf; 6297365Sgblack@eecs.umich.edu 6307365Sgblack@eecs.umich.edu if ((changed & Regs::Config_Reset)) { 6317365Sgblack@eecs.umich.edu assert(regs.Config & Regs::Config_Reset); 6327365Sgblack@eecs.umich.edu reset(); 6337365Sgblack@eecs.umich.edu regs.Config &= ~Regs::Config_Reset; 6347365Sgblack@eecs.umich.edu } 6357365Sgblack@eecs.umich.edu 6367365Sgblack@eecs.umich.edu if ((changed & Regs::Config_IntEn)) { 6377365Sgblack@eecs.umich.edu cpuIntrEnable = regs.Config & Regs::Config_IntEn; 6387365Sgblack@eecs.umich.edu if (cpuIntrEnable) { 6397365Sgblack@eecs.umich.edu if (regs.IntrStatus & regs.IntrMask) 6407365Sgblack@eecs.umich.edu cpuIntrPost(curTick); 6417365Sgblack@eecs.umich.edu } else { 6427365Sgblack@eecs.umich.edu cpuIntrClear(); 6437365Sgblack@eecs.umich.edu } 6447363Sgblack@eecs.umich.edu } 6457369Sgblack@eecs.umich.edu 6467369Sgblack@eecs.umich.edu if ((changed & Regs::Config_TxEn)) { 6477369Sgblack@eecs.umich.edu txEnable = regs.Config & Regs::Config_TxEn; 6487369Sgblack@eecs.umich.edu if (txEnable) 6497369Sgblack@eecs.umich.edu txKick(); 6507369Sgblack@eecs.umich.edu } 6517369Sgblack@eecs.umich.edu 6527369Sgblack@eecs.umich.edu if ((changed & Regs::Config_RxEn)) { 6537369Sgblack@eecs.umich.edu rxEnable = regs.Config & Regs::Config_RxEn; 6547369Sgblack@eecs.umich.edu if (rxEnable) 6557369Sgblack@eecs.umich.edu rxKick(); 6567369Sgblack@eecs.umich.edu } 6577369Sgblack@eecs.umich.edu} 6587369Sgblack@eecs.umich.edu 6597369Sgblack@eecs.umich.eduvoid 6607363Sgblack@eecs.umich.eduDevice::reset() 6617363Sgblack@eecs.umich.edu{ 6627363Sgblack@eecs.umich.edu using namespace Regs; 6637363Sgblack@eecs.umich.edu memset(®s, 0, sizeof(regs)); 6647363Sgblack@eecs.umich.edu regs.RxMaxCopy = params()->rx_max_copy; 6657363Sgblack@eecs.umich.edu regs.TxMaxCopy = params()->tx_max_copy; 6667363Sgblack@eecs.umich.edu regs.IntrMask = Intr_TxFifo | Intr_RxFifo | Intr_RxData; 6677363Sgblack@eecs.umich.edu 6687363Sgblack@eecs.umich.edu rxState = rxIdle; 6697363Sgblack@eecs.umich.edu txState = txIdle; 6707363Sgblack@eecs.umich.edu 6717363Sgblack@eecs.umich.edu rxFifo.clear(); 6727363Sgblack@eecs.umich.edu txFifo.clear(); 6737363Sgblack@eecs.umich.edu} 6747363Sgblack@eecs.umich.edu 6757363Sgblack@eecs.umich.eduvoid 6767363Sgblack@eecs.umich.eduDevice::rxDmaCopy() 6777363Sgblack@eecs.umich.edu{ 6787363Sgblack@eecs.umich.edu assert(rxState == rxCopy); 6797363Sgblack@eecs.umich.edu rxState = rxCopyDone; 6807363Sgblack@eecs.umich.edu physmem->dma_write(rxDmaAddr, (uint8_t *)rxDmaData, rxDmaLen); 6817363Sgblack@eecs.umich.edu DPRINTF(EthernetDMA, "rx dma write paddr=%#x len=%d\n", 6827363Sgblack@eecs.umich.edu rxDmaAddr, rxDmaLen); 6837363Sgblack@eecs.umich.edu DDUMP(EthernetDMA, rxDmaData, rxDmaLen); 6847363Sgblack@eecs.umich.edu} 6857363Sgblack@eecs.umich.edu 6867363Sgblack@eecs.umich.eduvoid 6877363Sgblack@eecs.umich.eduDevice::rxDmaDone() 6887363Sgblack@eecs.umich.edu{ 6897363Sgblack@eecs.umich.edu rxDmaCopy(); 6907363Sgblack@eecs.umich.edu rxKick(); 6917363Sgblack@eecs.umich.edu} 6927363Sgblack@eecs.umich.edu 6937363Sgblack@eecs.umich.eduvoid 6947363Sgblack@eecs.umich.eduDevice::rxKick() 6957363Sgblack@eecs.umich.edu{ 6967363Sgblack@eecs.umich.edu DPRINTF(EthernetSM, "receive kick rxState=%s (rxFifo.size=%d)\n", 6977363Sgblack@eecs.umich.edu RxStateStrings[rxState], rxFifo.size()); 6987363Sgblack@eecs.umich.edu 6997363Sgblack@eecs.umich.edu if (rxKickTick > curTick) { 7007363Sgblack@eecs.umich.edu DPRINTF(EthernetSM, "receive kick exiting, can't run till %d\n", 7017363Sgblack@eecs.umich.edu rxKickTick); 702 return; 703 } 704 705 next: 706 switch (rxState) { 707 case rxIdle: 708 if (rxPioRequest) { 709 pioInterface->respond(rxPioRequest, curTick); 710 rxPioRequest = 0; 711 } 712 goto exit; 713 714 case rxFifoBlock: 715 if (rxPacket) { 716 rxState = rxBeginCopy; 717 break; 718 } 719 720 if (rxFifo.empty()) { 721 DPRINTF(EthernetSM, "receive waiting for data. Nothing to do.\n"); 722 goto exit; 723 } 724 725 // Grab a new packet from the fifo. 726 rxPacket = rxFifo.front(); 727 rxPacketBufPtr = rxPacket->data; 728 rxPktBytes = rxPacket->length; 729 assert(rxPktBytes); 730 731 rxDoneData = 0; 732 /* scope for variables */ { 733 IpPtr ip(rxPacket); 734 if (ip) { 735 rxDoneData |= Regs::RxDone_IpPacket; 736 rxIpChecksums++; 737 if (cksum(ip) != 0) { 738 DPRINTF(EthernetCksum, "Rx IP Checksum Error\n"); 739 rxDoneData |= Regs::RxDone_IpError; 740 } 741 TcpPtr tcp(ip); 742 UdpPtr udp(ip); 743 if (tcp) { 744 rxDoneData |= Regs::RxDone_TcpPacket; 745 rxTcpChecksums++; 746 if (cksum(tcp) != 0) { 747 DPRINTF(EthernetCksum, "Rx TCP Checksum Error\n"); 748 rxDoneData |= Regs::RxDone_TcpError; 749 } 750 } else if (udp) { 751 rxDoneData |= Regs::RxDone_UdpPacket; 752 rxUdpChecksums++; 753 if (cksum(udp) != 0) { 754 DPRINTF(EthernetCksum, "Rx UDP Checksum Error\n"); 755 rxDoneData |= Regs::RxDone_UdpError; 756 } 757 } 758 } 759 } 760 rxState = rxBeginCopy; 761 break; 762 763 case rxBeginCopy: 764 rxDmaAddr = plat->pciToDma(Regs::get_RxData_Addr(regs.RxData)); 765 rxDmaLen = min<int>(Regs::get_RxData_Len(regs.RxData), rxPktBytes); 766 rxDmaData = rxPacketBufPtr; 767 768 if (dmaInterface) { 769 if (!dmaInterface->busy()) { 770 dmaInterface->doDMA(WriteInvalidate, rxDmaAddr, rxDmaLen, 771 curTick, &rxDmaEvent, true); 772 rxState = rxCopy; 773 } 774 goto exit; 775 } 776 777 rxState = rxCopy; 778 if (dmaWriteDelay != 0 || dmaWriteFactor != 0) { 779 Tick factor = ((rxDmaLen + ULL(63)) >> ULL(6)) * dmaWriteFactor; 780 Tick start = curTick + dmaWriteDelay + factor; 781 rxDmaEvent.schedule(start); 782 goto exit; 783 } 784 785 rxDmaCopy(); 786 break; 787 788 case rxCopy: 789 DPRINTF(EthernetSM, "receive machine still copying\n"); 790 goto exit; 791 792 case rxCopyDone: 793 regs.RxDone = rxDoneData | rxDmaLen; 794 795 if (rxPktBytes == rxDmaLen) { 796 rxPacket = NULL; 797 rxFifo.pop(); 798 } else { 799 regs.RxDone |= Regs::RxDone_More; 800 rxPktBytes -= rxDmaLen; 801 rxPacketBufPtr += rxDmaLen; 802 } 803 804 regs.RxDone |= Regs::RxDone_Complete; 805 devIntrPost(Regs::Intr_RxData); 806 rxState = rxIdle; 807 break; 808 809 default: 810 panic("Invalid rxState!"); 811 } 812 813 DPRINTF(EthernetSM, "entering next rxState=%s\n", 814 RxStateStrings[rxState]); 815 816 goto next; 817 818 exit: 819 /** 820 * @todo do we want to schedule a future kick? 821 */ 822 DPRINTF(EthernetSM, "rx state machine exited rxState=%s\n", 823 RxStateStrings[rxState]); 824} 825 826void 827Device::txDmaCopy() 828{ 829 assert(txState == txCopy); 830 txState = txCopyDone; 831 physmem->dma_read((uint8_t *)txDmaData, txDmaAddr, txDmaLen); 832 DPRINTF(EthernetDMA, "tx dma read paddr=%#x len=%d\n", 833 txDmaAddr, txDmaLen); 834 DDUMP(EthernetDMA, txDmaData, txDmaLen); 835} 836 837void 838Device::txDmaDone() 839{ 840 txDmaCopy(); 841 txKick(); 842} 843 844void 845Device::transmit() 846{ 847 if (txFifo.empty()) { 848 DPRINTF(Ethernet, "nothing to transmit\n"); 849 return; 850 } 851 852 PacketPtr packet = txFifo.front(); 853 if (!interface->sendPacket(packet)) { 854 DPRINTF(Ethernet, "Packet Transmit: failed txFifo available %d\n", 855 txFifo.avail()); 856 goto reschedule; 857 } 858 859 txFifo.pop(); 860 861#if TRACING_ON 862 if (DTRACE(Ethernet)) { 863 IpPtr ip(packet); 864 if (ip) { 865 DPRINTF(Ethernet, "ID is %d\n", ip->id()); 866 TcpPtr tcp(ip); 867 if (tcp) { 868 DPRINTF(Ethernet, "Src Port=%d, Dest Port=%d\n", 869 tcp->sport(), tcp->dport()); 870 } 871 } 872 } 873#endif 874 875 DDUMP(Ethernet, packet->data, packet->length); 876 txBytes += packet->length; 877 txPackets++; 878 879 DPRINTF(Ethernet, "Packet Transmit: successful txFifo Available %d\n", 880 txFifo.avail()); 881 882 if (txFifo.size() <= params()->tx_fifo_threshold) 883 devIntrPost(Regs::Intr_TxFifo); 884 885 devIntrPost(Regs::Intr_TxDone); 886 887 reschedule: 888 if (!txFifo.empty() && !txEvent.scheduled()) { 889 DPRINTF(Ethernet, "reschedule transmit\n"); 890 txEvent.schedule(curTick + retryTime); 891 } 892} 893 894void 895Device::txKick() 896{ 897 DPRINTF(EthernetSM, "transmit kick txState=%s (txFifo.size=%d)\n", 898 TxStateStrings[txState], txFifo.size()); 899 900 if (txKickTick > curTick) { 901 DPRINTF(EthernetSM, "transmit kick exiting, can't run till %d\n", 902 txKickTick); 903 return; 904 } 905 906 next: 907 switch (txState) { 908 case txIdle: 909 if (txPioRequest) { 910 pioInterface->respond(txPioRequest, curTick + pioLatency); 911 txPioRequest = 0; 912 } 913 goto exit; 914 915 case txFifoBlock: 916 if (!txPacket) { 917 // Grab a new packet from the fifo. 918 txPacket = new PacketData(16384); 919 txPacketBufPtr = txPacket->data; 920 } 921 922 if (txFifo.avail() - txPacket->length < 923 Regs::get_TxData_Len(regs.TxData)) { 924 DPRINTF(EthernetSM, "transmit fifo full. Nothing to do.\n"); 925 goto exit; 926 } 927 928 txState = txBeginCopy; 929 break; 930 931 case txBeginCopy: 932 txDmaAddr = plat->pciToDma(Regs::get_TxData_Addr(regs.TxData)); 933 txDmaLen = Regs::get_TxData_Len(regs.TxData); 934 txDmaData = txPacketBufPtr; 935 936 if (dmaInterface) { 937 if (!dmaInterface->busy()) { 938 dmaInterface->doDMA(Read, txDmaAddr, txDmaLen, 939 curTick, &txDmaEvent, true); 940 txState = txCopy; 941 } 942 943 goto exit; 944 } 945 946 txState = txCopy; 947 if (dmaReadDelay != 0 || dmaReadFactor != 0) { 948 Tick factor = ((txDmaLen + ULL(63)) >> ULL(6)) * dmaReadFactor; 949 Tick start = curTick + dmaReadDelay + factor; 950 txDmaEvent.schedule(start); 951 goto exit; 952 } 953 954 txDmaCopy(); 955 break; 956 957 case txCopy: 958 DPRINTF(EthernetSM, "transmit machine still copying\n"); 959 goto exit; 960 961 case txCopyDone: 962 txPacket->length += txDmaLen; 963 if ((regs.TxData & Regs::TxData_More)) { 964 txPacketBufPtr += txDmaLen; 965 } else { 966 assert(txPacket->length <= txFifo.avail()); 967 if ((regs.TxData & Regs::TxData_Checksum)) { 968 IpPtr ip(txPacket); 969 if (ip) { 970 TcpPtr tcp(ip); 971 if (tcp) { 972 tcp->sum(0); 973 tcp->sum(cksum(tcp)); 974 txTcpChecksums++; 975 } 976 977 UdpPtr udp(ip); 978 if (udp) { 979 udp->sum(0); 980 udp->sum(cksum(udp)); 981 txUdpChecksums++; 982 } 983 984 ip->sum(0); 985 ip->sum(cksum(ip)); 986 txIpChecksums++; 987 } 988 } 989 txFifo.push(txPacket); 990 txPacket = 0; 991 transmit(); 992 } 993 994 regs.TxDone = txDmaLen | Regs::TxDone_Complete; 995 devIntrPost(Regs::Intr_TxData); 996 txState = txIdle; 997 break; 998 999 default: 1000 panic("Invalid txState!"); 1001 } 1002 1003 DPRINTF(EthernetSM, "entering next txState=%s\n", 1004 TxStateStrings[txState]); 1005 1006 goto next; 1007 1008 exit: 1009 /** 1010 * @todo do we want to schedule a future kick? 1011 */ 1012 DPRINTF(EthernetSM, "tx state machine exited txState=%s\n", 1013 TxStateStrings[txState]); 1014} 1015 1016void 1017Device::transferDone() 1018{ 1019 if (txFifo.empty()) { 1020 DPRINTF(Ethernet, "transfer complete: txFifo empty...nothing to do\n"); 1021 return; 1022 } 1023 1024 DPRINTF(Ethernet, "transfer complete: data in txFifo...schedule xmit\n"); 1025 1026 if (txEvent.scheduled()) 1027 txEvent.reschedule(curTick + cycles(1)); 1028 else 1029 txEvent.schedule(curTick + cycles(1)); 1030} 1031 1032bool 1033Device::rxFilter(const PacketPtr &packet) 1034{ 1035 if (!Regs::get_Config_Filter(regs.Config)) 1036 return false; 1037 1038 panic("receive filter not implemented\n"); 1039 bool drop = true; 1040 1041#if 0 1042 string type; 1043 1044 EthHdr *eth = packet->eth(); 1045 if (eth->unicast()) { 1046 // If we're accepting all unicast addresses 1047 if (acceptUnicast) 1048 drop = false; 1049 1050 // If we make a perfect match 1051 if (acceptPerfect && params->eaddr == eth.dst()) 1052 drop = false; 1053 1054 if (acceptArp && eth->type() == ETH_TYPE_ARP) 1055 drop = false; 1056 1057 } else if (eth->broadcast()) { 1058 // if we're accepting broadcasts 1059 if (acceptBroadcast) 1060 drop = false; 1061 1062 } else if (eth->multicast()) { 1063 // if we're accepting all multicasts 1064 if (acceptMulticast) 1065 drop = false; 1066 1067 } 1068 1069 if (drop) { 1070 DPRINTF(Ethernet, "rxFilter drop\n"); 1071 DDUMP(EthernetData, packet->data, packet->length); 1072 } 1073#endif 1074 return drop; 1075} 1076 1077bool 1078Device::recvPacket(PacketPtr packet) 1079{ 1080 rxBytes += packet->length; 1081 rxPackets++; 1082 1083 DPRINTF(Ethernet, "Receiving packet from wire, rxFifo Available is %d\n", 1084 rxFifo.avail()); 1085 1086 if (!rxEnable) { 1087 DPRINTF(Ethernet, "receive disabled...packet dropped\n"); 1088 interface->recvDone(); 1089 return true; 1090 } 1091 1092 if (rxFilter(packet)) { 1093 DPRINTF(Ethernet, "packet filtered...dropped\n"); 1094 interface->recvDone(); 1095 return true; 1096 } 1097 1098 if (rxFifo.size() >= params()->rx_fifo_threshold) 1099 devIntrPost(Regs::Intr_RxFifo); 1100 1101 if (!rxFifo.push(packet)) { 1102 DPRINTF(Ethernet, 1103 "packet will not fit in receive buffer...packet dropped\n"); 1104 return false; 1105 } 1106 1107 interface->recvDone(); 1108 devIntrPost(Regs::Intr_RxDone); 1109 rxKick(); 1110 return true; 1111} 1112 1113//===================================================================== 1114// 1115// 1116void 1117Base::serialize(ostream &os) 1118{ 1119 // Serialize the PciDev base class 1120 PciDev::serialize(os); 1121 1122 SERIALIZE_SCALAR(rxEnable); 1123 SERIALIZE_SCALAR(txEnable); 1124 SERIALIZE_SCALAR(cpuIntrEnable); 1125 1126 /* 1127 * Keep track of pending interrupt status. 1128 */ 1129 SERIALIZE_SCALAR(intrTick); 1130 SERIALIZE_SCALAR(cpuPendingIntr); 1131 Tick intrEventTick = 0; 1132 if (intrEvent) 1133 intrEventTick = intrEvent->when(); 1134 SERIALIZE_SCALAR(intrEventTick); 1135} 1136 1137void 1138Base::unserialize(Checkpoint *cp, const std::string §ion) 1139{ 1140 // Unserialize the PciDev base class 1141 PciDev::unserialize(cp, section); 1142 1143 UNSERIALIZE_SCALAR(rxEnable); 1144 UNSERIALIZE_SCALAR(txEnable); 1145 UNSERIALIZE_SCALAR(cpuIntrEnable); 1146 1147 /* 1148 * Keep track of pending interrupt status. 1149 */ 1150 UNSERIALIZE_SCALAR(intrTick); 1151 UNSERIALIZE_SCALAR(cpuPendingIntr); 1152 Tick intrEventTick; 1153 UNSERIALIZE_SCALAR(intrEventTick); 1154 if (intrEventTick) { 1155 intrEvent = new IntrEvent(this, true); 1156 intrEvent->schedule(intrEventTick); 1157 } 1158} 1159 1160void 1161Device::serialize(ostream &os) 1162{ 1163 // Serialize the PciDev base class 1164 Base::serialize(os); 1165 1166 if (rxDmaEvent.scheduled()) 1167 rxDmaCopy(); 1168 1169 if (txDmaEvent.scheduled()) 1170 txDmaCopy(); 1171 1172 /* 1173 * Serialize the device registers 1174 */ 1175 SERIALIZE_SCALAR(regs.Config); 1176 SERIALIZE_SCALAR(regs.RxMaxCopy); 1177 SERIALIZE_SCALAR(regs.TxMaxCopy); 1178 SERIALIZE_SCALAR(regs.RxThreshold); 1179 SERIALIZE_SCALAR(regs.TxThreshold); 1180 SERIALIZE_SCALAR(regs.IntrStatus); 1181 SERIALIZE_SCALAR(regs.IntrMask); 1182 SERIALIZE_SCALAR(regs.RxData); 1183 SERIALIZE_SCALAR(regs.RxDone); 1184 SERIALIZE_SCALAR(regs.TxData); 1185 SERIALIZE_SCALAR(regs.TxDone); 1186 1187 /* 1188 * Serialize rx state machine 1189 */ 1190 int rxState = this->rxState; 1191 SERIALIZE_SCALAR(rxState); 1192 rxFifo.serialize("rxFifo", os); 1193 bool rxPacketExists = rxPacket; 1194 SERIALIZE_SCALAR(rxPacketExists); 1195 if (rxPacketExists) { 1196 rxPacket->serialize("rxPacket", os); 1197 uint32_t rxPktBufPtr = (uint32_t) (rxPacketBufPtr - rxPacket->data); 1198 SERIALIZE_SCALAR(rxPktBufPtr); 1199 SERIALIZE_SCALAR(rxPktBytes); 1200 } 1201 SERIALIZE_SCALAR(rxDoneData); 1202 1203 /* 1204 * Serialize tx state machine 1205 */ 1206 int txState = this->txState; 1207 SERIALIZE_SCALAR(txState); 1208 txFifo.serialize("txFifo", os); 1209 bool txPacketExists = txPacket; 1210 SERIALIZE_SCALAR(txPacketExists); 1211 if (txPacketExists) { 1212 txPacket->serialize("txPacket", os); 1213 uint32_t txPktBufPtr = (uint32_t) (txPacketBufPtr - txPacket->data); 1214 SERIALIZE_SCALAR(txPktBufPtr); 1215 SERIALIZE_SCALAR(txPktBytes); 1216 } 1217 1218 /* 1219 * If there's a pending transmit, store the time so we can 1220 * reschedule it later 1221 */ 1222 Tick transmitTick = txEvent.scheduled() ? txEvent.when() - curTick : 0; 1223 SERIALIZE_SCALAR(transmitTick); 1224} 1225 1226void 1227Device::unserialize(Checkpoint *cp, const std::string §ion) 1228{ 1229 // Unserialize the PciDev base class 1230 Base::unserialize(cp, section); 1231 1232 /* 1233 * Unserialize the device registers 1234 */ 1235 UNSERIALIZE_SCALAR(regs.Config); 1236 UNSERIALIZE_SCALAR(regs.RxMaxCopy); 1237 UNSERIALIZE_SCALAR(regs.TxMaxCopy); 1238 UNSERIALIZE_SCALAR(regs.RxThreshold); 1239 UNSERIALIZE_SCALAR(regs.TxThreshold); 1240 UNSERIALIZE_SCALAR(regs.IntrStatus); 1241 UNSERIALIZE_SCALAR(regs.IntrMask); 1242 UNSERIALIZE_SCALAR(regs.RxData); 1243 UNSERIALIZE_SCALAR(regs.RxDone); 1244 UNSERIALIZE_SCALAR(regs.TxData); 1245 UNSERIALIZE_SCALAR(regs.TxDone); 1246 1247 /* 1248 * Unserialize rx state machine 1249 */ 1250 int rxState; 1251 UNSERIALIZE_SCALAR(rxState); 1252 this->rxState = (RxState) rxState; 1253 rxFifo.unserialize("rxFifo", cp, section); 1254 bool rxPacketExists; 1255 UNSERIALIZE_SCALAR(rxPacketExists); 1256 rxPacket = 0; 1257 if (rxPacketExists) { 1258 rxPacket = new PacketData(16384); 1259 rxPacket->unserialize("rxPacket", cp, section); 1260 uint32_t rxPktBufPtr; 1261 UNSERIALIZE_SCALAR(rxPktBufPtr); 1262 this->rxPacketBufPtr = (uint8_t *) rxPacket->data + rxPktBufPtr; 1263 UNSERIALIZE_SCALAR(rxPktBytes); 1264 } 1265 UNSERIALIZE_SCALAR(rxDoneData); 1266 1267 /* 1268 * Unserialize tx state machine 1269 */ 1270 int txState; 1271 UNSERIALIZE_SCALAR(txState); 1272 this->txState = (TxState) txState; 1273 txFifo.unserialize("txFifo", cp, section); 1274 bool txPacketExists; 1275 UNSERIALIZE_SCALAR(txPacketExists); 1276 txPacket = 0; 1277 if (txPacketExists) { 1278 txPacket = new PacketData(16384); 1279 txPacket->unserialize("txPacket", cp, section); 1280 uint32_t txPktBufPtr; 1281 UNSERIALIZE_SCALAR(txPktBufPtr); 1282 this->txPacketBufPtr = (uint8_t *) txPacket->data + txPktBufPtr; 1283 UNSERIALIZE_SCALAR(txPktBytes); 1284 } 1285 1286 /* 1287 * If there's a pending transmit, reschedule it now 1288 */ 1289 Tick transmitTick; 1290 UNSERIALIZE_SCALAR(transmitTick); 1291 if (transmitTick) 1292 txEvent.schedule(curTick + transmitTick); 1293 1294 /* 1295 * re-add addrRanges to bus bridges 1296 */ 1297 if (pioInterface) 1298 pioInterface->addAddrRange(RangeSize(BARAddrs[0], BARSize[0])); 1299} 1300 1301Tick 1302Device::cacheAccess(MemReqPtr &req) 1303{ 1304 //The mask is to give you only the offset into the device register file 1305 Addr daddr = req->paddr - addr; 1306 1307 DPRINTF(EthernetPIO, "timing access to paddr=%#x (daddr=%#x)\n", 1308 req->paddr, daddr); 1309 1310 Tick when = curTick + pioLatency; 1311 1312 switch (daddr) { 1313 case Regs::RxDone: 1314 if (rxState != rxIdle) { 1315 rxPioRequest = req; 1316 when = 0; 1317 } 1318 break; 1319 1320 case Regs::TxDone: 1321 if (txState != txIdle) { 1322 txPioRequest = req; 1323 when = 0; 1324 } 1325 break; 1326 } 1327 1328 return when; 1329} 1330 1331BEGIN_DECLARE_SIM_OBJECT_PARAMS(Interface) 1332 1333 SimObjectParam<EtherInt *> peer; 1334 SimObjectParam<Device *> device; 1335 1336END_DECLARE_SIM_OBJECT_PARAMS(Interface) 1337 1338BEGIN_INIT_SIM_OBJECT_PARAMS(Interface) 1339 1340 INIT_PARAM_DFLT(peer, "peer interface", NULL), 1341 INIT_PARAM(device, "Ethernet device of this interface") 1342 1343END_INIT_SIM_OBJECT_PARAMS(Interface) 1344 1345CREATE_SIM_OBJECT(Interface) 1346{ 1347 Interface *dev_int = new Interface(getInstanceName(), device); 1348 1349 EtherInt *p = (EtherInt *)peer; 1350 if (p) { 1351 dev_int->setPeer(p); 1352 p->setPeer(dev_int); 1353 } 1354 1355 return dev_int; 1356} 1357 1358REGISTER_SIM_OBJECT("SinicInt", Interface) 1359 1360 1361BEGIN_DECLARE_SIM_OBJECT_PARAMS(Device) 1362 1363 Param<Tick> cycle_time; 1364 Param<Tick> tx_delay; 1365 Param<Tick> rx_delay; 1366 Param<Tick> intr_delay; 1367 SimObjectParam<MemoryController *> mmu; 1368 SimObjectParam<PhysicalMemory *> physmem; 1369 Param<bool> rx_filter; 1370 Param<string> hardware_address; 1371 SimObjectParam<Bus*> header_bus; 1372 SimObjectParam<Bus*> payload_bus; 1373 SimObjectParam<HierParams *> hier; 1374 Param<Tick> pio_latency; 1375 SimObjectParam<PciConfigAll *> configspace; 1376 SimObjectParam<PciConfigData *> configdata; 1377 SimObjectParam<Platform *> platform; 1378 Param<uint32_t> pci_bus; 1379 Param<uint32_t> pci_dev; 1380 Param<uint32_t> pci_func; 1381 Param<uint32_t> rx_max_copy; 1382 Param<uint32_t> tx_max_copy; 1383 Param<uint32_t> rx_fifo_size; 1384 Param<uint32_t> tx_fifo_size; 1385 Param<uint32_t> rx_fifo_threshold; 1386 Param<uint32_t> tx_fifo_threshold; 1387 Param<Tick> dma_read_delay; 1388 Param<Tick> dma_read_factor; 1389 Param<Tick> dma_write_delay; 1390 Param<Tick> dma_write_factor; 1391 1392END_DECLARE_SIM_OBJECT_PARAMS(Device) 1393 1394BEGIN_INIT_SIM_OBJECT_PARAMS(Device) 1395 1396 INIT_PARAM(cycle_time, "State machine cycle time"), 1397 INIT_PARAM_DFLT(tx_delay, "Transmit Delay", 1000), 1398 INIT_PARAM_DFLT(rx_delay, "Receive Delay", 1000), 1399 INIT_PARAM_DFLT(intr_delay, "Interrupt Delay in microseconds", 0), 1400 INIT_PARAM(mmu, "Memory Controller"), 1401 INIT_PARAM(physmem, "Physical Memory"), 1402 INIT_PARAM_DFLT(rx_filter, "Enable Receive Filter", true), 1403 INIT_PARAM_DFLT(hardware_address, "Ethernet Hardware Address", 1404 "00:99:00:00:00:01"), 1405 INIT_PARAM_DFLT(header_bus, "The IO Bus to attach to for headers", NULL), 1406 INIT_PARAM_DFLT(payload_bus, "The IO Bus to attach to for payload", NULL), 1407 INIT_PARAM_DFLT(hier, "Hierarchy global variables", &defaultHierParams), 1408 INIT_PARAM_DFLT(pio_latency, "Programmed IO latency in bus cycles", 1), 1409 INIT_PARAM(configspace, "PCI Configspace"), 1410 INIT_PARAM(configdata, "PCI Config data"), 1411 INIT_PARAM(platform, "Platform"), 1412 INIT_PARAM(pci_bus, "PCI bus"), 1413 INIT_PARAM(pci_dev, "PCI device number"), 1414 INIT_PARAM(pci_func, "PCI function code"), 1415 INIT_PARAM_DFLT(rx_max_copy, "rx max copy", 16*1024), 1416 INIT_PARAM_DFLT(tx_max_copy, "rx max copy", 16*1024), 1417 INIT_PARAM_DFLT(rx_fifo_size, "max size in bytes of rxFifo", 64*1024), 1418 INIT_PARAM_DFLT(tx_fifo_size, "max size in bytes of txFifo", 64*1024), 1419 INIT_PARAM_DFLT(rx_fifo_threshold, "max size in bytes of rxFifo", 48*1024), 1420 INIT_PARAM_DFLT(tx_fifo_threshold, "max size in bytes of txFifo", 16*1024), 1421 INIT_PARAM_DFLT(dma_read_delay, "fixed delay for dma reads", 0), 1422 INIT_PARAM_DFLT(dma_read_factor, "multiplier for dma reads", 0), 1423 INIT_PARAM_DFLT(dma_write_delay, "fixed delay for dma writes", 0), 1424 INIT_PARAM_DFLT(dma_write_factor, "multiplier for dma writes", 0) 1425 1426END_INIT_SIM_OBJECT_PARAMS(Device) 1427 1428 1429CREATE_SIM_OBJECT(Device) 1430{ 1431 Device::Params *params = new Device::Params; 1432 params->name = getInstanceName(); 1433 params->intr_delay = intr_delay; 1434 params->physmem = physmem; 1435 params->cycle_time = cycle_time; 1436 params->tx_delay = tx_delay; 1437 params->rx_delay = rx_delay; 1438 params->mmu = mmu; 1439 params->hier = hier; 1440 params->header_bus = header_bus; 1441 params->payload_bus = payload_bus; 1442 params->pio_latency = pio_latency; 1443 params->configSpace = configspace; 1444 params->configData = configdata; 1445 params->plat = platform; 1446 params->busNum = pci_bus; 1447 params->deviceNum = pci_dev; 1448 params->functionNum = pci_func; 1449 params->rx_filter = rx_filter; 1450 params->eaddr = hardware_address; 1451 params->rx_max_copy = rx_max_copy; 1452 params->tx_max_copy = tx_max_copy; 1453 params->rx_fifo_size = rx_fifo_size; 1454 params->tx_fifo_size = tx_fifo_size; 1455 params->rx_fifo_threshold = rx_fifo_threshold; 1456 params->tx_fifo_threshold = tx_fifo_threshold; 1457 params->dma_read_delay = dma_read_delay; 1458 params->dma_read_factor = dma_read_factor; 1459 params->dma_write_delay = dma_write_delay; 1460 params->dma_write_factor = dma_write_factor; 1461 return new Device(params); 1462} 1463 1464REGISTER_SIM_OBJECT("Sinic", Device) 1465 1466/* namespace Sinic */ } 1467