ns_gige.cc revision 998
16657Snate@binkert.org/* 26657Snate@binkert.org * Copyright (c) 2004 The Regents of The University of Michigan 36657Snate@binkert.org * All rights reserved. 46657Snate@binkert.org * 56657Snate@binkert.org * Redistribution and use in source and binary forms, with or without 66657Snate@binkert.org * modification, are permitted provided that the following conditions are 76657Snate@binkert.org * met: redistributions of source code must retain the above copyright 86657Snate@binkert.org * notice, this list of conditions and the following disclaimer; 96657Snate@binkert.org * redistributions in binary form must reproduce the above copyright 106657Snate@binkert.org * notice, this list of conditions and the following disclaimer in the 116657Snate@binkert.org * documentation and/or other materials provided with the distribution; 126657Snate@binkert.org * neither the name of the copyright holders nor the names of its 136657Snate@binkert.org * contributors may be used to endorse or promote products derived from 146657Snate@binkert.org * this software without specific prior written permission. 156657Snate@binkert.org * 166657Snate@binkert.org * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 176657Snate@binkert.org * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 186657Snate@binkert.org * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR 196657Snate@binkert.org * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT 206657Snate@binkert.org * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 216657Snate@binkert.org * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT 226657Snate@binkert.org * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 236657Snate@binkert.org * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 246657Snate@binkert.org * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 256657Snate@binkert.org * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 266657Snate@binkert.org * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 276657Snate@binkert.org */ 286999Snate@binkert.org 296657Snate@binkert.org/* @file 306657Snate@binkert.org * Device module for modelling the National Semiconductor 316657Snate@binkert.org * DP83820 ethernet controller. Does not support priority queueing 326657Snate@binkert.org */ 338189SLisa.Hsu@amd.com#include <cstdio> 346657Snate@binkert.org#include <deque> 356882SBrad.Beckmann@amd.com#include <string> 367055Snate@binkert.org 376882SBrad.Beckmann@amd.com#include "base/inet.hh" 386882SBrad.Beckmann@amd.com#include "cpu/exec_context.hh" 398191SLisa.Hsu@amd.com#include "cpu/intr_control.hh" 406882SBrad.Beckmann@amd.com#include "dev/dma.hh" 416882SBrad.Beckmann@amd.com#include "dev/ns_gige.hh" 429102SNuwan.Jayasena@amd.com#include "dev/etherlink.hh" 436888SBrad.Beckmann@amd.com#include "mem/bus/bus.hh" 446882SBrad.Beckmann@amd.com#include "mem/bus/dma_interface.hh" 456882SBrad.Beckmann@amd.com#include "mem/bus/pio_interface.hh" 466657Snate@binkert.org#include "mem/bus/pio_interface_impl.hh" 476657Snate@binkert.org#include "mem/functional_mem/memory_control.hh" 486657Snate@binkert.org#include "mem/functional_mem/physical_memory.hh" 496657Snate@binkert.org#include "sim/builder.hh" 506657Snate@binkert.org#include "sim/host.hh" 517839Snilay@cs.wisc.edu#include "sim/sim_stats.hh" 526657Snate@binkert.org#include "targetarch/vtophys.hh" 536882SBrad.Beckmann@amd.com#include "dev/pciconfigall.hh" 546882SBrad.Beckmann@amd.com#include "dev/tsunami_cchip.hh" 556882SBrad.Beckmann@amd.com 566882SBrad.Beckmann@amd.comconst char *NsRxStateStrings[] = 576882SBrad.Beckmann@amd.com{ 586882SBrad.Beckmann@amd.com "rxIdle", 596657Snate@binkert.org "rxDescRefr", 606657Snate@binkert.org "rxDescRead", 616657Snate@binkert.org "rxFifoBlock", 626657Snate@binkert.org "rxFragWrite", 636657Snate@binkert.org "rxDescWrite", 649104Shestness@cs.utexas.edu "rxAdvance" 656657Snate@binkert.org}; 666657Snate@binkert.org 676657Snate@binkert.orgconst char *NsTxStateStrings[] = 686657Snate@binkert.org{ 697839Snilay@cs.wisc.edu "txIdle", 707839Snilay@cs.wisc.edu "txDescRefr", 716657Snate@binkert.org "txDescRead", 726657Snate@binkert.org "txFifoBlock", 736657Snate@binkert.org "txFragRead", 746657Snate@binkert.org "txDescWrite", 756657Snate@binkert.org "txAdvance" 766657Snate@binkert.org}; 776657Snate@binkert.org 786657Snate@binkert.orgconst char *NsDmaState[] = 796657Snate@binkert.org{ 806657Snate@binkert.org "dmaIdle", 816657Snate@binkert.org "dmaReading", 826657Snate@binkert.org "dmaWriting", 836657Snate@binkert.org "dmaReadWaiting", 846657Snate@binkert.org "dmaWriteWaiting" 856657Snate@binkert.org}; 866657Snate@binkert.org 876657Snate@binkert.orgusing namespace std; 886657Snate@binkert.org 896657Snate@binkert.org//helper function declarations 906657Snate@binkert.org//These functions reverse Endianness so we can evaluate network data correctly 916779SBrad.Beckmann@amd.comuint16_t reverseEnd16(uint16_t); 926657Snate@binkert.orguint32_t reverseEnd32(uint32_t); 936657Snate@binkert.org 946657Snate@binkert.org/////////////////////////////////////////////////////////////////////// 956657Snate@binkert.org// 966657Snate@binkert.org// NSGigE PCI Device 976657Snate@binkert.org// 986657Snate@binkert.orgNSGigE::NSGigE(const std::string &name, IntrControl *i, Tick intr_delay, 996657Snate@binkert.org PhysicalMemory *pmem, Tick tx_delay, Tick rx_delay, 1006657Snate@binkert.org MemoryController *mmu, HierParams *hier, Bus *header_bus, 1019104Shestness@cs.utexas.edu Bus *payload_bus, Tick pio_latency, bool dma_desc_free, 1029104Shestness@cs.utexas.edu bool dma_data_free, Tick dma_read_delay, Tick dma_write_delay, 1039104Shestness@cs.utexas.edu Tick dma_read_factor, Tick dma_write_factor, PciConfigAll *cf, 1049104Shestness@cs.utexas.edu PciConfigData *cd, Tsunami *t, uint32_t bus, uint32_t dev, 1056657Snate@binkert.org uint32_t func, bool rx_filter, const int eaddr[6], 1066657Snate@binkert.org uint32_t tx_fifo_size, uint32_t rx_fifo_size) 1076657Snate@binkert.org : PciDev(name, mmu, cf, cd, bus, dev, func), tsunami(t), ioEnable(false), 1086657Snate@binkert.org maxTxFifoSize(tx_fifo_size), maxRxFifoSize(rx_fifo_size), 1096657Snate@binkert.org txPacket(0), rxPacket(0), txPacketBufPtr(NULL), rxPacketBufPtr(NULL), 1106657Snate@binkert.org txXferLen(0), rxXferLen(0), txState(txIdle), CTDD(false), 1116657Snate@binkert.org txFifoAvail(tx_fifo_size), txHalt(false), 1126657Snate@binkert.org txFragPtr(0), txDescCnt(0), txDmaState(dmaIdle), rxState(rxIdle), 1136657Snate@binkert.org CRDD(false), rxPktBytes(0), rxFifoCnt(0), rxHalt(false), 1146657Snate@binkert.org rxFragPtr(0), rxDescCnt(0), rxDmaState(dmaIdle), extstsEnable(false), 1156657Snate@binkert.org rxDmaReadEvent(this), rxDmaWriteEvent(this), 1166657Snate@binkert.org txDmaReadEvent(this), txDmaWriteEvent(this), 1176657Snate@binkert.org dmaDescFree(dma_desc_free), dmaDataFree(dma_data_free), 1186657Snate@binkert.org txDelay(tx_delay), rxDelay(rx_delay), rxKickTick(0), txKickTick(0), 1196657Snate@binkert.org txEvent(this), rxFilterEnable(rx_filter), acceptBroadcast(false), 1207839Snilay@cs.wisc.edu acceptMulticast(false), acceptUnicast(false), 1217839Snilay@cs.wisc.edu acceptPerfect(false), acceptArp(false), 1227839Snilay@cs.wisc.edu physmem(pmem), intctrl(i), intrTick(0), cpuPendingIntr(false), 1237839Snilay@cs.wisc.edu intrEvent(0), interface(0) 1247839Snilay@cs.wisc.edu{ 1257839Snilay@cs.wisc.edu tsunami->ethernet = this; 1267839Snilay@cs.wisc.edu 1277839Snilay@cs.wisc.edu if (header_bus) { 1287839Snilay@cs.wisc.edu pioInterface = newPioInterface(name, hier, header_bus, this, 1297839Snilay@cs.wisc.edu &NSGigE::cacheAccess); 1307839Snilay@cs.wisc.edu 1317839Snilay@cs.wisc.edu pioLatency = pio_latency * header_bus->clockRatio; 1327839Snilay@cs.wisc.edu 1337839Snilay@cs.wisc.edu if (payload_bus) 1347839Snilay@cs.wisc.edu dmaInterface = new DMAInterface<Bus>(name + ".dma", 1356657Snate@binkert.org header_bus, payload_bus, 1); 1366657Snate@binkert.org else 1376657Snate@binkert.org dmaInterface = new DMAInterface<Bus>(name + ".dma", 1386657Snate@binkert.org header_bus, header_bus, 1); 1396657Snate@binkert.org } else if (payload_bus) { 1406657Snate@binkert.org pioInterface = newPioInterface(name, hier, payload_bus, this, 1416657Snate@binkert.org &NSGigE::cacheAccess); 1426657Snate@binkert.org 1436657Snate@binkert.org pioLatency = pio_latency * payload_bus->clockRatio; 1446657Snate@binkert.org 1456657Snate@binkert.org dmaInterface = new DMAInterface<Bus>(name + ".dma", payload_bus, 1466657Snate@binkert.org payload_bus, 1); 1476657Snate@binkert.org } 1486657Snate@binkert.org 1496657Snate@binkert.org 1506657Snate@binkert.org intrDelay = US2Ticks(intr_delay); 1516657Snate@binkert.org dmaReadDelay = dma_read_delay; 1526657Snate@binkert.org dmaWriteDelay = dma_write_delay; 1536657Snate@binkert.org dmaReadFactor = dma_read_factor; 1546657Snate@binkert.org dmaWriteFactor = dma_write_factor; 1556657Snate@binkert.org 1566657Snate@binkert.org regsReset(); 1576657Snate@binkert.org rom.perfectMatch[0] = eaddr[0]; 1586657Snate@binkert.org rom.perfectMatch[1] = eaddr[1]; 1596657Snate@binkert.org rom.perfectMatch[2] = eaddr[2]; 1606657Snate@binkert.org rom.perfectMatch[3] = eaddr[3]; 1616657Snate@binkert.org rom.perfectMatch[4] = eaddr[4]; 1626657Snate@binkert.org rom.perfectMatch[5] = eaddr[5]; 1636657Snate@binkert.org} 1646657Snate@binkert.org 1659219Spower.jg@gmail.comNSGigE::~NSGigE() 1666877Ssteve.reinhardt@amd.com{} 1676657Snate@binkert.org 1689219Spower.jg@gmail.comvoid 1696657Snate@binkert.orgNSGigE::regStats() 1709219Spower.jg@gmail.com{ 1716657Snate@binkert.org txBytes 1726657Snate@binkert.org .name(name() + ".txBytes") 1737542SBrad.Beckmann@amd.com .desc("Bytes Transmitted") 1747542SBrad.Beckmann@amd.com .prereq(txBytes) 1756657Snate@binkert.org ; 1766877Ssteve.reinhardt@amd.com 1776999Snate@binkert.org rxBytes 1786877Ssteve.reinhardt@amd.com .name(name() + ".rxBytes") 1796877Ssteve.reinhardt@amd.com .desc("Bytes Received") 1806877Ssteve.reinhardt@amd.com .prereq(rxBytes) 1816877Ssteve.reinhardt@amd.com ; 1826877Ssteve.reinhardt@amd.com 1836877Ssteve.reinhardt@amd.com txPackets 1846877Ssteve.reinhardt@amd.com .name(name() + ".txPackets") 1856877Ssteve.reinhardt@amd.com .desc("Number of Packets Transmitted") 1866877Ssteve.reinhardt@amd.com .prereq(txBytes) 1876877Ssteve.reinhardt@amd.com ; 1886877Ssteve.reinhardt@amd.com 1896877Ssteve.reinhardt@amd.com rxPackets 1906877Ssteve.reinhardt@amd.com .name(name() + ".rxPackets") 1916877Ssteve.reinhardt@amd.com .desc("Number of Packets Received") 1926877Ssteve.reinhardt@amd.com .prereq(rxBytes) 1936877Ssteve.reinhardt@amd.com ; 1946882SBrad.Beckmann@amd.com 1956882SBrad.Beckmann@amd.com txIPChecksums 1966882SBrad.Beckmann@amd.com .name(name() + ".txIPChecksums") 1976882SBrad.Beckmann@amd.com .desc("Number of tx IP Checksums done by device") 1986882SBrad.Beckmann@amd.com .precision(0) 1996882SBrad.Beckmann@amd.com .prereq(txBytes) 2006882SBrad.Beckmann@amd.com ; 2016877Ssteve.reinhardt@amd.com 2026877Ssteve.reinhardt@amd.com rxIPChecksums 2036877Ssteve.reinhardt@amd.com .name(name() + ".rxIPChecksums") 2046877Ssteve.reinhardt@amd.com .desc("Number of rx IP Checksums done by device") 2056657Snate@binkert.org .precision(0) 2066657Snate@binkert.org .prereq(rxBytes) 2076999Snate@binkert.org ; 2086657Snate@binkert.org 2096657Snate@binkert.org txTCPChecksums 2106657Snate@binkert.org .name(name() + ".txTCPChecksums") 2116657Snate@binkert.org .desc("Number of tx TCP Checksums done by device") 2126657Snate@binkert.org .precision(0) 2136657Snate@binkert.org .prereq(txBytes) 2147007Snate@binkert.org ; 2156657Snate@binkert.org 2166657Snate@binkert.org rxTCPChecksums 2176657Snate@binkert.org .name(name() + ".rxTCPChecksums") 2186657Snate@binkert.org .desc("Number of rx TCP Checksums done by device") 2196657Snate@binkert.org .precision(0) 2207007Snate@binkert.org .prereq(rxBytes) 2217007Snate@binkert.org ; 2226657Snate@binkert.org 2237002Snate@binkert.org descDmaReads 2247002Snate@binkert.org .name(name() + ".descDMAReads") 2257002Snate@binkert.org .desc("Number of descriptors the device read w/ DMA") 2267002Snate@binkert.org .precision(0) 2278229Snate@binkert.org ; 2288229Snate@binkert.org 2296657Snate@binkert.org descDmaWrites 2306657Snate@binkert.org .name(name() + ".descDMAWrites") 2318229Snate@binkert.org .desc("Number of descriptors the device wrote w/ DMA") 2328229Snate@binkert.org .precision(0) 2338229Snate@binkert.org ; 2348229Snate@binkert.org 2356657Snate@binkert.org descDmaRdBytes 2366657Snate@binkert.org .name(name() + ".descDmaReadBytes") 2376657Snate@binkert.org .desc("number of descriptor bytes read w/ DMA") 2386657Snate@binkert.org .precision(0) 2396793SBrad.Beckmann@amd.com ; 2406657Snate@binkert.org 2416657Snate@binkert.org descDmaWrBytes 2426657Snate@binkert.org .name(name() + ".descDmaWriteBytes") 2436657Snate@binkert.org .desc("number of descriptor bytes write w/ DMA") 2446657Snate@binkert.org .precision(0) 2457002Snate@binkert.org ; 2466657Snate@binkert.org 2477007Snate@binkert.org 2487007Snate@binkert.org txBandwidth 2499271Snilay@cs.wisc.edu .name(name() + ".txBandwidth") 2506877Ssteve.reinhardt@amd.com .desc("Transmit Bandwidth (bits/s)") 2516877Ssteve.reinhardt@amd.com .precision(0) 2526657Snate@binkert.org .prereq(txBytes) 2536877Ssteve.reinhardt@amd.com ; 2546657Snate@binkert.org 2556657Snate@binkert.org rxBandwidth 2567002Snate@binkert.org .name(name() + ".rxBandwidth") 2577002Snate@binkert.org .desc("Receive Bandwidth (bits/s)") 2587567SBrad.Beckmann@amd.com .precision(0) 2597567SBrad.Beckmann@amd.com .prereq(rxBytes) 2607922SBrad.Beckmann@amd.com ; 2616881SBrad.Beckmann@amd.com 2627002Snate@binkert.org txPacketRate 2637002Snate@binkert.org .name(name() + ".txPPS") 2646657Snate@binkert.org .desc("Packet Tranmission Rate (packets/s)") 2657002Snate@binkert.org .precision(0) 2666902SBrad.Beckmann@amd.com .prereq(txBytes) 2676863Sdrh5@cs.wisc.edu ; 2686863Sdrh5@cs.wisc.edu 2698683Snilay@cs.wisc.edu rxPacketRate 2708683Snilay@cs.wisc.edu .name(name() + ".rxPPS") 2717007Snate@binkert.org .desc("Packet Reception Rate (packets/s)") 2729302Snilay@cs.wisc.edu .precision(0) 2739302Snilay@cs.wisc.edu .prereq(rxBytes) 2749302Snilay@cs.wisc.edu ; 2756657Snate@binkert.org 2766657Snate@binkert.org txBandwidth = txBytes * Stats::constant(8) / simSeconds; 2776657Snate@binkert.org rxBandwidth = rxBytes * Stats::constant(8) / simSeconds; 2786657Snate@binkert.org txPacketRate = txPackets / simSeconds; 2796657Snate@binkert.org rxPacketRate = rxPackets / simSeconds; 2806657Snate@binkert.org} 2816882SBrad.Beckmann@amd.com 2826882SBrad.Beckmann@amd.com/** 2836882SBrad.Beckmann@amd.com * This is to read the PCI general configuration registers 2846882SBrad.Beckmann@amd.com */ 2856657Snate@binkert.orgvoid 2866657Snate@binkert.orgNSGigE::ReadConfig(int offset, int size, uint8_t *data) 2876657Snate@binkert.org{ 2886657Snate@binkert.org if (offset < PCI_DEVICE_SPECIFIC) 2897007Snate@binkert.org PciDev::ReadConfig(offset, size, data); 2907839Snilay@cs.wisc.edu else 2917839Snilay@cs.wisc.edu panic("Device specific PCI config space not implemented!\n"); 2927839Snilay@cs.wisc.edu} 2937839Snilay@cs.wisc.edu 2947839Snilay@cs.wisc.edu/** 2957839Snilay@cs.wisc.edu * This is to write to the PCI general configuration registers 2967839Snilay@cs.wisc.edu */ 2977839Snilay@cs.wisc.eduvoid 2987839Snilay@cs.wisc.eduNSGigE::WriteConfig(int offset, int size, uint32_t data) 2997839Snilay@cs.wisc.edu{ 3007839Snilay@cs.wisc.edu if (offset < PCI_DEVICE_SPECIFIC) 3017839Snilay@cs.wisc.edu PciDev::WriteConfig(offset, size, data); 3027007Snate@binkert.org else 3037007Snate@binkert.org panic("Device specific PCI config space not implemented!\n"); 3047007Snate@binkert.org 3057007Snate@binkert.org // Need to catch writes to BARs to update the PIO interface 3067007Snate@binkert.org switch (offset) { 3077839Snilay@cs.wisc.edu //seems to work fine without all these PCI settings, but i put in the IO 3087839Snilay@cs.wisc.edu //to double check, an assertion will fail if we need to properly 3097839Snilay@cs.wisc.edu // implement it 3107839Snilay@cs.wisc.edu case PCI_COMMAND: 3117839Snilay@cs.wisc.edu if (config.data[offset] & PCI_CMD_IOSE) 3127839Snilay@cs.wisc.edu ioEnable = true; 3137839Snilay@cs.wisc.edu else 3147839Snilay@cs.wisc.edu ioEnable = false; 3157839Snilay@cs.wisc.edu 3167839Snilay@cs.wisc.edu#if 0 3177839Snilay@cs.wisc.edu if (config.data[offset] & PCI_CMD_BME) { 3187839Snilay@cs.wisc.edu bmEnabled = true; 3197007Snate@binkert.org } 3207007Snate@binkert.org else { 3217002Snate@binkert.org bmEnabled = false; 3226657Snate@binkert.org } 3236657Snate@binkert.org 3246657Snate@binkert.org if (config.data[offset] & PCI_CMD_MSE) { 3257055Snate@binkert.org memEnable = true; 3266657Snate@binkert.org } 3276657Snate@binkert.org else { 3286657Snate@binkert.org memEnable = false; 3296863Sdrh5@cs.wisc.edu } 3307055Snate@binkert.org#endif 3317567SBrad.Beckmann@amd.com break; 3328943Sandreas.hansson@arm.com 3337567SBrad.Beckmann@amd.com case PCI0_BASE_ADDR0: 3347567SBrad.Beckmann@amd.com if (BARAddrs[0] != 0) { 3357567SBrad.Beckmann@amd.com 3367542SBrad.Beckmann@amd.com if (pioInterface) 3377542SBrad.Beckmann@amd.com pioInterface->addAddrRange(BARAddrs[0], BARAddrs[0] + BARSize[0] - 1); 3386657Snate@binkert.org 3397007Snate@binkert.org BARAddrs[0] &= PA_UNCACHED_MASK; 3406657Snate@binkert.org 3416657Snate@binkert.org } 3426657Snate@binkert.org break; 3436657Snate@binkert.org case PCI0_BASE_ADDR1: 3446657Snate@binkert.org if (BARAddrs[1] != 0) { 3456657Snate@binkert.org 3466657Snate@binkert.org if (pioInterface) 3476657Snate@binkert.org pioInterface->addAddrRange(BARAddrs[1], BARAddrs[1] + BARSize[1] - 1); 3487839Snilay@cs.wisc.edu 3497839Snilay@cs.wisc.edu BARAddrs[1] &= PA_UNCACHED_MASK; 3507839Snilay@cs.wisc.edu 3517839Snilay@cs.wisc.edu } 3527839Snilay@cs.wisc.edu break; 3537839Snilay@cs.wisc.edu } 3547839Snilay@cs.wisc.edu} 3557839Snilay@cs.wisc.edu 3567839Snilay@cs.wisc.edu/** 3577839Snilay@cs.wisc.edu * This reads the device registers, which are detailed in the NS83820 3587839Snilay@cs.wisc.edu * spec sheet 3597839Snilay@cs.wisc.edu */ 3607839Snilay@cs.wisc.eduFault 3617839Snilay@cs.wisc.eduNSGigE::read(MemReqPtr &req, uint8_t *data) 3627839Snilay@cs.wisc.edu{ 3637839Snilay@cs.wisc.edu assert(ioEnable); 3646657Snate@binkert.org 3656657Snate@binkert.org //The mask is to give you only the offset into the device register file 3666657Snate@binkert.org Addr daddr = req->paddr & 0xfff; 3676657Snate@binkert.org DPRINTF(EthernetPIO, "read da=%#x pa=%#x va=%#x size=%d\n", 3687839Snilay@cs.wisc.edu daddr, req->paddr, req->vaddr, req->size); 3697839Snilay@cs.wisc.edu 3707839Snilay@cs.wisc.edu 3717839Snilay@cs.wisc.edu //there are some reserved registers, you can see ns_gige_reg.h and 3727839Snilay@cs.wisc.edu //the spec sheet for details 3737839Snilay@cs.wisc.edu if (daddr > LAST && daddr <= RESERVED) { 3747839Snilay@cs.wisc.edu panic("Accessing reserved register"); 3757839Snilay@cs.wisc.edu } else if (daddr > RESERVED && daddr <= 0x3FC) { 3767839Snilay@cs.wisc.edu ReadConfig(daddr & 0xff, req->size, data); 3777839Snilay@cs.wisc.edu return No_Fault; 3787839Snilay@cs.wisc.edu } else if (daddr >= MIB_START && daddr <= MIB_END) { 3797839Snilay@cs.wisc.edu // don't implement all the MIB's. hopefully the kernel 3807839Snilay@cs.wisc.edu // doesn't actually DEPEND upon their values 3817839Snilay@cs.wisc.edu // MIB are just hardware stats keepers 3827839Snilay@cs.wisc.edu uint32_t ® = *(uint32_t *) data; 3837839Snilay@cs.wisc.edu reg = 0; 3846657Snate@binkert.org return No_Fault; 3856657Snate@binkert.org } else if (daddr > 0x3FC) 3866657Snate@binkert.org panic("Something is messed up!\n"); 3876657Snate@binkert.org 3887007Snate@binkert.org switch (req->size) { 3896657Snate@binkert.org case sizeof(uint32_t): 3906657Snate@binkert.org { 3919273Snilay@cs.wisc.edu uint32_t ® = *(uint32_t *)data; 3926657Snate@binkert.org 3936657Snate@binkert.org switch (daddr) { 3946657Snate@binkert.org case CR: 3956657Snate@binkert.org reg = regs.command; 3966657Snate@binkert.org //these are supposed to be cleared on a read 3976657Snate@binkert.org reg &= ~(CR_RXD | CR_TXD | CR_TXR | CR_RXR); 3986657Snate@binkert.org break; 3997007Snate@binkert.org 4006657Snate@binkert.org case CFG: 4016657Snate@binkert.org reg = regs.config; 4029219Spower.jg@gmail.com break; 4036657Snate@binkert.org 4046657Snate@binkert.org case MEAR: 4056999Snate@binkert.org reg = regs.mear; 4066657Snate@binkert.org break; 4076657Snate@binkert.org 4086657Snate@binkert.org case PTSCR: 4096657Snate@binkert.org reg = regs.ptscr; 4107007Snate@binkert.org break; 4116657Snate@binkert.org 4126657Snate@binkert.org case ISR: 4136657Snate@binkert.org reg = regs.isr; 4146657Snate@binkert.org devIntrClear(ISR_ALL); 4156657Snate@binkert.org break; 4168946Sandreas.hansson@arm.com 4178946Sandreas.hansson@arm.com case IMR: 4188946Sandreas.hansson@arm.com reg = regs.imr; 4197832Snate@binkert.org break; 4207002Snate@binkert.org 4217002Snate@binkert.org case IER: 4227002Snate@binkert.org reg = regs.ier; 4238641Snate@binkert.org break; 4247056Snate@binkert.org 4258232Snate@binkert.org case IHR: 4268232Snate@binkert.org reg = regs.ihr; 4276657Snate@binkert.org break; 4288229Snate@binkert.org 4296657Snate@binkert.org case TXDP: 4306657Snate@binkert.org reg = regs.txdp; 4317056Snate@binkert.org break; 4326657Snate@binkert.org 4339219Spower.jg@gmail.com case TXDP_HI: 4349219Spower.jg@gmail.com reg = regs.txdp_hi; 4359219Spower.jg@gmail.com break; 4369219Spower.jg@gmail.com 4379219Spower.jg@gmail.com case TXCFG: 4387002Snate@binkert.org reg = regs.txcfg; 4397002Snate@binkert.org break; 4406657Snate@binkert.org 4416657Snate@binkert.org case GPIOR: 4426657Snate@binkert.org reg = regs.gpior; 4436657Snate@binkert.org break; 4446657Snate@binkert.org 4456793SBrad.Beckmann@amd.com case RXDP: 4466657Snate@binkert.org reg = regs.rxdp; 4476657Snate@binkert.org break; 4486657Snate@binkert.org 4496657Snate@binkert.org case RXDP_HI: 4506877Ssteve.reinhardt@amd.com reg = regs.rxdp_hi; 4516877Ssteve.reinhardt@amd.com break; 4526877Ssteve.reinhardt@amd.com 4536877Ssteve.reinhardt@amd.com case RXCFG: 4546877Ssteve.reinhardt@amd.com reg = regs.rxcfg; 4556877Ssteve.reinhardt@amd.com break; 4566657Snate@binkert.org 4577542SBrad.Beckmann@amd.com case PQCR: 4586657Snate@binkert.org reg = regs.pqcr; 4597007Snate@binkert.org break; 4606657Snate@binkert.org 4616657Snate@binkert.org case WCSR: 4627007Snate@binkert.org reg = regs.wcsr; 4636657Snate@binkert.org break; 4646877Ssteve.reinhardt@amd.com 4656877Ssteve.reinhardt@amd.com case PCR: 4666657Snate@binkert.org reg = regs.pcr; 4676877Ssteve.reinhardt@amd.com break; 4686877Ssteve.reinhardt@amd.com 4696877Ssteve.reinhardt@amd.com //see the spec sheet for how RFCR and RFDR work 4706877Ssteve.reinhardt@amd.com //basically, you write to RFCR to tell the machine what you want to do next 4716877Ssteve.reinhardt@amd.com //then you act upon RFDR, and the device will be prepared b/c 4726969SBrad.Beckmann@amd.com //of what you wrote to RFCR 4738532SLisa.Hsu@amd.com case RFCR: 4746657Snate@binkert.org reg = regs.rfcr; 4757567SBrad.Beckmann@amd.com break; 4767567SBrad.Beckmann@amd.com 4777567SBrad.Beckmann@amd.com case RFDR: 4787567SBrad.Beckmann@amd.com switch (regs.rfcr & RFCR_RFADDR) { 4797567SBrad.Beckmann@amd.com case 0x000: 4807567SBrad.Beckmann@amd.com reg = rom.perfectMatch[1]; 4816657Snate@binkert.org reg = reg << 8; 4826882SBrad.Beckmann@amd.com reg += rom.perfectMatch[0]; 4836882SBrad.Beckmann@amd.com break; 4846882SBrad.Beckmann@amd.com case 0x002: 4856882SBrad.Beckmann@amd.com reg = rom.perfectMatch[3] << 8; 4866882SBrad.Beckmann@amd.com reg += rom.perfectMatch[2]; 4876882SBrad.Beckmann@amd.com break; 4886882SBrad.Beckmann@amd.com case 0x004: 4898189SLisa.Hsu@amd.com reg = rom.perfectMatch[5] << 8; 4908189SLisa.Hsu@amd.com reg += rom.perfectMatch[4]; 4916877Ssteve.reinhardt@amd.com break; 4928189SLisa.Hsu@amd.com default: 4938189SLisa.Hsu@amd.com panic("reading from RFDR for something for other than PMATCH!\n"); 4948189SLisa.Hsu@amd.com //didn't implement other RFDR functionality b/c driver didn't use 4958189SLisa.Hsu@amd.com } 4966882SBrad.Beckmann@amd.com break; 4976882SBrad.Beckmann@amd.com 4986882SBrad.Beckmann@amd.com case SRR: 4996882SBrad.Beckmann@amd.com reg = regs.srr; 5006882SBrad.Beckmann@amd.com break; 5016882SBrad.Beckmann@amd.com 5026882SBrad.Beckmann@amd.com case MIBC: 5036882SBrad.Beckmann@amd.com reg = regs.mibc; 5046882SBrad.Beckmann@amd.com reg &= ~(MIBC_MIBS | MIBC_ACLR); 5056882SBrad.Beckmann@amd.com break; 5068189SLisa.Hsu@amd.com 5076882SBrad.Beckmann@amd.com case VRCR: 5086882SBrad.Beckmann@amd.com reg = regs.vrcr; 5096882SBrad.Beckmann@amd.com break; 5108189SLisa.Hsu@amd.com 5118189SLisa.Hsu@amd.com case VTCR: 5128189SLisa.Hsu@amd.com reg = regs.vtcr; 5138189SLisa.Hsu@amd.com break; 5148938SLisa.Hsu@amd.com 5158938SLisa.Hsu@amd.com case VDR: 5168938SLisa.Hsu@amd.com reg = regs.vdr; 5178938SLisa.Hsu@amd.com break; 5188938SLisa.Hsu@amd.com 5198938SLisa.Hsu@amd.com case CCSR: 5208938SLisa.Hsu@amd.com reg = regs.ccsr; 5216888SBrad.Beckmann@amd.com break; 5226888SBrad.Beckmann@amd.com 5236888SBrad.Beckmann@amd.com case TBICR: 5246888SBrad.Beckmann@amd.com reg = regs.tbicr; 5256888SBrad.Beckmann@amd.com break; 5268189SLisa.Hsu@amd.com 5276888SBrad.Beckmann@amd.com case TBISR: 5286888SBrad.Beckmann@amd.com reg = regs.tbisr; 5296657Snate@binkert.org break; 5306888SBrad.Beckmann@amd.com 5316888SBrad.Beckmann@amd.com case TANAR: 5326888SBrad.Beckmann@amd.com reg = regs.tanar; 5336888SBrad.Beckmann@amd.com break; 5346657Snate@binkert.org 5356657Snate@binkert.org case TANLPAR: 5366657Snate@binkert.org reg = regs.tanlpar; 5376657Snate@binkert.org break; 5386657Snate@binkert.org 5396657Snate@binkert.org case TANER: 5406657Snate@binkert.org reg = regs.taner; 5416657Snate@binkert.org break; 5426657Snate@binkert.org 5437007Snate@binkert.org case TESR: 5447007Snate@binkert.org reg = regs.tesr; 5456657Snate@binkert.org break; 5467007Snate@binkert.org 5477007Snate@binkert.org default: 5487007Snate@binkert.org panic("reading unimplemented register: addr = %#x", daddr); 5496657Snate@binkert.org } 5506657Snate@binkert.org 5516657Snate@binkert.org DPRINTF(EthernetPIO, "read from %#x: data=%d data=%#x\n", 5527007Snate@binkert.org daddr, reg, reg); 5537542SBrad.Beckmann@amd.com } 5547542SBrad.Beckmann@amd.com break; 5557007Snate@binkert.org 5566657Snate@binkert.org default: 5576657Snate@binkert.org panic("accessing register with invalid size: addr=%#x, size=%d", 5586657Snate@binkert.org daddr, req->size); 5596657Snate@binkert.org } 5606657Snate@binkert.org 5616657Snate@binkert.org return No_Fault; 5626657Snate@binkert.org} 5636657Snate@binkert.org 5646657Snate@binkert.orgFault 5656657Snate@binkert.orgNSGigE::write(MemReqPtr &req, const uint8_t *data) 5666657Snate@binkert.org{ 5676657Snate@binkert.org assert(ioEnable); 5686657Snate@binkert.org 5696657Snate@binkert.org Addr daddr = req->paddr & 0xfff; 5706657Snate@binkert.org DPRINTF(EthernetPIO, "write da=%#x pa=%#x va=%#x size=%d\n", 5716657Snate@binkert.org daddr, req->paddr, req->vaddr, req->size); 5726657Snate@binkert.org 5736657Snate@binkert.org if (daddr > LAST && daddr <= RESERVED) { 5749273Snilay@cs.wisc.edu panic("Accessing reserved register"); 5756657Snate@binkert.org } else if (daddr > RESERVED && daddr <= 0x3FC) { 5766657Snate@binkert.org WriteConfig(daddr & 0xff, req->size, *(uint32_t *)data); 5776657Snate@binkert.org return No_Fault; 5786657Snate@binkert.org } else if (daddr > 0x3FC) 5796657Snate@binkert.org panic("Something is messed up!\n"); 5806657Snate@binkert.org 5816657Snate@binkert.org if (req->size == sizeof(uint32_t)) { 5826657Snate@binkert.org uint32_t reg = *(uint32_t *)data; 5836657Snate@binkert.org DPRINTF(EthernetPIO, "write data=%d data=%#x\n", reg, reg); 5847007Snate@binkert.org 5856657Snate@binkert.org switch (daddr) { 5866657Snate@binkert.org case CR: 5876657Snate@binkert.org regs.command = reg; 5886657Snate@binkert.org if ((reg & (CR_TXE | CR_TXD)) == (CR_TXE | CR_TXD)) { 5897007Snate@binkert.org txHalt = true; 5906657Snate@binkert.org } else if (reg & CR_TXE) { 5917007Snate@binkert.org //the kernel is enabling the transmit machine 5927007Snate@binkert.org if (txState == txIdle) 5936657Snate@binkert.org txKick(); 5946657Snate@binkert.org } else if (reg & CR_TXD) { 5956657Snate@binkert.org txHalt = true; 5966657Snate@binkert.org } 5976657Snate@binkert.org 5986657Snate@binkert.org if ((reg & (CR_RXE | CR_RXD)) == (CR_RXE | CR_RXD)) { 5996657Snate@binkert.org rxHalt = true; 6006657Snate@binkert.org } else if (reg & CR_RXE) { 6016657Snate@binkert.org if (rxState == rxIdle) { 6026657Snate@binkert.org rxKick(); 6036657Snate@binkert.org } 6046657Snate@binkert.org } else if (reg & CR_RXD) { 6056657Snate@binkert.org rxHalt = true; 6066657Snate@binkert.org } 6076657Snate@binkert.org 6087566SBrad.Beckmann@amd.com if (reg & CR_TXR) 6096657Snate@binkert.org txReset(); 6106657Snate@binkert.org 6116657Snate@binkert.org if (reg & CR_RXR) 6126657Snate@binkert.org rxReset(); 6136657Snate@binkert.org 6148308Stushar@csail.mit.edu if (reg & CR_SWI) 6156657Snate@binkert.org devIntrPost(ISR_SWI); 6166657Snate@binkert.org 6176657Snate@binkert.org if (reg & CR_RST) { 6187007Snate@binkert.org txReset(); 6197007Snate@binkert.org rxReset(); 6208308Stushar@csail.mit.edu 6216657Snate@binkert.org regsReset(); 6226657Snate@binkert.org } 6236657Snate@binkert.org break; 6246657Snate@binkert.org 6256657Snate@binkert.org case CFG: 6266657Snate@binkert.org if (reg & CFG_LNKSTS || reg & CFG_SPDSTS || reg & CFG_DUPSTS 6276657Snate@binkert.org || reg & CFG_RESERVED || reg & CFG_T64ADDR 6286657Snate@binkert.org || reg & CFG_PCI64_DET) 6296657Snate@binkert.org panic("writing to read-only or reserved CFG bits!\n"); 6306657Snate@binkert.org 6316657Snate@binkert.org regs.config |= reg & ~(CFG_LNKSTS | CFG_SPDSTS | CFG_DUPSTS | CFG_RESERVED | 6326657Snate@binkert.org CFG_T64ADDR | CFG_PCI64_DET); 6338187SLisa.Hsu@amd.com 6346657Snate@binkert.org// all these #if 0's are because i don't THINK the kernel needs to have these implemented 6356657Snate@binkert.org// if there is a problem relating to one of these, you may need to add functionality in 6366657Snate@binkert.org#if 0 6376657Snate@binkert.org if (reg & CFG_TBI_EN) ; 6386657Snate@binkert.org if (reg & CFG_MODE_1000) ; 6396657Snate@binkert.org#endif 6406657Snate@binkert.org 6416657Snate@binkert.org if (reg & CFG_AUTO_1000) 6426657Snate@binkert.org panic("CFG_AUTO_1000 not implemented!\n"); 6437454Snate@binkert.org 6446657Snate@binkert.org#if 0 6456657Snate@binkert.org if (reg & CFG_PINT_DUPSTS || reg & CFG_PINT_LNKSTS || reg & CFG_PINT_SPDSTS) ; 6466657Snate@binkert.org if (reg & CFG_TMRTEST) ; 6476657Snate@binkert.org if (reg & CFG_MRM_DIS) ; 6487007Snate@binkert.org if (reg & CFG_MWI_DIS) ; 6497056Snate@binkert.org 6507007Snate@binkert.org if (reg & CFG_T64ADDR) 6517007Snate@binkert.org panic("CFG_T64ADDR is read only register!\n"); 6526657Snate@binkert.org 6537566SBrad.Beckmann@amd.com if (reg & CFG_PCI64_DET) 6547566SBrad.Beckmann@amd.com panic("CFG_PCI64_DET is read only register!\n"); 6557566SBrad.Beckmann@amd.com 6567566SBrad.Beckmann@amd.com if (reg & CFG_DATA64_EN) ; 6577566SBrad.Beckmann@amd.com if (reg & CFG_M64ADDR) ; 6587566SBrad.Beckmann@amd.com if (reg & CFG_PHY_RST) ; 6597566SBrad.Beckmann@amd.com if (reg & CFG_PHY_DIS) ; 6606657Snate@binkert.org#endif 6617672Snate@binkert.org 6626657Snate@binkert.org if (reg & CFG_EXTSTS_EN) 6636657Snate@binkert.org extstsEnable = true; 6646657Snate@binkert.org else 6656657Snate@binkert.org extstsEnable = false; 6667672Snate@binkert.org 6676657Snate@binkert.org#if 0 6687056Snate@binkert.org if (reg & CFG_REQALG) ; 6696657Snate@binkert.org if (reg & CFG_SB) ; 6706657Snate@binkert.org if (reg & CFG_POW) ; 6717672Snate@binkert.org if (reg & CFG_EXD) ; 6726657Snate@binkert.org if (reg & CFG_PESEL) ; 6736657Snate@binkert.org if (reg & CFG_BROM_DIS) ; 6746657Snate@binkert.org if (reg & CFG_EXT_125) ; 6756657Snate@binkert.org if (reg & CFG_BEM) ; 6766657Snate@binkert.org#endif 6776657Snate@binkert.org break; 6786657Snate@binkert.org 6796657Snate@binkert.org case MEAR: 6806657Snate@binkert.org regs.mear = reg; 6816657Snate@binkert.org /* since phy is completely faked, MEAR_MD* don't matter 6826657Snate@binkert.org and since the driver never uses MEAR_EE*, they don't matter */ 6837542SBrad.Beckmann@amd.com#if 0 6846657Snate@binkert.org if (reg & MEAR_EEDI) ; 6856657Snate@binkert.org if (reg & MEAR_EEDO) ; //this one is read only 6866657Snate@binkert.org if (reg & MEAR_EECLK) ; 6876657Snate@binkert.org if (reg & MEAR_EESEL) ; 6886657Snate@binkert.org if (reg & MEAR_MDIO) ; 6896657Snate@binkert.org if (reg & MEAR_MDDIR) ; 6906657Snate@binkert.org if (reg & MEAR_MDC) ; 6916657Snate@binkert.org#endif 6926657Snate@binkert.org break; 6936657Snate@binkert.org 6946657Snate@binkert.org case PTSCR: 6956657Snate@binkert.org regs.ptscr = reg & ~(PTSCR_RBIST_RDONLY); 6966657Snate@binkert.org /* these control BISTs for various parts of chip - we don't care or do 6976657Snate@binkert.org just fake that the BIST is done */ 6988683Snilay@cs.wisc.edu if (reg & PTSCR_RBIST_EN) 6998683Snilay@cs.wisc.edu regs.ptscr |= PTSCR_RBIST_DONE; 7008683Snilay@cs.wisc.edu if (reg & PTSCR_EEBIST_EN) 7018683Snilay@cs.wisc.edu regs.ptscr &= ~PTSCR_EEBIST_EN; 7028683Snilay@cs.wisc.edu if (reg & PTSCR_EELOAD_EN) 7038683Snilay@cs.wisc.edu regs.ptscr &= ~PTSCR_EELOAD_EN; 7046657Snate@binkert.org break; 7057007Snate@binkert.org 7067007Snate@binkert.org case ISR: /* writing to the ISR has no effect */ 7077007Snate@binkert.org panic("ISR is a read only register!\n"); 7086657Snate@binkert.org 7096657Snate@binkert.org case IMR: 7106657Snate@binkert.org regs.imr = reg; 7117007Snate@binkert.org devIntrChangeMask(); 7127007Snate@binkert.org break; 7137007Snate@binkert.org 7146657Snate@binkert.org case IER: 7156657Snate@binkert.org regs.ier = reg; 7166657Snate@binkert.org break; 7178683Snilay@cs.wisc.edu 7188683Snilay@cs.wisc.edu case IHR: 7198683Snilay@cs.wisc.edu regs.ihr = reg; 7208683Snilay@cs.wisc.edu /* not going to implement real interrupt holdoff */ 7218683Snilay@cs.wisc.edu break; 7228683Snilay@cs.wisc.edu 7237007Snate@binkert.org case TXDP: 7247007Snate@binkert.org regs.txdp = (reg & 0xFFFFFFFC); 7257007Snate@binkert.org assert(txState == txIdle); 7266657Snate@binkert.org CTDD = false; 7276657Snate@binkert.org break; 7286657Snate@binkert.org 7297007Snate@binkert.org case TXDP_HI: 7307007Snate@binkert.org regs.txdp_hi = reg; 7317007Snate@binkert.org break; 7326657Snate@binkert.org 7336657Snate@binkert.org case TXCFG: 7346657Snate@binkert.org regs.txcfg = reg; 7357007Snate@binkert.org#if 0 7367007Snate@binkert.org if (reg & TXCFG_CSI) ; 7377007Snate@binkert.org if (reg & TXCFG_HBI) ; 7386657Snate@binkert.org if (reg & TXCFG_MLB) ; 7396657Snate@binkert.org if (reg & TXCFG_ATP) ; 7407007Snate@binkert.org if (reg & TXCFG_ECRETRY) ; /* this could easily be implemented, but 7417007Snate@binkert.org considering the network is just a fake 7427567SBrad.Beckmann@amd.com pipe, wouldn't make sense to do this */ 7437567SBrad.Beckmann@amd.com 7447567SBrad.Beckmann@amd.com if (reg & TXCFG_BRST_DIS) ; 7457567SBrad.Beckmann@amd.com#endif 7467567SBrad.Beckmann@amd.com 7477567SBrad.Beckmann@amd.com 7487567SBrad.Beckmann@amd.com /* we handle our own DMA, ignore the kernel's exhortations */ 7497567SBrad.Beckmann@amd.com //if (reg & TXCFG_MXDMA) ; 7507567SBrad.Beckmann@amd.com 7517567SBrad.Beckmann@amd.com //also, we currently don't care about fill/drain thresholds 7527567SBrad.Beckmann@amd.com //though this may change in the future with more realistic 7537567SBrad.Beckmann@amd.com //networks or a driver which changes it according to feedback 7547567SBrad.Beckmann@amd.com 7558155Snilay@cs.wisc.edu break; 7568155Snilay@cs.wisc.edu 7578155Snilay@cs.wisc.edu case GPIOR: 7588155Snilay@cs.wisc.edu regs.gpior = reg; 7598155Snilay@cs.wisc.edu /* these just control general purpose i/o pins, don't matter */ 7608155Snilay@cs.wisc.edu break; 7618155Snilay@cs.wisc.edu 7628155Snilay@cs.wisc.edu case RXDP: 7638155Snilay@cs.wisc.edu regs.rxdp = reg; 7648155Snilay@cs.wisc.edu break; 7658155Snilay@cs.wisc.edu 7667567SBrad.Beckmann@amd.com case RXDP_HI: 7678155Snilay@cs.wisc.edu regs.rxdp_hi = reg; 7688155Snilay@cs.wisc.edu break; 7697567SBrad.Beckmann@amd.com 7707567SBrad.Beckmann@amd.com case RXCFG: 7717567SBrad.Beckmann@amd.com regs.rxcfg = reg; 7727567SBrad.Beckmann@amd.com#if 0 7737922SBrad.Beckmann@amd.com if (reg & RXCFG_AEP) ; 7747922SBrad.Beckmann@amd.com if (reg & RXCFG_ARP) ; 7757922SBrad.Beckmann@amd.com if (reg & RXCFG_STRIPCRC) ; 7767922SBrad.Beckmann@amd.com if (reg & RXCFG_RX_RD) ; 7777922SBrad.Beckmann@amd.com if (reg & RXCFG_ALP) ; 7787922SBrad.Beckmann@amd.com if (reg & RXCFG_AIRL) ; 7797922SBrad.Beckmann@amd.com#endif 7807922SBrad.Beckmann@amd.com 7818154Snilay@cs.wisc.edu /* we handle our own DMA, ignore what kernel says about it */ 7828154Snilay@cs.wisc.edu //if (reg & RXCFG_MXDMA) ; 7838154Snilay@cs.wisc.edu 7848154Snilay@cs.wisc.edu#if 0 7858154Snilay@cs.wisc.edu //also, we currently don't care about fill/drain thresholds 7868154Snilay@cs.wisc.edu //though this may change in the future with more realistic 7878154Snilay@cs.wisc.edu //networks or a driver which changes it according to feedback 7888154Snilay@cs.wisc.edu if (reg & (RXCFG_DRTH | RXCFG_DRTH0)) ; 7898154Snilay@cs.wisc.edu#endif 7908154Snilay@cs.wisc.edu break; 7918154Snilay@cs.wisc.edu 7928154Snilay@cs.wisc.edu case PQCR: 7938154Snilay@cs.wisc.edu /* there is no priority queueing used in the linux 2.6 driver */ 7948154Snilay@cs.wisc.edu regs.pqcr = reg; 7958154Snilay@cs.wisc.edu break; 7968154Snilay@cs.wisc.edu 7978154Snilay@cs.wisc.edu case WCSR: 7988154Snilay@cs.wisc.edu /* not going to implement wake on LAN */ 7998154Snilay@cs.wisc.edu regs.wcsr = reg; 8008154Snilay@cs.wisc.edu break; 8018154Snilay@cs.wisc.edu 8027922SBrad.Beckmann@amd.com case PCR: 8037922SBrad.Beckmann@amd.com /* not going to implement pause control */ 8047922SBrad.Beckmann@amd.com regs.pcr = reg; 8057922SBrad.Beckmann@amd.com break; 8067007Snate@binkert.org 8077007Snate@binkert.org case RFCR: 8086863Sdrh5@cs.wisc.edu regs.rfcr = reg; 8096863Sdrh5@cs.wisc.edu 8106863Sdrh5@cs.wisc.edu rxFilterEnable = (reg & RFCR_RFEN) ? true : false; 8117007Snate@binkert.org acceptBroadcast = (reg & RFCR_AAB) ? true : false; 8127007Snate@binkert.org acceptMulticast = (reg & RFCR_AAM) ? true : false; 8137007Snate@binkert.org acceptUnicast = (reg & RFCR_AAU) ? true : false; 8147007Snate@binkert.org acceptPerfect = (reg & RFCR_APM) ? true : false; 8156863Sdrh5@cs.wisc.edu acceptArp = (reg & RFCR_AARP) ? true : false; 8166863Sdrh5@cs.wisc.edu 8176863Sdrh5@cs.wisc.edu if (reg & RFCR_APAT) ; 8186863Sdrh5@cs.wisc.edu// panic("RFCR_APAT not implemented!\n"); 8196863Sdrh5@cs.wisc.edu 8206863Sdrh5@cs.wisc.edu if (reg & RFCR_MHEN || reg & RFCR_UHEN) 8217007Snate@binkert.org panic("hash filtering not implemented!\n"); 8227007Snate@binkert.org 8237007Snate@binkert.org if (reg & RFCR_ULM) 8247007Snate@binkert.org panic("RFCR_ULM not implemented!\n"); 8257007Snate@binkert.org 8266657Snate@binkert.org break; 8277007Snate@binkert.org 8287007Snate@binkert.org case RFDR: 8297007Snate@binkert.org panic("the driver never writes to RFDR, something is wrong!\n"); 8306657Snate@binkert.org 8316657Snate@binkert.org case BRAR: 8327007Snate@binkert.org panic("the driver never uses BRAR, something is wrong!\n"); 8337007Snate@binkert.org 8347007Snate@binkert.org case BRDR: 8356657Snate@binkert.org panic("the driver never uses BRDR, something is wrong!\n"); 8366657Snate@binkert.org 8377007Snate@binkert.org case SRR: 8387007Snate@binkert.org panic("SRR is read only register!\n"); 8397007Snate@binkert.org 8406902SBrad.Beckmann@amd.com case MIBC: 8416902SBrad.Beckmann@amd.com panic("the driver never uses MIBC, something is wrong!\n"); 8426902SBrad.Beckmann@amd.com 8436902SBrad.Beckmann@amd.com case VRCR: 8446902SBrad.Beckmann@amd.com regs.vrcr = reg; 8456902SBrad.Beckmann@amd.com break; 8466902SBrad.Beckmann@amd.com 8477025SBrad.Beckmann@amd.com case VTCR: 8486902SBrad.Beckmann@amd.com regs.vtcr = reg; 8496902SBrad.Beckmann@amd.com break; 8506902SBrad.Beckmann@amd.com 8516902SBrad.Beckmann@amd.com case VDR: 8526902SBrad.Beckmann@amd.com panic("the driver never uses VDR, something is wrong!\n"); 8537542SBrad.Beckmann@amd.com break; 8547542SBrad.Beckmann@amd.com 8557542SBrad.Beckmann@amd.com case CCSR: 8566902SBrad.Beckmann@amd.com /* not going to implement clockrun stuff */ 8576902SBrad.Beckmann@amd.com regs.ccsr = reg; 8586902SBrad.Beckmann@amd.com break; 8596902SBrad.Beckmann@amd.com 8606902SBrad.Beckmann@amd.com case TBICR: 8616902SBrad.Beckmann@amd.com regs.tbicr = reg; 8626902SBrad.Beckmann@amd.com if (reg & TBICR_MR_LOOPBACK) 8636902SBrad.Beckmann@amd.com panic("TBICR_MR_LOOPBACK never used, something wrong!\n"); 8646902SBrad.Beckmann@amd.com 8656902SBrad.Beckmann@amd.com if (reg & TBICR_MR_AN_ENABLE) { 8666902SBrad.Beckmann@amd.com regs.tanlpar = regs.tanar; 8676902SBrad.Beckmann@amd.com regs.tbisr |= (TBISR_MR_AN_COMPLETE | TBISR_MR_LINK_STATUS); 8686902SBrad.Beckmann@amd.com } 8696902SBrad.Beckmann@amd.com 8706902SBrad.Beckmann@amd.com#if 0 8717542SBrad.Beckmann@amd.com if (reg & TBICR_MR_RESTART_AN) ; 8726902SBrad.Beckmann@amd.com#endif 8737839Snilay@cs.wisc.edu 8747839Snilay@cs.wisc.edu break; 8757839Snilay@cs.wisc.edu 8767839Snilay@cs.wisc.edu case TBISR: 8777839Snilay@cs.wisc.edu panic("TBISR is read only register!\n"); 8787839Snilay@cs.wisc.edu 8797839Snilay@cs.wisc.edu case TANAR: 8807839Snilay@cs.wisc.edu regs.tanar = reg; 8817839Snilay@cs.wisc.edu if (reg & TANAR_PS2) 8827839Snilay@cs.wisc.edu panic("this isn't used in driver, something wrong!\n"); 8837839Snilay@cs.wisc.edu 8847839Snilay@cs.wisc.edu if (reg & TANAR_PS1) 8857839Snilay@cs.wisc.edu panic("this isn't used in driver, something wrong!\n"); 8867839Snilay@cs.wisc.edu break; 8877839Snilay@cs.wisc.edu 8887839Snilay@cs.wisc.edu case TANLPAR: 8897839Snilay@cs.wisc.edu panic("this should only be written to by the fake phy!\n"); 8907839Snilay@cs.wisc.edu 8917839Snilay@cs.wisc.edu case TANER: 8927839Snilay@cs.wisc.edu panic("TANER is read only register!\n"); 8937839Snilay@cs.wisc.edu 8947839Snilay@cs.wisc.edu case TESR: 8957839Snilay@cs.wisc.edu regs.tesr = reg; 8967839Snilay@cs.wisc.edu break; 8977839Snilay@cs.wisc.edu 8987839Snilay@cs.wisc.edu default: 8997839Snilay@cs.wisc.edu panic("thought i covered all the register, what is this? addr=%#x", 9007839Snilay@cs.wisc.edu daddr); 9017839Snilay@cs.wisc.edu } 9027839Snilay@cs.wisc.edu } else 9037839Snilay@cs.wisc.edu panic("Invalid Request Size"); 9047839Snilay@cs.wisc.edu 9057839Snilay@cs.wisc.edu return No_Fault; 9067839Snilay@cs.wisc.edu} 9077839Snilay@cs.wisc.edu 9087839Snilay@cs.wisc.eduvoid 9097839Snilay@cs.wisc.eduNSGigE::devIntrPost(uint32_t interrupts) 9106902SBrad.Beckmann@amd.com{ 9118683Snilay@cs.wisc.edu bool delay = false; 9128683Snilay@cs.wisc.edu 9138683Snilay@cs.wisc.edu if (interrupts & ISR_RESERVE) 9148683Snilay@cs.wisc.edu panic("Cannot set a reserved interrupt"); 9158683Snilay@cs.wisc.edu 9168683Snilay@cs.wisc.edu if (interrupts & ISR_TXRCMP) 9178683Snilay@cs.wisc.edu regs.isr |= ISR_TXRCMP; 9188683Snilay@cs.wisc.edu 9198683Snilay@cs.wisc.edu if (interrupts & ISR_RXRCMP) 9208683Snilay@cs.wisc.edu regs.isr |= ISR_RXRCMP; 9218683Snilay@cs.wisc.edu 9228683Snilay@cs.wisc.edu//ISR_DPERR not implemented 9238683Snilay@cs.wisc.edu//ISR_SSERR not implemented 9248683Snilay@cs.wisc.edu//ISR_RMABT not implemented 9258683Snilay@cs.wisc.edu//ISR_RXSOVR not implemented 9268683Snilay@cs.wisc.edu//ISR_HIBINT not implemented 9278683Snilay@cs.wisc.edu//ISR_PHY not implemented 9286657Snate@binkert.org//ISR_PME not implemented 9296657Snate@binkert.org 9307839Snilay@cs.wisc.edu if (interrupts & ISR_SWI) 9317839Snilay@cs.wisc.edu regs.isr |= ISR_SWI; 9327839Snilay@cs.wisc.edu 9337839Snilay@cs.wisc.edu//ISR_MIB not implemented 9346657Snate@binkert.org//ISR_TXURN not implemented 9357839Snilay@cs.wisc.edu 9367839Snilay@cs.wisc.edu if (interrupts & ISR_TXIDLE) 9377839Snilay@cs.wisc.edu regs.isr |= ISR_TXIDLE; 9387839Snilay@cs.wisc.edu 9397839Snilay@cs.wisc.edu if (interrupts & ISR_TXERR) 9408055Sksewell@umich.edu regs.isr |= ISR_TXERR; 9417839Snilay@cs.wisc.edu 9427839Snilay@cs.wisc.edu if (interrupts & ISR_TXDESC) 9436657Snate@binkert.org regs.isr |= ISR_TXDESC; 9447839Snilay@cs.wisc.edu 9457839Snilay@cs.wisc.edu if (interrupts & ISR_TXOK) { 9467839Snilay@cs.wisc.edu regs.isr |= ISR_TXOK; 9477839Snilay@cs.wisc.edu delay = true; 9487839Snilay@cs.wisc.edu } 9497839Snilay@cs.wisc.edu 9507839Snilay@cs.wisc.edu if (interrupts & ISR_RXORN) 9517839Snilay@cs.wisc.edu regs.isr |= ISR_RXORN; 9527839Snilay@cs.wisc.edu 9537839Snilay@cs.wisc.edu if (interrupts & ISR_RXIDLE) 9547839Snilay@cs.wisc.edu regs.isr |= ISR_RXIDLE; 9558055Sksewell@umich.edu 9567839Snilay@cs.wisc.edu//ISR_RXEARLY not implemented 9577839Snilay@cs.wisc.edu 9587839Snilay@cs.wisc.edu if (interrupts & ISR_RXERR) 9597839Snilay@cs.wisc.edu regs.isr |= ISR_RXERR; 9607839Snilay@cs.wisc.edu 9617839Snilay@cs.wisc.edu if (interrupts & ISR_RXDESC) 9627839Snilay@cs.wisc.edu regs.isr |= ISR_RXDESC; 9637839Snilay@cs.wisc.edu 9647839Snilay@cs.wisc.edu if (interrupts & ISR_RXOK) { 9657839Snilay@cs.wisc.edu delay = true; 9667839Snilay@cs.wisc.edu regs.isr |= ISR_RXOK; 9677839Snilay@cs.wisc.edu } 9687839Snilay@cs.wisc.edu 9697839Snilay@cs.wisc.edu if ((regs.isr & regs.imr)) { 9708055Sksewell@umich.edu Tick when = curTick; 9717839Snilay@cs.wisc.edu if (delay) 9727839Snilay@cs.wisc.edu when += intrDelay; 9737839Snilay@cs.wisc.edu cpuIntrPost(when); 9747839Snilay@cs.wisc.edu } 9757839Snilay@cs.wisc.edu 9767839Snilay@cs.wisc.edu DPRINTF(EthernetIntr, "**interrupt written to ISR: intr=%#x isr=%#x imr=%#x\n", 9777839Snilay@cs.wisc.edu interrupts, regs.isr, regs.imr); 9787839Snilay@cs.wisc.edu} 9797839Snilay@cs.wisc.edu 9807839Snilay@cs.wisc.eduvoid 9816657Snate@binkert.orgNSGigE::devIntrClear(uint32_t interrupts) 9827007Snate@binkert.org{ 9837007Snate@binkert.org if (interrupts & ISR_RESERVE) 9846657Snate@binkert.org panic("Cannot clear a reserved interrupt"); 9858055Sksewell@umich.edu 9866657Snate@binkert.org if (interrupts & ISR_TXRCMP) 9876657Snate@binkert.org regs.isr &= ~ISR_TXRCMP; 9886657Snate@binkert.org 9896657Snate@binkert.org if (interrupts & ISR_RXRCMP) 9908478Snilay@cs.wisc.edu regs.isr &= ~ISR_RXRCMP; 9918478Snilay@cs.wisc.edu 9928478Snilay@cs.wisc.edu//ISR_DPERR not implemented 9939302Snilay@cs.wisc.edu//ISR_SSERR not implemented 9949302Snilay@cs.wisc.edu//ISR_RMABT not implemented 9959302Snilay@cs.wisc.edu//ISR_RXSOVR not implemented 9969302Snilay@cs.wisc.edu//ISR_HIBINT not implemented 9979302Snilay@cs.wisc.edu//ISR_PHY not implemented 9989302Snilay@cs.wisc.edu//ISR_PME not implemented 9999302Snilay@cs.wisc.edu 10009302Snilay@cs.wisc.edu if (interrupts & ISR_SWI) 10019302Snilay@cs.wisc.edu regs.isr &= ~ISR_SWI; 10029302Snilay@cs.wisc.edu 10039302Snilay@cs.wisc.edu//ISR_MIB not implemented 10049302Snilay@cs.wisc.edu//ISR_TXURN not implemented 10059302Snilay@cs.wisc.edu 10069302Snilay@cs.wisc.edu if (interrupts & ISR_TXIDLE) 10079302Snilay@cs.wisc.edu regs.isr &= ~ISR_TXIDLE; 10089302Snilay@cs.wisc.edu 10099302Snilay@cs.wisc.edu if (interrupts & ISR_TXERR) 10109302Snilay@cs.wisc.edu regs.isr &= ~ISR_TXERR; 10119302Snilay@cs.wisc.edu 10129302Snilay@cs.wisc.edu if (interrupts & ISR_TXDESC) 10139302Snilay@cs.wisc.edu regs.isr &= ~ISR_TXDESC; 10149302Snilay@cs.wisc.edu 10159302Snilay@cs.wisc.edu if (interrupts & ISR_TXOK) 10169302Snilay@cs.wisc.edu regs.isr &= ~ISR_TXOK; 10179302Snilay@cs.wisc.edu 10189302Snilay@cs.wisc.edu if (interrupts & ISR_RXORN) 10199302Snilay@cs.wisc.edu regs.isr &= ~ISR_RXORN; 10209302Snilay@cs.wisc.edu 10219302Snilay@cs.wisc.edu if (interrupts & ISR_RXIDLE) 10229302Snilay@cs.wisc.edu regs.isr &= ~ISR_RXIDLE; 10239302Snilay@cs.wisc.edu 10249302Snilay@cs.wisc.edu//ISR_RXEARLY not implemented 10259302Snilay@cs.wisc.edu 10266657Snate@binkert.org if (interrupts & ISR_RXERR) 10276657Snate@binkert.org regs.isr &= ~ISR_RXERR; 10289219Spower.jg@gmail.com 10296657Snate@binkert.org if (interrupts & ISR_RXDESC) 10306657Snate@binkert.org regs.isr &= ~ISR_RXDESC; 10316999Snate@binkert.org 10326657Snate@binkert.org if (interrupts & ISR_RXOK) 10336657Snate@binkert.org regs.isr &= ~ISR_RXOK; 10349104Shestness@cs.utexas.edu 10359104Shestness@cs.utexas.edu if (!(regs.isr & regs.imr)) 10369104Shestness@cs.utexas.edu cpuIntrClear(); 10379104Shestness@cs.utexas.edu 10386657Snate@binkert.org DPRINTF(EthernetIntr, "**interrupt cleared from ISR: intr=%x isr=%x imr=%x\n", 10396657Snate@binkert.org interrupts, regs.isr, regs.imr); 10406657Snate@binkert.org} 10416657Snate@binkert.org 10428946Sandreas.hansson@arm.comvoid 10438946Sandreas.hansson@arm.comNSGigE::devIntrChangeMask() 10448946Sandreas.hansson@arm.com{ 10457832Snate@binkert.org DPRINTF(EthernetIntr, "interrupt mask changed\n"); 10467832Snate@binkert.org 10477007Snate@binkert.org if (regs.isr & regs.imr) 10488232Snate@binkert.org cpuIntrPost(curTick); 10498229Snate@binkert.org else 10508229Snate@binkert.org cpuIntrClear(); 10518229Snate@binkert.org} 10529104Shestness@cs.utexas.edu 10539104Shestness@cs.utexas.eduvoid 10549104Shestness@cs.utexas.eduNSGigE::cpuIntrPost(Tick when) 10559104Shestness@cs.utexas.edu{ 10569104Shestness@cs.utexas.edu //If the interrupt you want to post is later than an 10579104Shestness@cs.utexas.edu //interrupt already scheduled, just let it post in the coming one and 10588229Snate@binkert.org //don't schedule another. 10596657Snate@binkert.org //HOWEVER, must be sure that the scheduled intrTick is in the future 10606657Snate@binkert.org //(this was formerly the source of a bug) 10619219Spower.jg@gmail.com assert((intrTick >= curTick) || (intrTick == 0)); 10629219Spower.jg@gmail.com if (when > intrTick && intrTick != 0) 10639219Spower.jg@gmail.com return; 10649219Spower.jg@gmail.com 10659219Spower.jg@gmail.com intrTick = when; 10669219Spower.jg@gmail.com 10679219Spower.jg@gmail.com if (intrEvent) { 10686657Snate@binkert.org intrEvent->squash(); 10697055Snate@binkert.org intrEvent = 0; 10707055Snate@binkert.org } 10717007Snate@binkert.org 10727007Snate@binkert.org if (when < curTick) { 10736657Snate@binkert.org cpuInterrupt(); 10746657Snate@binkert.org } else { 10756657Snate@binkert.org DPRINTF(EthernetIntr, "going to schedule an interrupt for intrTick=%d\n", 10766657Snate@binkert.org intrTick); 10776657Snate@binkert.org intrEvent = new IntrEvent(this, true); 10786657Snate@binkert.org intrEvent->schedule(intrTick); 10797007Snate@binkert.org } 10807007Snate@binkert.org} 10817007Snate@binkert.org 10827007Snate@binkert.orgvoid 10839230Snilay@cs.wisc.eduNSGigE::cpuInterrupt() 10846657Snate@binkert.org{ 10856657Snate@binkert.org // Don't send an interrupt if there's already one 10866657Snate@binkert.org if (cpuPendingIntr) { 10876657Snate@binkert.org DPRINTF(EthernetIntr, 10886657Snate@binkert.org "would send an interrupt now, but there's already pending\n"); 10896657Snate@binkert.org intrTick = 0; 10906657Snate@binkert.org return; 10916657Snate@binkert.org } 10926657Snate@binkert.org // Don't send an interrupt if it's supposed to be delayed 10936657Snate@binkert.org if (intrTick > curTick) { 10946657Snate@binkert.org DPRINTF(EthernetIntr, "an interrupt is scheduled for %d, wait til then\n", 10956657Snate@binkert.org intrTick); 10967567SBrad.Beckmann@amd.com return; 10977567SBrad.Beckmann@amd.com } 10987567SBrad.Beckmann@amd.com 10997567SBrad.Beckmann@amd.com // Whether or not there's a pending interrupt, we don't care about 11006657Snate@binkert.org // it anymore 11016657Snate@binkert.org intrEvent = 0; 11026657Snate@binkert.org intrTick = 0; 11036657Snate@binkert.org 11046657Snate@binkert.org // Send interrupt 11056657Snate@binkert.org cpuPendingIntr = true; 11066657Snate@binkert.org /** @todo rework the intctrl to be tsunami ok */ 11076657Snate@binkert.org //intctrl->post(TheISA::INTLEVEL_IRQ1, TheISA::INTINDEX_ETHERNET); 11086657Snate@binkert.org DPRINTF(EthernetIntr, "Posting interrupts to cchip!\n"); 11096657Snate@binkert.org tsunami->cchip->postDRIR(configData->config.hdr.pci0.interruptLine); 11106657Snate@binkert.org} 11116657Snate@binkert.org 11126657Snate@binkert.orgvoid 11136657Snate@binkert.orgNSGigE::cpuIntrClear() 11146657Snate@binkert.org{ 11156657Snate@binkert.org if (cpuPendingIntr) { 11166657Snate@binkert.org cpuPendingIntr = false; 11176657Snate@binkert.org /** @todo rework the intctrl to be tsunami ok */ 11186999Snate@binkert.org //intctrl->clear(TheISA::INTLEVEL_IRQ1, TheISA::INTINDEX_ETHERNET); 11196657Snate@binkert.org DPRINTF(EthernetIntr, "clearing all interrupts from cchip\n"); 11206657Snate@binkert.org tsunami->cchip->clearDRIR(configData->config.hdr.pci0.interruptLine); 11216657Snate@binkert.org } 11226657Snate@binkert.org} 11236657Snate@binkert.org 11246657Snate@binkert.orgbool 11257832Snate@binkert.orgNSGigE::cpuIntrPending() const 11267832Snate@binkert.org{ return cpuPendingIntr; } 11277805Snilay@cs.wisc.edu 11287832Snate@binkert.orgvoid 11298232Snate@binkert.orgNSGigE::txReset() 11308232Snate@binkert.org{ 11318229Snate@binkert.org 11328229Snate@binkert.org DPRINTF(Ethernet, "transmit reset\n"); 11338229Snate@binkert.org 11348229Snate@binkert.org CTDD = false; 11356657Snate@binkert.org txFifoAvail = maxTxFifoSize; 11366657Snate@binkert.org txHalt = false; 11376657Snate@binkert.org txFragPtr = 0; 11386657Snate@binkert.org assert(txDescCnt == 0); 11396657Snate@binkert.org txFifo.clear(); 11406657Snate@binkert.org regs.command &= ~CR_TXE; 11416657Snate@binkert.org txState = txIdle; 11426657Snate@binkert.org assert(txDmaState == dmaIdle); 11437007Snate@binkert.org} 11447007Snate@binkert.org 11457839Snilay@cs.wisc.eduvoid 11467839Snilay@cs.wisc.eduNSGigE::rxReset() 11477839Snilay@cs.wisc.edu{ 11487839Snilay@cs.wisc.edu DPRINTF(Ethernet, "receive reset\n"); 11497839Snilay@cs.wisc.edu 11507839Snilay@cs.wisc.edu CRDD = false; 11517839Snilay@cs.wisc.edu assert(rxPktBytes == 0); 11527839Snilay@cs.wisc.edu rxFifoCnt = 0; 11537839Snilay@cs.wisc.edu rxHalt = false; 11547839Snilay@cs.wisc.edu rxFragPtr = 0; 11557007Snate@binkert.org assert(rxDescCnt == 0); 11566657Snate@binkert.org assert(rxDmaState == dmaIdle); 11577839Snilay@cs.wisc.edu rxFifo.clear(); 11587839Snilay@cs.wisc.edu regs.command &= ~CR_RXE; 11598337Snilay@cs.wisc.edu rxState = rxIdle; 11607839Snilay@cs.wisc.edu} 11618337Snilay@cs.wisc.edu 11627839Snilay@cs.wisc.eduvoid NSGigE::regsReset() 11638337Snilay@cs.wisc.edu{ 11647839Snilay@cs.wisc.edu memset(®s, 0, sizeof(regs)); 11658337Snilay@cs.wisc.edu regs.config = 0x80000000; 11667839Snilay@cs.wisc.edu regs.mear = 0x12; 11677839Snilay@cs.wisc.edu regs.isr = 0x00608000; 11686657Snate@binkert.org regs.txcfg = 0x120; 11696657Snate@binkert.org regs.rxcfg = 0x4; 11707780Snilay@cs.wisc.edu regs.srr = 0x0103; 11719171Snilay@cs.wisc.edu regs.mibc = 0x2; 11729171Snilay@cs.wisc.edu regs.vdr = 0x81; 11736657Snate@binkert.org regs.tesr = 0xc000; 11747007Snate@binkert.org 11757839Snilay@cs.wisc.edu extstsEnable = false; 11767839Snilay@cs.wisc.edu acceptBroadcast = false; 11777839Snilay@cs.wisc.edu acceptMulticast = false; 11787839Snilay@cs.wisc.edu acceptUnicast = false; 11797839Snilay@cs.wisc.edu acceptPerfect = false; 11807839Snilay@cs.wisc.edu acceptArp = false; 11817839Snilay@cs.wisc.edu} 11827839Snilay@cs.wisc.edu 11837839Snilay@cs.wisc.eduvoid 11846657Snate@binkert.orgNSGigE::rxDmaReadCopy() 11857839Snilay@cs.wisc.edu{ 11866657Snate@binkert.org assert(rxDmaState == dmaReading); 11877780Snilay@cs.wisc.edu 11887780Snilay@cs.wisc.edu memcpy(rxDmaData, physmem->dma_addr(rxDmaAddr, rxDmaLen), rxDmaLen); 11897542SBrad.Beckmann@amd.com rxDmaState = dmaIdle; 11908266Sksewell@umich.edu 11918266Sksewell@umich.edu DPRINTF(EthernetDMA, "rx dma read paddr=%#x len=%d\n", 11928266Sksewell@umich.edu rxDmaAddr, rxDmaLen); 11938266Sksewell@umich.edu DDUMP(EthernetDMA, rxDmaData, rxDmaLen); 11948266Sksewell@umich.edu} 11958266Sksewell@umich.edu 11966657Snate@binkert.orgbool 11977832Snate@binkert.orgNSGigE::doRxDmaRead() 11987839Snilay@cs.wisc.edu{ 11997839Snilay@cs.wisc.edu assert(rxDmaState == dmaIdle || rxDmaState == dmaReadWaiting); 12008337Snilay@cs.wisc.edu rxDmaState = dmaReading; 12018341Snilay@cs.wisc.edu 12027839Snilay@cs.wisc.edu if (dmaInterface && !rxDmaFree) { 12038337Snilay@cs.wisc.edu if (dmaInterface->busy()) 12048341Snilay@cs.wisc.edu rxDmaState = dmaReadWaiting; 12057839Snilay@cs.wisc.edu else 12068337Snilay@cs.wisc.edu dmaInterface->doDMA(Read, rxDmaAddr, rxDmaLen, curTick, 12078341Snilay@cs.wisc.edu &rxDmaReadEvent, true); 12087839Snilay@cs.wisc.edu return true; 12098337Snilay@cs.wisc.edu } 12108341Snilay@cs.wisc.edu 12117839Snilay@cs.wisc.edu if (dmaReadDelay == 0 && dmaReadFactor == 0) { 12127839Snilay@cs.wisc.edu rxDmaReadCopy(); 12136657Snate@binkert.org return false; 12148266Sksewell@umich.edu } 12158266Sksewell@umich.edu 12168266Sksewell@umich.edu Tick factor = ((rxDmaLen + ULL(63)) >> ULL(6)) * dmaReadFactor; 12178266Sksewell@umich.edu Tick start = curTick + dmaReadDelay + factor; 12188266Sksewell@umich.edu rxDmaReadEvent.schedule(start); 12198266Sksewell@umich.edu return true; 12206657Snate@binkert.org} 12217780Snilay@cs.wisc.edu 12228266Sksewell@umich.eduvoid 12238266Sksewell@umich.eduNSGigE::rxDmaReadDone() 12248266Sksewell@umich.edu{ 12258266Sksewell@umich.edu assert(rxDmaState == dmaReading); 12268266Sksewell@umich.edu rxDmaReadCopy(); 12278266Sksewell@umich.edu 12286657Snate@binkert.org // If the transmit state machine has a pending DMA, let it go first 12296657Snate@binkert.org if (txDmaState == dmaReadWaiting || txDmaState == dmaWriteWaiting) 12306657Snate@binkert.org txKick(); 12316657Snate@binkert.org 12326657Snate@binkert.org rxKick(); 12337007Snate@binkert.org} 12347007Snate@binkert.org 12357007Snate@binkert.orgvoid 12367007Snate@binkert.orgNSGigE::rxDmaWriteCopy() 12377839Snilay@cs.wisc.edu{ 12387839Snilay@cs.wisc.edu assert(rxDmaState == dmaWriting); 12397839Snilay@cs.wisc.edu 12407839Snilay@cs.wisc.edu memcpy(physmem->dma_addr(rxDmaAddr, rxDmaLen), rxDmaData, rxDmaLen); 12417839Snilay@cs.wisc.edu rxDmaState = dmaIdle; 12427839Snilay@cs.wisc.edu 12437839Snilay@cs.wisc.edu DPRINTF(EthernetDMA, "rx dma write paddr=%#x len=%d\n", 12447839Snilay@cs.wisc.edu rxDmaAddr, rxDmaLen); 12457839Snilay@cs.wisc.edu DDUMP(EthernetDMA, rxDmaData, rxDmaLen); 12467839Snilay@cs.wisc.edu} 12477839Snilay@cs.wisc.edu 12487007Snate@binkert.orgbool 12496657Snate@binkert.orgNSGigE::doRxDmaWrite() 12506657Snate@binkert.org{ 12516657Snate@binkert.org assert(rxDmaState == dmaIdle || rxDmaState == dmaWriteWaiting); 12526657Snate@binkert.org rxDmaState = dmaWriting; 12536657Snate@binkert.org 12546657Snate@binkert.org if (dmaInterface && !rxDmaFree) { 12556657Snate@binkert.org if (dmaInterface->busy()) 12566657Snate@binkert.org rxDmaState = dmaWriteWaiting; 12576657Snate@binkert.org else 12586657Snate@binkert.org dmaInterface->doDMA(WriteInvalidate, rxDmaAddr, rxDmaLen, curTick, 12596657Snate@binkert.org &rxDmaWriteEvent, true); 12606999Snate@binkert.org return true; 12616657Snate@binkert.org } 12626657Snate@binkert.org 12636657Snate@binkert.org if (dmaWriteDelay == 0 && dmaWriteFactor == 0) { 12646657Snate@binkert.org rxDmaWriteCopy(); 12656657Snate@binkert.org return false; 12666657Snate@binkert.org } 12679104Shestness@cs.utexas.edu 12686657Snate@binkert.org Tick factor = ((rxDmaLen + ULL(63)) >> ULL(6)) * dmaWriteFactor; 12696657Snate@binkert.org Tick start = curTick + dmaWriteDelay + factor; 12706657Snate@binkert.org rxDmaWriteEvent.schedule(start); 12716657Snate@binkert.org return true; 12726657Snate@binkert.org} 12736657Snate@binkert.org 12746657Snate@binkert.orgvoid 12757007Snate@binkert.orgNSGigE::rxDmaWriteDone() 12766657Snate@binkert.org{ 12776657Snate@binkert.org assert(rxDmaState == dmaWriting); 12786657Snate@binkert.org rxDmaWriteCopy(); 12796657Snate@binkert.org 12809105SBrad.Beckmann@amd.com // If the transmit state machine has a pending DMA, let it go first 12819105SBrad.Beckmann@amd.com if (txDmaState == dmaReadWaiting || txDmaState == dmaWriteWaiting) 12829105SBrad.Beckmann@amd.com txKick(); 12839105SBrad.Beckmann@amd.com 12849105SBrad.Beckmann@amd.com rxKick(); 12859105SBrad.Beckmann@amd.com} 12869105SBrad.Beckmann@amd.com 12879105SBrad.Beckmann@amd.comvoid 12886657Snate@binkert.orgNSGigE::rxKick() 12896657Snate@binkert.org{ 12906657Snate@binkert.org DPRINTF(EthernetSM, "receive kick state=%s (rxBuf.size=%d)\n", 12916657Snate@binkert.org NsRxStateStrings[rxState], rxFifo.size()); 12926657Snate@binkert.org 12936657Snate@binkert.org if (rxKickTick > curTick) { 12946657Snate@binkert.org DPRINTF(EthernetSM, "receive kick exiting, can't run till %d\n", 12959104Shestness@cs.utexas.edu rxKickTick); 12969104Shestness@cs.utexas.edu return; 12979104Shestness@cs.utexas.edu } 12989104Shestness@cs.utexas.edu 12996657Snate@binkert.org next: 13006657Snate@binkert.org switch(rxDmaState) { 13016657Snate@binkert.org case dmaReadWaiting: 13026657Snate@binkert.org if (doRxDmaRead()) 13036657Snate@binkert.org goto exit; 13046657Snate@binkert.org break; 13056657Snate@binkert.org case dmaWriteWaiting: 13066657Snate@binkert.org if (doRxDmaWrite()) 13076657Snate@binkert.org goto exit; 13086657Snate@binkert.org break; 13097839Snilay@cs.wisc.edu default: 13107839Snilay@cs.wisc.edu break; 13117839Snilay@cs.wisc.edu } 13127839Snilay@cs.wisc.edu 13137839Snilay@cs.wisc.edu // see state machine from spec for details 13147839Snilay@cs.wisc.edu // the way this works is, if you finish work on one state and can go directly to 13157839Snilay@cs.wisc.edu // another, you do that through jumping to the label "next". however, if you have 13167839Snilay@cs.wisc.edu // intermediate work, like DMA so that you can't go to the next state yet, you go to 13177839Snilay@cs.wisc.edu // exit and exit the loop. however, when the DMA is done it will trigger an 13187839Snilay@cs.wisc.edu // event and come back to this loop. 13197839Snilay@cs.wisc.edu switch (rxState) { 13207839Snilay@cs.wisc.edu case rxIdle: 13216657Snate@binkert.org if (!regs.command & CR_RXE) { 13226657Snate@binkert.org DPRINTF(EthernetSM, "Receive Disabled! Nothing to do.\n"); 13236657Snate@binkert.org goto exit; 13246657Snate@binkert.org } 13256657Snate@binkert.org 13266657Snate@binkert.org if (CRDD) { 13276657Snate@binkert.org rxState = rxDescRefr; 13286657Snate@binkert.org 13296657Snate@binkert.org rxDmaAddr = regs.rxdp & 0x3fffffff; 13306657Snate@binkert.org rxDmaData = &rxDescCache + offsetof(ns_desc, link); 13316657Snate@binkert.org rxDmaLen = sizeof(rxDescCache.link); 13326657Snate@binkert.org rxDmaFree = dmaDescFree; 13336657Snate@binkert.org 13346657Snate@binkert.org descDmaReads++; 13356657Snate@binkert.org descDmaRdBytes += rxDmaLen; 13366657Snate@binkert.org 13376657Snate@binkert.org if (doRxDmaRead()) 13386657Snate@binkert.org goto exit; 13396657Snate@binkert.org } else { 13406657Snate@binkert.org rxState = rxDescRead; 13416657Snate@binkert.org 13427805Snilay@cs.wisc.edu rxDmaAddr = regs.rxdp & 0x3fffffff; 13438159SBrad.Beckmann@amd.com rxDmaData = &rxDescCache; 13449171Snilay@cs.wisc.edu rxDmaLen = sizeof(ns_desc); 13456657Snate@binkert.org rxDmaFree = dmaDescFree; 13466657Snate@binkert.org 13476657Snate@binkert.org descDmaReads++; 13486657Snate@binkert.org descDmaRdBytes += rxDmaLen; 13496657Snate@binkert.org 13506657Snate@binkert.org if (doRxDmaRead()) 13517542SBrad.Beckmann@amd.com goto exit; 13527542SBrad.Beckmann@amd.com } 13537542SBrad.Beckmann@amd.com break; 13547542SBrad.Beckmann@amd.com 13557542SBrad.Beckmann@amd.com case rxDescRefr: 13567542SBrad.Beckmann@amd.com if (rxDmaState != dmaIdle) 13577542SBrad.Beckmann@amd.com goto exit; 13587542SBrad.Beckmann@amd.com 13597542SBrad.Beckmann@amd.com rxState = rxAdvance; 13607542SBrad.Beckmann@amd.com break; 13617542SBrad.Beckmann@amd.com 13627832Snate@binkert.org case rxDescRead: 13637542SBrad.Beckmann@amd.com if (rxDmaState != dmaIdle) 13647542SBrad.Beckmann@amd.com goto exit; 13657542SBrad.Beckmann@amd.com 13668229Snate@binkert.org DPRINTF(EthernetDesc, 13677542SBrad.Beckmann@amd.com "rxDescCache:\n\tlink=%08x\n\tbufptr=%08x\n\tcmdsts=%08x\n\textsts=%08x\n" 13687542SBrad.Beckmann@amd.com ,rxDescCache.link, rxDescCache.bufptr, rxDescCache.cmdsts, 13697542SBrad.Beckmann@amd.com rxDescCache.extsts); 13707542SBrad.Beckmann@amd.com 13717542SBrad.Beckmann@amd.com if (rxDescCache.cmdsts & CMDSTS_OWN) { 13727542SBrad.Beckmann@amd.com rxState = rxIdle; 13737542SBrad.Beckmann@amd.com } else { 13747542SBrad.Beckmann@amd.com rxState = rxFifoBlock; 13757542SBrad.Beckmann@amd.com rxFragPtr = rxDescCache.bufptr; 13767542SBrad.Beckmann@amd.com rxDescCnt = rxDescCache.cmdsts & CMDSTS_LEN_MASK; 13777542SBrad.Beckmann@amd.com } 13787542SBrad.Beckmann@amd.com break; 13797542SBrad.Beckmann@amd.com 13807542SBrad.Beckmann@amd.com case rxFifoBlock: 13817542SBrad.Beckmann@amd.com if (!rxPacket) { 13827542SBrad.Beckmann@amd.com /** 13837542SBrad.Beckmann@amd.com * @todo in reality, we should be able to start processing 13847542SBrad.Beckmann@amd.com * the packet as it arrives, and not have to wait for the 13857542SBrad.Beckmann@amd.com * full packet ot be in the receive fifo. 13867542SBrad.Beckmann@amd.com */ 13877542SBrad.Beckmann@amd.com if (rxFifo.empty()) 13887542SBrad.Beckmann@amd.com goto exit; 13897542SBrad.Beckmann@amd.com 13907542SBrad.Beckmann@amd.com DPRINTF(EthernetSM, "\n\n*****processing receive of new packet\n"); 13917542SBrad.Beckmann@amd.com 13927542SBrad.Beckmann@amd.com // If we don't have a packet, grab a new one from the fifo. 13937542SBrad.Beckmann@amd.com rxPacket = rxFifo.front(); 13947542SBrad.Beckmann@amd.com rxPktBytes = rxPacket->length; 13957542SBrad.Beckmann@amd.com rxPacketBufPtr = rxPacket->data; 13967542SBrad.Beckmann@amd.com 13977542SBrad.Beckmann@amd.com if (DTRACE(Ethernet)) { 13987542SBrad.Beckmann@amd.com if (rxPacket->isIpPkt()) { 13997542SBrad.Beckmann@amd.com ip_header *ip = rxPacket->getIpHdr(); 14007542SBrad.Beckmann@amd.com DPRINTF(Ethernet, "ID is %d\n", reverseEnd16(ip->ID)); 14017542SBrad.Beckmann@amd.com if (rxPacket->isTcpPkt()) { 14027542SBrad.Beckmann@amd.com tcp_header *tcp = rxPacket->getTcpHdr(ip); 14037542SBrad.Beckmann@amd.com DPRINTF(Ethernet, "Src Port = %d, Dest Port = %d\n", 14047542SBrad.Beckmann@amd.com reverseEnd16(tcp->src_port_num), 14057542SBrad.Beckmann@amd.com reverseEnd16(tcp->dest_port_num)); 14067542SBrad.Beckmann@amd.com } 14077542SBrad.Beckmann@amd.com } 14087542SBrad.Beckmann@amd.com } 14097542SBrad.Beckmann@amd.com 14107542SBrad.Beckmann@amd.com // sanity check - i think the driver behaves like this 14117542SBrad.Beckmann@amd.com assert(rxDescCnt >= rxPktBytes); 14127542SBrad.Beckmann@amd.com 14137542SBrad.Beckmann@amd.com // Must clear the value before popping to decrement the 14147542SBrad.Beckmann@amd.com // reference count 14157542SBrad.Beckmann@amd.com rxFifo.front() = NULL; 14167542SBrad.Beckmann@amd.com rxFifo.pop_front(); 14177542SBrad.Beckmann@amd.com rxFifoCnt -= rxPacket->length; 14187542SBrad.Beckmann@amd.com } 14197542SBrad.Beckmann@amd.com 14207542SBrad.Beckmann@amd.com 14217542SBrad.Beckmann@amd.com // dont' need the && rxDescCnt > 0 if driver sanity check above holds 14227542SBrad.Beckmann@amd.com if (rxPktBytes > 0) { 14237542SBrad.Beckmann@amd.com rxState = rxFragWrite; 14247542SBrad.Beckmann@amd.com // don't need min<>(rxPktBytes,rxDescCnt) if above sanity check holds 14257542SBrad.Beckmann@amd.com rxXferLen = rxPktBytes; 14267542SBrad.Beckmann@amd.com 14277542SBrad.Beckmann@amd.com rxDmaAddr = rxFragPtr & 0x3fffffff; 14287542SBrad.Beckmann@amd.com rxDmaData = rxPacketBufPtr; 14297542SBrad.Beckmann@amd.com rxDmaLen = rxXferLen; 14307542SBrad.Beckmann@amd.com rxDmaFree = dmaDataFree; 14317542SBrad.Beckmann@amd.com 14327542SBrad.Beckmann@amd.com if (doRxDmaWrite()) 14337542SBrad.Beckmann@amd.com goto exit; 14347542SBrad.Beckmann@amd.com 14357542SBrad.Beckmann@amd.com } else { 14367542SBrad.Beckmann@amd.com rxState = rxDescWrite; 14377542SBrad.Beckmann@amd.com 14387542SBrad.Beckmann@amd.com //if (rxPktBytes == 0) { /* packet is done */ 14397542SBrad.Beckmann@amd.com assert(rxPktBytes == 0); 14407542SBrad.Beckmann@amd.com DPRINTF(EthernetSM, "done with receiving packet\n"); 14417542SBrad.Beckmann@amd.com 14427542SBrad.Beckmann@amd.com rxDescCache.cmdsts |= CMDSTS_OWN; 14437542SBrad.Beckmann@amd.com rxDescCache.cmdsts &= ~CMDSTS_MORE; 14447542SBrad.Beckmann@amd.com rxDescCache.cmdsts |= CMDSTS_OK; 14457542SBrad.Beckmann@amd.com rxDescCache.cmdsts &= 0xffff0000; 14467542SBrad.Beckmann@amd.com rxDescCache.cmdsts += rxPacket->length; //i.e. set CMDSTS_SIZE 14476657Snate@binkert.org 14486999Snate@binkert.org#if 0 14496657Snate@binkert.org /* all the driver uses these are for its own stats keeping 14506657Snate@binkert.org which we don't care about, aren't necessary for functionality 14516657Snate@binkert.org and doing this would just slow us down. if they end up using 14526657Snate@binkert.org this in a later version for functional purposes, just undef 14536657Snate@binkert.org */ 14546657Snate@binkert.org if (rxFilterEnable) { 14557542SBrad.Beckmann@amd.com rxDescCache.cmdsts &= ~CMDSTS_DEST_MASK; 14567542SBrad.Beckmann@amd.com if (rxFifo.front()->IsUnicast()) 14576657Snate@binkert.org rxDescCache.cmdsts |= CMDSTS_DEST_SELF; 14587832Snate@binkert.org if (rxFifo.front()->IsMulticast()) 14597002Snate@binkert.org rxDescCache.cmdsts |= CMDSTS_DEST_MULTI; 14607002Snate@binkert.org if (rxFifo.front()->IsBroadcast()) 14618229Snate@binkert.org rxDescCache.cmdsts |= CMDSTS_DEST_MASK; 14628229Snate@binkert.org } 14638608Snilay@cs.wisc.edu#endif 14646657Snate@binkert.org 14657007Snate@binkert.org if (rxPacket->isIpPkt() && extstsEnable) { 14667007Snate@binkert.org rxDescCache.extsts |= EXTSTS_IPPKT; 14676657Snate@binkert.org rxIPChecksums++; 14686657Snate@binkert.org if (!ipChecksum(rxPacket, false)) { 14696657Snate@binkert.org DPRINTF(EthernetCksum, "Rx IP Checksum Error\n"); 14706657Snate@binkert.org rxDescCache.extsts |= EXTSTS_IPERR; 14716657Snate@binkert.org } 14727542SBrad.Beckmann@amd.com if (rxPacket->isTcpPkt()) { 14737542SBrad.Beckmann@amd.com rxDescCache.extsts |= EXTSTS_TCPPKT; 14747542SBrad.Beckmann@amd.com rxTCPChecksums++; 14756657Snate@binkert.org if (!tcpChecksum(rxPacket, false)) { 14766657Snate@binkert.org DPRINTF(EthernetCksum, "Rx TCP Checksum Error\n"); 14776657Snate@binkert.org rxDescCache.extsts |= EXTSTS_TCPERR; 14786657Snate@binkert.org 14796657Snate@binkert.org } 14806657Snate@binkert.org } else if (rxPacket->isUdpPkt()) { 14816657Snate@binkert.org rxDescCache.extsts |= EXTSTS_UDPPKT; 14826657Snate@binkert.org if (!udpChecksum(rxPacket, false)) { 14836657Snate@binkert.org DPRINTF(EthernetCksum, "Rx UDP Checksum Error\n"); 14847007Snate@binkert.org rxDescCache.extsts |= EXTSTS_UDPERR; 14856657Snate@binkert.org } 14866657Snate@binkert.org } 14876657Snate@binkert.org } 14886657Snate@binkert.org rxPacket = 0; 14896999Snate@binkert.org 14906657Snate@binkert.org /* the driver seems to always receive into desc buffers 14916657Snate@binkert.org of size 1514, so you never have a pkt that is split 14926657Snate@binkert.org into multiple descriptors on the receive side, so 14936657Snate@binkert.org i don't implement that case, hence the assert above. 14946657Snate@binkert.org */ 14956657Snate@binkert.org 14967832Snate@binkert.org DPRINTF(EthernetDesc, "rxDesc writeback:\n\tcmdsts=%08x\n\textsts=%08x\n", 14977832Snate@binkert.org rxDescCache.cmdsts, rxDescCache.extsts); 14986657Snate@binkert.org 14996657Snate@binkert.org rxDmaAddr = (regs.rxdp + offsetof(ns_desc, cmdsts)) & 0x3fffffff; 15006657Snate@binkert.org rxDmaData = &(rxDescCache.cmdsts); 15016657Snate@binkert.org rxDmaLen = sizeof(rxDescCache.cmdsts) + sizeof(rxDescCache.extsts); 15026657Snate@binkert.org rxDmaFree = dmaDescFree; 15036657Snate@binkert.org 15046657Snate@binkert.org descDmaWrites++; 15056657Snate@binkert.org descDmaWrBytes += rxDmaLen; 15066657Snate@binkert.org 15076657Snate@binkert.org if (doRxDmaWrite()) 15086657Snate@binkert.org goto exit; 15096657Snate@binkert.org } 15106657Snate@binkert.org break; 15116657Snate@binkert.org 15127007Snate@binkert.org case rxFragWrite: 15137007Snate@binkert.org if (rxDmaState != dmaIdle) 15147007Snate@binkert.org goto exit; 15156657Snate@binkert.org 15166657Snate@binkert.org rxPacketBufPtr += rxXferLen; 15176657Snate@binkert.org rxFragPtr += rxXferLen; 15187007Snate@binkert.org rxPktBytes -= rxXferLen; 15197007Snate@binkert.org 15207007Snate@binkert.org rxState = rxFifoBlock; 15216657Snate@binkert.org break; 15226657Snate@binkert.org 15236657Snate@binkert.org case rxDescWrite: 15246657Snate@binkert.org if (rxDmaState != dmaIdle) 15256657Snate@binkert.org goto exit; 15266657Snate@binkert.org 15276657Snate@binkert.org assert(rxDescCache.cmdsts & CMDSTS_OWN); 15286657Snate@binkert.org 15296657Snate@binkert.org assert(rxPacket == 0); 15306657Snate@binkert.org devIntrPost(ISR_RXOK); 15316657Snate@binkert.org 15327007Snate@binkert.org if (rxDescCache.cmdsts & CMDSTS_INTR) 15337007Snate@binkert.org devIntrPost(ISR_RXDESC); 15346657Snate@binkert.org 15356657Snate@binkert.org if (rxHalt) { 15366657Snate@binkert.org DPRINTF(EthernetSM, "Halting the RX state machine\n"); 15376657Snate@binkert.org rxState = rxIdle; 15386657Snate@binkert.org rxHalt = false; 15397007Snate@binkert.org } else 15407007Snate@binkert.org rxState = rxAdvance; 15417007Snate@binkert.org break; 15426657Snate@binkert.org 15436657Snate@binkert.org case rxAdvance: 15446657Snate@binkert.org if (rxDescCache.link == 0) { 15457007Snate@binkert.org rxState = rxIdle; 15467542SBrad.Beckmann@amd.com return; 15477542SBrad.Beckmann@amd.com } else { 15486657Snate@binkert.org rxState = rxDescRead; 15497542SBrad.Beckmann@amd.com regs.rxdp = rxDescCache.link; 15507542SBrad.Beckmann@amd.com CRDD = false; 15517002Snate@binkert.org 15527542SBrad.Beckmann@amd.com rxDmaAddr = regs.rxdp & 0x3fffffff; 15537542SBrad.Beckmann@amd.com rxDmaData = &rxDescCache; 15547542SBrad.Beckmann@amd.com rxDmaLen = sizeof(ns_desc); 15557542SBrad.Beckmann@amd.com rxDmaFree = dmaDescFree; 15566657Snate@binkert.org 15577542SBrad.Beckmann@amd.com if (doRxDmaRead()) 15587542SBrad.Beckmann@amd.com goto exit; 15597542SBrad.Beckmann@amd.com } 15607542SBrad.Beckmann@amd.com break; 15617542SBrad.Beckmann@amd.com 15627542SBrad.Beckmann@amd.com default: 15637542SBrad.Beckmann@amd.com panic("Invalid rxState!"); 15647542SBrad.Beckmann@amd.com } 15656657Snate@binkert.org 15666657Snate@binkert.org 15676657Snate@binkert.org DPRINTF(EthernetSM, "entering next rx state = %s\n", 15686657Snate@binkert.org NsRxStateStrings[rxState]); 15696657Snate@binkert.org 15706657Snate@binkert.org if (rxState == rxIdle) { 15717007Snate@binkert.org regs.command &= ~CR_RXE; 15726999Snate@binkert.org devIntrPost(ISR_RXIDLE); 15737007Snate@binkert.org return; 15747007Snate@binkert.org } 15757007Snate@binkert.org 15767007Snate@binkert.org goto next; 15777007Snate@binkert.org 15787007Snate@binkert.org exit: 15796657Snate@binkert.org /** 15806657Snate@binkert.org * @todo do we want to schedule a future kick? 15816657Snate@binkert.org */ 15826657Snate@binkert.org DPRINTF(EthernetSM, "rx state machine exited state=%s\n", 15836657Snate@binkert.org NsRxStateStrings[rxState]); 15846657Snate@binkert.org} 15856657Snate@binkert.org 15866657Snate@binkert.orgvoid 15876657Snate@binkert.orgNSGigE::transmit() 15886657Snate@binkert.org{ 15896657Snate@binkert.org if (txFifo.empty()) { 15906657Snate@binkert.org DPRINTF(Ethernet, "nothing to transmit\n"); 15916657Snate@binkert.org return; 15926657Snate@binkert.org } 15936657Snate@binkert.org 15946657Snate@binkert.org DPRINTF(Ethernet, "\n\nAttempt Pkt Transmit: txFifo length = %d\n", 15956657Snate@binkert.org maxTxFifoSize - txFifoAvail); 15966657Snate@binkert.org if (interface->sendPacket(txFifo.front())) { 15976657Snate@binkert.org if (DTRACE(Ethernet)) { 15986657Snate@binkert.org if (txFifo.front()->isIpPkt()) { 15996657Snate@binkert.org ip_header *ip = txFifo.front()->getIpHdr(); 16006657Snate@binkert.org DPRINTF(Ethernet, "ID is %d\n", reverseEnd16(ip->ID)); 16016657Snate@binkert.org if (txFifo.front()->isTcpPkt()) { 16026657Snate@binkert.org tcp_header *tcp = txFifo.front()->getTcpHdr(ip); 16036657Snate@binkert.org DPRINTF(Ethernet, "Src Port = %d, Dest Port = %d\n", 16046657Snate@binkert.org reverseEnd16(tcp->src_port_num), 16056657Snate@binkert.org reverseEnd16(tcp->dest_port_num)); 16066657Snate@binkert.org } 16076657Snate@binkert.org } 16086999Snate@binkert.org } 16096657Snate@binkert.org 16106657Snate@binkert.org DDUMP(Ethernet, txFifo.front()->data, txFifo.front()->length); 16117007Snate@binkert.org txBytes += txFifo.front()->length; 16127007Snate@binkert.org txPackets++; 16136657Snate@binkert.org 16146657Snate@binkert.org txFifoAvail += txFifo.front()->length; 16156657Snate@binkert.org 16166657Snate@binkert.org DPRINTF(Ethernet, "Successful Xmit! now txFifoAvail is %d\n", txFifoAvail); 16176657Snate@binkert.org txFifo.front() = NULL; 16186657Snate@binkert.org txFifo.pop_front(); 16196657Snate@binkert.org 16206657Snate@binkert.org /* normally do a writeback of the descriptor here, and ONLY after that is 16216657Snate@binkert.org done, send this interrupt. but since our stuff never actually fails, 16226657Snate@binkert.org just do this interrupt here, otherwise the code has to stray from this 16236657Snate@binkert.org nice format. besides, it's functionally the same. 16246657Snate@binkert.org */ 16256657Snate@binkert.org devIntrPost(ISR_TXOK); 16266657Snate@binkert.org } else 16276657Snate@binkert.org DPRINTF(Ethernet, "May need to rethink always sending the descriptors back?\n"); 16286657Snate@binkert.org 16296657Snate@binkert.org if (!txFifo.empty() && !txEvent.scheduled()) { 16306657Snate@binkert.org DPRINTF(Ethernet, "reschedule transmit\n"); 16316657Snate@binkert.org txEvent.schedule(curTick + 1000); 16326657Snate@binkert.org } 16336657Snate@binkert.org} 16346657Snate@binkert.org 16356657Snate@binkert.orgvoid 16366657Snate@binkert.orgNSGigE::txDmaReadCopy() 16376657Snate@binkert.org{ 16386657Snate@binkert.org assert(txDmaState == dmaReading); 16396657Snate@binkert.org 16406657Snate@binkert.org memcpy(txDmaData, physmem->dma_addr(txDmaAddr, txDmaLen), txDmaLen); 16416657Snate@binkert.org txDmaState = dmaIdle; 16426657Snate@binkert.org 16436657Snate@binkert.org DPRINTF(EthernetDMA, "tx dma read paddr=%#x len=%d\n", 16446657Snate@binkert.org txDmaAddr, txDmaLen); 16456657Snate@binkert.org DDUMP(EthernetDMA, txDmaData, txDmaLen); 16466657Snate@binkert.org} 16476657Snate@binkert.org 16486657Snate@binkert.orgbool 16496657Snate@binkert.orgNSGigE::doTxDmaRead() 16506657Snate@binkert.org{ 16516657Snate@binkert.org assert(txDmaState == dmaIdle || txDmaState == dmaReadWaiting); 16526657Snate@binkert.org txDmaState = dmaReading; 16536657Snate@binkert.org 16546657Snate@binkert.org if (dmaInterface && !txDmaFree) { 16556657Snate@binkert.org if (dmaInterface->busy()) 16566657Snate@binkert.org txDmaState = dmaReadWaiting; 16576657Snate@binkert.org else 16586657Snate@binkert.org dmaInterface->doDMA(Read, txDmaAddr, txDmaLen, curTick, 16596657Snate@binkert.org &txDmaReadEvent, true); 16606657Snate@binkert.org return true; 16616657Snate@binkert.org } 16626657Snate@binkert.org 16636657Snate@binkert.org if (dmaReadDelay == 0 && dmaReadFactor == 0.0) { 16646657Snate@binkert.org txDmaReadCopy(); 16656657Snate@binkert.org return false; 16666657Snate@binkert.org } 16676657Snate@binkert.org 16686657Snate@binkert.org Tick factor = ((txDmaLen + ULL(63)) >> ULL(6)) * dmaReadFactor; 16696657Snate@binkert.org Tick start = curTick + dmaReadDelay + factor; 16706657Snate@binkert.org txDmaReadEvent.schedule(start); 16716657Snate@binkert.org return true; 16726657Snate@binkert.org} 16736657Snate@binkert.org 16746657Snate@binkert.orgvoid 16756657Snate@binkert.orgNSGigE::txDmaReadDone() 16766657Snate@binkert.org{ 16776657Snate@binkert.org assert(txDmaState == dmaReading); 16786657Snate@binkert.org txDmaReadCopy(); 16796657Snate@binkert.org 16806657Snate@binkert.org // If the receive state machine has a pending DMA, let it go first 16816657Snate@binkert.org if (rxDmaState == dmaReadWaiting || rxDmaState == dmaWriteWaiting) 16826657Snate@binkert.org rxKick(); 16836657Snate@binkert.org 16846657Snate@binkert.org txKick(); 16856657Snate@binkert.org} 16866657Snate@binkert.org 16876657Snate@binkert.orgvoid 16886657Snate@binkert.orgNSGigE::txDmaWriteCopy() 16896657Snate@binkert.org{ 16906657Snate@binkert.org assert(txDmaState == dmaWriting); 16916657Snate@binkert.org 16926657Snate@binkert.org memcpy(physmem->dma_addr(txDmaAddr, txDmaLen), txDmaData, txDmaLen); 16936657Snate@binkert.org txDmaState = dmaIdle; 16946657Snate@binkert.org 16956657Snate@binkert.org DPRINTF(EthernetDMA, "tx dma write paddr=%#x len=%d\n", 16966657Snate@binkert.org txDmaAddr, txDmaLen); 16976657Snate@binkert.org DDUMP(EthernetDMA, txDmaData, txDmaLen); 16986657Snate@binkert.org} 16996657Snate@binkert.org 17006657Snate@binkert.orgbool 17017007Snate@binkert.orgNSGigE::doTxDmaWrite() 17026657Snate@binkert.org{ 17036657Snate@binkert.org assert(txDmaState == dmaIdle || txDmaState == dmaWriteWaiting); 17046657Snate@binkert.org txDmaState = dmaWriting; 17056657Snate@binkert.org 17066657Snate@binkert.org if (dmaInterface && !txDmaFree) { 17076657Snate@binkert.org if (dmaInterface->busy()) 17086657Snate@binkert.org txDmaState = dmaWriteWaiting; 17097007Snate@binkert.org else 17106657Snate@binkert.org dmaInterface->doDMA(WriteInvalidate, txDmaAddr, txDmaLen, curTick, 17116657Snate@binkert.org &txDmaWriteEvent, true); 17126657Snate@binkert.org return true; 17136657Snate@binkert.org } 17146657Snate@binkert.org 17156657Snate@binkert.org if (dmaWriteDelay == 0 && dmaWriteFactor == 0.0) { 17166657Snate@binkert.org txDmaWriteCopy(); 17176657Snate@binkert.org return false; 17186657Snate@binkert.org } 17196657Snate@binkert.org 17206657Snate@binkert.org Tick factor = ((txDmaLen + ULL(63)) >> ULL(6)) * dmaWriteFactor; 17216657Snate@binkert.org Tick start = curTick + dmaWriteDelay + factor; 17226657Snate@binkert.org txDmaWriteEvent.schedule(start); 17236657Snate@binkert.org return true; 17246657Snate@binkert.org} 17257007Snate@binkert.org 17266657Snate@binkert.orgvoid 17276657Snate@binkert.orgNSGigE::txDmaWriteDone() 17286657Snate@binkert.org{ 17296657Snate@binkert.org assert(txDmaState == dmaWriting); 17306657Snate@binkert.org txDmaWriteCopy(); 17316657Snate@binkert.org 17326657Snate@binkert.org // If the receive state machine has a pending DMA, let it go first 17336657Snate@binkert.org if (rxDmaState == dmaReadWaiting || rxDmaState == dmaWriteWaiting) 17346657Snate@binkert.org rxKick(); 17356657Snate@binkert.org 17366657Snate@binkert.org txKick(); 17376657Snate@binkert.org} 17386657Snate@binkert.org 17396657Snate@binkert.orgvoid 17406657Snate@binkert.orgNSGigE::txKick() 17416657Snate@binkert.org{ 17426657Snate@binkert.org DPRINTF(EthernetSM, "transmit kick state=%s\n", NsTxStateStrings[txState]); 17436657Snate@binkert.org 17446657Snate@binkert.org if (txKickTick > curTick) { 17456657Snate@binkert.org DPRINTF(EthernetSM, "transmit kick exiting, can't run till %d\n", 17466657Snate@binkert.org txKickTick); 17476657Snate@binkert.org 1748 return; 1749 } 1750 1751 next: 1752 switch(txDmaState) { 1753 case dmaReadWaiting: 1754 if (doTxDmaRead()) 1755 goto exit; 1756 break; 1757 case dmaWriteWaiting: 1758 if (doTxDmaWrite()) 1759 goto exit; 1760 break; 1761 default: 1762 break; 1763 } 1764 1765 switch (txState) { 1766 case txIdle: 1767 if (!regs.command & CR_TXE) { 1768 DPRINTF(EthernetSM, "Transmit disabled. Nothing to do.\n"); 1769 goto exit; 1770 } 1771 1772 if (CTDD) { 1773 txState = txDescRefr; 1774 1775 txDmaAddr = regs.txdp & 0x3fffffff; 1776 txDmaData = &txDescCache + offsetof(ns_desc, link); 1777 txDmaLen = sizeof(txDescCache.link); 1778 txDmaFree = dmaDescFree; 1779 1780 descDmaReads++; 1781 descDmaRdBytes += txDmaLen; 1782 1783 if (doTxDmaRead()) 1784 goto exit; 1785 1786 } else { 1787 txState = txDescRead; 1788 1789 txDmaAddr = regs.txdp & 0x3fffffff; 1790 txDmaData = &txDescCache; 1791 txDmaLen = sizeof(ns_desc); 1792 txDmaFree = dmaDescFree; 1793 1794 descDmaReads++; 1795 descDmaRdBytes += txDmaLen; 1796 1797 if (doTxDmaRead()) 1798 goto exit; 1799 } 1800 break; 1801 1802 case txDescRefr: 1803 if (txDmaState != dmaIdle) 1804 goto exit; 1805 1806 txState = txAdvance; 1807 break; 1808 1809 case txDescRead: 1810 if (txDmaState != dmaIdle) 1811 goto exit; 1812 1813 DPRINTF(EthernetDesc, 1814 "txDescCache data:\n\tlink=%08x\n\tbufptr=%08x\n\tcmdsts=%08x\n\textsts=%08x\n" 1815 ,txDescCache.link, txDescCache.bufptr, txDescCache.cmdsts, 1816 txDescCache.extsts); 1817 1818 if (txDescCache.cmdsts & CMDSTS_OWN) { 1819 txState = txFifoBlock; 1820 txFragPtr = txDescCache.bufptr; 1821 txDescCnt = txDescCache.cmdsts & CMDSTS_LEN_MASK; 1822 } else { 1823 txState = txIdle; 1824 } 1825 break; 1826 1827 case txFifoBlock: 1828 if (!txPacket) { 1829 DPRINTF(EthernetSM, "\n\n*****starting the tx of a new packet\n"); 1830 txPacket = new EtherPacket; 1831 txPacket->data = new uint8_t[16384]; 1832 txPacketBufPtr = txPacket->data; 1833 } 1834 1835 if (txDescCnt == 0) { 1836 DPRINTF(EthernetSM, "the txDescCnt == 0, done with descriptor\n"); 1837 if (txDescCache.cmdsts & CMDSTS_MORE) { 1838 DPRINTF(EthernetSM, "there are more descriptors to come\n"); 1839 txState = txDescWrite; 1840 1841 txDescCache.cmdsts &= ~CMDSTS_OWN; 1842 1843 txDmaAddr = (regs.txdp + offsetof(ns_desc, cmdsts)) & 0x3fffffff; 1844 txDmaData = &(txDescCache.cmdsts); 1845 txDmaLen = sizeof(txDescCache.cmdsts); 1846 txDmaFree = dmaDescFree; 1847 1848 if (doTxDmaWrite()) 1849 goto exit; 1850 1851 } else { /* this packet is totally done */ 1852 DPRINTF(EthernetSM, "This packet is done, let's wrap it up\n"); 1853 /* deal with the the packet that just finished */ 1854 if ((regs.vtcr & VTCR_PPCHK) && extstsEnable) { 1855 if (txDescCache.extsts & EXTSTS_UDPPKT) { 1856 udpChecksum(txPacket, true); 1857 } else if (txDescCache.extsts & EXTSTS_TCPPKT) { 1858 tcpChecksum(txPacket, true); 1859 txTCPChecksums++; 1860 } 1861 if (txDescCache.extsts & EXTSTS_IPPKT) { 1862 ipChecksum(txPacket, true); 1863 txIPChecksums++; 1864 } 1865 } 1866 1867 txPacket->length = txPacketBufPtr - txPacket->data; 1868 /* this is just because the receive can't handle a packet bigger 1869 want to make sure */ 1870 assert(txPacket->length <= 1514); 1871 txFifo.push_back(txPacket); 1872 1873 /* this following section is not to spec, but functionally shouldn't 1874 be any different. normally, the chip will wait til the transmit has 1875 occurred before writing back the descriptor because it has to wait 1876 to see that it was successfully transmitted to decide whether to set 1877 CMDSTS_OK or not. however, in the simulator since it is always 1878 successfully transmitted, and writing it exactly to spec would 1879 complicate the code, we just do it here 1880 */ 1881 1882 txDescCache.cmdsts &= ~CMDSTS_OWN; 1883 txDescCache.cmdsts |= CMDSTS_OK; 1884 1885 DPRINTF(EthernetDesc, 1886 "txDesc writeback:\n\tcmdsts=%08x\n\textsts=%08x\n", 1887 txDescCache.cmdsts, txDescCache.extsts); 1888 1889 txDmaAddr = (regs.txdp + offsetof(ns_desc, cmdsts)) & 0x3fffffff; 1890 txDmaData = &(txDescCache.cmdsts); 1891 txDmaLen = sizeof(txDescCache.cmdsts) + sizeof(txDescCache.extsts); 1892 txDmaFree = dmaDescFree; 1893 1894 descDmaWrites++; 1895 descDmaWrBytes += txDmaLen; 1896 1897 transmit(); 1898 txPacket = 0; 1899 1900 if (txHalt) { 1901 DPRINTF(EthernetSM, "halting TX state machine\n"); 1902 txState = txIdle; 1903 txHalt = false; 1904 } else 1905 txState = txAdvance; 1906 1907 if (doTxDmaWrite()) 1908 goto exit; 1909 } 1910 } else { 1911 DPRINTF(EthernetSM, "this descriptor isn't done yet\n"); 1912 if (txFifoAvail) { 1913 txState = txFragRead; 1914 1915 /* The number of bytes transferred is either whatever is left 1916 in the descriptor (txDescCnt), or if there is not enough 1917 room in the fifo, just whatever room is left in the fifo 1918 */ 1919 txXferLen = min<uint32_t>(txDescCnt, txFifoAvail); 1920 1921 txDmaAddr = txFragPtr & 0x3fffffff; 1922 txDmaData = txPacketBufPtr; 1923 txDmaLen = txXferLen; 1924 txDmaFree = dmaDataFree; 1925 1926 if (doTxDmaRead()) 1927 goto exit; 1928 } else { 1929 txState = txFifoBlock; 1930 transmit(); 1931 1932 goto exit; 1933 } 1934 1935 } 1936 break; 1937 1938 case txFragRead: 1939 if (txDmaState != dmaIdle) 1940 goto exit; 1941 1942 txPacketBufPtr += txXferLen; 1943 txFragPtr += txXferLen; 1944 txDescCnt -= txXferLen; 1945 txFifoAvail -= txXferLen; 1946 1947 txState = txFifoBlock; 1948 break; 1949 1950 case txDescWrite: 1951 if (txDmaState != dmaIdle) 1952 goto exit; 1953 1954 if (txDescCache.cmdsts & CMDSTS_INTR) { 1955 devIntrPost(ISR_TXDESC); 1956 } 1957 1958 txState = txAdvance; 1959 break; 1960 1961 case txAdvance: 1962 if (txDescCache.link == 0) { 1963 txState = txIdle; 1964 } else { 1965 txState = txDescRead; 1966 regs.txdp = txDescCache.link; 1967 CTDD = false; 1968 1969 txDmaAddr = txDescCache.link & 0x3fffffff; 1970 txDmaData = &txDescCache; 1971 txDmaLen = sizeof(ns_desc); 1972 txDmaFree = dmaDescFree; 1973 1974 if (doTxDmaRead()) 1975 goto exit; 1976 } 1977 break; 1978 1979 default: 1980 panic("invalid state"); 1981 } 1982 1983 DPRINTF(EthernetSM, "entering next tx state=%s\n", 1984 NsTxStateStrings[txState]); 1985 1986 if (txState == txIdle) { 1987 regs.command &= ~CR_TXE; 1988 devIntrPost(ISR_TXIDLE); 1989 return; 1990 } 1991 1992 goto next; 1993 1994 exit: 1995 /** 1996 * @todo do we want to schedule a future kick? 1997 */ 1998 DPRINTF(EthernetSM, "tx state machine exited state=%s\n", 1999 NsTxStateStrings[txState]); 2000} 2001 2002void 2003NSGigE::transferDone() 2004{ 2005 if (txFifo.empty()) 2006 return; 2007 2008 if (txEvent.scheduled()) 2009 txEvent.reschedule(curTick + 1); 2010 else 2011 txEvent.schedule(curTick + 1); 2012} 2013 2014bool 2015NSGigE::rxFilter(PacketPtr packet) 2016{ 2017 bool drop = true; 2018 string type; 2019 2020 if (packet->IsUnicast()) { 2021 type = "unicast"; 2022 2023 // If we're accepting all unicast addresses 2024 if (acceptUnicast) 2025 drop = false; 2026 2027 // If we make a perfect match 2028 if ((acceptPerfect) 2029 && (memcmp(rom.perfectMatch, packet->data, sizeof(rom.perfectMatch)) == 0)) 2030 drop = false; 2031 2032 eth_header *eth = (eth_header *) packet->data; 2033 if ((acceptArp) && (eth->type == 0x608)) 2034 drop = false; 2035 2036 } else if (packet->IsBroadcast()) { 2037 type = "broadcast"; 2038 2039 // if we're accepting broadcasts 2040 if (acceptBroadcast) 2041 drop = false; 2042 2043 } else if (packet->IsMulticast()) { 2044 type = "multicast"; 2045 2046 // if we're accepting all multicasts 2047 if (acceptMulticast) 2048 drop = false; 2049 2050 } else { 2051 type = "unknown"; 2052 2053 // oh well, punt on this one 2054 } 2055 2056 if (drop) { 2057 DPRINTF(Ethernet, "rxFilter drop\n"); 2058 DDUMP(EthernetData, packet->data, packet->length); 2059 } 2060 2061 return drop; 2062} 2063 2064bool 2065NSGigE::recvPacket(PacketPtr packet) 2066{ 2067 rxBytes += packet->length; 2068 rxPackets++; 2069 2070 DPRINTF(Ethernet, "\n\nReceiving packet from wire, rxFifoAvail = %d\n", maxRxFifoSize - rxFifoCnt); 2071 2072 if (rxState == rxIdle) { 2073 DPRINTF(Ethernet, "receive disabled...packet dropped\n"); 2074 interface->recvDone(); 2075 return true; 2076 } 2077 2078 if (rxFilterEnable && rxFilter(packet)) { 2079 DPRINTF(Ethernet, "packet filtered...dropped\n"); 2080 interface->recvDone(); 2081 return true; 2082 } 2083 2084 if ((rxFifoCnt + packet->length) >= maxRxFifoSize) { 2085 DPRINTF(Ethernet, 2086 "packet will not fit in receive buffer...packet dropped\n"); 2087 devIntrPost(ISR_RXORN); 2088 return false; 2089 } 2090 2091 rxFifo.push_back(packet); 2092 rxFifoCnt += packet->length; 2093 interface->recvDone(); 2094 2095 rxKick(); 2096 return true; 2097} 2098 2099/** 2100 * does a udp checksum. if gen is true, then it generates it and puts it in the right place 2101 * else, it just checks what it calculates against the value in the header in packet 2102 */ 2103bool 2104NSGigE::udpChecksum(PacketPtr packet, bool gen) 2105{ 2106 ip_header *ip = packet->getIpHdr(); 2107 udp_header *hdr = packet->getUdpHdr(ip); 2108 2109 pseudo_header *pseudo = new pseudo_header; 2110 2111 pseudo->src_ip_addr = ip->src_ip_addr; 2112 pseudo->dest_ip_addr = ip->dest_ip_addr; 2113 pseudo->protocol = ip->protocol; 2114 pseudo->len = hdr->len; 2115 2116 uint16_t cksum = checksumCalc((uint16_t *) pseudo, (uint16_t *) hdr, 2117 (uint32_t) hdr->len); 2118 2119 delete pseudo; 2120 if (gen) 2121 hdr->chksum = cksum; 2122 else 2123 if (cksum != 0) 2124 return false; 2125 2126 return true; 2127} 2128 2129bool 2130NSGigE::tcpChecksum(PacketPtr packet, bool gen) 2131{ 2132 ip_header *ip = packet->getIpHdr(); 2133 tcp_header *hdr = packet->getTcpHdr(ip); 2134 2135 uint16_t cksum; 2136 pseudo_header *pseudo = new pseudo_header; 2137 if (!gen) { 2138 pseudo->src_ip_addr = ip->src_ip_addr; 2139 pseudo->dest_ip_addr = ip->dest_ip_addr; 2140 pseudo->protocol = reverseEnd16(ip->protocol); 2141 pseudo->len = reverseEnd16(reverseEnd16(ip->dgram_len) - (ip->vers_len & 0xf)*4); 2142 2143 cksum = checksumCalc((uint16_t *) pseudo, (uint16_t *) hdr, 2144 (uint32_t) reverseEnd16(pseudo->len)); 2145 } else { 2146 pseudo->src_ip_addr = 0; 2147 pseudo->dest_ip_addr = 0; 2148 pseudo->protocol = hdr->chksum; 2149 pseudo->len = 0; 2150 hdr->chksum = 0; 2151 cksum = checksumCalc((uint16_t *) pseudo, (uint16_t *) hdr, 2152 (uint32_t) (reverseEnd16(ip->dgram_len) - (ip->vers_len & 0xf)*4)); 2153 } 2154 2155 delete pseudo; 2156 if (gen) 2157 hdr->chksum = cksum; 2158 else 2159 if (cksum != 0) 2160 return false; 2161 2162 return true; 2163} 2164 2165bool 2166NSGigE::ipChecksum(PacketPtr packet, bool gen) 2167{ 2168 ip_header *hdr = packet->getIpHdr(); 2169 2170 uint16_t cksum = checksumCalc(NULL, (uint16_t *) hdr, (hdr->vers_len & 0xf)*4); 2171 2172 if (gen) { 2173 DPRINTF(EthernetCksum, "generated checksum: %#x\n", cksum); 2174 hdr->hdr_chksum = cksum; 2175 } 2176 else 2177 if (cksum != 0) 2178 return false; 2179 2180 return true; 2181} 2182 2183uint16_t 2184NSGigE::checksumCalc(uint16_t *pseudo, uint16_t *buf, uint32_t len) 2185{ 2186 uint32_t sum = 0; 2187 2188 uint16_t last_pad = 0; 2189 if (len & 1) { 2190 last_pad = buf[len/2] & 0xff; 2191 len--; 2192 sum += last_pad; 2193 } 2194 2195 if (pseudo) { 2196 sum = pseudo[0] + pseudo[1] + pseudo[2] + 2197 pseudo[3] + pseudo[4] + pseudo[5]; 2198 } 2199 2200 for (int i=0; i < (len/2); ++i) { 2201 sum += buf[i]; 2202 } 2203 2204 while (sum >> 16) 2205 sum = (sum >> 16) + (sum & 0xffff); 2206 2207 return ~sum; 2208} 2209 2210//===================================================================== 2211// 2212// 2213void 2214NSGigE::serialize(ostream &os) 2215{ 2216 // Serialize the PciDev base class 2217 PciDev::serialize(os); 2218 2219 /* 2220 * Finalize any DMA events now. 2221 */ 2222 if (rxDmaReadEvent.scheduled()) 2223 rxDmaReadCopy(); 2224 if (rxDmaWriteEvent.scheduled()) 2225 rxDmaWriteCopy(); 2226 if (txDmaReadEvent.scheduled()) 2227 txDmaReadCopy(); 2228 if (txDmaWriteEvent.scheduled()) 2229 txDmaWriteCopy(); 2230 2231 /* 2232 * Serialize the device registers 2233 */ 2234 SERIALIZE_SCALAR(regs.command); 2235 SERIALIZE_SCALAR(regs.config); 2236 SERIALIZE_SCALAR(regs.mear); 2237 SERIALIZE_SCALAR(regs.ptscr); 2238 SERIALIZE_SCALAR(regs.isr); 2239 SERIALIZE_SCALAR(regs.imr); 2240 SERIALIZE_SCALAR(regs.ier); 2241 SERIALIZE_SCALAR(regs.ihr); 2242 SERIALIZE_SCALAR(regs.txdp); 2243 SERIALIZE_SCALAR(regs.txdp_hi); 2244 SERIALIZE_SCALAR(regs.txcfg); 2245 SERIALIZE_SCALAR(regs.gpior); 2246 SERIALIZE_SCALAR(regs.rxdp); 2247 SERIALIZE_SCALAR(regs.rxdp_hi); 2248 SERIALIZE_SCALAR(regs.rxcfg); 2249 SERIALIZE_SCALAR(regs.pqcr); 2250 SERIALIZE_SCALAR(regs.wcsr); 2251 SERIALIZE_SCALAR(regs.pcr); 2252 SERIALIZE_SCALAR(regs.rfcr); 2253 SERIALIZE_SCALAR(regs.rfdr); 2254 SERIALIZE_SCALAR(regs.srr); 2255 SERIALIZE_SCALAR(regs.mibc); 2256 SERIALIZE_SCALAR(regs.vrcr); 2257 SERIALIZE_SCALAR(regs.vtcr); 2258 SERIALIZE_SCALAR(regs.vdr); 2259 SERIALIZE_SCALAR(regs.ccsr); 2260 SERIALIZE_SCALAR(regs.tbicr); 2261 SERIALIZE_SCALAR(regs.tbisr); 2262 SERIALIZE_SCALAR(regs.tanar); 2263 SERIALIZE_SCALAR(regs.tanlpar); 2264 SERIALIZE_SCALAR(regs.taner); 2265 SERIALIZE_SCALAR(regs.tesr); 2266 2267 SERIALIZE_ARRAY(rom.perfectMatch, EADDR_LEN); 2268 2269 SERIALIZE_SCALAR(ioEnable); 2270 2271 /* 2272 * Serialize the data Fifos 2273 */ 2274 int txNumPkts = txFifo.size(); 2275 SERIALIZE_SCALAR(txNumPkts); 2276 int i = 0; 2277 pktiter_t end = txFifo.end(); 2278 for (pktiter_t p = txFifo.begin(); p != end; ++p) { 2279 nameOut(os, csprintf("%s.txFifo%d", name(), i++)); 2280 (*p)->serialize(os); 2281 } 2282 2283 int rxNumPkts = rxFifo.size(); 2284 SERIALIZE_SCALAR(rxNumPkts); 2285 i = 0; 2286 end = rxFifo.end(); 2287 for (pktiter_t p = rxFifo.begin(); p != end; ++p) { 2288 nameOut(os, csprintf("%s.rxFifo%d", name(), i++)); 2289 (*p)->serialize(os); 2290 } 2291 2292 /* 2293 * Serialize the various helper variables 2294 */ 2295 bool txPacketExists = txPacket; 2296 SERIALIZE_SCALAR(txPacketExists); 2297 if (txPacketExists) { 2298 nameOut(os, csprintf("%s.txPacket", name())); 2299 txPacket->serialize(os); 2300 uint32_t txPktBufPtr = (uint32_t) (txPacketBufPtr - txPacket->data); 2301 SERIALIZE_SCALAR(txPktBufPtr); 2302 } 2303 2304 bool rxPacketExists = rxPacket; 2305 SERIALIZE_SCALAR(rxPacketExists); 2306 if (rxPacketExists) { 2307 nameOut(os, csprintf("%s.rxPacket", name())); 2308 rxPacket->serialize(os); 2309 uint32_t rxPktBufPtr = (uint32_t) (rxPacketBufPtr - rxPacket->data); 2310 SERIALIZE_SCALAR(rxPktBufPtr); 2311 } 2312 2313 SERIALIZE_SCALAR(txXferLen); 2314 SERIALIZE_SCALAR(rxXferLen); 2315 2316 /* 2317 * Serialize DescCaches 2318 */ 2319 SERIALIZE_SCALAR(txDescCache.link); 2320 SERIALIZE_SCALAR(txDescCache.bufptr); 2321 SERIALIZE_SCALAR(txDescCache.cmdsts); 2322 SERIALIZE_SCALAR(txDescCache.extsts); 2323 SERIALIZE_SCALAR(rxDescCache.link); 2324 SERIALIZE_SCALAR(rxDescCache.bufptr); 2325 SERIALIZE_SCALAR(rxDescCache.cmdsts); 2326 SERIALIZE_SCALAR(rxDescCache.extsts); 2327 2328 /* 2329 * Serialize tx state machine 2330 */ 2331 int txState = this->txState; 2332 SERIALIZE_SCALAR(txState); 2333 SERIALIZE_SCALAR(CTDD); 2334 SERIALIZE_SCALAR(txFifoAvail); 2335 SERIALIZE_SCALAR(txHalt); 2336 SERIALIZE_SCALAR(txFragPtr); 2337 SERIALIZE_SCALAR(txDescCnt); 2338 int txDmaState = this->txDmaState; 2339 SERIALIZE_SCALAR(txDmaState); 2340 2341 /* 2342 * Serialize rx state machine 2343 */ 2344 int rxState = this->rxState; 2345 SERIALIZE_SCALAR(rxState); 2346 SERIALIZE_SCALAR(CRDD); 2347 SERIALIZE_SCALAR(rxPktBytes); 2348 SERIALIZE_SCALAR(rxFifoCnt); 2349 SERIALIZE_SCALAR(rxHalt); 2350 SERIALIZE_SCALAR(rxDescCnt); 2351 int rxDmaState = this->rxDmaState; 2352 SERIALIZE_SCALAR(rxDmaState); 2353 2354 SERIALIZE_SCALAR(extstsEnable); 2355 2356 /* 2357 * If there's a pending transmit, store the time so we can 2358 * reschedule it later 2359 */ 2360 Tick transmitTick = txEvent.scheduled() ? txEvent.when() - curTick : 0; 2361 SERIALIZE_SCALAR(transmitTick); 2362 2363 /* 2364 * receive address filter settings 2365 */ 2366 SERIALIZE_SCALAR(rxFilterEnable); 2367 SERIALIZE_SCALAR(acceptBroadcast); 2368 SERIALIZE_SCALAR(acceptMulticast); 2369 SERIALIZE_SCALAR(acceptUnicast); 2370 SERIALIZE_SCALAR(acceptPerfect); 2371 SERIALIZE_SCALAR(acceptArp); 2372 2373 /* 2374 * Keep track of pending interrupt status. 2375 */ 2376 SERIALIZE_SCALAR(intrTick); 2377 SERIALIZE_SCALAR(cpuPendingIntr); 2378 Tick intrEventTick = 0; 2379 if (intrEvent) 2380 intrEventTick = intrEvent->when(); 2381 SERIALIZE_SCALAR(intrEventTick); 2382 2383} 2384 2385void 2386NSGigE::unserialize(Checkpoint *cp, const std::string §ion) 2387{ 2388 // Unserialize the PciDev base class 2389 PciDev::unserialize(cp, section); 2390 2391 UNSERIALIZE_SCALAR(regs.command); 2392 UNSERIALIZE_SCALAR(regs.config); 2393 UNSERIALIZE_SCALAR(regs.mear); 2394 UNSERIALIZE_SCALAR(regs.ptscr); 2395 UNSERIALIZE_SCALAR(regs.isr); 2396 UNSERIALIZE_SCALAR(regs.imr); 2397 UNSERIALIZE_SCALAR(regs.ier); 2398 UNSERIALIZE_SCALAR(regs.ihr); 2399 UNSERIALIZE_SCALAR(regs.txdp); 2400 UNSERIALIZE_SCALAR(regs.txdp_hi); 2401 UNSERIALIZE_SCALAR(regs.txcfg); 2402 UNSERIALIZE_SCALAR(regs.gpior); 2403 UNSERIALIZE_SCALAR(regs.rxdp); 2404 UNSERIALIZE_SCALAR(regs.rxdp_hi); 2405 UNSERIALIZE_SCALAR(regs.rxcfg); 2406 UNSERIALIZE_SCALAR(regs.pqcr); 2407 UNSERIALIZE_SCALAR(regs.wcsr); 2408 UNSERIALIZE_SCALAR(regs.pcr); 2409 UNSERIALIZE_SCALAR(regs.rfcr); 2410 UNSERIALIZE_SCALAR(regs.rfdr); 2411 UNSERIALIZE_SCALAR(regs.srr); 2412 UNSERIALIZE_SCALAR(regs.mibc); 2413 UNSERIALIZE_SCALAR(regs.vrcr); 2414 UNSERIALIZE_SCALAR(regs.vtcr); 2415 UNSERIALIZE_SCALAR(regs.vdr); 2416 UNSERIALIZE_SCALAR(regs.ccsr); 2417 UNSERIALIZE_SCALAR(regs.tbicr); 2418 UNSERIALIZE_SCALAR(regs.tbisr); 2419 UNSERIALIZE_SCALAR(regs.tanar); 2420 UNSERIALIZE_SCALAR(regs.tanlpar); 2421 UNSERIALIZE_SCALAR(regs.taner); 2422 UNSERIALIZE_SCALAR(regs.tesr); 2423 2424 UNSERIALIZE_ARRAY(rom.perfectMatch, EADDR_LEN); 2425 2426 UNSERIALIZE_SCALAR(ioEnable); 2427 2428 /* 2429 * unserialize the data fifos 2430 */ 2431 int txNumPkts; 2432 UNSERIALIZE_SCALAR(txNumPkts); 2433 int i; 2434 for (i = 0; i < txNumPkts; ++i) { 2435 PacketPtr p = new EtherPacket; 2436 p->unserialize(cp, csprintf("%s.rxFifo%d", section, i)); 2437 txFifo.push_back(p); 2438 } 2439 2440 int rxNumPkts; 2441 UNSERIALIZE_SCALAR(rxNumPkts); 2442 for (i = 0; i < rxNumPkts; ++i) { 2443 PacketPtr p = new EtherPacket; 2444 p->unserialize(cp, csprintf("%s.rxFifo%d", section, i)); 2445 rxFifo.push_back(p); 2446 } 2447 2448 /* 2449 * unserialize the various helper variables 2450 */ 2451 bool txPacketExists; 2452 UNSERIALIZE_SCALAR(txPacketExists); 2453 if (txPacketExists) { 2454 txPacket = new EtherPacket; 2455 txPacket->unserialize(cp, csprintf("%s.txPacket", section)); 2456 uint32_t txPktBufPtr; 2457 UNSERIALIZE_SCALAR(txPktBufPtr); 2458 txPacketBufPtr = (uint8_t *) txPacket->data + txPktBufPtr; 2459 } else 2460 txPacket = 0; 2461 2462 bool rxPacketExists; 2463 UNSERIALIZE_SCALAR(rxPacketExists); 2464 rxPacket = 0; 2465 if (rxPacketExists) { 2466 rxPacket = new EtherPacket; 2467 rxPacket->unserialize(cp, csprintf("%s.rxPacket", section)); 2468 uint32_t rxPktBufPtr; 2469 UNSERIALIZE_SCALAR(rxPktBufPtr); 2470 rxPacketBufPtr = (uint8_t *) rxPacket->data + rxPktBufPtr; 2471 } else 2472 rxPacket = 0; 2473 2474 UNSERIALIZE_SCALAR(txXferLen); 2475 UNSERIALIZE_SCALAR(rxXferLen); 2476 2477 /* 2478 * Unserialize DescCaches 2479 */ 2480 UNSERIALIZE_SCALAR(txDescCache.link); 2481 UNSERIALIZE_SCALAR(txDescCache.bufptr); 2482 UNSERIALIZE_SCALAR(txDescCache.cmdsts); 2483 UNSERIALIZE_SCALAR(txDescCache.extsts); 2484 UNSERIALIZE_SCALAR(rxDescCache.link); 2485 UNSERIALIZE_SCALAR(rxDescCache.bufptr); 2486 UNSERIALIZE_SCALAR(rxDescCache.cmdsts); 2487 UNSERIALIZE_SCALAR(rxDescCache.extsts); 2488 2489 /* 2490 * unserialize tx state machine 2491 */ 2492 int txState; 2493 UNSERIALIZE_SCALAR(txState); 2494 this->txState = (TxState) txState; 2495 UNSERIALIZE_SCALAR(CTDD); 2496 UNSERIALIZE_SCALAR(txFifoAvail); 2497 UNSERIALIZE_SCALAR(txHalt); 2498 UNSERIALIZE_SCALAR(txFragPtr); 2499 UNSERIALIZE_SCALAR(txDescCnt); 2500 int txDmaState; 2501 UNSERIALIZE_SCALAR(txDmaState); 2502 this->txDmaState = (DmaState) txDmaState; 2503 2504 /* 2505 * unserialize rx state machine 2506 */ 2507 int rxState; 2508 UNSERIALIZE_SCALAR(rxState); 2509 this->rxState = (RxState) rxState; 2510 UNSERIALIZE_SCALAR(CRDD); 2511 UNSERIALIZE_SCALAR(rxPktBytes); 2512 UNSERIALIZE_SCALAR(rxFifoCnt); 2513 UNSERIALIZE_SCALAR(rxHalt); 2514 UNSERIALIZE_SCALAR(rxDescCnt); 2515 int rxDmaState; 2516 UNSERIALIZE_SCALAR(rxDmaState); 2517 this->rxDmaState = (DmaState) rxDmaState; 2518 2519 UNSERIALIZE_SCALAR(extstsEnable); 2520 2521 /* 2522 * If there's a pending transmit, reschedule it now 2523 */ 2524 Tick transmitTick; 2525 UNSERIALIZE_SCALAR(transmitTick); 2526 if (transmitTick) 2527 txEvent.schedule(curTick + transmitTick); 2528 2529 /* 2530 * unserialize receive address filter settings 2531 */ 2532 UNSERIALIZE_SCALAR(rxFilterEnable); 2533 UNSERIALIZE_SCALAR(acceptBroadcast); 2534 UNSERIALIZE_SCALAR(acceptMulticast); 2535 UNSERIALIZE_SCALAR(acceptUnicast); 2536 UNSERIALIZE_SCALAR(acceptPerfect); 2537 UNSERIALIZE_SCALAR(acceptArp); 2538 2539 /* 2540 * Keep track of pending interrupt status. 2541 */ 2542 UNSERIALIZE_SCALAR(intrTick); 2543 UNSERIALIZE_SCALAR(cpuPendingIntr); 2544 Tick intrEventTick; 2545 UNSERIALIZE_SCALAR(intrEventTick); 2546 if (intrEventTick) { 2547 intrEvent = new IntrEvent(this, true); 2548 intrEvent->schedule(intrEventTick); 2549 } 2550 2551 /* 2552 * re-add addrRanges to bus bridges 2553 */ 2554 if (pioInterface) { 2555 pioInterface->addAddrRange(BARAddrs[0], BARAddrs[0] + BARSize[0] - 1); 2556 pioInterface->addAddrRange(BARAddrs[1], BARAddrs[1] + BARSize[1] - 1); 2557 } 2558} 2559 2560Tick 2561NSGigE::cacheAccess(MemReqPtr &req) 2562{ 2563 DPRINTF(EthernetPIO, "timing access to paddr=%#x (daddr=%#x)\n", 2564 req->paddr, req->paddr - addr); 2565 return curTick + pioLatency; 2566} 2567//===================================================================== 2568 2569 2570//********** helper functions****************************************** 2571 2572uint16_t reverseEnd16(uint16_t num) 2573{ 2574 uint16_t reverse = (num & 0xff)<<8; 2575 reverse += ((num & 0xff00) >> 8); 2576 return reverse; 2577} 2578 2579uint32_t reverseEnd32(uint32_t num) 2580{ 2581 uint32_t reverse = (reverseEnd16(num & 0xffff)) << 16; 2582 reverse += reverseEnd16((uint16_t) ((num & 0xffff0000) >> 8)); 2583 return reverse; 2584} 2585 2586 2587 2588//===================================================================== 2589 2590BEGIN_DECLARE_SIM_OBJECT_PARAMS(NSGigEInt) 2591 2592 SimObjectParam<EtherInt *> peer; 2593 SimObjectParam<NSGigE *> device; 2594 2595END_DECLARE_SIM_OBJECT_PARAMS(NSGigEInt) 2596 2597BEGIN_INIT_SIM_OBJECT_PARAMS(NSGigEInt) 2598 2599 INIT_PARAM_DFLT(peer, "peer interface", NULL), 2600 INIT_PARAM(device, "Ethernet device of this interface") 2601 2602END_INIT_SIM_OBJECT_PARAMS(NSGigEInt) 2603 2604CREATE_SIM_OBJECT(NSGigEInt) 2605{ 2606 NSGigEInt *dev_int = new NSGigEInt(getInstanceName(), device); 2607 2608 EtherInt *p = (EtherInt *)peer; 2609 if (p) { 2610 dev_int->setPeer(p); 2611 p->setPeer(dev_int); 2612 } 2613 2614 return dev_int; 2615} 2616 2617REGISTER_SIM_OBJECT("NSGigEInt", NSGigEInt) 2618 2619 2620BEGIN_DECLARE_SIM_OBJECT_PARAMS(NSGigE) 2621 2622 Param<Tick> tx_delay; 2623 Param<Tick> rx_delay; 2624 SimObjectParam<IntrControl *> intr_ctrl; 2625 Param<Tick> intr_delay; 2626 SimObjectParam<MemoryController *> mmu; 2627 SimObjectParam<PhysicalMemory *> physmem; 2628 Param<bool> rx_filter; 2629 Param<string> hardware_address; 2630 SimObjectParam<Bus*> header_bus; 2631 SimObjectParam<Bus*> payload_bus; 2632 SimObjectParam<HierParams *> hier; 2633 Param<Tick> pio_latency; 2634 Param<bool> dma_desc_free; 2635 Param<bool> dma_data_free; 2636 Param<Tick> dma_read_delay; 2637 Param<Tick> dma_write_delay; 2638 Param<Tick> dma_read_factor; 2639 Param<Tick> dma_write_factor; 2640 SimObjectParam<PciConfigAll *> configspace; 2641 SimObjectParam<PciConfigData *> configdata; 2642 SimObjectParam<Tsunami *> tsunami; 2643 Param<uint32_t> pci_bus; 2644 Param<uint32_t> pci_dev; 2645 Param<uint32_t> pci_func; 2646 Param<uint32_t> tx_fifo_size; 2647 Param<uint32_t> rx_fifo_size; 2648 2649END_DECLARE_SIM_OBJECT_PARAMS(NSGigE) 2650 2651BEGIN_INIT_SIM_OBJECT_PARAMS(NSGigE) 2652 2653 INIT_PARAM_DFLT(tx_delay, "Transmit Delay", 1000), 2654 INIT_PARAM_DFLT(rx_delay, "Receive Delay", 1000), 2655 INIT_PARAM(intr_ctrl, "Interrupt Controller"), 2656 INIT_PARAM_DFLT(intr_delay, "Interrupt Delay in microseconds", 0), 2657 INIT_PARAM(mmu, "Memory Controller"), 2658 INIT_PARAM(physmem, "Physical Memory"), 2659 INIT_PARAM_DFLT(rx_filter, "Enable Receive Filter", true), 2660 INIT_PARAM_DFLT(hardware_address, "Ethernet Hardware Address", 2661 "00:99:00:00:00:01"), 2662 INIT_PARAM_DFLT(header_bus, "The IO Bus to attach to for headers", NULL), 2663 INIT_PARAM_DFLT(payload_bus, "The IO Bus to attach to for payload", NULL), 2664 INIT_PARAM_DFLT(hier, "Hierarchy global variables", &defaultHierParams), 2665 INIT_PARAM_DFLT(pio_latency, "Programmed IO latency in bus cycles", 1), 2666 INIT_PARAM_DFLT(dma_desc_free, "DMA of Descriptors is free", false), 2667 INIT_PARAM_DFLT(dma_data_free, "DMA of Data is free", false), 2668 INIT_PARAM_DFLT(dma_read_delay, "fixed delay for dma reads", 0), 2669 INIT_PARAM_DFLT(dma_write_delay, "fixed delay for dma writes", 0), 2670 INIT_PARAM_DFLT(dma_read_factor, "multiplier for dma reads", 0), 2671 INIT_PARAM_DFLT(dma_write_factor, "multiplier for dma writes", 0), 2672 INIT_PARAM(configspace, "PCI Configspace"), 2673 INIT_PARAM(configdata, "PCI Config data"), 2674 INIT_PARAM(tsunami, "Tsunami"), 2675 INIT_PARAM(pci_bus, "PCI bus"), 2676 INIT_PARAM(pci_dev, "PCI device number"), 2677 INIT_PARAM(pci_func, "PCI function code"), 2678 INIT_PARAM_DFLT(tx_fifo_size, "max size in bytes of txFifo", 131072), 2679 INIT_PARAM_DFLT(rx_fifo_size, "max size in bytes of rxFifo", 131072) 2680 2681END_INIT_SIM_OBJECT_PARAMS(NSGigE) 2682 2683 2684CREATE_SIM_OBJECT(NSGigE) 2685{ 2686 int eaddr[6]; 2687 sscanf(((string)hardware_address).c_str(), "%x:%x:%x:%x:%x:%x", 2688 &eaddr[0], &eaddr[1], &eaddr[2], &eaddr[3], &eaddr[4], &eaddr[5]); 2689 2690 return new NSGigE(getInstanceName(), intr_ctrl, intr_delay, 2691 physmem, tx_delay, rx_delay, mmu, hier, header_bus, 2692 payload_bus, pio_latency, dma_desc_free, dma_data_free, 2693 dma_read_delay, dma_write_delay, dma_read_factor, 2694 dma_write_factor, configspace, configdata, 2695 tsunami, pci_bus, pci_dev, pci_func, rx_filter, eaddr, 2696 tx_fifo_size, rx_fifo_size); 2697} 2698 2699REGISTER_SIM_OBJECT("NSGigE", NSGigE) 2700