ns_gige.cc revision 1027
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> 369364Snilay@cs.wisc.edu 377055Snate@binkert.org#include "base/inet.hh" 386882SBrad.Beckmann@amd.com#include "cpu/exec_context.hh" 396882SBrad.Beckmann@amd.com#include "cpu/intr_control.hh" 408191SLisa.Hsu@amd.com#include "dev/dma.hh" 416882SBrad.Beckmann@amd.com#include "dev/etherlink.hh" 426882SBrad.Beckmann@amd.com#include "dev/ns_gige.hh" 439102SNuwan.Jayasena@amd.com#include "dev/pciconfigall.hh" 449366Snilay@cs.wisc.edu#include "dev/tsunami_cchip.hh" 459366Snilay@cs.wisc.edu#include "mem/bus/bus.hh" 466882SBrad.Beckmann@amd.com#include "mem/bus/dma_interface.hh" 476882SBrad.Beckmann@amd.com#include "mem/bus/pio_interface.hh" 486657Snate@binkert.org#include "mem/bus/pio_interface_impl.hh" 496657Snate@binkert.org#include "mem/functional_mem/memory_control.hh" 506657Snate@binkert.org#include "mem/functional_mem/physical_memory.hh" 516657Snate@binkert.org#include "sim/builder.hh" 526657Snate@binkert.org#include "sim/host.hh" 539366Snilay@cs.wisc.edu#include "sim/sim_stats.hh" 547839Snilay@cs.wisc.edu#include "targetarch/vtophys.hh" 556657Snate@binkert.org 566882SBrad.Beckmann@amd.comconst char *NsRxStateStrings[] = 576882SBrad.Beckmann@amd.com{ 586882SBrad.Beckmann@amd.com "rxIdle", 596882SBrad.Beckmann@amd.com "rxDescRefr", 606882SBrad.Beckmann@amd.com "rxDescRead", 616882SBrad.Beckmann@amd.com "rxFifoBlock", 626657Snate@binkert.org "rxFragWrite", 639366Snilay@cs.wisc.edu "rxDescWrite", 649366Snilay@cs.wisc.edu "rxAdvance" 656657Snate@binkert.org}; 666657Snate@binkert.org 676657Snate@binkert.orgconst char *NsTxStateStrings[] = 686657Snate@binkert.org{ 699104Shestness@cs.utexas.edu "txIdle", 706657Snate@binkert.org "txDescRefr", 716657Snate@binkert.org "txDescRead", 726657Snate@binkert.org "txFifoBlock", 736657Snate@binkert.org "txFragRead", 747839Snilay@cs.wisc.edu "txDescWrite", 757839Snilay@cs.wisc.edu "txAdvance" 769366Snilay@cs.wisc.edu}; 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 916657Snate@binkert.org// correctly 926657Snate@binkert.orguint16_t reverseEnd16(uint16_t); 936657Snate@binkert.orguint32_t reverseEnd32(uint32_t); 946657Snate@binkert.org 956657Snate@binkert.org/////////////////////////////////////////////////////////////////////// 966779SBrad.Beckmann@amd.com// 976657Snate@binkert.org// NSGigE PCI Device 986657Snate@binkert.org// 996657Snate@binkert.orgNSGigE::NSGigE(const std::string &name, IntrControl *i, Tick intr_delay, 1006657Snate@binkert.org PhysicalMemory *pmem, Tick tx_delay, Tick rx_delay, 1016657Snate@binkert.org MemoryController *mmu, HierParams *hier, Bus *header_bus, 1026657Snate@binkert.org Bus *payload_bus, Tick pio_latency, bool dma_desc_free, 1036657Snate@binkert.org bool dma_data_free, Tick dma_read_delay, Tick dma_write_delay, 1046657Snate@binkert.org Tick dma_read_factor, Tick dma_write_factor, PciConfigAll *cf, 1056657Snate@binkert.org PciConfigData *cd, Tsunami *t, uint32_t bus, uint32_t dev, 1069104Shestness@cs.utexas.edu uint32_t func, bool rx_filter, const int eaddr[6], 1079104Shestness@cs.utexas.edu uint32_t tx_fifo_size, uint32_t rx_fifo_size) 1089104Shestness@cs.utexas.edu : PciDev(name, mmu, cf, cd, bus, dev, func), tsunami(t), ioEnable(false), 1099104Shestness@cs.utexas.edu maxTxFifoSize(tx_fifo_size), maxRxFifoSize(rx_fifo_size), 1106657Snate@binkert.org txPacket(0), rxPacket(0), txPacketBufPtr(NULL), rxPacketBufPtr(NULL), 1116657Snate@binkert.org txXferLen(0), rxXferLen(0), txState(txIdle), CTDD(false), 1126657Snate@binkert.org txFifoAvail(tx_fifo_size), txHalt(false), 1136657Snate@binkert.org txFragPtr(0), txDescCnt(0), txDmaState(dmaIdle), rxState(rxIdle), 1146657Snate@binkert.org CRDD(false), rxPktBytes(0), rxFifoCnt(0), rxHalt(false), 1156657Snate@binkert.org rxFragPtr(0), rxDescCnt(0), rxDmaState(dmaIdle), extstsEnable(false), 1166657Snate@binkert.org rxDmaReadEvent(this), rxDmaWriteEvent(this), 1176657Snate@binkert.org txDmaReadEvent(this), txDmaWriteEvent(this), 1186657Snate@binkert.org dmaDescFree(dma_desc_free), dmaDataFree(dma_data_free), 1196657Snate@binkert.org txDelay(tx_delay), rxDelay(rx_delay), rxKickTick(0), txKickTick(0), 1206657Snate@binkert.org txEvent(this), rxFilterEnable(rx_filter), acceptBroadcast(false), 1216657Snate@binkert.org acceptMulticast(false), acceptUnicast(false), 1226657Snate@binkert.org acceptPerfect(false), acceptArp(false), 1236657Snate@binkert.org physmem(pmem), intctrl(i), intrTick(0), cpuPendingIntr(false), 1246657Snate@binkert.org intrEvent(0), interface(0) 1257839Snilay@cs.wisc.edu{ 1267839Snilay@cs.wisc.edu tsunami->ethernet = this; 1277839Snilay@cs.wisc.edu 1287839Snilay@cs.wisc.edu if (header_bus) { 1297839Snilay@cs.wisc.edu pioInterface = newPioInterface(name, hier, header_bus, this, 1307839Snilay@cs.wisc.edu &NSGigE::cacheAccess); 1317839Snilay@cs.wisc.edu 1327839Snilay@cs.wisc.edu pioLatency = pio_latency * header_bus->clockRatio; 1337839Snilay@cs.wisc.edu 1347839Snilay@cs.wisc.edu if (payload_bus) 1357839Snilay@cs.wisc.edu dmaInterface = new DMAInterface<Bus>(name + ".dma", 1367839Snilay@cs.wisc.edu header_bus, payload_bus, 1); 1377839Snilay@cs.wisc.edu else 1387839Snilay@cs.wisc.edu dmaInterface = new DMAInterface<Bus>(name + ".dma", 1397839Snilay@cs.wisc.edu header_bus, header_bus, 1); 1406657Snate@binkert.org } else if (payload_bus) { 1416657Snate@binkert.org pioInterface = newPioInterface(name, hier, payload_bus, this, 1426657Snate@binkert.org &NSGigE::cacheAccess); 1436657Snate@binkert.org 1446657Snate@binkert.org pioLatency = pio_latency * payload_bus->clockRatio; 1456657Snate@binkert.org 1466657Snate@binkert.org dmaInterface = new DMAInterface<Bus>(name + ".dma", payload_bus, 1476657Snate@binkert.org payload_bus, 1); 1486657Snate@binkert.org } 1496657Snate@binkert.org 1506657Snate@binkert.org 1516657Snate@binkert.org intrDelay = US2Ticks(intr_delay); 1526657Snate@binkert.org dmaReadDelay = dma_read_delay; 1536657Snate@binkert.org dmaWriteDelay = dma_write_delay; 1546657Snate@binkert.org dmaReadFactor = dma_read_factor; 1556657Snate@binkert.org dmaWriteFactor = dma_write_factor; 1566657Snate@binkert.org 1576657Snate@binkert.org regsReset(); 1586657Snate@binkert.org rom.perfectMatch[0] = eaddr[0]; 1596657Snate@binkert.org rom.perfectMatch[1] = eaddr[1]; 1606657Snate@binkert.org rom.perfectMatch[2] = eaddr[2]; 1616657Snate@binkert.org rom.perfectMatch[3] = eaddr[3]; 1626657Snate@binkert.org rom.perfectMatch[4] = eaddr[4]; 1636657Snate@binkert.org rom.perfectMatch[5] = eaddr[5]; 1646657Snate@binkert.org} 1656657Snate@binkert.org 1666657Snate@binkert.orgNSGigE::~NSGigE() 1676657Snate@binkert.org{} 1686657Snate@binkert.org 1696657Snate@binkert.orgvoid 1709219Spower.jg@gmail.comNSGigE::regStats() 1716877Ssteve.reinhardt@amd.com{ 1726657Snate@binkert.org txBytes 1739219Spower.jg@gmail.com .name(name() + ".txBytes") 1746657Snate@binkert.org .desc("Bytes Transmitted") 1759219Spower.jg@gmail.com .prereq(txBytes) 1766657Snate@binkert.org ; 1776657Snate@binkert.org 1787542SBrad.Beckmann@amd.com rxBytes 1797542SBrad.Beckmann@amd.com .name(name() + ".rxBytes") 1806657Snate@binkert.org .desc("Bytes Received") 1816877Ssteve.reinhardt@amd.com .prereq(rxBytes) 1826999Snate@binkert.org ; 1836877Ssteve.reinhardt@amd.com 1846877Ssteve.reinhardt@amd.com txPackets 1856877Ssteve.reinhardt@amd.com .name(name() + ".txPackets") 1866877Ssteve.reinhardt@amd.com .desc("Number of Packets Transmitted") 1876877Ssteve.reinhardt@amd.com .prereq(txBytes) 1886877Ssteve.reinhardt@amd.com ; 1896877Ssteve.reinhardt@amd.com 1906877Ssteve.reinhardt@amd.com rxPackets 1916877Ssteve.reinhardt@amd.com .name(name() + ".rxPackets") 1926877Ssteve.reinhardt@amd.com .desc("Number of Packets Received") 1939338SAndreas.Sandberg@arm.com .prereq(rxBytes) 1946877Ssteve.reinhardt@amd.com ; 1956877Ssteve.reinhardt@amd.com 1966877Ssteve.reinhardt@amd.com txIPChecksums 1976877Ssteve.reinhardt@amd.com .name(name() + ".txIPChecksums") 1986877Ssteve.reinhardt@amd.com .desc("Number of tx IP Checksums done by device") 1996877Ssteve.reinhardt@amd.com .precision(0) 2006882SBrad.Beckmann@amd.com .prereq(txBytes) 2016882SBrad.Beckmann@amd.com ; 2026882SBrad.Beckmann@amd.com 2036882SBrad.Beckmann@amd.com rxIPChecksums 2046882SBrad.Beckmann@amd.com .name(name() + ".rxIPChecksums") 2056882SBrad.Beckmann@amd.com .desc("Number of rx IP Checksums done by device") 2066882SBrad.Beckmann@amd.com .precision(0) 2076877Ssteve.reinhardt@amd.com .prereq(rxBytes) 2086877Ssteve.reinhardt@amd.com ; 2096877Ssteve.reinhardt@amd.com 2106877Ssteve.reinhardt@amd.com txTCPChecksums 2116657Snate@binkert.org .name(name() + ".txTCPChecksums") 2126657Snate@binkert.org .desc("Number of tx TCP Checksums done by device") 2136999Snate@binkert.org .precision(0) 2146657Snate@binkert.org .prereq(txBytes) 2156657Snate@binkert.org ; 2166657Snate@binkert.org 2176657Snate@binkert.org rxTCPChecksums 2186657Snate@binkert.org .name(name() + ".rxTCPChecksums") 2196657Snate@binkert.org .desc("Number of rx TCP Checksums done by device") 2207007Snate@binkert.org .precision(0) 2216657Snate@binkert.org .prereq(rxBytes) 2226657Snate@binkert.org ; 2236657Snate@binkert.org 2246657Snate@binkert.org descDmaReads 2256657Snate@binkert.org .name(name() + ".descDMAReads") 2267007Snate@binkert.org .desc("Number of descriptors the device read w/ DMA") 2277007Snate@binkert.org .precision(0) 2286657Snate@binkert.org ; 2297002Snate@binkert.org 2307002Snate@binkert.org descDmaWrites 2317002Snate@binkert.org .name(name() + ".descDMAWrites") 2327002Snate@binkert.org .desc("Number of descriptors the device wrote w/ DMA") 2338229Snate@binkert.org .precision(0) 2348229Snate@binkert.org ; 2356657Snate@binkert.org 2366657Snate@binkert.org descDmaRdBytes 2378229Snate@binkert.org .name(name() + ".descDmaReadBytes") 2388229Snate@binkert.org .desc("number of descriptor bytes read w/ DMA") 2398229Snate@binkert.org .precision(0) 2408229Snate@binkert.org ; 2416657Snate@binkert.org 2426657Snate@binkert.org descDmaWrBytes 2436657Snate@binkert.org .name(name() + ".descDmaWriteBytes") 2446657Snate@binkert.org .desc("number of descriptor bytes write w/ DMA") 2456793SBrad.Beckmann@amd.com .precision(0) 2466657Snate@binkert.org ; 2476657Snate@binkert.org 2486657Snate@binkert.org 2496657Snate@binkert.org txBandwidth 2506657Snate@binkert.org .name(name() + ".txBandwidth") 2517002Snate@binkert.org .desc("Transmit Bandwidth (bits/s)") 2526657Snate@binkert.org .precision(0) 2537007Snate@binkert.org .prereq(txBytes) 2547007Snate@binkert.org ; 2559271Snilay@cs.wisc.edu 2566877Ssteve.reinhardt@amd.com rxBandwidth 2576877Ssteve.reinhardt@amd.com .name(name() + ".rxBandwidth") 2586657Snate@binkert.org .desc("Receive Bandwidth (bits/s)") 2596877Ssteve.reinhardt@amd.com .precision(0) 2606657Snate@binkert.org .prereq(rxBytes) 2616657Snate@binkert.org ; 2627002Snate@binkert.org 2637002Snate@binkert.org txPacketRate 2647567SBrad.Beckmann@amd.com .name(name() + ".txPPS") 2657567SBrad.Beckmann@amd.com .desc("Packet Tranmission Rate (packets/s)") 2667922SBrad.Beckmann@amd.com .precision(0) 2676881SBrad.Beckmann@amd.com .prereq(txBytes) 2687002Snate@binkert.org ; 2696657Snate@binkert.org 2707002Snate@binkert.org rxPacketRate 2716902SBrad.Beckmann@amd.com .name(name() + ".rxPPS") 2726863Sdrh5@cs.wisc.edu .desc("Packet Reception Rate (packets/s)") 2736863Sdrh5@cs.wisc.edu .precision(0) 2748683Snilay@cs.wisc.edu .prereq(rxBytes) 2758683Snilay@cs.wisc.edu ; 2767007Snate@binkert.org 2779302Snilay@cs.wisc.edu txBandwidth = txBytes * Stats::constant(8) / simSeconds; 2789302Snilay@cs.wisc.edu rxBandwidth = rxBytes * Stats::constant(8) / simSeconds; 2799302Snilay@cs.wisc.edu txPacketRate = txPackets / simSeconds; 2806657Snate@binkert.org rxPacketRate = rxPackets / simSeconds; 2816657Snate@binkert.org} 2826657Snate@binkert.org 2836657Snate@binkert.org/** 2846657Snate@binkert.org * This is to read the PCI general configuration registers 2856657Snate@binkert.org */ 2866882SBrad.Beckmann@amd.comvoid 2876882SBrad.Beckmann@amd.comNSGigE::ReadConfig(int offset, int size, uint8_t *data) 2886882SBrad.Beckmann@amd.com{ 2896882SBrad.Beckmann@amd.com if (offset < PCI_DEVICE_SPECIFIC) 2906657Snate@binkert.org PciDev::ReadConfig(offset, size, data); 2916657Snate@binkert.org else 2927007Snate@binkert.org panic("Device specific PCI config space not implemented!\n"); 2937839Snilay@cs.wisc.edu} 2947839Snilay@cs.wisc.edu 2957839Snilay@cs.wisc.edu/** 2967839Snilay@cs.wisc.edu * This is to write to the PCI general configuration registers 2977839Snilay@cs.wisc.edu */ 2987839Snilay@cs.wisc.eduvoid 2997839Snilay@cs.wisc.eduNSGigE::WriteConfig(int offset, int size, uint32_t data) 3007839Snilay@cs.wisc.edu{ 3017839Snilay@cs.wisc.edu if (offset < PCI_DEVICE_SPECIFIC) 3027839Snilay@cs.wisc.edu PciDev::WriteConfig(offset, size, data); 3037839Snilay@cs.wisc.edu else 3047839Snilay@cs.wisc.edu panic("Device specific PCI config space not implemented!\n"); 3057007Snate@binkert.org 3067007Snate@binkert.org // Need to catch writes to BARs to update the PIO interface 3077007Snate@binkert.org switch (offset) { 3087007Snate@binkert.org // seems to work fine without all these PCI settings, but i 3097007Snate@binkert.org // put in the IO to double check, an assertion will fail if we 3107839Snilay@cs.wisc.edu // need to properly implement it 3117839Snilay@cs.wisc.edu case PCI_COMMAND: 3127839Snilay@cs.wisc.edu if (config.data[offset] & PCI_CMD_IOSE) 3137839Snilay@cs.wisc.edu ioEnable = true; 3147839Snilay@cs.wisc.edu else 3157839Snilay@cs.wisc.edu ioEnable = false; 3167839Snilay@cs.wisc.edu 3177839Snilay@cs.wisc.edu#if 0 3187839Snilay@cs.wisc.edu if (config.data[offset] & PCI_CMD_BME) { 3197839Snilay@cs.wisc.edu bmEnabled = true; 3207839Snilay@cs.wisc.edu } 3217839Snilay@cs.wisc.edu else { 3227007Snate@binkert.org bmEnabled = false; 3237007Snate@binkert.org } 3247542SBrad.Beckmann@amd.com 3257542SBrad.Beckmann@amd.com if (config.data[offset] & PCI_CMD_MSE) { 3266657Snate@binkert.org memEnable = true; 3277007Snate@binkert.org } 3286657Snate@binkert.org else { 3296657Snate@binkert.org memEnable = false; 3306657Snate@binkert.org } 3316657Snate@binkert.org#endif 3326657Snate@binkert.org break; 3336657Snate@binkert.org 3346657Snate@binkert.org case PCI0_BASE_ADDR0: 3356657Snate@binkert.org if (BARAddrs[0] != 0) { 3367839Snilay@cs.wisc.edu if (pioInterface) 3377839Snilay@cs.wisc.edu pioInterface->addAddrRange(BARAddrs[0], 3387839Snilay@cs.wisc.edu BARAddrs[0] + BARSize[0] - 1); 3397839Snilay@cs.wisc.edu 3407839Snilay@cs.wisc.edu BARAddrs[0] &= PA_UNCACHED_MASK; 3417839Snilay@cs.wisc.edu } 3427839Snilay@cs.wisc.edu break; 3437839Snilay@cs.wisc.edu case PCI0_BASE_ADDR1: 3447839Snilay@cs.wisc.edu if (BARAddrs[1] != 0) { 3457839Snilay@cs.wisc.edu if (pioInterface) 3467839Snilay@cs.wisc.edu pioInterface->addAddrRange(BARAddrs[1], 3477839Snilay@cs.wisc.edu 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 break; 3526657Snate@binkert.org } 3536657Snate@binkert.org} 3546657Snate@binkert.org 3556657Snate@binkert.org/** 3567839Snilay@cs.wisc.edu * This reads the device registers, which are detailed in the NS83820 3577839Snilay@cs.wisc.edu * spec sheet 3587839Snilay@cs.wisc.edu */ 3597839Snilay@cs.wisc.eduFault 3607839Snilay@cs.wisc.eduNSGigE::read(MemReqPtr &req, uint8_t *data) 3617839Snilay@cs.wisc.edu{ 3627839Snilay@cs.wisc.edu assert(ioEnable); 3637839Snilay@cs.wisc.edu 3647839Snilay@cs.wisc.edu //The mask is to give you only the offset into the device register file 3657839Snilay@cs.wisc.edu Addr daddr = req->paddr & 0xfff; 3667839Snilay@cs.wisc.edu DPRINTF(EthernetPIO, "read da=%#x pa=%#x va=%#x size=%d\n", 3677839Snilay@cs.wisc.edu daddr, req->paddr, req->vaddr, req->size); 3687839Snilay@cs.wisc.edu 3697839Snilay@cs.wisc.edu 3707839Snilay@cs.wisc.edu // there are some reserved registers, you can see ns_gige_reg.h and 3717839Snilay@cs.wisc.edu // the spec sheet for details 3726657Snate@binkert.org if (daddr > LAST && daddr <= RESERVED) { 3736657Snate@binkert.org panic("Accessing reserved register"); 3746657Snate@binkert.org } else if (daddr > RESERVED && daddr <= 0x3FC) { 3756657Snate@binkert.org ReadConfig(daddr & 0xff, req->size, data); 3767007Snate@binkert.org return No_Fault; 3776657Snate@binkert.org } else if (daddr >= MIB_START && daddr <= MIB_END) { 3786657Snate@binkert.org // don't implement all the MIB's. hopefully the kernel 3799273Snilay@cs.wisc.edu // doesn't actually DEPEND upon their values 3806657Snate@binkert.org // MIB are just hardware stats keepers 3816657Snate@binkert.org uint32_t ® = *(uint32_t *) data; 3826657Snate@binkert.org reg = 0; 3836657Snate@binkert.org return No_Fault; 3846657Snate@binkert.org } else if (daddr > 0x3FC) 3856657Snate@binkert.org panic("Something is messed up!\n"); 3866657Snate@binkert.org 3877007Snate@binkert.org switch (req->size) { 3886657Snate@binkert.org case sizeof(uint32_t): 3896657Snate@binkert.org { 3909219Spower.jg@gmail.com uint32_t ® = *(uint32_t *)data; 3916657Snate@binkert.org 3926657Snate@binkert.org switch (daddr) { 3936999Snate@binkert.org case CR: 3946657Snate@binkert.org reg = regs.command; 3956657Snate@binkert.org //these are supposed to be cleared on a read 3966657Snate@binkert.org reg &= ~(CR_RXD | CR_TXD | CR_TXR | CR_RXR); 3976657Snate@binkert.org break; 3987007Snate@binkert.org 3996657Snate@binkert.org case CFG: 4006657Snate@binkert.org reg = regs.config; 4016657Snate@binkert.org break; 4026657Snate@binkert.org 4036657Snate@binkert.org case MEAR: 4048946Sandreas.hansson@arm.com reg = regs.mear; 4058946Sandreas.hansson@arm.com break; 4068946Sandreas.hansson@arm.com 4077832Snate@binkert.org case PTSCR: 4087002Snate@binkert.org reg = regs.ptscr; 4097002Snate@binkert.org break; 4107002Snate@binkert.org 4118641Snate@binkert.org case ISR: 4127056Snate@binkert.org reg = regs.isr; 4138232Snate@binkert.org devIntrClear(ISR_ALL); 4148232Snate@binkert.org break; 4156657Snate@binkert.org 4168229Snate@binkert.org case IMR: 4176657Snate@binkert.org reg = regs.imr; 4186657Snate@binkert.org break; 4197056Snate@binkert.org 4206657Snate@binkert.org case IER: 4219219Spower.jg@gmail.com reg = regs.ier; 4229219Spower.jg@gmail.com break; 4239219Spower.jg@gmail.com 4249219Spower.jg@gmail.com case IHR: 4259219Spower.jg@gmail.com reg = regs.ihr; 4267002Snate@binkert.org break; 4277002Snate@binkert.org 4286657Snate@binkert.org case TXDP: 4296657Snate@binkert.org reg = regs.txdp; 4306657Snate@binkert.org break; 4316657Snate@binkert.org 4326657Snate@binkert.org case TXDP_HI: 4336793SBrad.Beckmann@amd.com reg = regs.txdp_hi; 4346657Snate@binkert.org break; 4356657Snate@binkert.org 4366657Snate@binkert.org case TXCFG: 4376657Snate@binkert.org reg = regs.txcfg; 4386877Ssteve.reinhardt@amd.com break; 4396877Ssteve.reinhardt@amd.com 4406877Ssteve.reinhardt@amd.com case GPIOR: 4416877Ssteve.reinhardt@amd.com reg = regs.gpior; 4426877Ssteve.reinhardt@amd.com break; 4436877Ssteve.reinhardt@amd.com 4446657Snate@binkert.org case RXDP: 4457542SBrad.Beckmann@amd.com reg = regs.rxdp; 4466657Snate@binkert.org break; 4477007Snate@binkert.org 4486657Snate@binkert.org case RXDP_HI: 4496657Snate@binkert.org reg = regs.rxdp_hi; 4507007Snate@binkert.org break; 4516657Snate@binkert.org 4526877Ssteve.reinhardt@amd.com case RXCFG: 4536877Ssteve.reinhardt@amd.com reg = regs.rxcfg; 4546657Snate@binkert.org break; 4558532SLisa.Hsu@amd.com 4566657Snate@binkert.org case PQCR: 4577567SBrad.Beckmann@amd.com reg = regs.pqcr; 4587567SBrad.Beckmann@amd.com break; 4597567SBrad.Beckmann@amd.com 4607567SBrad.Beckmann@amd.com case WCSR: 4617567SBrad.Beckmann@amd.com reg = regs.wcsr; 4627567SBrad.Beckmann@amd.com break; 4636657Snate@binkert.org 4646882SBrad.Beckmann@amd.com case PCR: 4656882SBrad.Beckmann@amd.com reg = regs.pcr; 4666882SBrad.Beckmann@amd.com break; 4676882SBrad.Beckmann@amd.com 4686882SBrad.Beckmann@amd.com // see the spec sheet for how RFCR and RFDR work 4696882SBrad.Beckmann@amd.com // basically, you write to RFCR to tell the machine 4706882SBrad.Beckmann@amd.com // what you want to do next, then you act upon RFDR, 4718189SLisa.Hsu@amd.com // and the device will be prepared b/c of what you 4728189SLisa.Hsu@amd.com // wrote to RFCR 4736877Ssteve.reinhardt@amd.com case RFCR: 4748189SLisa.Hsu@amd.com reg = regs.rfcr; 4758189SLisa.Hsu@amd.com break; 4768189SLisa.Hsu@amd.com 4778189SLisa.Hsu@amd.com case RFDR: 4786882SBrad.Beckmann@amd.com switch (regs.rfcr & RFCR_RFADDR) { 4796882SBrad.Beckmann@amd.com case 0x000: 4806882SBrad.Beckmann@amd.com reg = rom.perfectMatch[1]; 4816882SBrad.Beckmann@amd.com 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; 4888189SLisa.Hsu@amd.com case 0x004: 4896882SBrad.Beckmann@amd.com reg = rom.perfectMatch[5] << 8; 4906882SBrad.Beckmann@amd.com reg += rom.perfectMatch[4]; 4916882SBrad.Beckmann@amd.com break; 4928189SLisa.Hsu@amd.com default: 4938189SLisa.Hsu@amd.com panic("reading RFDR for something other than PMATCH!\n"); 4948189SLisa.Hsu@amd.com // didn't implement other RFDR functionality b/c 4958189SLisa.Hsu@amd.com // driver didn't use it 4968938SLisa.Hsu@amd.com } 4978938SLisa.Hsu@amd.com break; 4988938SLisa.Hsu@amd.com 4998938SLisa.Hsu@amd.com case SRR: 5008938SLisa.Hsu@amd.com reg = regs.srr; 5018938SLisa.Hsu@amd.com break; 5028938SLisa.Hsu@amd.com 5036888SBrad.Beckmann@amd.com case MIBC: 5046888SBrad.Beckmann@amd.com reg = regs.mibc; 5056888SBrad.Beckmann@amd.com reg &= ~(MIBC_MIBS | MIBC_ACLR); 5066888SBrad.Beckmann@amd.com break; 5076888SBrad.Beckmann@amd.com 5088189SLisa.Hsu@amd.com case VRCR: 5096888SBrad.Beckmann@amd.com reg = regs.vrcr; 5106888SBrad.Beckmann@amd.com break; 5116657Snate@binkert.org 5126888SBrad.Beckmann@amd.com case VTCR: 5136888SBrad.Beckmann@amd.com reg = regs.vtcr; 5146888SBrad.Beckmann@amd.com break; 5156888SBrad.Beckmann@amd.com 5166657Snate@binkert.org case VDR: 5176657Snate@binkert.org reg = regs.vdr; 5186657Snate@binkert.org break; 5196657Snate@binkert.org 5206657Snate@binkert.org case CCSR: 5216657Snate@binkert.org reg = regs.ccsr; 5226657Snate@binkert.org break; 5236657Snate@binkert.org 5246657Snate@binkert.org case TBICR: 5257007Snate@binkert.org reg = regs.tbicr; 5267007Snate@binkert.org break; 5276657Snate@binkert.org 5287007Snate@binkert.org case TBISR: 5297007Snate@binkert.org reg = regs.tbisr; 5309465Snilay@cs.wisc.edu break; 5319465Snilay@cs.wisc.edu 5327007Snate@binkert.org case TANAR: 5336657Snate@binkert.org reg = regs.tanar; 5346657Snate@binkert.org break; 5356657Snate@binkert.org 5367007Snate@binkert.org case TANLPAR: 5377542SBrad.Beckmann@amd.com reg = regs.tanlpar; 5387542SBrad.Beckmann@amd.com break; 5397007Snate@binkert.org 5406657Snate@binkert.org case TANER: 5416657Snate@binkert.org reg = regs.taner; 5426657Snate@binkert.org break; 5436657Snate@binkert.org 5446657Snate@binkert.org case TESR: 5456657Snate@binkert.org reg = regs.tesr; 5466657Snate@binkert.org break; 5476657Snate@binkert.org 5486657Snate@binkert.org default: 5496657Snate@binkert.org panic("reading unimplemented register: addr = %#x", daddr); 5506657Snate@binkert.org } 5516657Snate@binkert.org 5526657Snate@binkert.org DPRINTF(EthernetPIO, "read from %#x: data=%d data=%#x\n", 5536657Snate@binkert.org daddr, reg, reg); 5546657Snate@binkert.org } 5556657Snate@binkert.org break; 5566657Snate@binkert.org 5576657Snate@binkert.org default: 5589273Snilay@cs.wisc.edu panic("accessing register with invalid size: addr=%#x, size=%d", 5596657Snate@binkert.org daddr, req->size); 5606657Snate@binkert.org } 5616657Snate@binkert.org 5629364Snilay@cs.wisc.edu return No_Fault; 5637007Snate@binkert.org} 5646657Snate@binkert.org 5656657Snate@binkert.orgFault 5666657Snate@binkert.orgNSGigE::write(MemReqPtr &req, const uint8_t *data) 5676657Snate@binkert.org{ 5687007Snate@binkert.org assert(ioEnable); 5696657Snate@binkert.org 5707007Snate@binkert.org Addr daddr = req->paddr & 0xfff; 5717007Snate@binkert.org DPRINTF(EthernetPIO, "write da=%#x pa=%#x va=%#x size=%d\n", 5726657Snate@binkert.org daddr, req->paddr, req->vaddr, req->size); 5736657Snate@binkert.org 5746657Snate@binkert.org if (daddr > LAST && daddr <= RESERVED) { 5756657Snate@binkert.org panic("Accessing reserved register"); 5766657Snate@binkert.org } else if (daddr > RESERVED && daddr <= 0x3FC) { 5776657Snate@binkert.org WriteConfig(daddr & 0xff, req->size, *(uint32_t *)data); 5786657Snate@binkert.org return No_Fault; 5796657Snate@binkert.org } else if (daddr > 0x3FC) 5806657Snate@binkert.org panic("Something is messed up!\n"); 5816657Snate@binkert.org 5826657Snate@binkert.org if (req->size == sizeof(uint32_t)) { 5836657Snate@binkert.org uint32_t reg = *(uint32_t *)data; 5846657Snate@binkert.org DPRINTF(EthernetPIO, "write data=%d data=%#x\n", reg, reg); 5856657Snate@binkert.org 5866657Snate@binkert.org switch (daddr) { 5877566SBrad.Beckmann@amd.com case CR: 5886657Snate@binkert.org regs.command = reg; 5896657Snate@binkert.org if ((reg & (CR_TXE | CR_TXD)) == (CR_TXE | CR_TXD)) { 5906657Snate@binkert.org txHalt = true; 5916657Snate@binkert.org } else if (reg & CR_TXE) { 5926657Snate@binkert.org //the kernel is enabling the transmit machine 5938308Stushar@csail.mit.edu if (txState == txIdle) 5946657Snate@binkert.org txKick(); 5956657Snate@binkert.org } else if (reg & CR_TXD) { 5966657Snate@binkert.org txHalt = true; 5978308Stushar@csail.mit.edu } 5986657Snate@binkert.org 5996657Snate@binkert.org if ((reg & (CR_RXE | CR_RXD)) == (CR_RXE | CR_RXD)) { 6006657Snate@binkert.org rxHalt = true; 6016657Snate@binkert.org } else if (reg & CR_RXE) { 6026657Snate@binkert.org if (rxState == rxIdle) { 6036657Snate@binkert.org rxKick(); 6046657Snate@binkert.org } 6056657Snate@binkert.org } else if (reg & CR_RXD) { 6066657Snate@binkert.org rxHalt = true; 6076657Snate@binkert.org } 6086657Snate@binkert.org 6096657Snate@binkert.org if (reg & CR_TXR) 6108187SLisa.Hsu@amd.com txReset(); 6116657Snate@binkert.org 6126657Snate@binkert.org if (reg & CR_RXR) 6136657Snate@binkert.org rxReset(); 6146657Snate@binkert.org 6156657Snate@binkert.org if (reg & CR_SWI) 6166657Snate@binkert.org devIntrPost(ISR_SWI); 6176657Snate@binkert.org 6186657Snate@binkert.org if (reg & CR_RST) { 6196657Snate@binkert.org txReset(); 6207454Snate@binkert.org rxReset(); 6216657Snate@binkert.org 6226657Snate@binkert.org regsReset(); 6236657Snate@binkert.org } 6246657Snate@binkert.org break; 6257007Snate@binkert.org 6267056Snate@binkert.org case CFG: 6277007Snate@binkert.org if (reg & CFG_LNKSTS || 6287007Snate@binkert.org reg & CFG_SPDSTS || 6296657Snate@binkert.org reg & CFG_DUPSTS || 6307566SBrad.Beckmann@amd.com reg & CFG_RESERVED || 6317566SBrad.Beckmann@amd.com reg & CFG_T64ADDR || 6327566SBrad.Beckmann@amd.com reg & CFG_PCI64_DET) 6337566SBrad.Beckmann@amd.com panic("writing to read-only or reserved CFG bits!\n"); 6347566SBrad.Beckmann@amd.com 6357566SBrad.Beckmann@amd.com regs.config |= reg & ~(CFG_LNKSTS | CFG_SPDSTS | CFG_DUPSTS | 6369366Snilay@cs.wisc.edu CFG_RESERVED | CFG_T64ADDR | CFG_PCI64_DET); 6379366Snilay@cs.wisc.edu 6389366Snilay@cs.wisc.edu// all these #if 0's are because i don't THINK the kernel needs to 6399366Snilay@cs.wisc.edu// have these implemented. if there is a problem relating to one of 6407566SBrad.Beckmann@amd.com// these, you may need to add functionality in. 6417672Snate@binkert.org#if 0 6426657Snate@binkert.org if (reg & CFG_TBI_EN) ; 6439465Snilay@cs.wisc.edu if (reg & CFG_MODE_1000) ; 6446657Snate@binkert.org#endif 6459465Snilay@cs.wisc.edu 6467056Snate@binkert.org if (reg & CFG_AUTO_1000) 6479465Snilay@cs.wisc.edu panic("CFG_AUTO_1000 not implemented!\n"); 6489465Snilay@cs.wisc.edu 6496657Snate@binkert.org#if 0 6506657Snate@binkert.org if (reg & CFG_PINT_DUPSTS || 6517672Snate@binkert.org reg & CFG_PINT_LNKSTS || 6526657Snate@binkert.org reg & CFG_PINT_SPDSTS) 6536657Snate@binkert.org ; 6546657Snate@binkert.org 6556657Snate@binkert.org if (reg & CFG_TMRTEST) ; 6566657Snate@binkert.org if (reg & CFG_MRM_DIS) ; 6576657Snate@binkert.org if (reg & CFG_MWI_DIS) ; 6586657Snate@binkert.org 6596657Snate@binkert.org if (reg & CFG_T64ADDR) 6606657Snate@binkert.org panic("CFG_T64ADDR is read only register!\n"); 6616657Snate@binkert.org 6626657Snate@binkert.org if (reg & CFG_PCI64_DET) 6637542SBrad.Beckmann@amd.com panic("CFG_PCI64_DET is read only register!\n"); 6646657Snate@binkert.org 6656657Snate@binkert.org if (reg & CFG_DATA64_EN) ; 6669496Snilay@cs.wisc.edu if (reg & CFG_M64ADDR) ; 6679496Snilay@cs.wisc.edu if (reg & CFG_PHY_RST) ; 6689496Snilay@cs.wisc.edu if (reg & CFG_PHY_DIS) ; 6699496Snilay@cs.wisc.edu#endif 6709496Snilay@cs.wisc.edu 6716657Snate@binkert.org if (reg & CFG_EXTSTS_EN) 6726657Snate@binkert.org extstsEnable = true; 6736657Snate@binkert.org else 6746657Snate@binkert.org extstsEnable = false; 6756657Snate@binkert.org 6766657Snate@binkert.org#if 0 6776657Snate@binkert.org if (reg & CFG_REQALG) ; 6786657Snate@binkert.org if (reg & CFG_SB) ; 6796657Snate@binkert.org if (reg & CFG_POW) ; 6806657Snate@binkert.org if (reg & CFG_EXD) ; 6816657Snate@binkert.org if (reg & CFG_PESEL) ; 6828683Snilay@cs.wisc.edu if (reg & CFG_BROM_DIS) ; 6838683Snilay@cs.wisc.edu if (reg & CFG_EXT_125) ; 6848683Snilay@cs.wisc.edu if (reg & CFG_BEM) ; 6858683Snilay@cs.wisc.edu#endif 6868683Snilay@cs.wisc.edu break; 6878683Snilay@cs.wisc.edu 6886657Snate@binkert.org case MEAR: 6897007Snate@binkert.org regs.mear = reg; 6907007Snate@binkert.org // since phy is completely faked, MEAR_MD* don't matter 6917007Snate@binkert.org // and since the driver never uses MEAR_EE*, they don't 6926657Snate@binkert.org // matter 6936657Snate@binkert.org#if 0 6946657Snate@binkert.org if (reg & MEAR_EEDI) ; 6957007Snate@binkert.org if (reg & MEAR_EEDO) ; // this one is read only 6967007Snate@binkert.org if (reg & MEAR_EECLK) ; 6977007Snate@binkert.org if (reg & MEAR_EESEL) ; 6986657Snate@binkert.org if (reg & MEAR_MDIO) ; 6996657Snate@binkert.org if (reg & MEAR_MDDIR) ; 7006657Snate@binkert.org if (reg & MEAR_MDC) ; 7018683Snilay@cs.wisc.edu#endif 7028683Snilay@cs.wisc.edu break; 7038683Snilay@cs.wisc.edu 7048683Snilay@cs.wisc.edu case PTSCR: 7058683Snilay@cs.wisc.edu regs.ptscr = reg & ~(PTSCR_RBIST_RDONLY); 7068683Snilay@cs.wisc.edu // these control BISTs for various parts of chip - we 7077007Snate@binkert.org // don't care or do just fake that the BIST is done 7087007Snate@binkert.org if (reg & PTSCR_RBIST_EN) 7097007Snate@binkert.org regs.ptscr |= PTSCR_RBIST_DONE; 7106657Snate@binkert.org if (reg & PTSCR_EEBIST_EN) 7116657Snate@binkert.org regs.ptscr &= ~PTSCR_EEBIST_EN; 7126657Snate@binkert.org if (reg & PTSCR_EELOAD_EN) 7137007Snate@binkert.org regs.ptscr &= ~PTSCR_EELOAD_EN; 7147007Snate@binkert.org break; 7157007Snate@binkert.org 7166657Snate@binkert.org case ISR: /* writing to the ISR has no effect */ 7176657Snate@binkert.org panic("ISR is a read only register!\n"); 7186657Snate@binkert.org 7197007Snate@binkert.org case IMR: 7207007Snate@binkert.org regs.imr = reg; 7217007Snate@binkert.org devIntrChangeMask(); 7226657Snate@binkert.org break; 7236657Snate@binkert.org 7247007Snate@binkert.org case IER: 7257007Snate@binkert.org regs.ier = reg; 7267567SBrad.Beckmann@amd.com break; 7277567SBrad.Beckmann@amd.com 7287567SBrad.Beckmann@amd.com case IHR: 7297567SBrad.Beckmann@amd.com regs.ihr = reg; 7307567SBrad.Beckmann@amd.com /* not going to implement real interrupt holdoff */ 7317567SBrad.Beckmann@amd.com break; 7327567SBrad.Beckmann@amd.com 7337567SBrad.Beckmann@amd.com case TXDP: 7347567SBrad.Beckmann@amd.com regs.txdp = (reg & 0xFFFFFFFC); 7357567SBrad.Beckmann@amd.com assert(txState == txIdle); 7367567SBrad.Beckmann@amd.com CTDD = false; 7377567SBrad.Beckmann@amd.com break; 7387567SBrad.Beckmann@amd.com 7398155Snilay@cs.wisc.edu case TXDP_HI: 7408155Snilay@cs.wisc.edu regs.txdp_hi = reg; 7418155Snilay@cs.wisc.edu break; 7428155Snilay@cs.wisc.edu 7438155Snilay@cs.wisc.edu case TXCFG: 7448155Snilay@cs.wisc.edu regs.txcfg = reg; 7458155Snilay@cs.wisc.edu#if 0 7468155Snilay@cs.wisc.edu if (reg & TXCFG_CSI) ; 7478155Snilay@cs.wisc.edu if (reg & TXCFG_HBI) ; 7488155Snilay@cs.wisc.edu if (reg & TXCFG_MLB) ; 7498155Snilay@cs.wisc.edu if (reg & TXCFG_ATP) ; 7507567SBrad.Beckmann@amd.com if (reg & TXCFG_ECRETRY) { 7518155Snilay@cs.wisc.edu /* 7528155Snilay@cs.wisc.edu * this could easily be implemented, but considering 7537567SBrad.Beckmann@amd.com * the network is just a fake pipe, wouldn't make 7547567SBrad.Beckmann@amd.com * sense to do this 7557567SBrad.Beckmann@amd.com */ 7567567SBrad.Beckmann@amd.com } 7577922SBrad.Beckmann@amd.com 7587922SBrad.Beckmann@amd.com if (reg & TXCFG_BRST_DIS) ; 7597922SBrad.Beckmann@amd.com#endif 7607922SBrad.Beckmann@amd.com 7617922SBrad.Beckmann@amd.com#if 0 7627922SBrad.Beckmann@amd.com /* we handle our own DMA, ignore the kernel's exhortations */ 7637922SBrad.Beckmann@amd.com if (reg & TXCFG_MXDMA) ; 7647922SBrad.Beckmann@amd.com#endif 7658154Snilay@cs.wisc.edu 7668154Snilay@cs.wisc.edu // also, we currently don't care about fill/drain 7678154Snilay@cs.wisc.edu // thresholds though this may change in the future with 7688154Snilay@cs.wisc.edu // more realistic networks or a driver which changes it 7698154Snilay@cs.wisc.edu // according to feedback 7708154Snilay@cs.wisc.edu 7718154Snilay@cs.wisc.edu break; 7728154Snilay@cs.wisc.edu 7738154Snilay@cs.wisc.edu case GPIOR: 7748154Snilay@cs.wisc.edu regs.gpior = reg; 7758154Snilay@cs.wisc.edu /* these just control general purpose i/o pins, don't matter */ 7768154Snilay@cs.wisc.edu break; 7778154Snilay@cs.wisc.edu 7788154Snilay@cs.wisc.edu case RXDP: 7798154Snilay@cs.wisc.edu regs.rxdp = reg; 7808154Snilay@cs.wisc.edu break; 7818154Snilay@cs.wisc.edu 7828154Snilay@cs.wisc.edu case RXDP_HI: 7838154Snilay@cs.wisc.edu regs.rxdp_hi = reg; 7848154Snilay@cs.wisc.edu break; 7858154Snilay@cs.wisc.edu 7867922SBrad.Beckmann@amd.com case RXCFG: 7877922SBrad.Beckmann@amd.com regs.rxcfg = reg; 7887922SBrad.Beckmann@amd.com#if 0 7897922SBrad.Beckmann@amd.com if (reg & RXCFG_AEP) ; 7907007Snate@binkert.org if (reg & RXCFG_ARP) ; 7917007Snate@binkert.org if (reg & RXCFG_STRIPCRC) ; 7926863Sdrh5@cs.wisc.edu if (reg & RXCFG_RX_RD) ; 7936863Sdrh5@cs.wisc.edu if (reg & RXCFG_ALP) ; 7946863Sdrh5@cs.wisc.edu if (reg & RXCFG_AIRL) ; 7957007Snate@binkert.org 7967007Snate@binkert.org /* we handle our own DMA, ignore what kernel says about it */ 7977007Snate@binkert.org if (reg & RXCFG_MXDMA) ; 7987007Snate@binkert.org 7996863Sdrh5@cs.wisc.edu //also, we currently don't care about fill/drain thresholds 8006863Sdrh5@cs.wisc.edu //though this may change in the future with more realistic 8016863Sdrh5@cs.wisc.edu //networks or a driver which changes it according to feedback 8026863Sdrh5@cs.wisc.edu if (reg & (RXCFG_DRTH | RXCFG_DRTH0)) ; 8036863Sdrh5@cs.wisc.edu#endif 8046863Sdrh5@cs.wisc.edu break; 8057007Snate@binkert.org 8067007Snate@binkert.org case PQCR: 8077007Snate@binkert.org /* there is no priority queueing used in the linux 2.6 driver */ 8087007Snate@binkert.org regs.pqcr = reg; 8097007Snate@binkert.org break; 8106657Snate@binkert.org 8117007Snate@binkert.org case WCSR: 8127007Snate@binkert.org /* not going to implement wake on LAN */ 8137007Snate@binkert.org regs.wcsr = reg; 8146902SBrad.Beckmann@amd.com break; 8156902SBrad.Beckmann@amd.com 8166902SBrad.Beckmann@amd.com case PCR: 8176902SBrad.Beckmann@amd.com /* not going to implement pause control */ 8186902SBrad.Beckmann@amd.com regs.pcr = reg; 8196902SBrad.Beckmann@amd.com break; 8206902SBrad.Beckmann@amd.com 8217025SBrad.Beckmann@amd.com case RFCR: 8226902SBrad.Beckmann@amd.com regs.rfcr = reg; 8236902SBrad.Beckmann@amd.com 8246902SBrad.Beckmann@amd.com rxFilterEnable = (reg & RFCR_RFEN) ? true : false; 8256902SBrad.Beckmann@amd.com acceptBroadcast = (reg & RFCR_AAB) ? true : false; 8266902SBrad.Beckmann@amd.com acceptMulticast = (reg & RFCR_AAM) ? true : false; 8277542SBrad.Beckmann@amd.com acceptUnicast = (reg & RFCR_AAU) ? true : false; 8287542SBrad.Beckmann@amd.com acceptPerfect = (reg & RFCR_APM) ? true : false; 8297542SBrad.Beckmann@amd.com acceptArp = (reg & RFCR_AARP) ? true : false; 8306902SBrad.Beckmann@amd.com 8316902SBrad.Beckmann@amd.com#if 0 8326902SBrad.Beckmann@amd.com if (reg & RFCR_APAT) 8336902SBrad.Beckmann@amd.com panic("RFCR_APAT not implemented!\n"); 8346902SBrad.Beckmann@amd.com#endif 8356902SBrad.Beckmann@amd.com 8366902SBrad.Beckmann@amd.com if (reg & RFCR_MHEN || reg & RFCR_UHEN) 8376902SBrad.Beckmann@amd.com panic("hash filtering not implemented!\n"); 8386902SBrad.Beckmann@amd.com 8396902SBrad.Beckmann@amd.com if (reg & RFCR_ULM) 8406902SBrad.Beckmann@amd.com panic("RFCR_ULM not implemented!\n"); 8416902SBrad.Beckmann@amd.com 8426902SBrad.Beckmann@amd.com break; 8436902SBrad.Beckmann@amd.com 8446902SBrad.Beckmann@amd.com case RFDR: 8457542SBrad.Beckmann@amd.com panic("the driver never writes to RFDR, something is wrong!\n"); 8469496Snilay@cs.wisc.edu 8476902SBrad.Beckmann@amd.com case BRAR: 8487839Snilay@cs.wisc.edu panic("the driver never uses BRAR, something is wrong!\n"); 8497839Snilay@cs.wisc.edu 8507839Snilay@cs.wisc.edu case BRDR: 8517839Snilay@cs.wisc.edu panic("the driver never uses BRDR, something is wrong!\n"); 8527839Snilay@cs.wisc.edu 8537839Snilay@cs.wisc.edu case SRR: 8547839Snilay@cs.wisc.edu panic("SRR is read only register!\n"); 8557839Snilay@cs.wisc.edu 8567839Snilay@cs.wisc.edu case MIBC: 8577839Snilay@cs.wisc.edu panic("the driver never uses MIBC, something is wrong!\n"); 8587839Snilay@cs.wisc.edu 8597839Snilay@cs.wisc.edu case VRCR: 8607839Snilay@cs.wisc.edu regs.vrcr = reg; 8617839Snilay@cs.wisc.edu break; 8627839Snilay@cs.wisc.edu 8637839Snilay@cs.wisc.edu case VTCR: 8647839Snilay@cs.wisc.edu regs.vtcr = reg; 8657839Snilay@cs.wisc.edu break; 8667839Snilay@cs.wisc.edu 8677839Snilay@cs.wisc.edu case VDR: 8687839Snilay@cs.wisc.edu panic("the driver never uses VDR, something is wrong!\n"); 8697839Snilay@cs.wisc.edu break; 8707839Snilay@cs.wisc.edu 8717839Snilay@cs.wisc.edu case CCSR: 8727839Snilay@cs.wisc.edu /* not going to implement clockrun stuff */ 8737839Snilay@cs.wisc.edu regs.ccsr = reg; 8747839Snilay@cs.wisc.edu break; 8757839Snilay@cs.wisc.edu 8767839Snilay@cs.wisc.edu case TBICR: 8777839Snilay@cs.wisc.edu regs.tbicr = reg; 8787839Snilay@cs.wisc.edu if (reg & TBICR_MR_LOOPBACK) 8797839Snilay@cs.wisc.edu panic("TBICR_MR_LOOPBACK never used, something wrong!\n"); 8807839Snilay@cs.wisc.edu 8817839Snilay@cs.wisc.edu if (reg & TBICR_MR_AN_ENABLE) { 8827839Snilay@cs.wisc.edu regs.tanlpar = regs.tanar; 8837839Snilay@cs.wisc.edu regs.tbisr |= (TBISR_MR_AN_COMPLETE | TBISR_MR_LINK_STATUS); 8847839Snilay@cs.wisc.edu } 8856902SBrad.Beckmann@amd.com 8868683Snilay@cs.wisc.edu#if 0 8878683Snilay@cs.wisc.edu if (reg & TBICR_MR_RESTART_AN) ; 8888683Snilay@cs.wisc.edu#endif 8898683Snilay@cs.wisc.edu 8908683Snilay@cs.wisc.edu break; 8918683Snilay@cs.wisc.edu 8928683Snilay@cs.wisc.edu case TBISR: 8938683Snilay@cs.wisc.edu panic("TBISR is read only register!\n"); 8948683Snilay@cs.wisc.edu 8958683Snilay@cs.wisc.edu case TANAR: 8968683Snilay@cs.wisc.edu regs.tanar = reg; 8978683Snilay@cs.wisc.edu if (reg & TANAR_PS2) 8988683Snilay@cs.wisc.edu panic("this isn't used in driver, something wrong!\n"); 8998683Snilay@cs.wisc.edu 9008683Snilay@cs.wisc.edu if (reg & TANAR_PS1) 9018683Snilay@cs.wisc.edu panic("this isn't used in driver, something wrong!\n"); 9028683Snilay@cs.wisc.edu break; 9036657Snate@binkert.org 9046657Snate@binkert.org case TANLPAR: 9057839Snilay@cs.wisc.edu panic("this should only be written to by the fake phy!\n"); 9067839Snilay@cs.wisc.edu 9077839Snilay@cs.wisc.edu case TANER: 9087839Snilay@cs.wisc.edu panic("TANER is read only register!\n"); 9096657Snate@binkert.org 9107839Snilay@cs.wisc.edu case TESR: 9117839Snilay@cs.wisc.edu regs.tesr = reg; 9127839Snilay@cs.wisc.edu break; 9137839Snilay@cs.wisc.edu 9147839Snilay@cs.wisc.edu default: 9158055Sksewell@umich.edu panic("invalid register access daddr=%#x", daddr); 9167839Snilay@cs.wisc.edu } 9177839Snilay@cs.wisc.edu } else { 9186657Snate@binkert.org panic("Invalid Request Size"); 9197839Snilay@cs.wisc.edu } 9207839Snilay@cs.wisc.edu 9217839Snilay@cs.wisc.edu return No_Fault; 9227839Snilay@cs.wisc.edu} 9237839Snilay@cs.wisc.edu 9247839Snilay@cs.wisc.eduvoid 9257839Snilay@cs.wisc.eduNSGigE::devIntrPost(uint32_t interrupts) 9267839Snilay@cs.wisc.edu{ 9277839Snilay@cs.wisc.edu bool delay = false; 9287839Snilay@cs.wisc.edu 9297839Snilay@cs.wisc.edu if (interrupts & ISR_RESERVE) 9308055Sksewell@umich.edu panic("Cannot set a reserved interrupt"); 9317839Snilay@cs.wisc.edu 9327839Snilay@cs.wisc.edu if (interrupts & ISR_TXRCMP) 9337839Snilay@cs.wisc.edu regs.isr |= ISR_TXRCMP; 9347839Snilay@cs.wisc.edu 9357839Snilay@cs.wisc.edu if (interrupts & ISR_RXRCMP) 9367839Snilay@cs.wisc.edu regs.isr |= ISR_RXRCMP; 9377839Snilay@cs.wisc.edu 9387839Snilay@cs.wisc.edu//ISR_DPERR not implemented 9397839Snilay@cs.wisc.edu//ISR_SSERR not implemented 9407839Snilay@cs.wisc.edu//ISR_RMABT not implemented 9417839Snilay@cs.wisc.edu//ISR_RXSOVR not implemented 9427839Snilay@cs.wisc.edu//ISR_HIBINT not implemented 9437839Snilay@cs.wisc.edu//ISR_PHY not implemented 9447839Snilay@cs.wisc.edu//ISR_PME not implemented 9458055Sksewell@umich.edu 9467839Snilay@cs.wisc.edu if (interrupts & ISR_SWI) 9477839Snilay@cs.wisc.edu regs.isr |= ISR_SWI; 9487839Snilay@cs.wisc.edu 9497839Snilay@cs.wisc.edu//ISR_MIB not implemented 9507839Snilay@cs.wisc.edu//ISR_TXURN not implemented 9517839Snilay@cs.wisc.edu 9527839Snilay@cs.wisc.edu if (interrupts & ISR_TXIDLE) 9537839Snilay@cs.wisc.edu regs.isr |= ISR_TXIDLE; 9547839Snilay@cs.wisc.edu 9557839Snilay@cs.wisc.edu if (interrupts & ISR_TXERR) 9566657Snate@binkert.org regs.isr |= ISR_TXERR; 9577007Snate@binkert.org 9587007Snate@binkert.org if (interrupts & ISR_TXDESC) 9596657Snate@binkert.org regs.isr |= ISR_TXDESC; 9608055Sksewell@umich.edu 9616657Snate@binkert.org if (interrupts & ISR_TXOK) { 9626657Snate@binkert.org regs.isr |= ISR_TXOK; 9636657Snate@binkert.org delay = true; 9646657Snate@binkert.org } 9658478Snilay@cs.wisc.edu 9668478Snilay@cs.wisc.edu if (interrupts & ISR_RXORN) 9678478Snilay@cs.wisc.edu regs.isr |= ISR_RXORN; 9689302Snilay@cs.wisc.edu 9699302Snilay@cs.wisc.edu if (interrupts & ISR_RXIDLE) 9709302Snilay@cs.wisc.edu regs.isr |= ISR_RXIDLE; 9719302Snilay@cs.wisc.edu 9729302Snilay@cs.wisc.edu//ISR_RXEARLY not implemented 9739302Snilay@cs.wisc.edu 9749302Snilay@cs.wisc.edu if (interrupts & ISR_RXERR) 9759302Snilay@cs.wisc.edu regs.isr |= ISR_RXERR; 9769302Snilay@cs.wisc.edu 9779302Snilay@cs.wisc.edu if (interrupts & ISR_RXDESC) 9789302Snilay@cs.wisc.edu regs.isr |= ISR_RXDESC; 9799302Snilay@cs.wisc.edu 9809302Snilay@cs.wisc.edu if (interrupts & ISR_RXOK) { 9819302Snilay@cs.wisc.edu delay = true; 9829302Snilay@cs.wisc.edu regs.isr |= ISR_RXOK; 9839302Snilay@cs.wisc.edu } 9849302Snilay@cs.wisc.edu 9859302Snilay@cs.wisc.edu if ((regs.isr & regs.imr)) { 9869302Snilay@cs.wisc.edu Tick when = curTick; 9879302Snilay@cs.wisc.edu if (delay) 9889302Snilay@cs.wisc.edu when += intrDelay; 9899302Snilay@cs.wisc.edu cpuIntrPost(when); 9909302Snilay@cs.wisc.edu } 9919302Snilay@cs.wisc.edu 9929302Snilay@cs.wisc.edu DPRINTF(EthernetIntr, 9939302Snilay@cs.wisc.edu "interrupt written to ISR: intr=%#x isr=%#x imr=%#x\n", 9949302Snilay@cs.wisc.edu interrupts, regs.isr, regs.imr); 9959302Snilay@cs.wisc.edu} 9969302Snilay@cs.wisc.edu 9979302Snilay@cs.wisc.eduvoid 9989302Snilay@cs.wisc.eduNSGigE::devIntrClear(uint32_t interrupts) 9999302Snilay@cs.wisc.edu{ 10009302Snilay@cs.wisc.edu if (interrupts & ISR_RESERVE) 10016657Snate@binkert.org panic("Cannot clear a reserved interrupt"); 10026657Snate@binkert.org 10039219Spower.jg@gmail.com if (interrupts & ISR_TXRCMP) 10046657Snate@binkert.org regs.isr &= ~ISR_TXRCMP; 10056657Snate@binkert.org 10066999Snate@binkert.org if (interrupts & ISR_RXRCMP) 10076657Snate@binkert.org regs.isr &= ~ISR_RXRCMP; 10086657Snate@binkert.org 10099104Shestness@cs.utexas.edu//ISR_DPERR not implemented 10109104Shestness@cs.utexas.edu//ISR_SSERR not implemented 10119104Shestness@cs.utexas.edu//ISR_RMABT not implemented 10129104Shestness@cs.utexas.edu//ISR_RXSOVR not implemented 10136657Snate@binkert.org//ISR_HIBINT not implemented 10146657Snate@binkert.org//ISR_PHY not implemented 10156657Snate@binkert.org//ISR_PME not implemented 10166657Snate@binkert.org 10178946Sandreas.hansson@arm.com if (interrupts & ISR_SWI) 10188946Sandreas.hansson@arm.com regs.isr &= ~ISR_SWI; 10198946Sandreas.hansson@arm.com 10207832Snate@binkert.org//ISR_MIB not implemented 10217832Snate@binkert.org//ISR_TXURN not implemented 10227007Snate@binkert.org 10238232Snate@binkert.org if (interrupts & ISR_TXIDLE) 10248229Snate@binkert.org regs.isr &= ~ISR_TXIDLE; 10258229Snate@binkert.org 10268229Snate@binkert.org if (interrupts & ISR_TXERR) 10279104Shestness@cs.utexas.edu regs.isr &= ~ISR_TXERR; 10289104Shestness@cs.utexas.edu 10299104Shestness@cs.utexas.edu if (interrupts & ISR_TXDESC) 10309104Shestness@cs.utexas.edu regs.isr &= ~ISR_TXDESC; 10319104Shestness@cs.utexas.edu 10329104Shestness@cs.utexas.edu if (interrupts & ISR_TXOK) 10338229Snate@binkert.org regs.isr &= ~ISR_TXOK; 10346657Snate@binkert.org 10356657Snate@binkert.org if (interrupts & ISR_RXORN) 10369219Spower.jg@gmail.com regs.isr &= ~ISR_RXORN; 10379219Spower.jg@gmail.com 10389219Spower.jg@gmail.com if (interrupts & ISR_RXIDLE) 10399219Spower.jg@gmail.com regs.isr &= ~ISR_RXIDLE; 10409219Spower.jg@gmail.com 10419219Spower.jg@gmail.com//ISR_RXEARLY not implemented 10429219Spower.jg@gmail.com 10436657Snate@binkert.org if (interrupts & ISR_RXERR) 10447055Snate@binkert.org regs.isr &= ~ISR_RXERR; 10457055Snate@binkert.org 10467007Snate@binkert.org if (interrupts & ISR_RXDESC) 10477007Snate@binkert.org regs.isr &= ~ISR_RXDESC; 10486657Snate@binkert.org 10496657Snate@binkert.org if (interrupts & ISR_RXOK) 10506657Snate@binkert.org regs.isr &= ~ISR_RXOK; 10516657Snate@binkert.org 10526657Snate@binkert.org if (!(regs.isr & regs.imr)) 10536657Snate@binkert.org cpuIntrClear(); 10547007Snate@binkert.org 10559496Snilay@cs.wisc.edu DPRINTF(EthernetIntr, 10567007Snate@binkert.org "interrupt cleared from ISR: intr=%x isr=%x imr=%x\n", 10577007Snate@binkert.org interrupts, regs.isr, regs.imr); 10589230Snilay@cs.wisc.edu} 10596657Snate@binkert.org 10606657Snate@binkert.orgvoid 10616657Snate@binkert.orgNSGigE::devIntrChangeMask() 10626657Snate@binkert.org{ 10636657Snate@binkert.org DPRINTF(EthernetIntr, "interrupt mask changed\n"); 10646657Snate@binkert.org 10656657Snate@binkert.org if (regs.isr & regs.imr) 10666657Snate@binkert.org cpuIntrPost(curTick); 10676657Snate@binkert.org else 10686657Snate@binkert.org cpuIntrClear(); 10696657Snate@binkert.org} 10706657Snate@binkert.org 10717567SBrad.Beckmann@amd.comvoid 10727567SBrad.Beckmann@amd.comNSGigE::cpuIntrPost(Tick when) 10737567SBrad.Beckmann@amd.com{ 10747567SBrad.Beckmann@amd.com // If the interrupt you want to post is later than an interrupt 10756657Snate@binkert.org // already scheduled, just let it post in the coming one and don't 10766657Snate@binkert.org // schedule another. 10776657Snate@binkert.org // HOWEVER, must be sure that the scheduled intrTick is in the 10786657Snate@binkert.org // future (this was formerly the source of a bug) 10796657Snate@binkert.org assert((intrTick >= curTick) || (intrTick == 0)); 10806657Snate@binkert.org if (when > intrTick && intrTick != 0) 10816657Snate@binkert.org return; 10826657Snate@binkert.org 10836657Snate@binkert.org intrTick = when; 10846657Snate@binkert.org 10856657Snate@binkert.org if (intrEvent) { 10866657Snate@binkert.org intrEvent->squash(); 10876657Snate@binkert.org intrEvent = 0; 10886657Snate@binkert.org } 10896657Snate@binkert.org 10906657Snate@binkert.org if (when < curTick) { 10916657Snate@binkert.org cpuInterrupt(); 10926657Snate@binkert.org } else { 10936999Snate@binkert.org DPRINTF(EthernetIntr, 10946657Snate@binkert.org "going to schedule an interrupt for intrTick=%d\n", 10956657Snate@binkert.org intrTick); 10966657Snate@binkert.org intrEvent = new IntrEvent(this, true); 10976657Snate@binkert.org intrEvent->schedule(intrTick); 10986657Snate@binkert.org } 10996657Snate@binkert.org} 11007832Snate@binkert.org 11017832Snate@binkert.orgvoid 11027805Snilay@cs.wisc.eduNSGigE::cpuInterrupt() 11037832Snate@binkert.org{ 11048232Snate@binkert.org // Don't send an interrupt if there's already one 11058232Snate@binkert.org if (cpuPendingIntr) { 11068229Snate@binkert.org DPRINTF(EthernetIntr, 11078229Snate@binkert.org "would send an interrupt now, but there's already pending\n"); 11088229Snate@binkert.org intrTick = 0; 11098229Snate@binkert.org return; 11106657Snate@binkert.org } 11116657Snate@binkert.org // Don't send an interrupt if it's supposed to be delayed 11126657Snate@binkert.org if (intrTick > curTick) { 11136657Snate@binkert.org DPRINTF(EthernetIntr, 11146657Snate@binkert.org "an interrupt is scheduled for %d, wait til then\n", 11156657Snate@binkert.org intrTick); 11166657Snate@binkert.org return; 11176657Snate@binkert.org } 11187007Snate@binkert.org 11197007Snate@binkert.org // Whether or not there's a pending interrupt, we don't care about 11207839Snilay@cs.wisc.edu // it anymore 11217839Snilay@cs.wisc.edu intrEvent = 0; 11227839Snilay@cs.wisc.edu intrTick = 0; 11237839Snilay@cs.wisc.edu 11247839Snilay@cs.wisc.edu // Send interrupt 11257839Snilay@cs.wisc.edu cpuPendingIntr = true; 11267839Snilay@cs.wisc.edu /** @todo rework the intctrl to be tsunami ok */ 11277839Snilay@cs.wisc.edu //intctrl->post(TheISA::INTLEVEL_IRQ1, TheISA::INTINDEX_ETHERNET); 11287839Snilay@cs.wisc.edu DPRINTF(EthernetIntr, "Posting interrupts to cchip!\n"); 11297839Snilay@cs.wisc.edu tsunami->cchip->postDRIR(configData->config.hdr.pci0.interruptLine); 11307007Snate@binkert.org} 11316657Snate@binkert.org 11327839Snilay@cs.wisc.eduvoid 11337839Snilay@cs.wisc.eduNSGigE::cpuIntrClear() 11348337Snilay@cs.wisc.edu{ 11357839Snilay@cs.wisc.edu if (!cpuPendingIntr) 11368337Snilay@cs.wisc.edu return; 11377839Snilay@cs.wisc.edu 11388337Snilay@cs.wisc.edu cpuPendingIntr = false; 11397839Snilay@cs.wisc.edu /** @todo rework the intctrl to be tsunami ok */ 11408337Snilay@cs.wisc.edu //intctrl->clear(TheISA::INTLEVEL_IRQ1, TheISA::INTINDEX_ETHERNET); 11417839Snilay@cs.wisc.edu DPRINTF(EthernetIntr, "clearing all interrupts from cchip\n"); 11427839Snilay@cs.wisc.edu tsunami->cchip->clearDRIR(configData->config.hdr.pci0.interruptLine); 11436657Snate@binkert.org} 11446657Snate@binkert.org 11457780Snilay@cs.wisc.edubool 11469465Snilay@cs.wisc.eduNSGigE::cpuIntrPending() const 11479171Snilay@cs.wisc.edu{ return cpuPendingIntr; } 11486657Snate@binkert.org 11497007Snate@binkert.orgvoid 11507839Snilay@cs.wisc.eduNSGigE::txReset() 11517839Snilay@cs.wisc.edu{ 11527839Snilay@cs.wisc.edu 11537839Snilay@cs.wisc.edu DPRINTF(Ethernet, "transmit reset\n"); 11547839Snilay@cs.wisc.edu 11557839Snilay@cs.wisc.edu CTDD = false; 11567839Snilay@cs.wisc.edu txFifoAvail = maxTxFifoSize; 11577839Snilay@cs.wisc.edu txHalt = false; 11587839Snilay@cs.wisc.edu txFragPtr = 0; 11596657Snate@binkert.org assert(txDescCnt == 0); 11607839Snilay@cs.wisc.edu txFifo.clear(); 11616657Snate@binkert.org regs.command &= ~CR_TXE; 11627780Snilay@cs.wisc.edu txState = txIdle; 11637780Snilay@cs.wisc.edu assert(txDmaState == dmaIdle); 11647542SBrad.Beckmann@amd.com} 11658266Sksewell@umich.edu 11668266Sksewell@umich.eduvoid 11678266Sksewell@umich.eduNSGigE::rxReset() 11688266Sksewell@umich.edu{ 11698266Sksewell@umich.edu DPRINTF(Ethernet, "receive reset\n"); 11708266Sksewell@umich.edu 11716657Snate@binkert.org CRDD = false; 11727832Snate@binkert.org assert(rxPktBytes == 0); 11737839Snilay@cs.wisc.edu rxFifoCnt = 0; 11747839Snilay@cs.wisc.edu rxHalt = false; 11758337Snilay@cs.wisc.edu rxFragPtr = 0; 11768341Snilay@cs.wisc.edu assert(rxDescCnt == 0); 11777839Snilay@cs.wisc.edu assert(rxDmaState == dmaIdle); 11788337Snilay@cs.wisc.edu rxFifo.clear(); 11798341Snilay@cs.wisc.edu regs.command &= ~CR_RXE; 11807839Snilay@cs.wisc.edu rxState = rxIdle; 11818337Snilay@cs.wisc.edu} 11828341Snilay@cs.wisc.edu 11837839Snilay@cs.wisc.eduvoid NSGigE::regsReset() 11848337Snilay@cs.wisc.edu{ 11858341Snilay@cs.wisc.edu memset(®s, 0, sizeof(regs)); 11867839Snilay@cs.wisc.edu regs.config = 0x80000000; 11877839Snilay@cs.wisc.edu regs.mear = 0x12; 11886657Snate@binkert.org regs.isr = 0x00608000; 11898266Sksewell@umich.edu regs.txcfg = 0x120; 11908266Sksewell@umich.edu regs.rxcfg = 0x4; 11918266Sksewell@umich.edu regs.srr = 0x0103; 11928266Sksewell@umich.edu regs.mibc = 0x2; 11938266Sksewell@umich.edu regs.vdr = 0x81; 11948266Sksewell@umich.edu regs.tesr = 0xc000; 11956657Snate@binkert.org 11967780Snilay@cs.wisc.edu extstsEnable = false; 11978266Sksewell@umich.edu acceptBroadcast = false; 11988266Sksewell@umich.edu acceptMulticast = false; 11998266Sksewell@umich.edu acceptUnicast = false; 12008266Sksewell@umich.edu acceptPerfect = false; 12018266Sksewell@umich.edu acceptArp = false; 12028266Sksewell@umich.edu} 12036657Snate@binkert.org 12046657Snate@binkert.orgvoid 12056657Snate@binkert.orgNSGigE::rxDmaReadCopy() 12066657Snate@binkert.org{ 12076657Snate@binkert.org assert(rxDmaState == dmaReading); 12087007Snate@binkert.org 12097007Snate@binkert.org memcpy(rxDmaData, physmem->dma_addr(rxDmaAddr, rxDmaLen), rxDmaLen); 12107007Snate@binkert.org rxDmaState = dmaIdle; 12117007Snate@binkert.org 12127839Snilay@cs.wisc.edu DPRINTF(EthernetDMA, "rx dma read paddr=%#x len=%d\n", 12137839Snilay@cs.wisc.edu rxDmaAddr, rxDmaLen); 12147839Snilay@cs.wisc.edu DDUMP(EthernetDMA, rxDmaData, rxDmaLen); 12157839Snilay@cs.wisc.edu} 12167839Snilay@cs.wisc.edu 12177839Snilay@cs.wisc.edubool 12187839Snilay@cs.wisc.eduNSGigE::doRxDmaRead() 12197839Snilay@cs.wisc.edu{ 12207839Snilay@cs.wisc.edu assert(rxDmaState == dmaIdle || rxDmaState == dmaReadWaiting); 12217839Snilay@cs.wisc.edu rxDmaState = dmaReading; 12227839Snilay@cs.wisc.edu 12237007Snate@binkert.org if (dmaInterface && !rxDmaFree) { 12246657Snate@binkert.org if (dmaInterface->busy()) 12256657Snate@binkert.org rxDmaState = dmaReadWaiting; 12266657Snate@binkert.org else 12276657Snate@binkert.org dmaInterface->doDMA(Read, rxDmaAddr, rxDmaLen, curTick, 12286657Snate@binkert.org &rxDmaReadEvent, true); 12296657Snate@binkert.org return true; 12306657Snate@binkert.org } 12316657Snate@binkert.org 12326657Snate@binkert.org if (dmaReadDelay == 0 && dmaReadFactor == 0) { 12336657Snate@binkert.org rxDmaReadCopy(); 12346657Snate@binkert.org return false; 12356999Snate@binkert.org } 12366657Snate@binkert.org 12376657Snate@binkert.org Tick factor = ((rxDmaLen + ULL(63)) >> ULL(6)) * dmaReadFactor; 12386657Snate@binkert.org Tick start = curTick + dmaReadDelay + factor; 12396657Snate@binkert.org rxDmaReadEvent.schedule(start); 12406657Snate@binkert.org return true; 12416657Snate@binkert.org} 12429104Shestness@cs.utexas.edu 12436657Snate@binkert.orgvoid 12446657Snate@binkert.orgNSGigE::rxDmaReadDone() 12456657Snate@binkert.org{ 12466657Snate@binkert.org assert(rxDmaState == dmaReading); 12476657Snate@binkert.org rxDmaReadCopy(); 12486657Snate@binkert.org 12496657Snate@binkert.org // If the transmit state machine has a pending DMA, let it go first 12507007Snate@binkert.org if (txDmaState == dmaReadWaiting || txDmaState == dmaWriteWaiting) 12516657Snate@binkert.org txKick(); 12526657Snate@binkert.org 12536657Snate@binkert.org rxKick(); 12546657Snate@binkert.org} 12559105SBrad.Beckmann@amd.com 12569105SBrad.Beckmann@amd.comvoid 12579105SBrad.Beckmann@amd.comNSGigE::rxDmaWriteCopy() 12589105SBrad.Beckmann@amd.com{ 12599105SBrad.Beckmann@amd.com assert(rxDmaState == dmaWriting); 12609105SBrad.Beckmann@amd.com 12619105SBrad.Beckmann@amd.com memcpy(physmem->dma_addr(rxDmaAddr, rxDmaLen), rxDmaData, rxDmaLen); 12629105SBrad.Beckmann@amd.com rxDmaState = dmaIdle; 12636657Snate@binkert.org 12646657Snate@binkert.org DPRINTF(EthernetDMA, "rx dma write paddr=%#x len=%d\n", 12656657Snate@binkert.org rxDmaAddr, rxDmaLen); 12666657Snate@binkert.org DDUMP(EthernetDMA, rxDmaData, rxDmaLen); 12676657Snate@binkert.org} 12686657Snate@binkert.org 12696657Snate@binkert.orgbool 12709104Shestness@cs.utexas.eduNSGigE::doRxDmaWrite() 12719104Shestness@cs.utexas.edu{ 12729104Shestness@cs.utexas.edu assert(rxDmaState == dmaIdle || rxDmaState == dmaWriteWaiting); 12739104Shestness@cs.utexas.edu rxDmaState = dmaWriting; 12746657Snate@binkert.org 12756657Snate@binkert.org if (dmaInterface && !rxDmaFree) { 12766657Snate@binkert.org if (dmaInterface->busy()) 12776657Snate@binkert.org rxDmaState = dmaWriteWaiting; 12786657Snate@binkert.org else 12796657Snate@binkert.org dmaInterface->doDMA(WriteInvalidate, rxDmaAddr, rxDmaLen, curTick, 12806657Snate@binkert.org &rxDmaWriteEvent, true); 12816657Snate@binkert.org return true; 12826657Snate@binkert.org } 12836657Snate@binkert.org 12847839Snilay@cs.wisc.edu if (dmaWriteDelay == 0 && dmaWriteFactor == 0) { 12857839Snilay@cs.wisc.edu rxDmaWriteCopy(); 12867839Snilay@cs.wisc.edu return false; 12877839Snilay@cs.wisc.edu } 12887839Snilay@cs.wisc.edu 12897839Snilay@cs.wisc.edu Tick factor = ((rxDmaLen + ULL(63)) >> ULL(6)) * dmaWriteFactor; 12907839Snilay@cs.wisc.edu Tick start = curTick + dmaWriteDelay + factor; 12917839Snilay@cs.wisc.edu rxDmaWriteEvent.schedule(start); 12927839Snilay@cs.wisc.edu return true; 12937839Snilay@cs.wisc.edu} 12947839Snilay@cs.wisc.edu 12957839Snilay@cs.wisc.eduvoid 12966657Snate@binkert.orgNSGigE::rxDmaWriteDone() 12976657Snate@binkert.org{ 12986657Snate@binkert.org assert(rxDmaState == dmaWriting); 12996657Snate@binkert.org rxDmaWriteCopy(); 13006657Snate@binkert.org 13016657Snate@binkert.org // If the transmit state machine has a pending DMA, let it go first 13026657Snate@binkert.org if (txDmaState == dmaReadWaiting || txDmaState == dmaWriteWaiting) 13036657Snate@binkert.org txKick(); 13046657Snate@binkert.org 13056657Snate@binkert.org rxKick(); 13066657Snate@binkert.org} 13076657Snate@binkert.org 13086657Snate@binkert.orgvoid 13096657Snate@binkert.orgNSGigE::rxKick() 13106657Snate@binkert.org{ 13116657Snate@binkert.org DPRINTF(EthernetSM, "receive kick state=%s (rxBuf.size=%d)\n", 13126657Snate@binkert.org NsRxStateStrings[rxState], rxFifo.size()); 13136657Snate@binkert.org 13146657Snate@binkert.org if (rxKickTick > curTick) { 13156657Snate@binkert.org DPRINTF(EthernetSM, "receive kick exiting, can't run till %d\n", 13166657Snate@binkert.org rxKickTick); 13177805Snilay@cs.wisc.edu return; 13188159SBrad.Beckmann@amd.com } 13199465Snilay@cs.wisc.edu 13206657Snate@binkert.org next: 13216657Snate@binkert.org switch(rxDmaState) { 13226657Snate@binkert.org case dmaReadWaiting: 13236657Snate@binkert.org if (doRxDmaRead()) 13246657Snate@binkert.org goto exit; 13256657Snate@binkert.org break; 13267542SBrad.Beckmann@amd.com case dmaWriteWaiting: 13277542SBrad.Beckmann@amd.com if (doRxDmaWrite()) 13287542SBrad.Beckmann@amd.com goto exit; 13297542SBrad.Beckmann@amd.com break; 13307542SBrad.Beckmann@amd.com default: 13317542SBrad.Beckmann@amd.com break; 13327542SBrad.Beckmann@amd.com } 13337542SBrad.Beckmann@amd.com 13347542SBrad.Beckmann@amd.com // see state machine from spec for details 13357542SBrad.Beckmann@amd.com // the way this works is, if you finish work on one state and can 13367542SBrad.Beckmann@amd.com // go directly to another, you do that through jumping to the 13377832Snate@binkert.org // label "next". however, if you have intermediate work, like DMA 13387542SBrad.Beckmann@amd.com // so that you can't go to the next state yet, you go to exit and 13397542SBrad.Beckmann@amd.com // exit the loop. however, when the DMA is done it will trigger 13407542SBrad.Beckmann@amd.com // an event and come back to this loop. 13418229Snate@binkert.org switch (rxState) { 13427542SBrad.Beckmann@amd.com case rxIdle: 13437542SBrad.Beckmann@amd.com if (!regs.command & CR_RXE) { 13447542SBrad.Beckmann@amd.com DPRINTF(EthernetSM, "Receive Disabled! Nothing to do.\n"); 13457542SBrad.Beckmann@amd.com goto exit; 13467542SBrad.Beckmann@amd.com } 13477542SBrad.Beckmann@amd.com 13487542SBrad.Beckmann@amd.com if (CRDD) { 13497542SBrad.Beckmann@amd.com rxState = rxDescRefr; 13507542SBrad.Beckmann@amd.com 13517542SBrad.Beckmann@amd.com rxDmaAddr = regs.rxdp & 0x3fffffff; 13527542SBrad.Beckmann@amd.com rxDmaData = &rxDescCache + offsetof(ns_desc, link); 13537542SBrad.Beckmann@amd.com rxDmaLen = sizeof(rxDescCache.link); 13547542SBrad.Beckmann@amd.com rxDmaFree = dmaDescFree; 13557542SBrad.Beckmann@amd.com 13567542SBrad.Beckmann@amd.com descDmaReads++; 13577542SBrad.Beckmann@amd.com descDmaRdBytes += rxDmaLen; 13587542SBrad.Beckmann@amd.com 13597542SBrad.Beckmann@amd.com if (doRxDmaRead()) 13607542SBrad.Beckmann@amd.com goto exit; 13617542SBrad.Beckmann@amd.com } else { 13627542SBrad.Beckmann@amd.com rxState = rxDescRead; 13637542SBrad.Beckmann@amd.com 13647542SBrad.Beckmann@amd.com rxDmaAddr = regs.rxdp & 0x3fffffff; 13657542SBrad.Beckmann@amd.com rxDmaData = &rxDescCache; 13667542SBrad.Beckmann@amd.com rxDmaLen = sizeof(ns_desc); 13677542SBrad.Beckmann@amd.com rxDmaFree = dmaDescFree; 13687542SBrad.Beckmann@amd.com 13697542SBrad.Beckmann@amd.com descDmaReads++; 13707542SBrad.Beckmann@amd.com descDmaRdBytes += rxDmaLen; 13717542SBrad.Beckmann@amd.com 13727542SBrad.Beckmann@amd.com if (doRxDmaRead()) 13737542SBrad.Beckmann@amd.com goto exit; 13747542SBrad.Beckmann@amd.com } 13757542SBrad.Beckmann@amd.com break; 13767542SBrad.Beckmann@amd.com 13777542SBrad.Beckmann@amd.com case rxDescRefr: 13787542SBrad.Beckmann@amd.com if (rxDmaState != dmaIdle) 13797542SBrad.Beckmann@amd.com goto exit; 13807542SBrad.Beckmann@amd.com 13817542SBrad.Beckmann@amd.com rxState = rxAdvance; 13827542SBrad.Beckmann@amd.com break; 13837542SBrad.Beckmann@amd.com 13847542SBrad.Beckmann@amd.com case rxDescRead: 13857542SBrad.Beckmann@amd.com if (rxDmaState != dmaIdle) 13867542SBrad.Beckmann@amd.com goto exit; 13877542SBrad.Beckmann@amd.com 13887542SBrad.Beckmann@amd.com DPRINTF(EthernetDesc, 13897542SBrad.Beckmann@amd.com "rxDescCache:\n" 13907542SBrad.Beckmann@amd.com "\tlink=%08x\n" 13917542SBrad.Beckmann@amd.com "\tbufptr=%08x\n" 13927542SBrad.Beckmann@amd.com "\tcmdsts=%08x\n" 13937542SBrad.Beckmann@amd.com "\textsts=%08x\n", 13947542SBrad.Beckmann@amd.com rxDescCache.link, rxDescCache.bufptr, rxDescCache.cmdsts, 13957542SBrad.Beckmann@amd.com rxDescCache.extsts); 13967542SBrad.Beckmann@amd.com 13977542SBrad.Beckmann@amd.com if (rxDescCache.cmdsts & CMDSTS_OWN) { 13987542SBrad.Beckmann@amd.com rxState = rxIdle; 13997542SBrad.Beckmann@amd.com } else { 14007542SBrad.Beckmann@amd.com rxState = rxFifoBlock; 14017542SBrad.Beckmann@amd.com rxFragPtr = rxDescCache.bufptr; 14027542SBrad.Beckmann@amd.com rxDescCnt = rxDescCache.cmdsts & CMDSTS_LEN_MASK; 14037542SBrad.Beckmann@amd.com } 14047542SBrad.Beckmann@amd.com break; 14057542SBrad.Beckmann@amd.com 14067542SBrad.Beckmann@amd.com case rxFifoBlock: 14077542SBrad.Beckmann@amd.com if (!rxPacket) { 14087542SBrad.Beckmann@amd.com /** 14097542SBrad.Beckmann@amd.com * @todo in reality, we should be able to start processing 14107542SBrad.Beckmann@amd.com * the packet as it arrives, and not have to wait for the 14117542SBrad.Beckmann@amd.com * full packet ot be in the receive fifo. 14127542SBrad.Beckmann@amd.com */ 14137542SBrad.Beckmann@amd.com if (rxFifo.empty()) 14147542SBrad.Beckmann@amd.com goto exit; 14157542SBrad.Beckmann@amd.com 14167542SBrad.Beckmann@amd.com DPRINTF(EthernetSM, "\n\n*****processing receive of new packet\n"); 14177542SBrad.Beckmann@amd.com 14187542SBrad.Beckmann@amd.com // If we don't have a packet, grab a new one from the fifo. 14197542SBrad.Beckmann@amd.com rxPacket = rxFifo.front(); 14207542SBrad.Beckmann@amd.com rxPktBytes = rxPacket->length; 14217542SBrad.Beckmann@amd.com rxPacketBufPtr = rxPacket->data; 14226657Snate@binkert.org 14236999Snate@binkert.org#if TRACING_ON 14246657Snate@binkert.org if (DTRACE(Ethernet)) { 14256657Snate@binkert.org if (rxPacket->isIpPkt()) { 14266657Snate@binkert.org ip_header *ip = rxPacket->getIpHdr(); 14276657Snate@binkert.org DPRINTF(Ethernet, "ID is %d\n", reverseEnd16(ip->ID)); 14286657Snate@binkert.org if (rxPacket->isTcpPkt()) { 14296657Snate@binkert.org tcp_header *tcp = rxPacket->getTcpHdr(ip); 14307542SBrad.Beckmann@amd.com DPRINTF(Ethernet, "Src Port = %d, Dest Port = %d\n", 14317542SBrad.Beckmann@amd.com reverseEnd16(tcp->src_port_num), 14326657Snate@binkert.org reverseEnd16(tcp->dest_port_num)); 14337832Snate@binkert.org } 14347002Snate@binkert.org } 14357002Snate@binkert.org } 14368229Snate@binkert.org#endif 14378229Snate@binkert.org 14388608Snilay@cs.wisc.edu // sanity check - i think the driver behaves like this 14396657Snate@binkert.org assert(rxDescCnt >= rxPktBytes); 14407007Snate@binkert.org 14417007Snate@binkert.org // Must clear the value before popping to decrement the 14426657Snate@binkert.org // reference count 14436657Snate@binkert.org rxFifo.front() = NULL; 14446657Snate@binkert.org rxFifo.pop_front(); 14456657Snate@binkert.org rxFifoCnt -= rxPacket->length; 14466657Snate@binkert.org } 14477542SBrad.Beckmann@amd.com 14487542SBrad.Beckmann@amd.com 14497542SBrad.Beckmann@amd.com // dont' need the && rxDescCnt > 0 if driver sanity check 14506657Snate@binkert.org // above holds 14516657Snate@binkert.org if (rxPktBytes > 0) { 14526657Snate@binkert.org rxState = rxFragWrite; 14536657Snate@binkert.org // don't need min<>(rxPktBytes,rxDescCnt) if above sanity 14546657Snate@binkert.org // check holds 14556657Snate@binkert.org rxXferLen = rxPktBytes; 14566657Snate@binkert.org 14576657Snate@binkert.org rxDmaAddr = rxFragPtr & 0x3fffffff; 14586657Snate@binkert.org rxDmaData = rxPacketBufPtr; 14597007Snate@binkert.org rxDmaLen = rxXferLen; 14606657Snate@binkert.org rxDmaFree = dmaDataFree; 14616657Snate@binkert.org 14626657Snate@binkert.org if (doRxDmaWrite()) 14636657Snate@binkert.org goto exit; 14646999Snate@binkert.org 14656657Snate@binkert.org } else { 14666657Snate@binkert.org rxState = rxDescWrite; 14676657Snate@binkert.org 14686657Snate@binkert.org //if (rxPktBytes == 0) { /* packet is done */ 14696657Snate@binkert.org assert(rxPktBytes == 0); 14706657Snate@binkert.org DPRINTF(EthernetSM, "done with receiving packet\n"); 14717832Snate@binkert.org 14727832Snate@binkert.org rxDescCache.cmdsts |= CMDSTS_OWN; 14736657Snate@binkert.org rxDescCache.cmdsts &= ~CMDSTS_MORE; 14746657Snate@binkert.org rxDescCache.cmdsts |= CMDSTS_OK; 14756657Snate@binkert.org rxDescCache.cmdsts &= 0xffff0000; 14766657Snate@binkert.org rxDescCache.cmdsts += rxPacket->length; //i.e. set CMDSTS_SIZE 14776657Snate@binkert.org 14786657Snate@binkert.org#if 0 14796657Snate@binkert.org /* 14806657Snate@binkert.org * all the driver uses these are for its own stats keeping 14816657Snate@binkert.org * which we don't care about, aren't necessary for 14826657Snate@binkert.org * functionality and doing this would just slow us down. 14836657Snate@binkert.org * if they end up using this in a later version for 14846657Snate@binkert.org * functional purposes, just undef 14856657Snate@binkert.org */ 14866657Snate@binkert.org if (rxFilterEnable) { 14877007Snate@binkert.org rxDescCache.cmdsts &= ~CMDSTS_DEST_MASK; 14887007Snate@binkert.org if (rxFifo.front()->IsUnicast()) 14897007Snate@binkert.org rxDescCache.cmdsts |= CMDSTS_DEST_SELF; 14906657Snate@binkert.org if (rxFifo.front()->IsMulticast()) 14916657Snate@binkert.org rxDescCache.cmdsts |= CMDSTS_DEST_MULTI; 14926657Snate@binkert.org if (rxFifo.front()->IsBroadcast()) 14937007Snate@binkert.org rxDescCache.cmdsts |= CMDSTS_DEST_MASK; 14947007Snate@binkert.org } 14957007Snate@binkert.org#endif 14966657Snate@binkert.org 14976657Snate@binkert.org if (rxPacket->isIpPkt() && extstsEnable) { 14986657Snate@binkert.org rxDescCache.extsts |= EXTSTS_IPPKT; 14996657Snate@binkert.org rxIPChecksums++; 15006657Snate@binkert.org if (!ipChecksum(rxPacket, false)) { 15016657Snate@binkert.org DPRINTF(EthernetCksum, "Rx IP Checksum Error\n"); 15026657Snate@binkert.org rxDescCache.extsts |= EXTSTS_IPERR; 15036657Snate@binkert.org } 15046657Snate@binkert.org if (rxPacket->isTcpPkt()) { 15056657Snate@binkert.org rxDescCache.extsts |= EXTSTS_TCPPKT; 15066657Snate@binkert.org rxTCPChecksums++; 15077007Snate@binkert.org if (!tcpChecksum(rxPacket, false)) { 15087007Snate@binkert.org DPRINTF(EthernetCksum, "Rx TCP Checksum Error\n"); 15096657Snate@binkert.org rxDescCache.extsts |= EXTSTS_TCPERR; 15106657Snate@binkert.org 15116657Snate@binkert.org } 15126657Snate@binkert.org } else if (rxPacket->isUdpPkt()) { 15136657Snate@binkert.org rxDescCache.extsts |= EXTSTS_UDPPKT; 15147007Snate@binkert.org if (!udpChecksum(rxPacket, false)) { 15157007Snate@binkert.org DPRINTF(EthernetCksum, "Rx UDP Checksum Error\n"); 15167007Snate@binkert.org rxDescCache.extsts |= EXTSTS_UDPERR; 15176657Snate@binkert.org } 15186657Snate@binkert.org } 15196657Snate@binkert.org } 15207007Snate@binkert.org rxPacket = 0; 15217542SBrad.Beckmann@amd.com 15227542SBrad.Beckmann@amd.com /* 15236657Snate@binkert.org * the driver seems to always receive into desc buffers 15247542SBrad.Beckmann@amd.com * of size 1514, so you never have a pkt that is split 15257542SBrad.Beckmann@amd.com * into multiple descriptors on the receive side, so 15267002Snate@binkert.org * i don't implement that case, hence the assert above. 15277542SBrad.Beckmann@amd.com */ 15287542SBrad.Beckmann@amd.com 15297542SBrad.Beckmann@amd.com DPRINTF(EthernetDesc, 15307542SBrad.Beckmann@amd.com "rxDesc writeback:\n\tcmdsts=%08x\n\textsts=%08x\n", 15316657Snate@binkert.org rxDescCache.cmdsts, rxDescCache.extsts); 15327542SBrad.Beckmann@amd.com 15337542SBrad.Beckmann@amd.com rxDmaAddr = (regs.rxdp + offsetof(ns_desc, cmdsts)) & 0x3fffffff; 15347542SBrad.Beckmann@amd.com rxDmaData = &(rxDescCache.cmdsts); 15357542SBrad.Beckmann@amd.com rxDmaLen = sizeof(rxDescCache.cmdsts) + sizeof(rxDescCache.extsts); 15367542SBrad.Beckmann@amd.com rxDmaFree = dmaDescFree; 15377542SBrad.Beckmann@amd.com 15387542SBrad.Beckmann@amd.com descDmaWrites++; 15397542SBrad.Beckmann@amd.com descDmaWrBytes += rxDmaLen; 15406657Snate@binkert.org 15416657Snate@binkert.org if (doRxDmaWrite()) 15426657Snate@binkert.org goto exit; 15436657Snate@binkert.org } 15446657Snate@binkert.org break; 15456657Snate@binkert.org 15467007Snate@binkert.org case rxFragWrite: 15476999Snate@binkert.org if (rxDmaState != dmaIdle) 15487007Snate@binkert.org goto exit; 15497007Snate@binkert.org 15507007Snate@binkert.org rxPacketBufPtr += rxXferLen; 15517007Snate@binkert.org rxFragPtr += rxXferLen; 15527007Snate@binkert.org rxPktBytes -= rxXferLen; 15537007Snate@binkert.org 15546657Snate@binkert.org rxState = rxFifoBlock; 15556657Snate@binkert.org break; 15566657Snate@binkert.org 15576657Snate@binkert.org case rxDescWrite: 15586657Snate@binkert.org if (rxDmaState != dmaIdle) 15596657Snate@binkert.org goto exit; 15606657Snate@binkert.org 15616657Snate@binkert.org assert(rxDescCache.cmdsts & CMDSTS_OWN); 15626657Snate@binkert.org 15636657Snate@binkert.org assert(rxPacket == 0); 15646657Snate@binkert.org devIntrPost(ISR_RXOK); 15656657Snate@binkert.org 15666657Snate@binkert.org if (rxDescCache.cmdsts & CMDSTS_INTR) 15676657Snate@binkert.org devIntrPost(ISR_RXDESC); 15686657Snate@binkert.org 15696657Snate@binkert.org if (rxHalt) { 15706657Snate@binkert.org DPRINTF(EthernetSM, "Halting the RX state machine\n"); 15716657Snate@binkert.org rxState = rxIdle; 15726657Snate@binkert.org rxHalt = false; 15736657Snate@binkert.org } else 15746657Snate@binkert.org rxState = rxAdvance; 15756657Snate@binkert.org break; 15766657Snate@binkert.org 15776657Snate@binkert.org case rxAdvance: 15786657Snate@binkert.org if (rxDescCache.link == 0) { 15796657Snate@binkert.org rxState = rxIdle; 15806657Snate@binkert.org return; 15816657Snate@binkert.org } else { 15826657Snate@binkert.org rxState = rxDescRead; 15836999Snate@binkert.org regs.rxdp = rxDescCache.link; 15846657Snate@binkert.org CRDD = false; 15856657Snate@binkert.org 15867007Snate@binkert.org rxDmaAddr = regs.rxdp & 0x3fffffff; 15877007Snate@binkert.org rxDmaData = &rxDescCache; 15886657Snate@binkert.org rxDmaLen = sizeof(ns_desc); 15896657Snate@binkert.org rxDmaFree = dmaDescFree; 15906657Snate@binkert.org 15916657Snate@binkert.org if (doRxDmaRead()) 15926657Snate@binkert.org goto exit; 15936657Snate@binkert.org } 15946657Snate@binkert.org break; 15956657Snate@binkert.org 15966657Snate@binkert.org default: 15976657Snate@binkert.org panic("Invalid rxState!"); 15986657Snate@binkert.org } 15996657Snate@binkert.org 16006657Snate@binkert.org 16016657Snate@binkert.org DPRINTF(EthernetSM, "entering next rx state = %s\n", 16026657Snate@binkert.org NsRxStateStrings[rxState]); 16036657Snate@binkert.org 16046657Snate@binkert.org if (rxState == rxIdle) { 16056657Snate@binkert.org regs.command &= ~CR_RXE; 16066657Snate@binkert.org devIntrPost(ISR_RXIDLE); 16076657Snate@binkert.org return; 16086657Snate@binkert.org } 16096657Snate@binkert.org 16106657Snate@binkert.org goto next; 16116657Snate@binkert.org 16126657Snate@binkert.org exit: 16136657Snate@binkert.org /** 16146657Snate@binkert.org * @todo do we want to schedule a future kick? 16156657Snate@binkert.org */ 16166657Snate@binkert.org DPRINTF(EthernetSM, "rx state machine exited state=%s\n", 16176657Snate@binkert.org NsRxStateStrings[rxState]); 16186657Snate@binkert.org} 16196657Snate@binkert.org 16206657Snate@binkert.orgvoid 16216657Snate@binkert.orgNSGigE::transmit() 16226657Snate@binkert.org{ 16236657Snate@binkert.org if (txFifo.empty()) { 16246657Snate@binkert.org DPRINTF(Ethernet, "nothing to transmit\n"); 16256657Snate@binkert.org return; 16266657Snate@binkert.org } 16276657Snate@binkert.org 16286657Snate@binkert.org DPRINTF(Ethernet, "\n\nAttempt Pkt Transmit: txFifo length = %d\n", 16296657Snate@binkert.org maxTxFifoSize - txFifoAvail); 16306657Snate@binkert.org if (interface->sendPacket(txFifo.front())) { 16316657Snate@binkert.org#if TRACING_ON 16326657Snate@binkert.org if (DTRACE(Ethernet)) { 16336657Snate@binkert.org if (txFifo.front()->isIpPkt()) { 16346657Snate@binkert.org ip_header *ip = txFifo.front()->getIpHdr(); 16356657Snate@binkert.org DPRINTF(Ethernet, "ID is %d\n", reverseEnd16(ip->ID)); 16366657Snate@binkert.org if (txFifo.front()->isTcpPkt()) { 16376657Snate@binkert.org tcp_header *tcp = txFifo.front()->getTcpHdr(ip); 16386657Snate@binkert.org DPRINTF(Ethernet, "Src Port = %d, Dest Port = %d\n", 16396657Snate@binkert.org reverseEnd16(tcp->src_port_num), 16406657Snate@binkert.org reverseEnd16(tcp->dest_port_num)); 16416657Snate@binkert.org } 16426657Snate@binkert.org } 16436657Snate@binkert.org } 16446657Snate@binkert.org#endif 16456657Snate@binkert.org 16466657Snate@binkert.org DDUMP(Ethernet, txFifo.front()->data, txFifo.front()->length); 16476657Snate@binkert.org txBytes += txFifo.front()->length; 16486657Snate@binkert.org txPackets++; 16496657Snate@binkert.org 16506657Snate@binkert.org txFifoAvail += txFifo.front()->length; 16516657Snate@binkert.org 16526657Snate@binkert.org DPRINTF(Ethernet, "Successful Xmit! now txFifoAvail is %d\n", 16536657Snate@binkert.org txFifoAvail); 16546657Snate@binkert.org txFifo.front() = NULL; 16556657Snate@binkert.org txFifo.pop_front(); 16566657Snate@binkert.org 16576657Snate@binkert.org /* 16586657Snate@binkert.org * normally do a writeback of the descriptor here, and ONLY 16596657Snate@binkert.org * after that is done, send this interrupt. but since our 16606657Snate@binkert.org * stuff never actually fails, just do this interrupt here, 16616657Snate@binkert.org * otherwise the code has to stray from this nice format. 16626657Snate@binkert.org * besides, it's functionally the same. 16636657Snate@binkert.org */ 16646657Snate@binkert.org devIntrPost(ISR_TXOK); 16656657Snate@binkert.org } else { 16666657Snate@binkert.org DPRINTF(Ethernet, 16676657Snate@binkert.org "May need to rethink always sending the descriptors back?\n"); 16686657Snate@binkert.org } 16696657Snate@binkert.org 16706657Snate@binkert.org if (!txFifo.empty() && !txEvent.scheduled()) { 16716657Snate@binkert.org DPRINTF(Ethernet, "reschedule transmit\n"); 16726657Snate@binkert.org txEvent.schedule(curTick + 1000); 16736657Snate@binkert.org } 16746657Snate@binkert.org} 16756657Snate@binkert.org 16767007Snate@binkert.orgvoid 16776657Snate@binkert.orgNSGigE::txDmaReadCopy() 16786657Snate@binkert.org{ 16796657Snate@binkert.org assert(txDmaState == dmaReading); 16806657Snate@binkert.org 16816657Snate@binkert.org memcpy(txDmaData, physmem->dma_addr(txDmaAddr, txDmaLen), txDmaLen); 16826657Snate@binkert.org txDmaState = dmaIdle; 16836657Snate@binkert.org 16847007Snate@binkert.org DPRINTF(EthernetDMA, "tx dma read paddr=%#x len=%d\n", 16856657Snate@binkert.org txDmaAddr, txDmaLen); 16866657Snate@binkert.org DDUMP(EthernetDMA, txDmaData, txDmaLen); 16876657Snate@binkert.org} 16886657Snate@binkert.org 16896657Snate@binkert.orgbool 16906657Snate@binkert.orgNSGigE::doTxDmaRead() 16916657Snate@binkert.org{ 16926657Snate@binkert.org assert(txDmaState == dmaIdle || txDmaState == dmaReadWaiting); 16936657Snate@binkert.org txDmaState = dmaReading; 16946657Snate@binkert.org 16956657Snate@binkert.org if (dmaInterface && !txDmaFree) { 16966657Snate@binkert.org if (dmaInterface->busy()) 16976657Snate@binkert.org txDmaState = dmaReadWaiting; 16986657Snate@binkert.org else 16996657Snate@binkert.org dmaInterface->doDMA(Read, txDmaAddr, txDmaLen, curTick, 17007007Snate@binkert.org &txDmaReadEvent, true); 17016657Snate@binkert.org return true; 17026657Snate@binkert.org } 17036657Snate@binkert.org 17046657Snate@binkert.org if (dmaReadDelay == 0 && dmaReadFactor == 0.0) { 17056657Snate@binkert.org txDmaReadCopy(); 17066657Snate@binkert.org return false; 17076657Snate@binkert.org } 17086657Snate@binkert.org 17096657Snate@binkert.org Tick factor = ((txDmaLen + ULL(63)) >> ULL(6)) * dmaReadFactor; 17106657Snate@binkert.org Tick start = curTick + dmaReadDelay + factor; 17116657Snate@binkert.org txDmaReadEvent.schedule(start); 17126657Snate@binkert.org return true; 17136657Snate@binkert.org} 17146657Snate@binkert.org 17156657Snate@binkert.orgvoid 17166657Snate@binkert.orgNSGigE::txDmaReadDone() 17176657Snate@binkert.org{ 17186657Snate@binkert.org assert(txDmaState == dmaReading); 17196657Snate@binkert.org txDmaReadCopy(); 17206657Snate@binkert.org 17216657Snate@binkert.org // If the receive state machine has a pending DMA, let it go first 17226657Snate@binkert.org if (rxDmaState == dmaReadWaiting || rxDmaState == dmaWriteWaiting) 1723 rxKick(); 1724 1725 txKick(); 1726} 1727 1728void 1729NSGigE::txDmaWriteCopy() 1730{ 1731 assert(txDmaState == dmaWriting); 1732 1733 memcpy(physmem->dma_addr(txDmaAddr, txDmaLen), txDmaData, txDmaLen); 1734 txDmaState = dmaIdle; 1735 1736 DPRINTF(EthernetDMA, "tx dma write paddr=%#x len=%d\n", 1737 txDmaAddr, txDmaLen); 1738 DDUMP(EthernetDMA, txDmaData, txDmaLen); 1739} 1740 1741bool 1742NSGigE::doTxDmaWrite() 1743{ 1744 assert(txDmaState == dmaIdle || txDmaState == dmaWriteWaiting); 1745 txDmaState = dmaWriting; 1746 1747 if (dmaInterface && !txDmaFree) { 1748 if (dmaInterface->busy()) 1749 txDmaState = dmaWriteWaiting; 1750 else 1751 dmaInterface->doDMA(WriteInvalidate, txDmaAddr, txDmaLen, curTick, 1752 &txDmaWriteEvent, true); 1753 return true; 1754 } 1755 1756 if (dmaWriteDelay == 0 && dmaWriteFactor == 0.0) { 1757 txDmaWriteCopy(); 1758 return false; 1759 } 1760 1761 Tick factor = ((txDmaLen + ULL(63)) >> ULL(6)) * dmaWriteFactor; 1762 Tick start = curTick + dmaWriteDelay + factor; 1763 txDmaWriteEvent.schedule(start); 1764 return true; 1765} 1766 1767void 1768NSGigE::txDmaWriteDone() 1769{ 1770 assert(txDmaState == dmaWriting); 1771 txDmaWriteCopy(); 1772 1773 // If the receive state machine has a pending DMA, let it go first 1774 if (rxDmaState == dmaReadWaiting || rxDmaState == dmaWriteWaiting) 1775 rxKick(); 1776 1777 txKick(); 1778} 1779 1780void 1781NSGigE::txKick() 1782{ 1783 DPRINTF(EthernetSM, "transmit kick state=%s\n", NsTxStateStrings[txState]); 1784 1785 if (txKickTick > curTick) { 1786 DPRINTF(EthernetSM, "transmit kick exiting, can't run till %d\n", 1787 txKickTick); 1788 1789 return; 1790 } 1791 1792 next: 1793 switch(txDmaState) { 1794 case dmaReadWaiting: 1795 if (doTxDmaRead()) 1796 goto exit; 1797 break; 1798 case dmaWriteWaiting: 1799 if (doTxDmaWrite()) 1800 goto exit; 1801 break; 1802 default: 1803 break; 1804 } 1805 1806 switch (txState) { 1807 case txIdle: 1808 if (!regs.command & CR_TXE) { 1809 DPRINTF(EthernetSM, "Transmit disabled. Nothing to do.\n"); 1810 goto exit; 1811 } 1812 1813 if (CTDD) { 1814 txState = txDescRefr; 1815 1816 txDmaAddr = regs.txdp & 0x3fffffff; 1817 txDmaData = &txDescCache + offsetof(ns_desc, link); 1818 txDmaLen = sizeof(txDescCache.link); 1819 txDmaFree = dmaDescFree; 1820 1821 descDmaReads++; 1822 descDmaRdBytes += txDmaLen; 1823 1824 if (doTxDmaRead()) 1825 goto exit; 1826 1827 } else { 1828 txState = txDescRead; 1829 1830 txDmaAddr = regs.txdp & 0x3fffffff; 1831 txDmaData = &txDescCache; 1832 txDmaLen = sizeof(ns_desc); 1833 txDmaFree = dmaDescFree; 1834 1835 descDmaReads++; 1836 descDmaRdBytes += txDmaLen; 1837 1838 if (doTxDmaRead()) 1839 goto exit; 1840 } 1841 break; 1842 1843 case txDescRefr: 1844 if (txDmaState != dmaIdle) 1845 goto exit; 1846 1847 txState = txAdvance; 1848 break; 1849 1850 case txDescRead: 1851 if (txDmaState != dmaIdle) 1852 goto exit; 1853 1854 DPRINTF(EthernetDesc, 1855 "txDescCache data:\n" 1856 "\tlink=%08x\n" 1857 "\tbufptr=%08x\n" 1858 "\tcmdsts=%08x\n" 1859 "\textsts=%08x\n", 1860 txDescCache.link, txDescCache.bufptr, txDescCache.cmdsts, 1861 txDescCache.extsts); 1862 1863 if (txDescCache.cmdsts & CMDSTS_OWN) { 1864 txState = txFifoBlock; 1865 txFragPtr = txDescCache.bufptr; 1866 txDescCnt = txDescCache.cmdsts & CMDSTS_LEN_MASK; 1867 } else { 1868 txState = txIdle; 1869 } 1870 break; 1871 1872 case txFifoBlock: 1873 if (!txPacket) { 1874 DPRINTF(EthernetSM, "\n\n*****starting the tx of a new packet\n"); 1875 txPacket = new EtherPacket; 1876 txPacket->data = new uint8_t[16384]; 1877 txPacketBufPtr = txPacket->data; 1878 } 1879 1880 if (txDescCnt == 0) { 1881 DPRINTF(EthernetSM, "the txDescCnt == 0, done with descriptor\n"); 1882 if (txDescCache.cmdsts & CMDSTS_MORE) { 1883 DPRINTF(EthernetSM, "there are more descriptors to come\n"); 1884 txState = txDescWrite; 1885 1886 txDescCache.cmdsts &= ~CMDSTS_OWN; 1887 1888 txDmaAddr = regs.txdp + offsetof(ns_desc, cmdsts); 1889 txDmaAddr &= 0x3fffffff; 1890 txDmaData = &(txDescCache.cmdsts); 1891 txDmaLen = sizeof(txDescCache.cmdsts); 1892 txDmaFree = dmaDescFree; 1893 1894 if (doTxDmaWrite()) 1895 goto exit; 1896 1897 } else { /* this packet is totally done */ 1898 DPRINTF(EthernetSM, "This packet is done, let's wrap it up\n"); 1899 /* deal with the the packet that just finished */ 1900 if ((regs.vtcr & VTCR_PPCHK) && extstsEnable) { 1901 if (txDescCache.extsts & EXTSTS_UDPPKT) { 1902 udpChecksum(txPacket, true); 1903 } else if (txDescCache.extsts & EXTSTS_TCPPKT) { 1904 tcpChecksum(txPacket, true); 1905 txTCPChecksums++; 1906 } 1907 if (txDescCache.extsts & EXTSTS_IPPKT) { 1908 ipChecksum(txPacket, true); 1909 txIPChecksums++; 1910 } 1911 } 1912 1913 txPacket->length = txPacketBufPtr - txPacket->data; 1914 // this is just because the receive can't handle a 1915 // packet bigger want to make sure 1916 assert(txPacket->length <= 1514); 1917 txFifo.push_back(txPacket); 1918 1919 /* 1920 * this following section is not tqo spec, but 1921 * functionally shouldn't be any different. normally, 1922 * the chip will wait til the transmit has occurred 1923 * before writing back the descriptor because it has 1924 * to wait to see that it was successfully transmitted 1925 * to decide whether to set CMDSTS_OK or not. 1926 * however, in the simulator since it is always 1927 * successfully transmitted, and writing it exactly to 1928 * spec would complicate the code, we just do it here 1929 */ 1930 1931 txDescCache.cmdsts &= ~CMDSTS_OWN; 1932 txDescCache.cmdsts |= CMDSTS_OK; 1933 1934 DPRINTF(EthernetDesc, 1935 "txDesc writeback:\n\tcmdsts=%08x\n\textsts=%08x\n", 1936 txDescCache.cmdsts, txDescCache.extsts); 1937 1938 txDmaAddr = regs.txdp + offsetof(ns_desc, cmdsts); 1939 txDmaAddr &= 0x3fffffff; 1940 txDmaData = &(txDescCache.cmdsts); 1941 txDmaLen = sizeof(txDescCache.cmdsts) + 1942 sizeof(txDescCache.extsts); 1943 txDmaFree = dmaDescFree; 1944 1945 descDmaWrites++; 1946 descDmaWrBytes += txDmaLen; 1947 1948 transmit(); 1949 txPacket = 0; 1950 1951 if (txHalt) { 1952 DPRINTF(EthernetSM, "halting TX state machine\n"); 1953 txState = txIdle; 1954 txHalt = false; 1955 } else 1956 txState = txAdvance; 1957 1958 if (doTxDmaWrite()) 1959 goto exit; 1960 } 1961 } else { 1962 DPRINTF(EthernetSM, "this descriptor isn't done yet\n"); 1963 if (txFifoAvail) { 1964 txState = txFragRead; 1965 1966 /* 1967 * The number of bytes transferred is either whatever 1968 * is left in the descriptor (txDescCnt), or if there 1969 * is not enough room in the fifo, just whatever room 1970 * is left in the fifo 1971 */ 1972 txXferLen = min<uint32_t>(txDescCnt, txFifoAvail); 1973 1974 txDmaAddr = txFragPtr & 0x3fffffff; 1975 txDmaData = txPacketBufPtr; 1976 txDmaLen = txXferLen; 1977 txDmaFree = dmaDataFree; 1978 1979 if (doTxDmaRead()) 1980 goto exit; 1981 } else { 1982 txState = txFifoBlock; 1983 transmit(); 1984 1985 goto exit; 1986 } 1987 1988 } 1989 break; 1990 1991 case txFragRead: 1992 if (txDmaState != dmaIdle) 1993 goto exit; 1994 1995 txPacketBufPtr += txXferLen; 1996 txFragPtr += txXferLen; 1997 txDescCnt -= txXferLen; 1998 txFifoAvail -= txXferLen; 1999 2000 txState = txFifoBlock; 2001 break; 2002 2003 case txDescWrite: 2004 if (txDmaState != dmaIdle) 2005 goto exit; 2006 2007 if (txDescCache.cmdsts & CMDSTS_INTR) { 2008 devIntrPost(ISR_TXDESC); 2009 } 2010 2011 txState = txAdvance; 2012 break; 2013 2014 case txAdvance: 2015 if (txDescCache.link == 0) { 2016 txState = txIdle; 2017 } else { 2018 txState = txDescRead; 2019 regs.txdp = txDescCache.link; 2020 CTDD = false; 2021 2022 txDmaAddr = txDescCache.link & 0x3fffffff; 2023 txDmaData = &txDescCache; 2024 txDmaLen = sizeof(ns_desc); 2025 txDmaFree = dmaDescFree; 2026 2027 if (doTxDmaRead()) 2028 goto exit; 2029 } 2030 break; 2031 2032 default: 2033 panic("invalid state"); 2034 } 2035 2036 DPRINTF(EthernetSM, "entering next tx state=%s\n", 2037 NsTxStateStrings[txState]); 2038 2039 if (txState == txIdle) { 2040 regs.command &= ~CR_TXE; 2041 devIntrPost(ISR_TXIDLE); 2042 return; 2043 } 2044 2045 goto next; 2046 2047 exit: 2048 /** 2049 * @todo do we want to schedule a future kick? 2050 */ 2051 DPRINTF(EthernetSM, "tx state machine exited state=%s\n", 2052 NsTxStateStrings[txState]); 2053} 2054 2055void 2056NSGigE::transferDone() 2057{ 2058 if (txFifo.empty()) 2059 return; 2060 2061 if (txEvent.scheduled()) 2062 txEvent.reschedule(curTick + 1); 2063 else 2064 txEvent.schedule(curTick + 1); 2065} 2066 2067bool 2068NSGigE::rxFilter(PacketPtr packet) 2069{ 2070 bool drop = true; 2071 string type; 2072 2073 if (packet->IsUnicast()) { 2074 type = "unicast"; 2075 2076 // If we're accepting all unicast addresses 2077 if (acceptUnicast) 2078 drop = false; 2079 2080 // If we make a perfect match 2081 if (acceptPerfect && 2082 memcmp(rom.perfectMatch, packet->data, EADDR_LEN) == 0) 2083 drop = false; 2084 2085 eth_header *eth = (eth_header *) packet->data; 2086 if ((acceptArp) && (eth->type == 0x608)) 2087 drop = false; 2088 2089 } else if (packet->IsBroadcast()) { 2090 type = "broadcast"; 2091 2092 // if we're accepting broadcasts 2093 if (acceptBroadcast) 2094 drop = false; 2095 2096 } else if (packet->IsMulticast()) { 2097 type = "multicast"; 2098 2099 // if we're accepting all multicasts 2100 if (acceptMulticast) 2101 drop = false; 2102 2103 } else { 2104 type = "unknown"; 2105 2106 // oh well, punt on this one 2107 } 2108 2109 if (drop) { 2110 DPRINTF(Ethernet, "rxFilter drop\n"); 2111 DDUMP(EthernetData, packet->data, packet->length); 2112 } 2113 2114 return drop; 2115} 2116 2117bool 2118NSGigE::recvPacket(PacketPtr packet) 2119{ 2120 rxBytes += packet->length; 2121 rxPackets++; 2122 2123 DPRINTF(Ethernet, "\n\nReceiving packet from wire, rxFifoAvail=%d\n", 2124 maxRxFifoSize - rxFifoCnt); 2125 2126 if (rxState == rxIdle) { 2127 DPRINTF(Ethernet, "receive disabled...packet dropped\n"); 2128 interface->recvDone(); 2129 return true; 2130 } 2131 2132 if (rxFilterEnable && rxFilter(packet)) { 2133 DPRINTF(Ethernet, "packet filtered...dropped\n"); 2134 interface->recvDone(); 2135 return true; 2136 } 2137 2138 if ((rxFifoCnt + packet->length) >= maxRxFifoSize) { 2139 DPRINTF(Ethernet, 2140 "packet will not fit in receive buffer...packet dropped\n"); 2141 devIntrPost(ISR_RXORN); 2142 return false; 2143 } 2144 2145 rxFifo.push_back(packet); 2146 rxFifoCnt += packet->length; 2147 interface->recvDone(); 2148 2149 rxKick(); 2150 return true; 2151} 2152 2153/** 2154 * does a udp checksum. if gen is true, then it generates it and puts 2155 * it in the right place else, it just checks what it calculates 2156 * against the value in the header in packet 2157 */ 2158bool 2159NSGigE::udpChecksum(PacketPtr packet, bool gen) 2160{ 2161 ip_header *ip = packet->getIpHdr(); 2162 udp_header *hdr = packet->getUdpHdr(ip); 2163 2164 pseudo_header *pseudo = new pseudo_header; 2165 2166 pseudo->src_ip_addr = ip->src_ip_addr; 2167 pseudo->dest_ip_addr = ip->dest_ip_addr; 2168 pseudo->protocol = ip->protocol; 2169 pseudo->len = hdr->len; 2170 2171 uint16_t cksum = checksumCalc((uint16_t *) pseudo, (uint16_t *) hdr, 2172 (uint32_t) hdr->len); 2173 2174 delete pseudo; 2175 if (gen) 2176 hdr->chksum = cksum; 2177 else 2178 if (cksum != 0) 2179 return false; 2180 2181 return true; 2182} 2183 2184bool 2185NSGigE::tcpChecksum(PacketPtr packet, bool gen) 2186{ 2187 ip_header *ip = packet->getIpHdr(); 2188 tcp_header *hdr = packet->getTcpHdr(ip); 2189 2190 uint16_t cksum; 2191 pseudo_header *pseudo = new pseudo_header; 2192 if (!gen) { 2193 pseudo->src_ip_addr = ip->src_ip_addr; 2194 pseudo->dest_ip_addr = ip->dest_ip_addr; 2195 pseudo->protocol = reverseEnd16(ip->protocol); 2196 pseudo->len = reverseEnd16(reverseEnd16(ip->dgram_len) - 2197 (ip->vers_len & 0xf)*4); 2198 2199 cksum = checksumCalc((uint16_t *) pseudo, (uint16_t *) hdr, 2200 (uint32_t) reverseEnd16(pseudo->len)); 2201 } else { 2202 pseudo->src_ip_addr = 0; 2203 pseudo->dest_ip_addr = 0; 2204 pseudo->protocol = hdr->chksum; 2205 pseudo->len = 0; 2206 hdr->chksum = 0; 2207 cksum = checksumCalc((uint16_t *) pseudo, (uint16_t *) hdr, 2208 (uint32_t) (reverseEnd16(ip->dgram_len) - 2209 (ip->vers_len & 0xf)*4)); 2210 } 2211 2212 delete pseudo; 2213 if (gen) 2214 hdr->chksum = cksum; 2215 else 2216 if (cksum != 0) 2217 return false; 2218 2219 return true; 2220} 2221 2222bool 2223NSGigE::ipChecksum(PacketPtr packet, bool gen) 2224{ 2225 ip_header *hdr = packet->getIpHdr(); 2226 2227 uint16_t cksum = checksumCalc(NULL, (uint16_t *) hdr, 2228 (hdr->vers_len & 0xf)*4); 2229 2230 if (gen) { 2231 DPRINTF(EthernetCksum, "generated checksum: %#x\n", cksum); 2232 hdr->hdr_chksum = cksum; 2233 } 2234 else 2235 if (cksum != 0) 2236 return false; 2237 2238 return true; 2239} 2240 2241uint16_t 2242NSGigE::checksumCalc(uint16_t *pseudo, uint16_t *buf, uint32_t len) 2243{ 2244 uint32_t sum = 0; 2245 2246 uint16_t last_pad = 0; 2247 if (len & 1) { 2248 last_pad = buf[len/2] & 0xff; 2249 len--; 2250 sum += last_pad; 2251 } 2252 2253 if (pseudo) { 2254 sum = pseudo[0] + pseudo[1] + pseudo[2] + 2255 pseudo[3] + pseudo[4] + pseudo[5]; 2256 } 2257 2258 for (int i=0; i < (len/2); ++i) { 2259 sum += buf[i]; 2260 } 2261 2262 while (sum >> 16) 2263 sum = (sum >> 16) + (sum & 0xffff); 2264 2265 return ~sum; 2266} 2267 2268//===================================================================== 2269// 2270// 2271void 2272NSGigE::serialize(ostream &os) 2273{ 2274 // Serialize the PciDev base class 2275 PciDev::serialize(os); 2276 2277 /* 2278 * Finalize any DMA events now. 2279 */ 2280 if (rxDmaReadEvent.scheduled()) 2281 rxDmaReadCopy(); 2282 if (rxDmaWriteEvent.scheduled()) 2283 rxDmaWriteCopy(); 2284 if (txDmaReadEvent.scheduled()) 2285 txDmaReadCopy(); 2286 if (txDmaWriteEvent.scheduled()) 2287 txDmaWriteCopy(); 2288 2289 /* 2290 * Serialize the device registers 2291 */ 2292 SERIALIZE_SCALAR(regs.command); 2293 SERIALIZE_SCALAR(regs.config); 2294 SERIALIZE_SCALAR(regs.mear); 2295 SERIALIZE_SCALAR(regs.ptscr); 2296 SERIALIZE_SCALAR(regs.isr); 2297 SERIALIZE_SCALAR(regs.imr); 2298 SERIALIZE_SCALAR(regs.ier); 2299 SERIALIZE_SCALAR(regs.ihr); 2300 SERIALIZE_SCALAR(regs.txdp); 2301 SERIALIZE_SCALAR(regs.txdp_hi); 2302 SERIALIZE_SCALAR(regs.txcfg); 2303 SERIALIZE_SCALAR(regs.gpior); 2304 SERIALIZE_SCALAR(regs.rxdp); 2305 SERIALIZE_SCALAR(regs.rxdp_hi); 2306 SERIALIZE_SCALAR(regs.rxcfg); 2307 SERIALIZE_SCALAR(regs.pqcr); 2308 SERIALIZE_SCALAR(regs.wcsr); 2309 SERIALIZE_SCALAR(regs.pcr); 2310 SERIALIZE_SCALAR(regs.rfcr); 2311 SERIALIZE_SCALAR(regs.rfdr); 2312 SERIALIZE_SCALAR(regs.srr); 2313 SERIALIZE_SCALAR(regs.mibc); 2314 SERIALIZE_SCALAR(regs.vrcr); 2315 SERIALIZE_SCALAR(regs.vtcr); 2316 SERIALIZE_SCALAR(regs.vdr); 2317 SERIALIZE_SCALAR(regs.ccsr); 2318 SERIALIZE_SCALAR(regs.tbicr); 2319 SERIALIZE_SCALAR(regs.tbisr); 2320 SERIALIZE_SCALAR(regs.tanar); 2321 SERIALIZE_SCALAR(regs.tanlpar); 2322 SERIALIZE_SCALAR(regs.taner); 2323 SERIALIZE_SCALAR(regs.tesr); 2324 2325 SERIALIZE_ARRAY(rom.perfectMatch, EADDR_LEN); 2326 2327 SERIALIZE_SCALAR(ioEnable); 2328 2329 /* 2330 * Serialize the data Fifos 2331 */ 2332 int txNumPkts = txFifo.size(); 2333 SERIALIZE_SCALAR(txNumPkts); 2334 int i = 0; 2335 pktiter_t end = txFifo.end(); 2336 for (pktiter_t p = txFifo.begin(); p != end; ++p) { 2337 nameOut(os, csprintf("%s.txFifo%d", name(), i++)); 2338 (*p)->serialize(os); 2339 } 2340 2341 int rxNumPkts = rxFifo.size(); 2342 SERIALIZE_SCALAR(rxNumPkts); 2343 i = 0; 2344 end = rxFifo.end(); 2345 for (pktiter_t p = rxFifo.begin(); p != end; ++p) { 2346 nameOut(os, csprintf("%s.rxFifo%d", name(), i++)); 2347 (*p)->serialize(os); 2348 } 2349 2350 /* 2351 * Serialize the various helper variables 2352 */ 2353 bool txPacketExists = txPacket; 2354 SERIALIZE_SCALAR(txPacketExists); 2355 if (txPacketExists) { 2356 nameOut(os, csprintf("%s.txPacket", name())); 2357 txPacket->serialize(os); 2358 uint32_t txPktBufPtr = (uint32_t) (txPacketBufPtr - txPacket->data); 2359 SERIALIZE_SCALAR(txPktBufPtr); 2360 } 2361 2362 bool rxPacketExists = rxPacket; 2363 SERIALIZE_SCALAR(rxPacketExists); 2364 if (rxPacketExists) { 2365 nameOut(os, csprintf("%s.rxPacket", name())); 2366 rxPacket->serialize(os); 2367 uint32_t rxPktBufPtr = (uint32_t) (rxPacketBufPtr - rxPacket->data); 2368 SERIALIZE_SCALAR(rxPktBufPtr); 2369 } 2370 2371 SERIALIZE_SCALAR(txXferLen); 2372 SERIALIZE_SCALAR(rxXferLen); 2373 2374 /* 2375 * Serialize DescCaches 2376 */ 2377 SERIALIZE_SCALAR(txDescCache.link); 2378 SERIALIZE_SCALAR(txDescCache.bufptr); 2379 SERIALIZE_SCALAR(txDescCache.cmdsts); 2380 SERIALIZE_SCALAR(txDescCache.extsts); 2381 SERIALIZE_SCALAR(rxDescCache.link); 2382 SERIALIZE_SCALAR(rxDescCache.bufptr); 2383 SERIALIZE_SCALAR(rxDescCache.cmdsts); 2384 SERIALIZE_SCALAR(rxDescCache.extsts); 2385 2386 /* 2387 * Serialize tx state machine 2388 */ 2389 int txState = this->txState; 2390 SERIALIZE_SCALAR(txState); 2391 SERIALIZE_SCALAR(CTDD); 2392 SERIALIZE_SCALAR(txFifoAvail); 2393 SERIALIZE_SCALAR(txHalt); 2394 SERIALIZE_SCALAR(txFragPtr); 2395 SERIALIZE_SCALAR(txDescCnt); 2396 int txDmaState = this->txDmaState; 2397 SERIALIZE_SCALAR(txDmaState); 2398 2399 /* 2400 * Serialize rx state machine 2401 */ 2402 int rxState = this->rxState; 2403 SERIALIZE_SCALAR(rxState); 2404 SERIALIZE_SCALAR(CRDD); 2405 SERIALIZE_SCALAR(rxPktBytes); 2406 SERIALIZE_SCALAR(rxFifoCnt); 2407 SERIALIZE_SCALAR(rxHalt); 2408 SERIALIZE_SCALAR(rxDescCnt); 2409 int rxDmaState = this->rxDmaState; 2410 SERIALIZE_SCALAR(rxDmaState); 2411 2412 SERIALIZE_SCALAR(extstsEnable); 2413 2414 /* 2415 * If there's a pending transmit, store the time so we can 2416 * reschedule it later 2417 */ 2418 Tick transmitTick = txEvent.scheduled() ? txEvent.when() - curTick : 0; 2419 SERIALIZE_SCALAR(transmitTick); 2420 2421 /* 2422 * receive address filter settings 2423 */ 2424 SERIALIZE_SCALAR(rxFilterEnable); 2425 SERIALIZE_SCALAR(acceptBroadcast); 2426 SERIALIZE_SCALAR(acceptMulticast); 2427 SERIALIZE_SCALAR(acceptUnicast); 2428 SERIALIZE_SCALAR(acceptPerfect); 2429 SERIALIZE_SCALAR(acceptArp); 2430 2431 /* 2432 * Keep track of pending interrupt status. 2433 */ 2434 SERIALIZE_SCALAR(intrTick); 2435 SERIALIZE_SCALAR(cpuPendingIntr); 2436 Tick intrEventTick = 0; 2437 if (intrEvent) 2438 intrEventTick = intrEvent->when(); 2439 SERIALIZE_SCALAR(intrEventTick); 2440 2441} 2442 2443void 2444NSGigE::unserialize(Checkpoint *cp, const std::string §ion) 2445{ 2446 // Unserialize the PciDev base class 2447 PciDev::unserialize(cp, section); 2448 2449 UNSERIALIZE_SCALAR(regs.command); 2450 UNSERIALIZE_SCALAR(regs.config); 2451 UNSERIALIZE_SCALAR(regs.mear); 2452 UNSERIALIZE_SCALAR(regs.ptscr); 2453 UNSERIALIZE_SCALAR(regs.isr); 2454 UNSERIALIZE_SCALAR(regs.imr); 2455 UNSERIALIZE_SCALAR(regs.ier); 2456 UNSERIALIZE_SCALAR(regs.ihr); 2457 UNSERIALIZE_SCALAR(regs.txdp); 2458 UNSERIALIZE_SCALAR(regs.txdp_hi); 2459 UNSERIALIZE_SCALAR(regs.txcfg); 2460 UNSERIALIZE_SCALAR(regs.gpior); 2461 UNSERIALIZE_SCALAR(regs.rxdp); 2462 UNSERIALIZE_SCALAR(regs.rxdp_hi); 2463 UNSERIALIZE_SCALAR(regs.rxcfg); 2464 UNSERIALIZE_SCALAR(regs.pqcr); 2465 UNSERIALIZE_SCALAR(regs.wcsr); 2466 UNSERIALIZE_SCALAR(regs.pcr); 2467 UNSERIALIZE_SCALAR(regs.rfcr); 2468 UNSERIALIZE_SCALAR(regs.rfdr); 2469 UNSERIALIZE_SCALAR(regs.srr); 2470 UNSERIALIZE_SCALAR(regs.mibc); 2471 UNSERIALIZE_SCALAR(regs.vrcr); 2472 UNSERIALIZE_SCALAR(regs.vtcr); 2473 UNSERIALIZE_SCALAR(regs.vdr); 2474 UNSERIALIZE_SCALAR(regs.ccsr); 2475 UNSERIALIZE_SCALAR(regs.tbicr); 2476 UNSERIALIZE_SCALAR(regs.tbisr); 2477 UNSERIALIZE_SCALAR(regs.tanar); 2478 UNSERIALIZE_SCALAR(regs.tanlpar); 2479 UNSERIALIZE_SCALAR(regs.taner); 2480 UNSERIALIZE_SCALAR(regs.tesr); 2481 2482 UNSERIALIZE_ARRAY(rom.perfectMatch, EADDR_LEN); 2483 2484 UNSERIALIZE_SCALAR(ioEnable); 2485 2486 /* 2487 * unserialize the data fifos 2488 */ 2489 int txNumPkts; 2490 UNSERIALIZE_SCALAR(txNumPkts); 2491 int i; 2492 for (i = 0; i < txNumPkts; ++i) { 2493 PacketPtr p = new EtherPacket; 2494 p->unserialize(cp, csprintf("%s.rxFifo%d", section, i)); 2495 txFifo.push_back(p); 2496 } 2497 2498 int rxNumPkts; 2499 UNSERIALIZE_SCALAR(rxNumPkts); 2500 for (i = 0; i < rxNumPkts; ++i) { 2501 PacketPtr p = new EtherPacket; 2502 p->unserialize(cp, csprintf("%s.rxFifo%d", section, i)); 2503 rxFifo.push_back(p); 2504 } 2505 2506 /* 2507 * unserialize the various helper variables 2508 */ 2509 bool txPacketExists; 2510 UNSERIALIZE_SCALAR(txPacketExists); 2511 if (txPacketExists) { 2512 txPacket = new EtherPacket; 2513 txPacket->unserialize(cp, csprintf("%s.txPacket", section)); 2514 uint32_t txPktBufPtr; 2515 UNSERIALIZE_SCALAR(txPktBufPtr); 2516 txPacketBufPtr = (uint8_t *) txPacket->data + txPktBufPtr; 2517 } else 2518 txPacket = 0; 2519 2520 bool rxPacketExists; 2521 UNSERIALIZE_SCALAR(rxPacketExists); 2522 rxPacket = 0; 2523 if (rxPacketExists) { 2524 rxPacket = new EtherPacket; 2525 rxPacket->unserialize(cp, csprintf("%s.rxPacket", section)); 2526 uint32_t rxPktBufPtr; 2527 UNSERIALIZE_SCALAR(rxPktBufPtr); 2528 rxPacketBufPtr = (uint8_t *) rxPacket->data + rxPktBufPtr; 2529 } else 2530 rxPacket = 0; 2531 2532 UNSERIALIZE_SCALAR(txXferLen); 2533 UNSERIALIZE_SCALAR(rxXferLen); 2534 2535 /* 2536 * Unserialize DescCaches 2537 */ 2538 UNSERIALIZE_SCALAR(txDescCache.link); 2539 UNSERIALIZE_SCALAR(txDescCache.bufptr); 2540 UNSERIALIZE_SCALAR(txDescCache.cmdsts); 2541 UNSERIALIZE_SCALAR(txDescCache.extsts); 2542 UNSERIALIZE_SCALAR(rxDescCache.link); 2543 UNSERIALIZE_SCALAR(rxDescCache.bufptr); 2544 UNSERIALIZE_SCALAR(rxDescCache.cmdsts); 2545 UNSERIALIZE_SCALAR(rxDescCache.extsts); 2546 2547 /* 2548 * unserialize tx state machine 2549 */ 2550 int txState; 2551 UNSERIALIZE_SCALAR(txState); 2552 this->txState = (TxState) txState; 2553 UNSERIALIZE_SCALAR(CTDD); 2554 UNSERIALIZE_SCALAR(txFifoAvail); 2555 UNSERIALIZE_SCALAR(txHalt); 2556 UNSERIALIZE_SCALAR(txFragPtr); 2557 UNSERIALIZE_SCALAR(txDescCnt); 2558 int txDmaState; 2559 UNSERIALIZE_SCALAR(txDmaState); 2560 this->txDmaState = (DmaState) txDmaState; 2561 2562 /* 2563 * unserialize rx state machine 2564 */ 2565 int rxState; 2566 UNSERIALIZE_SCALAR(rxState); 2567 this->rxState = (RxState) rxState; 2568 UNSERIALIZE_SCALAR(CRDD); 2569 UNSERIALIZE_SCALAR(rxPktBytes); 2570 UNSERIALIZE_SCALAR(rxFifoCnt); 2571 UNSERIALIZE_SCALAR(rxHalt); 2572 UNSERIALIZE_SCALAR(rxDescCnt); 2573 int rxDmaState; 2574 UNSERIALIZE_SCALAR(rxDmaState); 2575 this->rxDmaState = (DmaState) rxDmaState; 2576 2577 UNSERIALIZE_SCALAR(extstsEnable); 2578 2579 /* 2580 * If there's a pending transmit, reschedule it now 2581 */ 2582 Tick transmitTick; 2583 UNSERIALIZE_SCALAR(transmitTick); 2584 if (transmitTick) 2585 txEvent.schedule(curTick + transmitTick); 2586 2587 /* 2588 * unserialize receive address filter settings 2589 */ 2590 UNSERIALIZE_SCALAR(rxFilterEnable); 2591 UNSERIALIZE_SCALAR(acceptBroadcast); 2592 UNSERIALIZE_SCALAR(acceptMulticast); 2593 UNSERIALIZE_SCALAR(acceptUnicast); 2594 UNSERIALIZE_SCALAR(acceptPerfect); 2595 UNSERIALIZE_SCALAR(acceptArp); 2596 2597 /* 2598 * Keep track of pending interrupt status. 2599 */ 2600 UNSERIALIZE_SCALAR(intrTick); 2601 UNSERIALIZE_SCALAR(cpuPendingIntr); 2602 Tick intrEventTick; 2603 UNSERIALIZE_SCALAR(intrEventTick); 2604 if (intrEventTick) { 2605 intrEvent = new IntrEvent(this, true); 2606 intrEvent->schedule(intrEventTick); 2607 } 2608 2609 /* 2610 * re-add addrRanges to bus bridges 2611 */ 2612 if (pioInterface) { 2613 pioInterface->addAddrRange(BARAddrs[0], BARAddrs[0] + BARSize[0] - 1); 2614 pioInterface->addAddrRange(BARAddrs[1], BARAddrs[1] + BARSize[1] - 1); 2615 } 2616} 2617 2618Tick 2619NSGigE::cacheAccess(MemReqPtr &req) 2620{ 2621 DPRINTF(EthernetPIO, "timing access to paddr=%#x (daddr=%#x)\n", 2622 req->paddr, req->paddr - addr); 2623 return curTick + pioLatency; 2624} 2625//===================================================================== 2626 2627 2628//********** helper functions****************************************** 2629 2630uint16_t reverseEnd16(uint16_t num) 2631{ 2632 uint16_t reverse = (num & 0xff)<<8; 2633 reverse += ((num & 0xff00) >> 8); 2634 return reverse; 2635} 2636 2637uint32_t reverseEnd32(uint32_t num) 2638{ 2639 uint32_t reverse = (reverseEnd16(num & 0xffff)) << 16; 2640 reverse += reverseEnd16((uint16_t) ((num & 0xffff0000) >> 8)); 2641 return reverse; 2642} 2643 2644 2645 2646//===================================================================== 2647 2648BEGIN_DECLARE_SIM_OBJECT_PARAMS(NSGigEInt) 2649 2650 SimObjectParam<EtherInt *> peer; 2651 SimObjectParam<NSGigE *> device; 2652 2653END_DECLARE_SIM_OBJECT_PARAMS(NSGigEInt) 2654 2655BEGIN_INIT_SIM_OBJECT_PARAMS(NSGigEInt) 2656 2657 INIT_PARAM_DFLT(peer, "peer interface", NULL), 2658 INIT_PARAM(device, "Ethernet device of this interface") 2659 2660END_INIT_SIM_OBJECT_PARAMS(NSGigEInt) 2661 2662CREATE_SIM_OBJECT(NSGigEInt) 2663{ 2664 NSGigEInt *dev_int = new NSGigEInt(getInstanceName(), device); 2665 2666 EtherInt *p = (EtherInt *)peer; 2667 if (p) { 2668 dev_int->setPeer(p); 2669 p->setPeer(dev_int); 2670 } 2671 2672 return dev_int; 2673} 2674 2675REGISTER_SIM_OBJECT("NSGigEInt", NSGigEInt) 2676 2677 2678BEGIN_DECLARE_SIM_OBJECT_PARAMS(NSGigE) 2679 2680 Param<Tick> tx_delay; 2681 Param<Tick> rx_delay; 2682 SimObjectParam<IntrControl *> intr_ctrl; 2683 Param<Tick> intr_delay; 2684 SimObjectParam<MemoryController *> mmu; 2685 SimObjectParam<PhysicalMemory *> physmem; 2686 Param<bool> rx_filter; 2687 Param<string> hardware_address; 2688 SimObjectParam<Bus*> header_bus; 2689 SimObjectParam<Bus*> payload_bus; 2690 SimObjectParam<HierParams *> hier; 2691 Param<Tick> pio_latency; 2692 Param<bool> dma_desc_free; 2693 Param<bool> dma_data_free; 2694 Param<Tick> dma_read_delay; 2695 Param<Tick> dma_write_delay; 2696 Param<Tick> dma_read_factor; 2697 Param<Tick> dma_write_factor; 2698 SimObjectParam<PciConfigAll *> configspace; 2699 SimObjectParam<PciConfigData *> configdata; 2700 SimObjectParam<Tsunami *> tsunami; 2701 Param<uint32_t> pci_bus; 2702 Param<uint32_t> pci_dev; 2703 Param<uint32_t> pci_func; 2704 Param<uint32_t> tx_fifo_size; 2705 Param<uint32_t> rx_fifo_size; 2706 2707END_DECLARE_SIM_OBJECT_PARAMS(NSGigE) 2708 2709BEGIN_INIT_SIM_OBJECT_PARAMS(NSGigE) 2710 2711 INIT_PARAM_DFLT(tx_delay, "Transmit Delay", 1000), 2712 INIT_PARAM_DFLT(rx_delay, "Receive Delay", 1000), 2713 INIT_PARAM(intr_ctrl, "Interrupt Controller"), 2714 INIT_PARAM_DFLT(intr_delay, "Interrupt Delay in microseconds", 0), 2715 INIT_PARAM(mmu, "Memory Controller"), 2716 INIT_PARAM(physmem, "Physical Memory"), 2717 INIT_PARAM_DFLT(rx_filter, "Enable Receive Filter", true), 2718 INIT_PARAM_DFLT(hardware_address, "Ethernet Hardware Address", 2719 "00:99:00:00:00:01"), 2720 INIT_PARAM_DFLT(header_bus, "The IO Bus to attach to for headers", NULL), 2721 INIT_PARAM_DFLT(payload_bus, "The IO Bus to attach to for payload", NULL), 2722 INIT_PARAM_DFLT(hier, "Hierarchy global variables", &defaultHierParams), 2723 INIT_PARAM_DFLT(pio_latency, "Programmed IO latency in bus cycles", 1), 2724 INIT_PARAM_DFLT(dma_desc_free, "DMA of Descriptors is free", false), 2725 INIT_PARAM_DFLT(dma_data_free, "DMA of Data is free", false), 2726 INIT_PARAM_DFLT(dma_read_delay, "fixed delay for dma reads", 0), 2727 INIT_PARAM_DFLT(dma_write_delay, "fixed delay for dma writes", 0), 2728 INIT_PARAM_DFLT(dma_read_factor, "multiplier for dma reads", 0), 2729 INIT_PARAM_DFLT(dma_write_factor, "multiplier for dma writes", 0), 2730 INIT_PARAM(configspace, "PCI Configspace"), 2731 INIT_PARAM(configdata, "PCI Config data"), 2732 INIT_PARAM(tsunami, "Tsunami"), 2733 INIT_PARAM(pci_bus, "PCI bus"), 2734 INIT_PARAM(pci_dev, "PCI device number"), 2735 INIT_PARAM(pci_func, "PCI function code"), 2736 INIT_PARAM_DFLT(tx_fifo_size, "max size in bytes of txFifo", 131072), 2737 INIT_PARAM_DFLT(rx_fifo_size, "max size in bytes of rxFifo", 131072) 2738 2739END_INIT_SIM_OBJECT_PARAMS(NSGigE) 2740 2741 2742CREATE_SIM_OBJECT(NSGigE) 2743{ 2744 int eaddr[6]; 2745 sscanf(((string)hardware_address).c_str(), "%x:%x:%x:%x:%x:%x", 2746 &eaddr[0], &eaddr[1], &eaddr[2], &eaddr[3], &eaddr[4], &eaddr[5]); 2747 2748 return new NSGigE(getInstanceName(), intr_ctrl, intr_delay, 2749 physmem, tx_delay, rx_delay, mmu, hier, header_bus, 2750 payload_bus, pio_latency, dma_desc_free, dma_data_free, 2751 dma_read_delay, dma_write_delay, dma_read_factor, 2752 dma_write_factor, configspace, configdata, 2753 tsunami, pci_bus, pci_dev, pci_func, rx_filter, eaddr, 2754 tx_fifo_size, rx_fifo_size); 2755} 2756 2757REGISTER_SIM_OBJECT("NSGigE", NSGigE) 2758