ns_gige.cc revision 1730
16657Snate@binkert.org/* 26657Snate@binkert.org * Copyright (c) 2004 The Regents of The University of Michigan 310972Sdavid.hashe@amd.com * 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 */ 286657Snate@binkert.org 296999Snate@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 */ 336657Snate@binkert.org#include <cstdio> 348189SLisa.Hsu@amd.com#include <deque> 356657Snate@binkert.org#include <string> 369499Snilay@cs.wisc.edu 379499Snilay@cs.wisc.edu#include "base/inet.hh" 3811308Santhony.gutierrez@amd.com#include "cpu/exec_context.hh" 399364Snilay@cs.wisc.edu#include "dev/dma.hh" 407055Snate@binkert.org#include "dev/etherlink.hh" 416882SBrad.Beckmann@amd.com#include "dev/ns_gige.hh" 426882SBrad.Beckmann@amd.com#include "dev/pciconfigall.hh" 438191SLisa.Hsu@amd.com#include "mem/bus/bus.hh" 446882SBrad.Beckmann@amd.com#include "mem/bus/dma_interface.hh" 4511308Santhony.gutierrez@amd.com#include "mem/bus/pio_interface.hh" 4611308Santhony.gutierrez@amd.com#include "mem/bus/pio_interface_impl.hh" 476882SBrad.Beckmann@amd.com#include "mem/functional_mem/memory_control.hh" 4811308Santhony.gutierrez@amd.com#include "mem/functional_mem/physical_memory.hh" 499102SNuwan.Jayasena@amd.com#include "sim/builder.hh" 5011084Snilay@cs.wisc.edu#include "sim/debug.hh" 519366Snilay@cs.wisc.edu#include "sim/host.hh" 529499Snilay@cs.wisc.edu#include "sim/stats.hh" 539499Snilay@cs.wisc.edu#include "targetarch/vtophys.hh" 549499Snilay@cs.wisc.edu 556882SBrad.Beckmann@amd.comconst char *NsRxStateStrings[] = 566657Snate@binkert.org{ 576657Snate@binkert.org "rxIdle", 586657Snate@binkert.org "rxDescRefr", 596657Snate@binkert.org "rxDescRead", 6010311Snilay@cs.wisc.edu "rxFifoBlock", 6110311Snilay@cs.wisc.edu "rxFragWrite", 6210311Snilay@cs.wisc.edu "rxDescWrite", 6310311Snilay@cs.wisc.edu "rxAdvance" 646657Snate@binkert.org}; 6510311Snilay@cs.wisc.edu 669366Snilay@cs.wisc.educonst char *NsTxStateStrings[] = 677839Snilay@cs.wisc.edu{ 686657Snate@binkert.org "txIdle", 696882SBrad.Beckmann@amd.com "txDescRefr", 7010308Snilay@cs.wisc.edu "txDescRead", 7110308Snilay@cs.wisc.edu "txFifoBlock", 726882SBrad.Beckmann@amd.com "txFragRead", 7310308Snilay@cs.wisc.edu "txDescWrite", 7410308Snilay@cs.wisc.edu "txAdvance" 7510308Snilay@cs.wisc.edu}; 7610308Snilay@cs.wisc.edu 7710308Snilay@cs.wisc.educonst char *NsDmaState[] = 789366Snilay@cs.wisc.edu{ 799366Snilay@cs.wisc.edu "dmaIdle", 806657Snate@binkert.org "dmaReading", 816657Snate@binkert.org "dmaWriting", 826657Snate@binkert.org "dmaReadWaiting", 836657Snate@binkert.org "dmaWriteWaiting" 849104Shestness@cs.utexas.edu}; 856657Snate@binkert.org 866657Snate@binkert.orgusing namespace std; 876657Snate@binkert.orgusing namespace Net; 8810311Snilay@cs.wisc.edu 8910311Snilay@cs.wisc.edu/////////////////////////////////////////////////////////////////////// 9010311Snilay@cs.wisc.edu// 9110311Snilay@cs.wisc.edu// NSGigE PCI Device 926657Snate@binkert.org// 937839Snilay@cs.wisc.eduNSGigE::NSGigE(Params *p) 947839Snilay@cs.wisc.edu : PciDev(p), ioEnable(false), 9510972Sdavid.hashe@amd.com txFifo(p->tx_fifo_size), rxFifo(p->rx_fifo_size), 9610972Sdavid.hashe@amd.com txPacket(0), rxPacket(0), txPacketBufPtr(NULL), rxPacketBufPtr(NULL), 9710972Sdavid.hashe@amd.com txXferLen(0), rxXferLen(0), clock(p->clock), 986657Snate@binkert.org txState(txIdle), txEnable(false), CTDD(false), 996657Snate@binkert.org txFragPtr(0), txDescCnt(0), txDmaState(dmaIdle), rxState(rxIdle), 1006657Snate@binkert.org rxEnable(false), CRDD(false), rxPktBytes(0), 1016657Snate@binkert.org rxFragPtr(0), rxDescCnt(0), rxDmaState(dmaIdle), extstsEnable(false), 1026657Snate@binkert.org rxDmaReadEvent(this), rxDmaWriteEvent(this), 1036657Snate@binkert.org txDmaReadEvent(this), txDmaWriteEvent(this), 1046657Snate@binkert.org dmaDescFree(p->dma_desc_free), dmaDataFree(p->dma_data_free), 1056657Snate@binkert.org txDelay(p->tx_delay), rxDelay(p->rx_delay), 1066657Snate@binkert.org rxKickTick(0), txKickTick(0), 1076657Snate@binkert.org txEvent(this), rxFilterEnable(p->rx_filter), acceptBroadcast(false), 1086657Snate@binkert.org acceptMulticast(false), acceptUnicast(false), 1096657Snate@binkert.org acceptPerfect(false), acceptArp(false), 1106657Snate@binkert.org physmem(p->pmem), intrTick(0), cpuPendingIntr(false), 1116657Snate@binkert.org intrEvent(0), interface(0) 1126657Snate@binkert.org{ 1136657Snate@binkert.org if (p->header_bus) { 1146657Snate@binkert.org pioInterface = newPioInterface(name(), p->hier, 1156657Snate@binkert.org p->header_bus, this, 1166779SBrad.Beckmann@amd.com &NSGigE::cacheAccess); 1176657Snate@binkert.org 1186657Snate@binkert.org pioLatency = p->pio_latency * p->header_bus->clockRate; 1196657Snate@binkert.org 1206657Snate@binkert.org if (p->payload_bus) 1216657Snate@binkert.org dmaInterface = new DMAInterface<Bus>(name() + ".dma", 1226657Snate@binkert.org p->header_bus, 1236657Snate@binkert.org p->payload_bus, 1, 1246657Snate@binkert.org p->dma_no_allocate); 1256657Snate@binkert.org else 12610972Sdavid.hashe@amd.com dmaInterface = new DMAInterface<Bus>(name() + ".dma", 12710972Sdavid.hashe@amd.com p->header_bus, 12810972Sdavid.hashe@amd.com p->header_bus, 1, 1299104Shestness@cs.utexas.edu p->dma_no_allocate); 1309104Shestness@cs.utexas.edu } else if (p->payload_bus) { 1319104Shestness@cs.utexas.edu pioInterface = newPioInterface(name(), p->hier, 1329104Shestness@cs.utexas.edu p->payload_bus, this, 1336657Snate@binkert.org &NSGigE::cacheAccess); 1346657Snate@binkert.org 1356657Snate@binkert.org pioLatency = p->pio_latency * p->payload_bus->clockRate; 1366657Snate@binkert.org 1376657Snate@binkert.org dmaInterface = new DMAInterface<Bus>(name() + ".dma", 1386657Snate@binkert.org p->payload_bus, 1396657Snate@binkert.org p->payload_bus, 1, 1406657Snate@binkert.org p->dma_no_allocate); 1416657Snate@binkert.org } 1426657Snate@binkert.org 1436657Snate@binkert.org 1446657Snate@binkert.org intrDelay = p->intr_delay; 1456657Snate@binkert.org dmaReadDelay = p->dma_read_delay; 14610307Snilay@cs.wisc.edu dmaWriteDelay = p->dma_write_delay; 1476657Snate@binkert.org dmaReadFactor = p->dma_read_factor; 1486657Snate@binkert.org dmaWriteFactor = p->dma_write_factor; 1497839Snilay@cs.wisc.edu 1507839Snilay@cs.wisc.edu regsReset(); 1517839Snilay@cs.wisc.edu memcpy(&rom.perfectMatch, p->eaddr.bytes(), ETH_ADDR_LEN); 1527839Snilay@cs.wisc.edu} 1537839Snilay@cs.wisc.edu 1547839Snilay@cs.wisc.eduNSGigE::~NSGigE() 1557839Snilay@cs.wisc.edu{} 1567839Snilay@cs.wisc.edu 1577839Snilay@cs.wisc.eduvoid 1587839Snilay@cs.wisc.eduNSGigE::regStats() 15910968Sdavid.hashe@amd.com{ 16010968Sdavid.hashe@amd.com txBytes 16110968Sdavid.hashe@amd.com .name(name() + ".txBytes") 16210968Sdavid.hashe@amd.com .desc("Bytes Transmitted") 16310968Sdavid.hashe@amd.com .prereq(txBytes) 16410968Sdavid.hashe@amd.com ; 16510968Sdavid.hashe@amd.com 1667839Snilay@cs.wisc.edu rxBytes 1676657Snate@binkert.org .name(name() + ".rxBytes") 1686657Snate@binkert.org .desc("Bytes Received") 1696657Snate@binkert.org .prereq(rxBytes) 1706657Snate@binkert.org ; 1716657Snate@binkert.org 1726657Snate@binkert.org txPackets 1736657Snate@binkert.org .name(name() + ".txPackets") 1746657Snate@binkert.org .desc("Number of Packets Transmitted") 1756657Snate@binkert.org .prereq(txBytes) 1766657Snate@binkert.org ; 1776657Snate@binkert.org 1786657Snate@binkert.org rxPackets 1796657Snate@binkert.org .name(name() + ".rxPackets") 1806657Snate@binkert.org .desc("Number of Packets Received") 1816657Snate@binkert.org .prereq(rxBytes) 1826657Snate@binkert.org ; 1836657Snate@binkert.org 1846657Snate@binkert.org txIpChecksums 1856657Snate@binkert.org .name(name() + ".txIpChecksums") 1866657Snate@binkert.org .desc("Number of tx IP Checksums done by device") 1876657Snate@binkert.org .precision(0) 1886657Snate@binkert.org .prereq(txBytes) 1896657Snate@binkert.org ; 1906657Snate@binkert.org 1916657Snate@binkert.org rxIpChecksums 1926657Snate@binkert.org .name(name() + ".rxIpChecksums") 1936657Snate@binkert.org .desc("Number of rx IP Checksums done by device") 1946657Snate@binkert.org .precision(0) 1956657Snate@binkert.org .prereq(rxBytes) 1966657Snate@binkert.org ; 19710963Sdavid.hashe@amd.com 19810963Sdavid.hashe@amd.com txTcpChecksums 19910963Sdavid.hashe@amd.com .name(name() + ".txTcpChecksums") 20010963Sdavid.hashe@amd.com .desc("Number of tx TCP Checksums done by device") 20110963Sdavid.hashe@amd.com .precision(0) 20210963Sdavid.hashe@amd.com .prereq(txBytes) 20311095Snilay@cs.wisc.edu ; 20410963Sdavid.hashe@amd.com 20510963Sdavid.hashe@amd.com rxTcpChecksums 20610963Sdavid.hashe@amd.com .name(name() + ".rxTcpChecksums") 20710963Sdavid.hashe@amd.com .desc("Number of rx TCP Checksums done by device") 20810963Sdavid.hashe@amd.com .precision(0) 20910963Sdavid.hashe@amd.com .prereq(rxBytes) 21010963Sdavid.hashe@amd.com ; 21110963Sdavid.hashe@amd.com 2129219Spower.jg@gmail.com txUdpChecksums 2136877Ssteve.reinhardt@amd.com .name(name() + ".txUdpChecksums") 2146657Snate@binkert.org .desc("Number of tx UDP Checksums done by device") 2159219Spower.jg@gmail.com .precision(0) 2166657Snate@binkert.org .prereq(txBytes) 2179219Spower.jg@gmail.com ; 2186657Snate@binkert.org 2196877Ssteve.reinhardt@amd.com rxUdpChecksums 2206999Snate@binkert.org .name(name() + ".rxUdpChecksums") 2216877Ssteve.reinhardt@amd.com .desc("Number of rx UDP Checksums done by device") 22210308Snilay@cs.wisc.edu .precision(0) 2236877Ssteve.reinhardt@amd.com .prereq(rxBytes) 2246877Ssteve.reinhardt@amd.com ; 22510308Snilay@cs.wisc.edu 2266877Ssteve.reinhardt@amd.com descDmaReads 2276877Ssteve.reinhardt@amd.com .name(name() + ".descDMAReads") 2286877Ssteve.reinhardt@amd.com .desc("Number of descriptors the device read w/ DMA") 2296877Ssteve.reinhardt@amd.com .precision(0) 2306877Ssteve.reinhardt@amd.com ; 2316877Ssteve.reinhardt@amd.com 2326877Ssteve.reinhardt@amd.com descDmaWrites 2339338SAndreas.Sandberg@arm.com .name(name() + ".descDMAWrites") 2346877Ssteve.reinhardt@amd.com .desc("Number of descriptors the device wrote w/ DMA") 2356877Ssteve.reinhardt@amd.com .precision(0) 2366877Ssteve.reinhardt@amd.com ; 2376877Ssteve.reinhardt@amd.com 23810308Snilay@cs.wisc.edu descDmaRdBytes 23910308Snilay@cs.wisc.edu .name(name() + ".descDmaReadBytes") 24010308Snilay@cs.wisc.edu .desc("number of descriptor bytes read w/ DMA") 24110308Snilay@cs.wisc.edu .precision(0) 24211084Snilay@cs.wisc.edu ; 2436882SBrad.Beckmann@amd.com 24410308Snilay@cs.wisc.edu descDmaWrBytes 24510308Snilay@cs.wisc.edu .name(name() + ".descDmaWriteBytes") 2466882SBrad.Beckmann@amd.com .desc("number of descriptor bytes write w/ DMA") 2476882SBrad.Beckmann@amd.com .precision(0) 2486882SBrad.Beckmann@amd.com ; 2496882SBrad.Beckmann@amd.com 25011021Sjthestness@gmail.com txBandwidth 2516877Ssteve.reinhardt@amd.com .name(name() + ".txBandwidth") 2526877Ssteve.reinhardt@amd.com .desc("Transmit Bandwidth (bits/s)") 25310917Sbrandon.potter@amd.com .precision(0) 2546877Ssteve.reinhardt@amd.com .prereq(txBytes) 2556657Snate@binkert.org ; 2566657Snate@binkert.org 2576999Snate@binkert.org rxBandwidth 2586657Snate@binkert.org .name(name() + ".rxBandwidth") 2596657Snate@binkert.org .desc("Receive Bandwidth (bits/s)") 2606657Snate@binkert.org .precision(0) 2616657Snate@binkert.org .prereq(rxBytes) 2627007Snate@binkert.org ; 2636657Snate@binkert.org 2646657Snate@binkert.org totBandwidth 2656657Snate@binkert.org .name(name() + ".totBandwidth") 2666657Snate@binkert.org .desc("Total Bandwidth (bits/s)") 2676657Snate@binkert.org .precision(0) 2687007Snate@binkert.org .prereq(totBytes) 2697007Snate@binkert.org ; 2706657Snate@binkert.org 2717002Snate@binkert.org totPackets 2727002Snate@binkert.org .name(name() + ".totPackets") 2737002Snate@binkert.org .desc("Total Packets") 2747002Snate@binkert.org .precision(0) 2756657Snate@binkert.org .prereq(totBytes) 2766657Snate@binkert.org ; 2778229Snate@binkert.org 2788229Snate@binkert.org totBytes 2798229Snate@binkert.org .name(name() + ".totBytes") 28010972Sdavid.hashe@amd.com .desc("Total Bytes") 2816657Snate@binkert.org .precision(0) 2826657Snate@binkert.org .prereq(totBytes) 2836657Snate@binkert.org ; 2846657Snate@binkert.org 2856793SBrad.Beckmann@amd.com totPacketRate 2866657Snate@binkert.org .name(name() + ".totPPS") 28710311Snilay@cs.wisc.edu .desc("Total Tranmission Rate (packets/s)") 2886657Snate@binkert.org .precision(0) 2896657Snate@binkert.org .prereq(totBytes) 2906657Snate@binkert.org ; 2917002Snate@binkert.org 2926657Snate@binkert.org txPacketRate 2937007Snate@binkert.org .name(name() + ".txPPS") 2947007Snate@binkert.org .desc("Packet Tranmission Rate (packets/s)") 2959271Snilay@cs.wisc.edu .precision(0) 2966877Ssteve.reinhardt@amd.com .prereq(txBytes) 2976877Ssteve.reinhardt@amd.com ; 2986657Snate@binkert.org 2996877Ssteve.reinhardt@amd.com rxPacketRate 30010311Snilay@cs.wisc.edu .name(name() + ".rxPPS") 30111084Snilay@cs.wisc.edu .desc("Packet Reception Rate (packets/s)") 30211084Snilay@cs.wisc.edu .precision(0) 30311021Sjthestness@gmail.com .prereq(rxBytes) 3049745Snilay@cs.wisc.edu ; 3057002Snate@binkert.org 3066657Snate@binkert.org postedSwi 30710012Snilay@cs.wisc.edu .name(name() + ".postedSwi") 3089745Snilay@cs.wisc.edu .desc("number of software interrupts posted to CPU") 3099745Snilay@cs.wisc.edu .precision(0) 3109745Snilay@cs.wisc.edu ; 3118683Snilay@cs.wisc.edu 31211308Santhony.gutierrez@amd.com totalSwi 31311309Sdavid.hashe@amd.com .name(name() + ".totalSwi") 3147007Snate@binkert.org .desc("number of total Swi written to ISR") 31510524Snilay@cs.wisc.edu .precision(0) 3169302Snilay@cs.wisc.edu ; 3179745Snilay@cs.wisc.edu 3189745Snilay@cs.wisc.edu coalescedSwi 31911061Snilay@cs.wisc.edu .name(name() + ".coalescedSwi") 3209745Snilay@cs.wisc.edu .desc("average number of Swi's coalesced into each post") 32111061Snilay@cs.wisc.edu .precision(0) 3229745Snilay@cs.wisc.edu ; 3236657Snate@binkert.org 3246657Snate@binkert.org postedRxIdle 3256657Snate@binkert.org .name(name() + ".postedRxIdle") 3266657Snate@binkert.org .desc("number of rxIdle interrupts posted to CPU") 3276657Snate@binkert.org .precision(0) 3286657Snate@binkert.org ; 3296882SBrad.Beckmann@amd.com 3306882SBrad.Beckmann@amd.com totalRxIdle 3316882SBrad.Beckmann@amd.com .name(name() + ".totalRxIdle") 3326882SBrad.Beckmann@amd.com .desc("number of total RxIdle written to ISR") 3336657Snate@binkert.org .precision(0) 3346657Snate@binkert.org ; 3357007Snate@binkert.org 3367839Snilay@cs.wisc.edu coalescedRxIdle 3377839Snilay@cs.wisc.edu .name(name() + ".coalescedRxIdle") 3387839Snilay@cs.wisc.edu .desc("average number of RxIdle's coalesced into each post") 3397839Snilay@cs.wisc.edu .precision(0) 3407839Snilay@cs.wisc.edu ; 3417839Snilay@cs.wisc.edu 3427839Snilay@cs.wisc.edu postedRxOk 3437839Snilay@cs.wisc.edu .name(name() + ".postedRxOk") 3447839Snilay@cs.wisc.edu .desc("number of RxOk interrupts posted to CPU") 3457839Snilay@cs.wisc.edu .precision(0) 3467839Snilay@cs.wisc.edu ; 3477839Snilay@cs.wisc.edu 34811025Snilay@cs.wisc.edu totalRxOk 3497007Snate@binkert.org .name(name() + ".totalRxOk") 3507007Snate@binkert.org .desc("number of total RxOk written to ISR") 3517007Snate@binkert.org .precision(0) 3527007Snate@binkert.org ; 3537839Snilay@cs.wisc.edu 3547839Snilay@cs.wisc.edu coalescedRxOk 3557839Snilay@cs.wisc.edu .name(name() + ".coalescedRxOk") 3567839Snilay@cs.wisc.edu .desc("average number of RxOk's coalesced into each post") 3577839Snilay@cs.wisc.edu .precision(0) 3587839Snilay@cs.wisc.edu ; 3597839Snilay@cs.wisc.edu 3607839Snilay@cs.wisc.edu postedRxDesc 3617839Snilay@cs.wisc.edu .name(name() + ".postedRxDesc") 3627839Snilay@cs.wisc.edu .desc("number of RxDesc interrupts posted to CPU") 3637839Snilay@cs.wisc.edu .precision(0) 3647839Snilay@cs.wisc.edu ; 36511025Snilay@cs.wisc.edu 3667007Snate@binkert.org totalRxDesc 3679745Snilay@cs.wisc.edu .name(name() + ".totalRxDesc") 3689745Snilay@cs.wisc.edu .desc("number of total RxDesc written to ISR") 3699745Snilay@cs.wisc.edu .precision(0) 3709745Snilay@cs.wisc.edu ; 3719745Snilay@cs.wisc.edu 3729745Snilay@cs.wisc.edu coalescedRxDesc 3736657Snate@binkert.org .name(name() + ".coalescedRxDesc") 3747007Snate@binkert.org .desc("average number of RxDesc's coalesced into each post") 3756657Snate@binkert.org .precision(0) 3766657Snate@binkert.org ; 3776657Snate@binkert.org 3786657Snate@binkert.org postedTxOk 3796657Snate@binkert.org .name(name() + ".postedTxOk") 3806657Snate@binkert.org .desc("number of TxOk interrupts posted to CPU") 3816657Snate@binkert.org .precision(0) 3826657Snate@binkert.org ; 3837839Snilay@cs.wisc.edu 3847839Snilay@cs.wisc.edu totalTxOk 3857839Snilay@cs.wisc.edu .name(name() + ".totalTxOk") 3867839Snilay@cs.wisc.edu .desc("number of total TxOk written to ISR") 3877839Snilay@cs.wisc.edu .precision(0) 3887839Snilay@cs.wisc.edu ; 3897839Snilay@cs.wisc.edu 3907839Snilay@cs.wisc.edu coalescedTxOk 3917839Snilay@cs.wisc.edu .name(name() + ".coalescedTxOk") 3927839Snilay@cs.wisc.edu .desc("average number of TxOk's coalesced into each post") 3937839Snilay@cs.wisc.edu .precision(0) 3947839Snilay@cs.wisc.edu ; 3957839Snilay@cs.wisc.edu 3967839Snilay@cs.wisc.edu postedTxIdle 3977839Snilay@cs.wisc.edu .name(name() + ".postedTxIdle") 3987839Snilay@cs.wisc.edu .desc("number of TxIdle interrupts posted to CPU") 39910121Snilay@cs.wisc.edu .precision(0) 4006657Snate@binkert.org ; 4016657Snate@binkert.org 4026657Snate@binkert.org totalTxIdle 4036657Snate@binkert.org .name(name() + ".totalTxIdle") 4047839Snilay@cs.wisc.edu .desc("number of total TxIdle written to ISR") 4057839Snilay@cs.wisc.edu .precision(0) 4067839Snilay@cs.wisc.edu ; 40710121Snilay@cs.wisc.edu 40810121Snilay@cs.wisc.edu coalescedTxIdle 40911025Snilay@cs.wisc.edu .name(name() + ".coalescedTxIdle") 4107839Snilay@cs.wisc.edu .desc("average number of TxIdle's coalesced into each post") 4117839Snilay@cs.wisc.edu .precision(0) 4127839Snilay@cs.wisc.edu ; 41310121Snilay@cs.wisc.edu 41411025Snilay@cs.wisc.edu postedTxDesc 4157839Snilay@cs.wisc.edu .name(name() + ".postedTxDesc") 4167839Snilay@cs.wisc.edu .desc("number of TxDesc interrupts posted to CPU") 4177839Snilay@cs.wisc.edu .precision(0) 41810121Snilay@cs.wisc.edu ; 41911025Snilay@cs.wisc.edu 4207839Snilay@cs.wisc.edu totalTxDesc 4217839Snilay@cs.wisc.edu .name(name() + ".totalTxDesc") 4227839Snilay@cs.wisc.edu .desc("number of total TxDesc written to ISR") 42311025Snilay@cs.wisc.edu .precision(0) 4246657Snate@binkert.org ; 4256657Snate@binkert.org 4266657Snate@binkert.org coalescedTxDesc 4276657Snate@binkert.org .name(name() + ".coalescedTxDesc") 4287007Snate@binkert.org .desc("average number of TxDesc's coalesced into each post") 4296657Snate@binkert.org .precision(0) 4306657Snate@binkert.org ; 4319273Snilay@cs.wisc.edu 43210305Snilay@cs.wisc.edu postedRxOrn 4336657Snate@binkert.org .name(name() + ".postedRxOrn") 4346657Snate@binkert.org .desc("number of RxOrn posted to CPU") 4356657Snate@binkert.org .precision(0) 4367007Snate@binkert.org ; 4376657Snate@binkert.org 4386657Snate@binkert.org totalRxOrn 4399219Spower.jg@gmail.com .name(name() + ".totalRxOrn") 4406657Snate@binkert.org .desc("number of total RxOrn written to ISR") 4416657Snate@binkert.org .precision(0) 4426999Snate@binkert.org ; 4436657Snate@binkert.org 4446657Snate@binkert.org coalescedRxOrn 4456657Snate@binkert.org .name(name() + ".coalescedRxOrn") 4466657Snate@binkert.org .desc("average number of RxOrn's coalesced into each post") 4477007Snate@binkert.org .precision(0) 4486657Snate@binkert.org ; 4496657Snate@binkert.org 4506657Snate@binkert.org coalescedTotal 4516657Snate@binkert.org .name(name() + ".coalescedTotal") 4526657Snate@binkert.org .desc("average number of interrupts coalesced into each post") 4538946Sandreas.hansson@arm.com .precision(0) 4548946Sandreas.hansson@arm.com ; 4558946Sandreas.hansson@arm.com 4567832Snate@binkert.org postedInterrupts 4577002Snate@binkert.org .name(name() + ".postedInterrupts") 4587002Snate@binkert.org .desc("number of posts to CPU") 45910972Sdavid.hashe@amd.com .precision(0) 4607002Snate@binkert.org ; 4618641Snate@binkert.org 46211704Santhony.gutierrez@amd.com droppedPackets 4637056Snate@binkert.org .name(name() + ".droppedPackets") 46410972Sdavid.hashe@amd.com .desc("number of packets dropped") 46510972Sdavid.hashe@amd.com .precision(0) 46610972Sdavid.hashe@amd.com ; 46710972Sdavid.hashe@amd.com 46810972Sdavid.hashe@amd.com coalescedSwi = totalSwi / postedInterrupts; 4696657Snate@binkert.org coalescedRxIdle = totalRxIdle / postedInterrupts; 4708229Snate@binkert.org coalescedRxOk = totalRxOk / postedInterrupts; 4716657Snate@binkert.org coalescedRxDesc = totalRxDesc / postedInterrupts; 4726657Snate@binkert.org coalescedTxOk = totalTxOk / postedInterrupts; 47311793Sbrandon.potter@amd.com coalescedTxIdle = totalTxIdle / postedInterrupts; 47411108Sdavid.hashe@amd.com coalescedTxDesc = totalTxDesc / postedInterrupts; 47510972Sdavid.hashe@amd.com coalescedRxOrn = totalRxOrn / postedInterrupts; 4769219Spower.jg@gmail.com 4779219Spower.jg@gmail.com coalescedTotal = (totalSwi + totalRxIdle + totalRxOk + totalRxDesc + totalTxOk 4789219Spower.jg@gmail.com + totalTxIdle + totalTxDesc + totalRxOrn) / postedInterrupts; 4799219Spower.jg@gmail.com 4809219Spower.jg@gmail.com txBandwidth = txBytes * Stats::constant(8) / simSeconds; 4817002Snate@binkert.org rxBandwidth = rxBytes * Stats::constant(8) / simSeconds; 4827002Snate@binkert.org totBandwidth = txBandwidth + rxBandwidth; 4836657Snate@binkert.org totBytes = txBytes + rxBytes; 4846657Snate@binkert.org totPackets = txPackets + rxPackets; 4856657Snate@binkert.org 4866657Snate@binkert.org txPacketRate = txPackets / simSeconds; 4876657Snate@binkert.org rxPacketRate = rxPackets / simSeconds; 4886793SBrad.Beckmann@amd.com} 4896657Snate@binkert.org 4906657Snate@binkert.org/** 4916657Snate@binkert.org * This is to read the PCI general configuration registers 49210121Snilay@cs.wisc.edu */ 49310121Snilay@cs.wisc.eduvoid 4946657Snate@binkert.orgNSGigE::ReadConfig(int offset, int size, uint8_t *data) 4956877Ssteve.reinhardt@amd.com{ 4966877Ssteve.reinhardt@amd.com if (offset < PCI_DEVICE_SPECIFIC) 4976877Ssteve.reinhardt@amd.com PciDev::ReadConfig(offset, size, data); 4986877Ssteve.reinhardt@amd.com else 4996877Ssteve.reinhardt@amd.com panic("Device specific PCI config space not implemented!\n"); 5006877Ssteve.reinhardt@amd.com} 5016657Snate@binkert.org 5029745Snilay@cs.wisc.edu/** 5039745Snilay@cs.wisc.edu * This is to write to the PCI general configuration registers 5046657Snate@binkert.org */ 5057007Snate@binkert.orgvoid 5066657Snate@binkert.orgNSGigE::WriteConfig(int offset, int size, uint32_t data) 5079801Snilay@cs.wisc.edu{ 5089801Snilay@cs.wisc.edu if (offset < PCI_DEVICE_SPECIFIC) 5096657Snate@binkert.org PciDev::WriteConfig(offset, size, data); 5109801Snilay@cs.wisc.edu else 5119801Snilay@cs.wisc.edu panic("Device specific PCI config space not implemented!\n"); 5129801Snilay@cs.wisc.edu 5137007Snate@binkert.org // Need to catch writes to BARs to update the PIO interface 5146657Snate@binkert.org switch (offset) { 5156877Ssteve.reinhardt@amd.com // seems to work fine without all these PCI settings, but i 5166877Ssteve.reinhardt@amd.com // put in the IO to double check, an assertion will fail if we 5176657Snate@binkert.org // need to properly implement it 51810078Snilay@cs.wisc.edu case PCI_COMMAND: 51910078Snilay@cs.wisc.edu if (config.data[offset] & PCI_CMD_IOSE) 52010121Snilay@cs.wisc.edu ioEnable = true; 52110121Snilay@cs.wisc.edu else 52210121Snilay@cs.wisc.edu ioEnable = false; 5236657Snate@binkert.org 5246657Snate@binkert.org#if 0 5256882SBrad.Beckmann@amd.com if (config.data[offset] & PCI_CMD_BME) { 5266882SBrad.Beckmann@amd.com bmEnabled = true; 5276882SBrad.Beckmann@amd.com } 52810121Snilay@cs.wisc.edu else { 52910121Snilay@cs.wisc.edu bmEnabled = false; 5306882SBrad.Beckmann@amd.com } 5316877Ssteve.reinhardt@amd.com 5326882SBrad.Beckmann@amd.com if (config.data[offset] & PCI_CMD_MSE) { 53310308Snilay@cs.wisc.edu memEnable = true; 5346882SBrad.Beckmann@amd.com } 53510308Snilay@cs.wisc.edu else { 53610311Snilay@cs.wisc.edu memEnable = false; 53711308Santhony.gutierrez@amd.com } 53811308Santhony.gutierrez@amd.com#endif 53911308Santhony.gutierrez@amd.com break; 54011308Santhony.gutierrez@amd.com 54111308Santhony.gutierrez@amd.com case PCI0_BASE_ADDR0: 54211308Santhony.gutierrez@amd.com if (BARAddrs[0] != 0) { 54311308Santhony.gutierrez@amd.com if (pioInterface) 54411308Santhony.gutierrez@amd.com pioInterface->addAddrRange(RangeSize(BARAddrs[0], BARSize[0])); 54510917Sbrandon.potter@amd.com 5469595Snilay@cs.wisc.edu BARAddrs[0] &= EV5::PAddrUncachedMask; 5479745Snilay@cs.wisc.edu } 5489745Snilay@cs.wisc.edu break; 5499745Snilay@cs.wisc.edu case PCI0_BASE_ADDR1: 5509745Snilay@cs.wisc.edu if (BARAddrs[1] != 0) { 5519745Snilay@cs.wisc.edu if (pioInterface) 5529745Snilay@cs.wisc.edu pioInterface->addAddrRange(RangeSize(BARAddrs[1], BARSize[1])); 5539745Snilay@cs.wisc.edu 5549745Snilay@cs.wisc.edu BARAddrs[1] &= EV5::PAddrUncachedMask; 5559745Snilay@cs.wisc.edu } 5569745Snilay@cs.wisc.edu break; 5579595Snilay@cs.wisc.edu } 5586657Snate@binkert.org} 5596657Snate@binkert.org 5606657Snate@binkert.org/** 5616657Snate@binkert.org * This reads the device registers, which are detailed in the NS83820 5627007Snate@binkert.org * spec sheet 56311021Sjthestness@gmail.com */ 56410311Snilay@cs.wisc.eduFault 56510311Snilay@cs.wisc.eduNSGigE::read(MemReqPtr &req, uint8_t *data) 56610311Snilay@cs.wisc.edu{ 56710311Snilay@cs.wisc.edu assert(ioEnable); 56810311Snilay@cs.wisc.edu 56910311Snilay@cs.wisc.edu //The mask is to give you only the offset into the device register file 57010311Snilay@cs.wisc.edu Addr daddr = req->paddr & 0xfff; 57110311Snilay@cs.wisc.edu DPRINTF(EthernetPIO, "read da=%#x pa=%#x va=%#x size=%d\n", 57210311Snilay@cs.wisc.edu daddr, req->paddr, req->vaddr, req->size); 57310311Snilay@cs.wisc.edu 57410311Snilay@cs.wisc.edu 57510311Snilay@cs.wisc.edu // there are some reserved registers, you can see ns_gige_reg.h and 57610311Snilay@cs.wisc.edu // the spec sheet for details 57711084Snilay@cs.wisc.edu if (daddr > LAST && daddr <= RESERVED) { 57810311Snilay@cs.wisc.edu panic("Accessing reserved register"); 57910311Snilay@cs.wisc.edu } else if (daddr > RESERVED && daddr <= 0x3FC) { 58011021Sjthestness@gmail.com ReadConfig(daddr & 0xff, req->size, data); 58111021Sjthestness@gmail.com return No_Fault; 58210311Snilay@cs.wisc.edu } else if (daddr >= MIB_START && daddr <= MIB_END) { 58310311Snilay@cs.wisc.edu // don't implement all the MIB's. hopefully the kernel 58410311Snilay@cs.wisc.edu // doesn't actually DEPEND upon their values 58510311Snilay@cs.wisc.edu // MIB are just hardware stats keepers 58610311Snilay@cs.wisc.edu uint32_t ® = *(uint32_t *) data; 58710311Snilay@cs.wisc.edu reg = 0; 58810311Snilay@cs.wisc.edu return No_Fault; 58910311Snilay@cs.wisc.edu } else if (daddr > 0x3FC) 59010311Snilay@cs.wisc.edu panic("Something is messed up!\n"); 59110311Snilay@cs.wisc.edu 59210311Snilay@cs.wisc.edu switch (req->size) { 59311021Sjthestness@gmail.com case sizeof(uint32_t): 59411021Sjthestness@gmail.com { 59510311Snilay@cs.wisc.edu uint32_t ® = *(uint32_t *)data; 59610311Snilay@cs.wisc.edu 59710311Snilay@cs.wisc.edu switch (daddr) { 59810311Snilay@cs.wisc.edu case CR: 59910311Snilay@cs.wisc.edu reg = regs.command; 60010311Snilay@cs.wisc.edu //these are supposed to be cleared on a read 60110311Snilay@cs.wisc.edu reg &= ~(CR_RXD | CR_TXD | CR_TXR | CR_RXR); 60210311Snilay@cs.wisc.edu break; 60310311Snilay@cs.wisc.edu 60410311Snilay@cs.wisc.edu case CFGR: 6057007Snate@binkert.org reg = regs.config; 6066657Snate@binkert.org break; 6077007Snate@binkert.org 6086657Snate@binkert.org case MEAR: 6096657Snate@binkert.org reg = regs.mear; 6106657Snate@binkert.org break; 61110311Snilay@cs.wisc.edu 6126657Snate@binkert.org case PTSCR: 6136657Snate@binkert.org reg = regs.ptscr; 61410305Snilay@cs.wisc.edu break; 6156657Snate@binkert.org 6166657Snate@binkert.org case ISR: 6176657Snate@binkert.org reg = regs.isr; 6186657Snate@binkert.org devIntrClear(ISR_ALL); 6196657Snate@binkert.org break; 6206657Snate@binkert.org 6216657Snate@binkert.org case IMR: 6226657Snate@binkert.org reg = regs.imr; 62311084Snilay@cs.wisc.edu break; 62411084Snilay@cs.wisc.edu 62511084Snilay@cs.wisc.edu case IER: 62611084Snilay@cs.wisc.edu reg = regs.ier; 62711084Snilay@cs.wisc.edu break; 6286657Snate@binkert.org 62911084Snilay@cs.wisc.edu case IHR: 6306657Snate@binkert.org reg = regs.ihr; 6316657Snate@binkert.org break; 6326657Snate@binkert.org 6337007Snate@binkert.org case TXDP: 6346657Snate@binkert.org reg = regs.txdp; 6357007Snate@binkert.org break; 6367007Snate@binkert.org 6376657Snate@binkert.org case TXDP_HI: 6389366Snilay@cs.wisc.edu reg = regs.txdp_hi; 6399366Snilay@cs.wisc.edu break; 6409366Snilay@cs.wisc.edu 6419366Snilay@cs.wisc.edu case TX_CFG: 6427566SBrad.Beckmann@amd.com reg = regs.txcfg; 6437672Snate@binkert.org break; 6446657Snate@binkert.org 6459465Snilay@cs.wisc.edu case GPIOR: 6466657Snate@binkert.org reg = regs.gpior; 6476657Snate@binkert.org break; 6486657Snate@binkert.org 6497672Snate@binkert.org case RXDP: 6506657Snate@binkert.org reg = regs.rxdp; 6516657Snate@binkert.org break; 6526657Snate@binkert.org 6536657Snate@binkert.org case RXDP_HI: 6546657Snate@binkert.org reg = regs.rxdp_hi; 6556657Snate@binkert.org break; 6566657Snate@binkert.org 6576657Snate@binkert.org case RX_CFG: 6586657Snate@binkert.org reg = regs.rxcfg; 6596657Snate@binkert.org break; 6606657Snate@binkert.org 6619745Snilay@cs.wisc.edu case PQCR: 6626657Snate@binkert.org reg = regs.pqcr; 6636657Snate@binkert.org break; 6649496Snilay@cs.wisc.edu 6659496Snilay@cs.wisc.edu case WCSR: 66610012Snilay@cs.wisc.edu reg = regs.wcsr; 6679496Snilay@cs.wisc.edu break; 6689496Snilay@cs.wisc.edu 6696657Snate@binkert.org case PCR: 67010121Snilay@cs.wisc.edu reg = regs.pcr; 6716657Snate@binkert.org break; 6726657Snate@binkert.org 67310305Snilay@cs.wisc.edu // see the spec sheet for how RFCR and RFDR work 6746657Snate@binkert.org // basically, you write to RFCR to tell the machine 67511021Sjthestness@gmail.com // what you want to do next, then you act upon RFDR, 67611021Sjthestness@gmail.com // and the device will be prepared b/c of what you 67711021Sjthestness@gmail.com // wrote to RFCR 67811021Sjthestness@gmail.com case RFCR: 67911021Sjthestness@gmail.com reg = regs.rfcr; 6808683Snilay@cs.wisc.edu break; 6818683Snilay@cs.wisc.edu 68210308Snilay@cs.wisc.edu case RFDR: 6838683Snilay@cs.wisc.edu switch (regs.rfcr & RFCR_RFADDR) { 68410308Snilay@cs.wisc.edu case 0x000: 6858683Snilay@cs.wisc.edu reg = rom.perfectMatch[1]; 68611309Sdavid.hashe@amd.com reg = reg << 8; 68711309Sdavid.hashe@amd.com reg += rom.perfectMatch[0]; 68811309Sdavid.hashe@amd.com break; 68911309Sdavid.hashe@amd.com case 0x002: 69011309Sdavid.hashe@amd.com reg = rom.perfectMatch[3] << 8; 69111309Sdavid.hashe@amd.com reg += rom.perfectMatch[2]; 69211308Santhony.gutierrez@amd.com break; 69311308Santhony.gutierrez@amd.com case 0x004: 69411308Santhony.gutierrez@amd.com reg = rom.perfectMatch[5] << 8; 69511308Santhony.gutierrez@amd.com reg += rom.perfectMatch[4]; 69611308Santhony.gutierrez@amd.com break; 69711308Santhony.gutierrez@amd.com default: 69811308Santhony.gutierrez@amd.com panic("reading RFDR for something other than PMATCH!\n"); 69911308Santhony.gutierrez@amd.com // didn't implement other RFDR functionality b/c 70011308Santhony.gutierrez@amd.com // driver didn't use it 70111308Santhony.gutierrez@amd.com } 70211308Santhony.gutierrez@amd.com break; 70311308Santhony.gutierrez@amd.com 70411308Santhony.gutierrez@amd.com case SRR: 70511308Santhony.gutierrez@amd.com reg = regs.srr; 70611308Santhony.gutierrez@amd.com break; 70711308Santhony.gutierrez@amd.com 70811308Santhony.gutierrez@amd.com case MIBC: 70911308Santhony.gutierrez@amd.com reg = regs.mibc; 71011308Santhony.gutierrez@amd.com reg &= ~(MIBC_MIBS | MIBC_ACLR); 71111308Santhony.gutierrez@amd.com break; 71211308Santhony.gutierrez@amd.com 71311308Santhony.gutierrez@amd.com case VRCR: 71411309Sdavid.hashe@amd.com reg = regs.vrcr; 71511309Sdavid.hashe@amd.com break; 71611309Sdavid.hashe@amd.com 71711309Sdavid.hashe@amd.com case VTCR: 71811309Sdavid.hashe@amd.com reg = regs.vtcr; 71911309Sdavid.hashe@amd.com break; 72011309Sdavid.hashe@amd.com 72111309Sdavid.hashe@amd.com case VDR: 72211309Sdavid.hashe@amd.com reg = regs.vdr; 72311309Sdavid.hashe@amd.com break; 72411309Sdavid.hashe@amd.com 72511309Sdavid.hashe@amd.com case CCSR: 72611309Sdavid.hashe@amd.com reg = regs.ccsr; 72711309Sdavid.hashe@amd.com break; 72811309Sdavid.hashe@amd.com 72911309Sdavid.hashe@amd.com case TBICR: 73011309Sdavid.hashe@amd.com reg = regs.tbicr; 73111309Sdavid.hashe@amd.com break; 73211309Sdavid.hashe@amd.com 73311309Sdavid.hashe@amd.com case TBISR: 73411309Sdavid.hashe@amd.com reg = regs.tbisr; 73511309Sdavid.hashe@amd.com break; 7366657Snate@binkert.org 7379745Snilay@cs.wisc.edu case TANAR: 7389745Snilay@cs.wisc.edu reg = regs.tanar; 7399745Snilay@cs.wisc.edu break; 7409745Snilay@cs.wisc.edu 74110012Snilay@cs.wisc.edu case TANLPAR: 74210012Snilay@cs.wisc.edu reg = regs.tanlpar; 7439745Snilay@cs.wisc.edu break; 7449745Snilay@cs.wisc.edu 7459745Snilay@cs.wisc.edu case TANER: 7469745Snilay@cs.wisc.edu reg = regs.taner; 7479745Snilay@cs.wisc.edu break; 74810919Sbrandon.potter@amd.com 74910012Snilay@cs.wisc.edu case TESR: 7509745Snilay@cs.wisc.edu reg = regs.tesr; 7519745Snilay@cs.wisc.edu break; 7529745Snilay@cs.wisc.edu 7539745Snilay@cs.wisc.edu case M5REG: 7549745Snilay@cs.wisc.edu reg = params()->m5reg; 7559745Snilay@cs.wisc.edu break; 7569745Snilay@cs.wisc.edu 7579745Snilay@cs.wisc.edu default: 7589745Snilay@cs.wisc.edu panic("reading unimplemented register: addr=%#x", daddr); 7599745Snilay@cs.wisc.edu } 7609745Snilay@cs.wisc.edu 7619745Snilay@cs.wisc.edu DPRINTF(EthernetPIO, "read from %#x: data=%d data=%#x\n", 7629745Snilay@cs.wisc.edu daddr, reg, reg); 7639745Snilay@cs.wisc.edu } 7649745Snilay@cs.wisc.edu break; 7659745Snilay@cs.wisc.edu 76610919Sbrandon.potter@amd.com default: 76710012Snilay@cs.wisc.edu panic("accessing register with invalid size: addr=%#x, size=%d", 7689745Snilay@cs.wisc.edu daddr, req->size); 7699745Snilay@cs.wisc.edu } 7709745Snilay@cs.wisc.edu 7719745Snilay@cs.wisc.edu return No_Fault; 7729745Snilay@cs.wisc.edu} 7739745Snilay@cs.wisc.edu 7749745Snilay@cs.wisc.eduFault 7759745Snilay@cs.wisc.eduNSGigE::write(MemReqPtr &req, const uint8_t *data) 7769745Snilay@cs.wisc.edu{ 7779745Snilay@cs.wisc.edu assert(ioEnable); 7789745Snilay@cs.wisc.edu 7799745Snilay@cs.wisc.edu Addr daddr = req->paddr & 0xfff; 7809745Snilay@cs.wisc.edu DPRINTF(EthernetPIO, "write da=%#x pa=%#x va=%#x size=%d\n", 7819745Snilay@cs.wisc.edu daddr, req->paddr, req->vaddr, req->size); 7829745Snilay@cs.wisc.edu 7839745Snilay@cs.wisc.edu if (daddr > LAST && daddr <= RESERVED) { 78410920Sbrandon.potter@amd.com panic("Accessing reserved register"); 7859745Snilay@cs.wisc.edu } else if (daddr > RESERVED && daddr <= 0x3FC) { 78610920Sbrandon.potter@amd.com WriteConfig(daddr & 0xff, req->size, *(uint32_t *)data); 78710920Sbrandon.potter@amd.com return No_Fault; 7889745Snilay@cs.wisc.edu } else if (daddr > 0x3FC) 7899745Snilay@cs.wisc.edu panic("Something is messed up!\n"); 7909745Snilay@cs.wisc.edu 7919745Snilay@cs.wisc.edu if (req->size == sizeof(uint32_t)) { 7929745Snilay@cs.wisc.edu uint32_t reg = *(uint32_t *)data; 7939745Snilay@cs.wisc.edu DPRINTF(EthernetPIO, "write data=%d data=%#x\n", reg, reg); 7949745Snilay@cs.wisc.edu 7959745Snilay@cs.wisc.edu switch (daddr) { 7969745Snilay@cs.wisc.edu case CR: 7979745Snilay@cs.wisc.edu regs.command = reg; 7989745Snilay@cs.wisc.edu if (reg & CR_TXD) { 7999745Snilay@cs.wisc.edu txEnable = false; 80010920Sbrandon.potter@amd.com } else if (reg & CR_TXE) { 8019745Snilay@cs.wisc.edu txEnable = true; 80210920Sbrandon.potter@amd.com 80310920Sbrandon.potter@amd.com // the kernel is enabling the transmit machine 8049745Snilay@cs.wisc.edu if (txState == txIdle) 8059745Snilay@cs.wisc.edu txKick(); 8069745Snilay@cs.wisc.edu } 8079745Snilay@cs.wisc.edu 8089745Snilay@cs.wisc.edu if (reg & CR_RXD) { 8099745Snilay@cs.wisc.edu rxEnable = false; 8109745Snilay@cs.wisc.edu } else if (reg & CR_RXE) { 8119745Snilay@cs.wisc.edu rxEnable = true; 8129745Snilay@cs.wisc.edu 8139745Snilay@cs.wisc.edu if (rxState == rxIdle) 8149745Snilay@cs.wisc.edu rxKick(); 8159745Snilay@cs.wisc.edu } 8169745Snilay@cs.wisc.edu 8179745Snilay@cs.wisc.edu if (reg & CR_TXR) 8189745Snilay@cs.wisc.edu txReset(); 8199745Snilay@cs.wisc.edu 8209745Snilay@cs.wisc.edu if (reg & CR_RXR) 8219745Snilay@cs.wisc.edu rxReset(); 8229745Snilay@cs.wisc.edu 8239745Snilay@cs.wisc.edu if (reg & CR_SWI) 8249745Snilay@cs.wisc.edu devIntrPost(ISR_SWI); 82511061Snilay@cs.wisc.edu 8269745Snilay@cs.wisc.edu if (reg & CR_RST) { 8279745Snilay@cs.wisc.edu txReset(); 8289745Snilay@cs.wisc.edu rxReset(); 8299745Snilay@cs.wisc.edu 8309745Snilay@cs.wisc.edu regsReset(); 8319745Snilay@cs.wisc.edu } 8329745Snilay@cs.wisc.edu break; 8339745Snilay@cs.wisc.edu 8349745Snilay@cs.wisc.edu case CFGR: 8359745Snilay@cs.wisc.edu if (reg & CFGR_LNKSTS || 8369745Snilay@cs.wisc.edu reg & CFGR_SPDSTS || 83711061Snilay@cs.wisc.edu reg & CFGR_DUPSTS || 8389745Snilay@cs.wisc.edu reg & CFGR_RESERVED || 8399745Snilay@cs.wisc.edu reg & CFGR_T64ADDR || 8409745Snilay@cs.wisc.edu reg & CFGR_PCI64_DET) 8419745Snilay@cs.wisc.edu panic("writing to read-only or reserved CFGR bits!\n"); 8429745Snilay@cs.wisc.edu 8439745Snilay@cs.wisc.edu regs.config |= reg & ~(CFGR_LNKSTS | CFGR_SPDSTS | CFGR_DUPSTS | 8447007Snate@binkert.org CFGR_RESERVED | CFGR_T64ADDR | CFGR_PCI64_DET); 8457007Snate@binkert.org 8467007Snate@binkert.org// all these #if 0's are because i don't THINK the kernel needs to 8476657Snate@binkert.org// have these implemented. if there is a problem relating to one of 8486657Snate@binkert.org// these, you may need to add functionality in. 8496657Snate@binkert.org#if 0 8507007Snate@binkert.org if (reg & CFGR_TBI_EN) ; 8517007Snate@binkert.org if (reg & CFGR_MODE_1000) ; 8527007Snate@binkert.org#endif 8536657Snate@binkert.org 8546657Snate@binkert.org if (reg & CFGR_AUTO_1000) 8556657Snate@binkert.org panic("CFGR_AUTO_1000 not implemented!\n"); 85611021Sjthestness@gmail.com 85711021Sjthestness@gmail.com#if 0 85811021Sjthestness@gmail.com if (reg & CFGR_PINT_DUPSTS || 85911021Sjthestness@gmail.com reg & CFGR_PINT_LNKSTS || 86011021Sjthestness@gmail.com reg & CFGR_PINT_SPDSTS) 86111021Sjthestness@gmail.com ; 8627007Snate@binkert.org 8637007Snate@binkert.org if (reg & CFGR_TMRTEST) ; 8647007Snate@binkert.org if (reg & CFGR_MRM_DIS) ; 8657007Snate@binkert.org if (reg & CFGR_MWI_DIS) ; 8667007Snate@binkert.org 8676657Snate@binkert.org if (reg & CFGR_T64ADDR) 86810012Snilay@cs.wisc.edu panic("CFGR_T64ADDR is read only register!\n"); 8699745Snilay@cs.wisc.edu 8709745Snilay@cs.wisc.edu if (reg & CFGR_PCI64_DET) 8719745Snilay@cs.wisc.edu panic("CFGR_PCI64_DET is read only register!\n"); 8729745Snilay@cs.wisc.edu 8739745Snilay@cs.wisc.edu if (reg & CFGR_DATA64_EN) ; 8749745Snilay@cs.wisc.edu if (reg & CFGR_M64ADDR) ; 8756902SBrad.Beckmann@amd.com if (reg & CFGR_PHY_RST) ; 8769745Snilay@cs.wisc.edu if (reg & CFGR_PHY_DIS) ; 8779745Snilay@cs.wisc.edu#endif 8789745Snilay@cs.wisc.edu 8799745Snilay@cs.wisc.edu if (reg & CFGR_EXTSTS_EN) 88010012Snilay@cs.wisc.edu extstsEnable = true; 8816902SBrad.Beckmann@amd.com else 8827839Snilay@cs.wisc.edu extstsEnable = false; 8837839Snilay@cs.wisc.edu 8847839Snilay@cs.wisc.edu#if 0 8857839Snilay@cs.wisc.edu if (reg & CFGR_REQALG) ; 8867839Snilay@cs.wisc.edu if (reg & CFGR_SB) ; 8877839Snilay@cs.wisc.edu if (reg & CFGR_POW) ; 8887839Snilay@cs.wisc.edu if (reg & CFGR_EXD) ; 8897839Snilay@cs.wisc.edu if (reg & CFGR_PESEL) ; 8907839Snilay@cs.wisc.edu if (reg & CFGR_BROM_DIS) ; 8917839Snilay@cs.wisc.edu if (reg & CFGR_EXT_125) ; 8927839Snilay@cs.wisc.edu if (reg & CFGR_BEM) ; 8937839Snilay@cs.wisc.edu#endif 8947839Snilay@cs.wisc.edu break; 8957839Snilay@cs.wisc.edu 8967839Snilay@cs.wisc.edu case MEAR: 8977839Snilay@cs.wisc.edu regs.mear = reg; 8987839Snilay@cs.wisc.edu // since phy is completely faked, MEAR_MD* don't matter 8997839Snilay@cs.wisc.edu // and since the driver never uses MEAR_EE*, they don't 9007839Snilay@cs.wisc.edu // matter 9017839Snilay@cs.wisc.edu#if 0 9027839Snilay@cs.wisc.edu if (reg & MEAR_EEDI) ; 9037839Snilay@cs.wisc.edu if (reg & MEAR_EEDO) ; // this one is read only 9047839Snilay@cs.wisc.edu if (reg & MEAR_EECLK) ; 9057839Snilay@cs.wisc.edu if (reg & MEAR_EESEL) ; 9067839Snilay@cs.wisc.edu if (reg & MEAR_MDIO) ; 9077839Snilay@cs.wisc.edu if (reg & MEAR_MDDIR) ; 9087839Snilay@cs.wisc.edu if (reg & MEAR_MDC) ; 9097839Snilay@cs.wisc.edu#endif 9107839Snilay@cs.wisc.edu break; 9117839Snilay@cs.wisc.edu 9127839Snilay@cs.wisc.edu case PTSCR: 9137839Snilay@cs.wisc.edu regs.ptscr = reg & ~(PTSCR_RBIST_RDONLY); 9147839Snilay@cs.wisc.edu // these control BISTs for various parts of chip - we 9157839Snilay@cs.wisc.edu // don't care or do just fake that the BIST is done 9167839Snilay@cs.wisc.edu if (reg & PTSCR_RBIST_EN) 9177839Snilay@cs.wisc.edu regs.ptscr |= PTSCR_RBIST_DONE; 9187839Snilay@cs.wisc.edu if (reg & PTSCR_EEBIST_EN) 9196902SBrad.Beckmann@amd.com regs.ptscr &= ~PTSCR_EEBIST_EN; 9208683Snilay@cs.wisc.edu if (reg & PTSCR_EELOAD_EN) 9218683Snilay@cs.wisc.edu regs.ptscr &= ~PTSCR_EELOAD_EN; 9228683Snilay@cs.wisc.edu break; 9238683Snilay@cs.wisc.edu 9248683Snilay@cs.wisc.edu case ISR: /* writing to the ISR has no effect */ 9258683Snilay@cs.wisc.edu panic("ISR is a read only register!\n"); 9268683Snilay@cs.wisc.edu 9278683Snilay@cs.wisc.edu case IMR: 9288683Snilay@cs.wisc.edu regs.imr = reg; 9298683Snilay@cs.wisc.edu devIntrChangeMask(); 9308683Snilay@cs.wisc.edu break; 9318683Snilay@cs.wisc.edu 9328683Snilay@cs.wisc.edu case IER: 9338683Snilay@cs.wisc.edu regs.ier = reg; 9348683Snilay@cs.wisc.edu break; 9358683Snilay@cs.wisc.edu 9368683Snilay@cs.wisc.edu case IHR: 9376657Snate@binkert.org regs.ihr = reg; 9386657Snate@binkert.org /* not going to implement real interrupt holdoff */ 9397839Snilay@cs.wisc.edu break; 9407839Snilay@cs.wisc.edu 9417839Snilay@cs.wisc.edu case TXDP: 9427839Snilay@cs.wisc.edu regs.txdp = (reg & 0xFFFFFFFC); 9436657Snate@binkert.org assert(txState == txIdle); 9447839Snilay@cs.wisc.edu CTDD = false; 9457839Snilay@cs.wisc.edu break; 9467839Snilay@cs.wisc.edu 94711025Snilay@cs.wisc.edu case TXDP_HI: 9487839Snilay@cs.wisc.edu regs.txdp_hi = reg; 9498055Sksewell@umich.edu break; 95010963Sdavid.hashe@amd.com 95110963Sdavid.hashe@amd.com case TX_CFG: 95210963Sdavid.hashe@amd.com regs.txcfg = reg; 95310963Sdavid.hashe@amd.com#if 0 95410963Sdavid.hashe@amd.com if (reg & TX_CFG_CSI) ; 95510963Sdavid.hashe@amd.com if (reg & TX_CFG_HBI) ; 95610963Sdavid.hashe@amd.com if (reg & TX_CFG_MLB) ; 9577839Snilay@cs.wisc.edu if (reg & TX_CFG_ATP) ; 9586657Snate@binkert.org if (reg & TX_CFG_ECRETRY) { 9597839Snilay@cs.wisc.edu /* 9607839Snilay@cs.wisc.edu * this could easily be implemented, but considering 9617839Snilay@cs.wisc.edu * the network is just a fake pipe, wouldn't make 9627839Snilay@cs.wisc.edu * sense to do this 9637839Snilay@cs.wisc.edu */ 9647839Snilay@cs.wisc.edu } 9657839Snilay@cs.wisc.edu 9667839Snilay@cs.wisc.edu if (reg & TX_CFG_BRST_DIS) ; 9677839Snilay@cs.wisc.edu#endif 96811025Snilay@cs.wisc.edu 9697839Snilay@cs.wisc.edu#if 0 9708055Sksewell@umich.edu /* we handle our own DMA, ignore the kernel's exhortations */ 9717839Snilay@cs.wisc.edu if (reg & TX_CFG_MXDMA) ; 9727839Snilay@cs.wisc.edu#endif 9737839Snilay@cs.wisc.edu 9747839Snilay@cs.wisc.edu // also, we currently don't care about fill/drain 9757839Snilay@cs.wisc.edu // thresholds though this may change in the future with 9767839Snilay@cs.wisc.edu // more realistic networks or a driver which changes it 9777839Snilay@cs.wisc.edu // according to feedback 9787839Snilay@cs.wisc.edu 9797839Snilay@cs.wisc.edu break; 9807839Snilay@cs.wisc.edu 9817839Snilay@cs.wisc.edu case GPIOR: 9827839Snilay@cs.wisc.edu regs.gpior = reg; 98311025Snilay@cs.wisc.edu /* these just control general purpose i/o pins, don't matter */ 9847839Snilay@cs.wisc.edu break; 9858055Sksewell@umich.edu 9867839Snilay@cs.wisc.edu case RXDP: 9877839Snilay@cs.wisc.edu regs.rxdp = reg; 9887839Snilay@cs.wisc.edu CRDD = false; 9897839Snilay@cs.wisc.edu break; 9907839Snilay@cs.wisc.edu 9917839Snilay@cs.wisc.edu case RXDP_HI: 9927839Snilay@cs.wisc.edu regs.rxdp_hi = reg; 9937839Snilay@cs.wisc.edu break; 9947839Snilay@cs.wisc.edu 9957839Snilay@cs.wisc.edu case RX_CFG: 9966657Snate@binkert.org regs.rxcfg = reg; 9977007Snate@binkert.org#if 0 99811025Snilay@cs.wisc.edu if (reg & RX_CFG_AEP) ; 9996657Snate@binkert.org if (reg & RX_CFG_ARP) ; 10008055Sksewell@umich.edu if (reg & RX_CFG_STRIPCRC) ; 10016657Snate@binkert.org if (reg & RX_CFG_RX_RD) ; 10026657Snate@binkert.org if (reg & RX_CFG_ALP) ; 10036657Snate@binkert.org if (reg & RX_CFG_AIRL) ; 10046657Snate@binkert.org 10058478Snilay@cs.wisc.edu /* we handle our own DMA, ignore what kernel says about it */ 10068478Snilay@cs.wisc.edu if (reg & RX_CFG_MXDMA) ; 10078478Snilay@cs.wisc.edu 10089302Snilay@cs.wisc.edu //also, we currently don't care about fill/drain thresholds 10099302Snilay@cs.wisc.edu //though this may change in the future with more realistic 101010524Snilay@cs.wisc.edu //networks or a driver which changes it according to feedback 10119302Snilay@cs.wisc.edu if (reg & (RX_CFG_DRTH | RX_CFG_DRTH0)) ; 10129302Snilay@cs.wisc.edu#endif 101310524Snilay@cs.wisc.edu break; 10149302Snilay@cs.wisc.edu 10159302Snilay@cs.wisc.edu case PQCR: 10169302Snilay@cs.wisc.edu /* there is no priority queueing used in the linux 2.6 driver */ 10179302Snilay@cs.wisc.edu regs.pqcr = reg; 101810305Snilay@cs.wisc.edu break; 10199302Snilay@cs.wisc.edu 102010311Snilay@cs.wisc.edu case WCSR: 102110311Snilay@cs.wisc.edu /* not going to implement wake on LAN */ 102210311Snilay@cs.wisc.edu regs.wcsr = reg; 102310311Snilay@cs.wisc.edu break; 102410311Snilay@cs.wisc.edu 102510311Snilay@cs.wisc.edu case PCR: 102610311Snilay@cs.wisc.edu /* not going to implement pause control */ 10279302Snilay@cs.wisc.edu regs.pcr = reg; 10289302Snilay@cs.wisc.edu break; 10299302Snilay@cs.wisc.edu 10309302Snilay@cs.wisc.edu case RFCR: 10319302Snilay@cs.wisc.edu regs.rfcr = reg; 10326657Snate@binkert.org 10336657Snate@binkert.org rxFilterEnable = (reg & RFCR_RFEN) ? true : false; 10349219Spower.jg@gmail.com acceptBroadcast = (reg & RFCR_AAB) ? true : false; 10356657Snate@binkert.org acceptMulticast = (reg & RFCR_AAM) ? true : false; 10366657Snate@binkert.org acceptUnicast = (reg & RFCR_AAU) ? true : false; 10376999Snate@binkert.org acceptPerfect = (reg & RFCR_APM) ? true : false; 10386657Snate@binkert.org acceptArp = (reg & RFCR_AARP) ? true : false; 10396657Snate@binkert.org 10409104Shestness@cs.utexas.edu#if 0 10419104Shestness@cs.utexas.edu if (reg & RFCR_APAT) 10429104Shestness@cs.utexas.edu panic("RFCR_APAT not implemented!\n"); 10439104Shestness@cs.utexas.edu#endif 10446657Snate@binkert.org 10456657Snate@binkert.org if (reg & RFCR_MHEN || reg & RFCR_UHEN) 10466657Snate@binkert.org panic("hash filtering not implemented!\n"); 10476657Snate@binkert.org 10488946Sandreas.hansson@arm.com if (reg & RFCR_ULM) 10498946Sandreas.hansson@arm.com panic("RFCR_ULM not implemented!\n"); 10508946Sandreas.hansson@arm.com 10517832Snate@binkert.org break; 105210972Sdavid.hashe@amd.com 10537832Snate@binkert.org case RFDR: 10547007Snate@binkert.org panic("the driver never writes to RFDR, something is wrong!\n"); 105510972Sdavid.hashe@amd.com 105610972Sdavid.hashe@amd.com case BRAR: 105710972Sdavid.hashe@amd.com panic("the driver never uses BRAR, something is wrong!\n"); 105810972Sdavid.hashe@amd.com 105910972Sdavid.hashe@amd.com case BRDR: 10608229Snate@binkert.org panic("the driver never uses BRDR, something is wrong!\n"); 10618229Snate@binkert.org 10628229Snate@binkert.org case SRR: 106310972Sdavid.hashe@amd.com panic("SRR is read only register!\n"); 10649104Shestness@cs.utexas.edu 10659104Shestness@cs.utexas.edu case MIBC: 10669104Shestness@cs.utexas.edu panic("the driver never uses MIBC, something is wrong!\n"); 10679104Shestness@cs.utexas.edu 10689104Shestness@cs.utexas.edu case VRCR: 10699104Shestness@cs.utexas.edu regs.vrcr = reg; 10708229Snate@binkert.org break; 107111108Sdavid.hashe@amd.com 107210972Sdavid.hashe@amd.com case VTCR: 10739219Spower.jg@gmail.com regs.vtcr = reg; 10749219Spower.jg@gmail.com break; 10759219Spower.jg@gmail.com 10769219Spower.jg@gmail.com case VDR: 10779219Spower.jg@gmail.com panic("the driver never uses VDR, something is wrong!\n"); 10789219Spower.jg@gmail.com break; 107910963Sdavid.hashe@amd.com 108010963Sdavid.hashe@amd.com case CCSR: 10819219Spower.jg@gmail.com /* not going to implement clockrun stuff */ 10826657Snate@binkert.org regs.ccsr = reg; 10837055Snate@binkert.org break; 10847055Snate@binkert.org 10857007Snate@binkert.org case TBICR: 10867007Snate@binkert.org regs.tbicr = reg; 10876657Snate@binkert.org if (reg & TBICR_MR_LOOPBACK) 10886657Snate@binkert.org panic("TBICR_MR_LOOPBACK never used, something wrong!\n"); 10896657Snate@binkert.org 109010963Sdavid.hashe@amd.com if (reg & TBICR_MR_AN_ENABLE) { 109110963Sdavid.hashe@amd.com regs.tanlpar = regs.tanar; 10926657Snate@binkert.org regs.tbisr |= (TBISR_MR_AN_COMPLETE | TBISR_MR_LINK_STATUS); 10936657Snate@binkert.org } 10946657Snate@binkert.org 10957007Snate@binkert.org#if 0 10969496Snilay@cs.wisc.edu if (reg & TBICR_MR_RESTART_AN) ; 10977007Snate@binkert.org#endif 10987007Snate@binkert.org 10999499Snilay@cs.wisc.edu break; 11006657Snate@binkert.org 11016657Snate@binkert.org case TBISR: 11026657Snate@binkert.org panic("TBISR is read only register!\n"); 11036657Snate@binkert.org 11046657Snate@binkert.org case TANAR: 11056657Snate@binkert.org regs.tanar = reg; 11066657Snate@binkert.org if (reg & TANAR_PS2) 11076657Snate@binkert.org panic("this isn't used in driver, something wrong!\n"); 11086657Snate@binkert.org 11096657Snate@binkert.org if (reg & TANAR_PS1) 11106657Snate@binkert.org panic("this isn't used in driver, something wrong!\n"); 11116657Snate@binkert.org break; 11127567SBrad.Beckmann@amd.com 11139996Snilay@cs.wisc.edu case TANLPAR: 11147567SBrad.Beckmann@amd.com panic("this should only be written to by the fake phy!\n"); 11159996Snilay@cs.wisc.edu 111610963Sdavid.hashe@amd.com case TANER: 111710963Sdavid.hashe@amd.com panic("TANER is read only register!\n"); 111810963Sdavid.hashe@amd.com 11196657Snate@binkert.org case TESR: 112010963Sdavid.hashe@amd.com regs.tesr = reg; 112110963Sdavid.hashe@amd.com break; 112210963Sdavid.hashe@amd.com 112310963Sdavid.hashe@amd.com default: 112410963Sdavid.hashe@amd.com panic("invalid register access daddr=%#x", daddr); 112510963Sdavid.hashe@amd.com } 112610963Sdavid.hashe@amd.com } else { 112710963Sdavid.hashe@amd.com panic("Invalid Request Size"); 11286657Snate@binkert.org } 11296657Snate@binkert.org 11306657Snate@binkert.org return No_Fault; 11316657Snate@binkert.org} 11326657Snate@binkert.org 11336657Snate@binkert.orgvoid 113410963Sdavid.hashe@amd.comNSGigE::devIntrPost(uint32_t interrupts) 113510963Sdavid.hashe@amd.com{ 113610963Sdavid.hashe@amd.com if (interrupts & ISR_RESERVE) 113710963Sdavid.hashe@amd.com panic("Cannot set a reserved interrupt"); 113810963Sdavid.hashe@amd.com 113910963Sdavid.hashe@amd.com if (interrupts & ISR_NOIMPL) 114011116Santhony.gutierrez@amd.com warn("interrupt not implemented %#x\n", interrupts); 114110963Sdavid.hashe@amd.com 114210963Sdavid.hashe@amd.com interrupts &= ~ISR_NOIMPL; 114310963Sdavid.hashe@amd.com regs.isr |= interrupts; 114410963Sdavid.hashe@amd.com 114510963Sdavid.hashe@amd.com if (interrupts & regs.imr) { 114610963Sdavid.hashe@amd.com if (interrupts & ISR_SWI) { 114710963Sdavid.hashe@amd.com totalSwi++; 114810963Sdavid.hashe@amd.com } 114910963Sdavid.hashe@amd.com if (interrupts & ISR_RXIDLE) { 115010963Sdavid.hashe@amd.com totalRxIdle++; 115110963Sdavid.hashe@amd.com } 115210963Sdavid.hashe@amd.com if (interrupts & ISR_RXOK) { 11536657Snate@binkert.org totalRxOk++; 11546657Snate@binkert.org } 11556657Snate@binkert.org if (interrupts & ISR_RXDESC) { 11566657Snate@binkert.org totalRxDesc++; 11576657Snate@binkert.org } 11586657Snate@binkert.org if (interrupts & ISR_TXOK) { 11596657Snate@binkert.org totalTxOk++; 11606657Snate@binkert.org } 11616657Snate@binkert.org if (interrupts & ISR_TXIDLE) { 11626999Snate@binkert.org totalTxIdle++; 11636657Snate@binkert.org } 11646657Snate@binkert.org if (interrupts & ISR_TXDESC) { 11656657Snate@binkert.org totalTxDesc++; 11666657Snate@binkert.org } 11676657Snate@binkert.org if (interrupts & ISR_RXORN) { 11686657Snate@binkert.org totalRxOrn++; 11697832Snate@binkert.org } 11707832Snate@binkert.org } 11717805Snilay@cs.wisc.edu 11727832Snate@binkert.org DPRINTF(EthernetIntr, 11738232Snate@binkert.org "interrupt written to ISR: intr=%#x isr=%#x imr=%#x\n", 11748232Snate@binkert.org interrupts, regs.isr, regs.imr); 11758229Snate@binkert.org 11768229Snate@binkert.org if ((regs.isr & regs.imr)) { 11778229Snate@binkert.org Tick when = curTick; 11788229Snate@binkert.org if (!(regs.isr & regs.imr & ISR_NODELAY)) 117911108Sdavid.hashe@amd.com when += intrDelay; 11806657Snate@binkert.org cpuIntrPost(when); 11816657Snate@binkert.org } 11826657Snate@binkert.org} 11836657Snate@binkert.org 11846657Snate@binkert.org/* writing this interrupt counting stats inside this means that this function 11856657Snate@binkert.org is now limited to being used to clear all interrupts upon the kernel 11867007Snate@binkert.org reading isr and servicing. just telling you in case you were thinking 11877007Snate@binkert.org of expanding use. 11887839Snilay@cs.wisc.edu*/ 11897839Snilay@cs.wisc.eduvoid 11907839Snilay@cs.wisc.eduNSGigE::devIntrClear(uint32_t interrupts) 11917839Snilay@cs.wisc.edu{ 11927839Snilay@cs.wisc.edu if (interrupts & ISR_RESERVE) 11937839Snilay@cs.wisc.edu panic("Cannot clear a reserved interrupt"); 11947839Snilay@cs.wisc.edu 11957839Snilay@cs.wisc.edu if (regs.isr & regs.imr & ISR_SWI) { 11967839Snilay@cs.wisc.edu postedSwi++; 11977839Snilay@cs.wisc.edu } 119811025Snilay@cs.wisc.edu if (regs.isr & regs.imr & ISR_RXIDLE) { 11996657Snate@binkert.org postedRxIdle++; 12007839Snilay@cs.wisc.edu } 120110305Snilay@cs.wisc.edu if (regs.isr & regs.imr & ISR_RXOK) { 120210305Snilay@cs.wisc.edu postedRxOk++; 12037839Snilay@cs.wisc.edu } 12048337Snilay@cs.wisc.edu if (regs.isr & regs.imr & ISR_RXDESC) { 12057839Snilay@cs.wisc.edu postedRxDesc++; 12068337Snilay@cs.wisc.edu } 12077839Snilay@cs.wisc.edu if (regs.isr & regs.imr & ISR_TXOK) { 12088337Snilay@cs.wisc.edu postedTxOk++; 12097839Snilay@cs.wisc.edu } 12108337Snilay@cs.wisc.edu if (regs.isr & regs.imr & ISR_TXIDLE) { 12117839Snilay@cs.wisc.edu postedTxIdle++; 12127839Snilay@cs.wisc.edu } 121310305Snilay@cs.wisc.edu if (regs.isr & regs.imr & ISR_TXDESC) { 12146657Snate@binkert.org postedTxDesc++; 121511118Snilay@cs.wisc.edu } 121610305Snilay@cs.wisc.edu if (regs.isr & regs.imr & ISR_RXORN) { 121710305Snilay@cs.wisc.edu postedRxOrn++; 12186657Snate@binkert.org } 121910305Snilay@cs.wisc.edu 12207839Snilay@cs.wisc.edu if (regs.isr & regs.imr & (ISR_SWI | ISR_RXIDLE | ISR_RXOK | ISR_RXDESC | 12217839Snilay@cs.wisc.edu ISR_TXOK | ISR_TXIDLE | ISR_TXDESC | ISR_RXORN) ) 12227839Snilay@cs.wisc.edu postedInterrupts++; 12237839Snilay@cs.wisc.edu 12247839Snilay@cs.wisc.edu interrupts &= ~ISR_NOIMPL; 12257839Snilay@cs.wisc.edu regs.isr &= ~interrupts; 12267839Snilay@cs.wisc.edu 12277839Snilay@cs.wisc.edu DPRINTF(EthernetIntr, 12287839Snilay@cs.wisc.edu "interrupt cleared from ISR: intr=%x isr=%x imr=%x\n", 12296657Snate@binkert.org interrupts, regs.isr, regs.imr); 123011049Snilay@cs.wisc.edu 123111049Snilay@cs.wisc.edu if (!(regs.isr & regs.imr)) 12327839Snilay@cs.wisc.edu cpuIntrClear(); 12336657Snate@binkert.org} 123410305Snilay@cs.wisc.edu 123510305Snilay@cs.wisc.eduvoid 123610305Snilay@cs.wisc.eduNSGigE::devIntrChangeMask() 123710305Snilay@cs.wisc.edu{ 123810305Snilay@cs.wisc.edu DPRINTF(EthernetIntr, "interrupt mask changed: isr=%x imr=%x masked=%x\n", 123911025Snilay@cs.wisc.edu regs.isr, regs.imr, regs.isr & regs.imr); 124010305Snilay@cs.wisc.edu 124110305Snilay@cs.wisc.edu if (regs.isr & regs.imr) 124210305Snilay@cs.wisc.edu cpuIntrPost(curTick); 124310305Snilay@cs.wisc.edu else 124411118Snilay@cs.wisc.edu cpuIntrClear(); 124510305Snilay@cs.wisc.edu} 124610305Snilay@cs.wisc.edu 12477839Snilay@cs.wisc.eduvoid 12487839Snilay@cs.wisc.eduNSGigE::cpuIntrPost(Tick when) 12498337Snilay@cs.wisc.edu{ 12508341Snilay@cs.wisc.edu // If the interrupt you want to post is later than an interrupt 12517839Snilay@cs.wisc.edu // already scheduled, just let it post in the coming one and don't 12528337Snilay@cs.wisc.edu // schedule another. 12538341Snilay@cs.wisc.edu // HOWEVER, must be sure that the scheduled intrTick is in the 12547839Snilay@cs.wisc.edu // future (this was formerly the source of a bug) 12558337Snilay@cs.wisc.edu /** 12568341Snilay@cs.wisc.edu * @todo this warning should be removed and the intrTick code should 12577839Snilay@cs.wisc.edu * be fixed. 12588337Snilay@cs.wisc.edu */ 12598341Snilay@cs.wisc.edu assert(when >= curTick); 12607839Snilay@cs.wisc.edu assert(intrTick >= curTick || intrTick == 0); 12617839Snilay@cs.wisc.edu if (when > intrTick && intrTick != 0) { 126210305Snilay@cs.wisc.edu DPRINTF(EthernetIntr, "don't need to schedule event...intrTick=%d\n", 126311025Snilay@cs.wisc.edu intrTick); 126410305Snilay@cs.wisc.edu return; 126510305Snilay@cs.wisc.edu } 126610305Snilay@cs.wisc.edu 126710305Snilay@cs.wisc.edu intrTick = when; 126811118Snilay@cs.wisc.edu if (intrTick < curTick) { 126910305Snilay@cs.wisc.edu debug_break(); 127010305Snilay@cs.wisc.edu intrTick = curTick; 127111025Snilay@cs.wisc.edu } 127210305Snilay@cs.wisc.edu 127310305Snilay@cs.wisc.edu DPRINTF(EthernetIntr, "going to schedule an interrupt for intrTick=%d\n", 127410305Snilay@cs.wisc.edu intrTick); 127510305Snilay@cs.wisc.edu 127611118Snilay@cs.wisc.edu if (intrEvent) 127710305Snilay@cs.wisc.edu intrEvent->squash(); 12786657Snate@binkert.org intrEvent = new IntrEvent(this, true); 127910305Snilay@cs.wisc.edu intrEvent->schedule(intrTick); 128010305Snilay@cs.wisc.edu} 128110305Snilay@cs.wisc.edu 128210305Snilay@cs.wisc.eduvoid 12836657Snate@binkert.orgNSGigE::cpuInterrupt() 12846657Snate@binkert.org{ 12857007Snate@binkert.org assert(intrTick == curTick); 12867007Snate@binkert.org 12877007Snate@binkert.org // Whether or not there's a pending interrupt, we don't care about 12887007Snate@binkert.org // it anymore 12897839Snilay@cs.wisc.edu intrEvent = 0; 12907839Snilay@cs.wisc.edu intrTick = 0; 12917839Snilay@cs.wisc.edu 12927839Snilay@cs.wisc.edu // Don't send an interrupt if there's already one 12937839Snilay@cs.wisc.edu if (cpuPendingIntr) { 12947839Snilay@cs.wisc.edu DPRINTF(EthernetIntr, 12957839Snilay@cs.wisc.edu "would send an interrupt now, but there's already pending\n"); 12967839Snilay@cs.wisc.edu } else { 12977839Snilay@cs.wisc.edu // Send interrupt 12987839Snilay@cs.wisc.edu cpuPendingIntr = true; 12997839Snilay@cs.wisc.edu 130011025Snilay@cs.wisc.edu DPRINTF(EthernetIntr, "posting interrupt\n"); 13016657Snate@binkert.org intrPost(); 13026657Snate@binkert.org } 13036657Snate@binkert.org} 13046657Snate@binkert.org 13056657Snate@binkert.orgvoid 13066657Snate@binkert.orgNSGigE::cpuIntrClear() 13076657Snate@binkert.org{ 13086657Snate@binkert.org if (!cpuPendingIntr) 13096657Snate@binkert.org return; 13106657Snate@binkert.org 13116657Snate@binkert.org if (intrEvent) { 13126999Snate@binkert.org intrEvent->squash(); 13136657Snate@binkert.org intrEvent = 0; 13146657Snate@binkert.org } 131510964Sdavid.hashe@amd.com 131610964Sdavid.hashe@amd.com intrTick = 0; 131710964Sdavid.hashe@amd.com 131810964Sdavid.hashe@amd.com cpuPendingIntr = false; 131910964Sdavid.hashe@amd.com 132010964Sdavid.hashe@amd.com DPRINTF(EthernetIntr, "clearing interrupt\n"); 132110964Sdavid.hashe@amd.com intrClear(); 132210964Sdavid.hashe@amd.com} 132310964Sdavid.hashe@amd.com 132410964Sdavid.hashe@amd.combool 132510964Sdavid.hashe@amd.comNSGigE::cpuIntrPending() const 13266657Snate@binkert.org{ return cpuPendingIntr; } 13276657Snate@binkert.org 13289104Shestness@cs.utexas.eduvoid 13296657Snate@binkert.orgNSGigE::txReset() 13306657Snate@binkert.org{ 13316657Snate@binkert.org 13326657Snate@binkert.org DPRINTF(Ethernet, "transmit reset\n"); 13336657Snate@binkert.org 133410228Snilay@cs.wisc.edu CTDD = false; 133511111Snilay@cs.wisc.edu txEnable = false;; 13366657Snate@binkert.org txFragPtr = 0; 13376657Snate@binkert.org assert(txDescCnt == 0); 13386657Snate@binkert.org txFifo.clear(); 13396657Snate@binkert.org txState = txIdle; 13409105SBrad.Beckmann@amd.com assert(txDmaState == dmaIdle); 13419105SBrad.Beckmann@amd.com} 13429105SBrad.Beckmann@amd.com 13439105SBrad.Beckmann@amd.comvoid 13449105SBrad.Beckmann@amd.comNSGigE::rxReset() 13459105SBrad.Beckmann@amd.com{ 13469105SBrad.Beckmann@amd.com DPRINTF(Ethernet, "receive reset\n"); 13479105SBrad.Beckmann@amd.com 13486657Snate@binkert.org CRDD = false; 13496657Snate@binkert.org assert(rxPktBytes == 0); 13506657Snate@binkert.org rxEnable = false; 13516657Snate@binkert.org rxFragPtr = 0; 13526657Snate@binkert.org assert(rxDescCnt == 0); 13536657Snate@binkert.org assert(rxDmaState == dmaIdle); 13546657Snate@binkert.org rxFifo.clear(); 13559104Shestness@cs.utexas.edu rxState = rxIdle; 13569104Shestness@cs.utexas.edu} 13579104Shestness@cs.utexas.edu 13589104Shestness@cs.utexas.eduvoid 13596657Snate@binkert.orgNSGigE::regsReset() 13606657Snate@binkert.org{ 13616657Snate@binkert.org memset(®s, 0, sizeof(regs)); 13626657Snate@binkert.org regs.config = CFGR_LNKSTS; 13636657Snate@binkert.org regs.mear = 0x22; 13646657Snate@binkert.org regs.txcfg = 0x120; // set drain threshold to 1024 bytes and 13656657Snate@binkert.org // fill threshold to 32 bytes 13666657Snate@binkert.org regs.rxcfg = 0x4; // set drain threshold to 16 bytes 13676657Snate@binkert.org regs.srr = 0x0103; // set the silicon revision to rev B or 0x103 13686657Snate@binkert.org regs.mibc = MIBC_FRZ; 13697839Snilay@cs.wisc.edu regs.vdr = 0x81; // set the vlan tag type to 802.1q 13707839Snilay@cs.wisc.edu regs.tesr = 0xc000; // TBI capable of both full and half duplex 13717839Snilay@cs.wisc.edu 13727839Snilay@cs.wisc.edu extstsEnable = false; 13737839Snilay@cs.wisc.edu acceptBroadcast = false; 13747839Snilay@cs.wisc.edu acceptMulticast = false; 13757839Snilay@cs.wisc.edu acceptUnicast = false; 13767839Snilay@cs.wisc.edu acceptPerfect = false; 13777839Snilay@cs.wisc.edu acceptArp = false; 13787839Snilay@cs.wisc.edu} 13797839Snilay@cs.wisc.edu 13807839Snilay@cs.wisc.eduvoid 13816657Snate@binkert.orgNSGigE::rxDmaReadCopy() 13826657Snate@binkert.org{ 13836657Snate@binkert.org assert(rxDmaState == dmaReading); 13846657Snate@binkert.org 13856657Snate@binkert.org physmem->dma_read((uint8_t *)rxDmaData, rxDmaAddr, rxDmaLen); 13866657Snate@binkert.org rxDmaState = dmaIdle; 13876657Snate@binkert.org 13886657Snate@binkert.org DPRINTF(EthernetDMA, "rx dma read paddr=%#x len=%d\n", 13896657Snate@binkert.org rxDmaAddr, rxDmaLen); 13906657Snate@binkert.org DDUMP(EthernetDMA, rxDmaData, rxDmaLen); 13916657Snate@binkert.org} 13926657Snate@binkert.org 13936657Snate@binkert.orgbool 13946657Snate@binkert.orgNSGigE::doRxDmaRead() 13956657Snate@binkert.org{ 13966657Snate@binkert.org assert(rxDmaState == dmaIdle || rxDmaState == dmaReadWaiting); 13976657Snate@binkert.org rxDmaState = dmaReading; 139810305Snilay@cs.wisc.edu 13996657Snate@binkert.org if (dmaInterface && !rxDmaFree) { 14006657Snate@binkert.org if (dmaInterface->busy()) 14016657Snate@binkert.org rxDmaState = dmaReadWaiting; 140210962SBrad.Beckmann@amd.com else 14038159SBrad.Beckmann@amd.com dmaInterface->doDMA(Read, rxDmaAddr, rxDmaLen, curTick, 14049465Snilay@cs.wisc.edu &rxDmaReadEvent, true); 14056657Snate@binkert.org return true; 140610305Snilay@cs.wisc.edu } 14076657Snate@binkert.org 14086657Snate@binkert.org if (dmaReadDelay == 0 && dmaReadFactor == 0) { 14096657Snate@binkert.org rxDmaReadCopy(); 14106657Snate@binkert.org return false; 14116657Snate@binkert.org } 14126657Snate@binkert.org 14136657Snate@binkert.org Tick factor = ((rxDmaLen + ULL(63)) >> ULL(6)) * dmaReadFactor; 14146657Snate@binkert.org Tick start = curTick + dmaReadDelay + factor; 14156657Snate@binkert.org rxDmaReadEvent.schedule(start); 14167007Snate@binkert.org return true; 14176999Snate@binkert.org} 14187007Snate@binkert.org 14197007Snate@binkert.orgvoid 14207007Snate@binkert.orgNSGigE::rxDmaReadDone() 14217007Snate@binkert.org{ 14227007Snate@binkert.org assert(rxDmaState == dmaReading); 14237007Snate@binkert.org rxDmaReadCopy(); 14246657Snate@binkert.org 14256657Snate@binkert.org // If the transmit state machine has a pending DMA, let it go first 14266657Snate@binkert.org if (txDmaState == dmaReadWaiting || txDmaState == dmaWriteWaiting) 14276657Snate@binkert.org txKick(); 14286657Snate@binkert.org 14296657Snate@binkert.org rxKick(); 14306657Snate@binkert.org} 14316657Snate@binkert.org 14326657Snate@binkert.orgvoid 14336657Snate@binkert.orgNSGigE::rxDmaWriteCopy() 14346657Snate@binkert.org{ 14356657Snate@binkert.org assert(rxDmaState == dmaWriting); 14366657Snate@binkert.org 14376657Snate@binkert.org physmem->dma_write(rxDmaAddr, (uint8_t *)rxDmaData, rxDmaLen); 14386657Snate@binkert.org rxDmaState = dmaIdle; 14396657Snate@binkert.org 14406657Snate@binkert.org DPRINTF(EthernetDMA, "rx dma write paddr=%#x len=%d\n", 14416657Snate@binkert.org rxDmaAddr, rxDmaLen); 14426657Snate@binkert.org DDUMP(EthernetDMA, rxDmaData, rxDmaLen); 14436657Snate@binkert.org} 14446657Snate@binkert.org 14456657Snate@binkert.orgbool 14466657Snate@binkert.orgNSGigE::doRxDmaWrite() 14476657Snate@binkert.org{ 14486657Snate@binkert.org assert(rxDmaState == dmaIdle || rxDmaState == dmaWriteWaiting); 14496657Snate@binkert.org rxDmaState = dmaWriting; 14506657Snate@binkert.org 14516657Snate@binkert.org if (dmaInterface && !rxDmaFree) { 14526657Snate@binkert.org if (dmaInterface->busy()) 14536999Snate@binkert.org rxDmaState = dmaWriteWaiting; 14546657Snate@binkert.org else 14556657Snate@binkert.org dmaInterface->doDMA(WriteInvalidate, rxDmaAddr, rxDmaLen, curTick, 14567007Snate@binkert.org &rxDmaWriteEvent, true); 14577007Snate@binkert.org return true; 14586657Snate@binkert.org } 14596657Snate@binkert.org 14606657Snate@binkert.org if (dmaWriteDelay == 0 && dmaWriteFactor == 0) { 14616657Snate@binkert.org rxDmaWriteCopy(); 14626657Snate@binkert.org return false; 14636657Snate@binkert.org } 14646657Snate@binkert.org 14656657Snate@binkert.org Tick factor = ((rxDmaLen + ULL(63)) >> ULL(6)) * dmaWriteFactor; 14666657Snate@binkert.org Tick start = curTick + dmaWriteDelay + factor; 14676657Snate@binkert.org rxDmaWriteEvent.schedule(start); 14686657Snate@binkert.org return true; 14696657Snate@binkert.org} 14706657Snate@binkert.org 14716657Snate@binkert.orgvoid 14726657Snate@binkert.orgNSGigE::rxDmaWriteDone() 14736657Snate@binkert.org{ 14746657Snate@binkert.org assert(rxDmaState == dmaWriting); 14756657Snate@binkert.org rxDmaWriteCopy(); 14766657Snate@binkert.org 14776657Snate@binkert.org // If the transmit state machine has a pending DMA, let it go first 14786657Snate@binkert.org if (txDmaState == dmaReadWaiting || txDmaState == dmaWriteWaiting) 14796657Snate@binkert.org txKick(); 14806657Snate@binkert.org 14816657Snate@binkert.org rxKick(); 14826657Snate@binkert.org} 14836657Snate@binkert.org 14846657Snate@binkert.orgvoid 14856657Snate@binkert.orgNSGigE::rxKick() 14866657Snate@binkert.org{ 14876657Snate@binkert.org DPRINTF(EthernetSM, "receive kick rxState=%s (rxBuf.size=%d)\n", 14886657Snate@binkert.org NsRxStateStrings[rxState], rxFifo.size()); 14896657Snate@binkert.org 14906657Snate@binkert.org if (rxKickTick > curTick) { 14916657Snate@binkert.org DPRINTF(EthernetSM, "receive kick exiting, can't run till %d\n", 14926657Snate@binkert.org rxKickTick); 14936657Snate@binkert.org return; 14946657Snate@binkert.org } 14956657Snate@binkert.org 14966657Snate@binkert.org next: 14976657Snate@binkert.org switch(rxDmaState) { 14986657Snate@binkert.org case dmaReadWaiting: 14996657Snate@binkert.org if (doRxDmaRead()) 15006657Snate@binkert.org goto exit; 15016657Snate@binkert.org break; 15026657Snate@binkert.org case dmaWriteWaiting: 15036657Snate@binkert.org if (doRxDmaWrite()) 15046657Snate@binkert.org goto exit; 15056657Snate@binkert.org break; 15066657Snate@binkert.org default: 15076657Snate@binkert.org break; 15086657Snate@binkert.org } 15096657Snate@binkert.org 15106657Snate@binkert.org // see state machine from spec for details 15116657Snate@binkert.org // the way this works is, if you finish work on one state and can 15126657Snate@binkert.org // go directly to another, you do that through jumping to the 15136657Snate@binkert.org // label "next". however, if you have intermediate work, like DMA 15146657Snate@binkert.org // so that you can't go to the next state yet, you go to exit and 15156657Snate@binkert.org // exit the loop. however, when the DMA is done it will trigger 15166657Snate@binkert.org // an event and come back to this loop. 15176657Snate@binkert.org switch (rxState) { 15186657Snate@binkert.org case rxIdle: 15196657Snate@binkert.org if (!rxEnable) { 15206657Snate@binkert.org DPRINTF(EthernetSM, "Receive Disabled! Nothing to do.\n"); 15216657Snate@binkert.org goto exit; 15226657Snate@binkert.org } 15236657Snate@binkert.org 15246657Snate@binkert.org if (CRDD) { 15256657Snate@binkert.org rxState = rxDescRefr; 15266657Snate@binkert.org 15276657Snate@binkert.org rxDmaAddr = regs.rxdp & 0x3fffffff; 15286657Snate@binkert.org rxDmaData = &rxDescCache + offsetof(ns_desc, link); 15296657Snate@binkert.org rxDmaLen = sizeof(rxDescCache.link); 15306657Snate@binkert.org rxDmaFree = dmaDescFree; 15316657Snate@binkert.org 15326657Snate@binkert.org descDmaReads++; 15336657Snate@binkert.org descDmaRdBytes += rxDmaLen; 15346657Snate@binkert.org 15356657Snate@binkert.org if (doRxDmaRead()) 15366657Snate@binkert.org goto exit; 15376657Snate@binkert.org } else { 15386657Snate@binkert.org rxState = rxDescRead; 15396657Snate@binkert.org 15406657Snate@binkert.org rxDmaAddr = regs.rxdp & 0x3fffffff; 15416657Snate@binkert.org rxDmaData = &rxDescCache; 15426657Snate@binkert.org rxDmaLen = sizeof(ns_desc); 15436657Snate@binkert.org rxDmaFree = dmaDescFree; 15446657Snate@binkert.org 15456657Snate@binkert.org descDmaReads++; 15467007Snate@binkert.org descDmaRdBytes += rxDmaLen; 15476657Snate@binkert.org 15486657Snate@binkert.org if (doRxDmaRead()) 15496657Snate@binkert.org goto exit; 15506657Snate@binkert.org } 15516657Snate@binkert.org break; 15526657Snate@binkert.org 15536657Snate@binkert.org case rxDescRefr: 15547007Snate@binkert.org if (rxDmaState != dmaIdle) 15556657Snate@binkert.org goto exit; 15566657Snate@binkert.org 15576657Snate@binkert.org rxState = rxAdvance; 15586657Snate@binkert.org break; 15596657Snate@binkert.org 15606657Snate@binkert.org case rxDescRead: 15616657Snate@binkert.org if (rxDmaState != dmaIdle) 15626657Snate@binkert.org goto exit; 15636657Snate@binkert.org 15646657Snate@binkert.org DPRINTF(EthernetDesc, 15656657Snate@binkert.org "rxDescCache: addr=%08x read descriptor\n", 15666657Snate@binkert.org regs.rxdp & 0x3fffffff); 15676657Snate@binkert.org DPRINTF(EthernetDesc, 15686657Snate@binkert.org "rxDescCache: link=%08x bufptr=%08x cmdsts=%08x extsts=%08x\n", 15696657Snate@binkert.org rxDescCache.link, rxDescCache.bufptr, rxDescCache.cmdsts, 157010917Sbrandon.potter@amd.com rxDescCache.extsts); 15716657Snate@binkert.org 15726657Snate@binkert.org if (rxDescCache.cmdsts & CMDSTS_OWN) { 15736657Snate@binkert.org devIntrPost(ISR_RXIDLE); 15746657Snate@binkert.org rxState = rxIdle; 15756657Snate@binkert.org goto exit; 15766657Snate@binkert.org } else { 15776657Snate@binkert.org rxState = rxFifoBlock; 15786657Snate@binkert.org rxFragPtr = rxDescCache.bufptr; 15796657Snate@binkert.org rxDescCnt = rxDescCache.cmdsts & CMDSTS_LEN_MASK; 15806657Snate@binkert.org } 15816657Snate@binkert.org break; 15826657Snate@binkert.org 15836657Snate@binkert.org case rxFifoBlock: 15846657Snate@binkert.org if (!rxPacket) { 15856657Snate@binkert.org /** 15866657Snate@binkert.org * @todo in reality, we should be able to start processing 15876657Snate@binkert.org * the packet as it arrives, and not have to wait for the 15886657Snate@binkert.org * full packet ot be in the receive fifo. 15896657Snate@binkert.org */ 15906657Snate@binkert.org if (rxFifo.empty()) 15916657Snate@binkert.org goto exit; 15926657Snate@binkert.org 1593 DPRINTF(EthernetSM, "****processing receive of new packet****\n"); 1594 1595 // If we don't have a packet, grab a new one from the fifo. 1596 rxPacket = rxFifo.front(); 1597 rxPktBytes = rxPacket->length; 1598 rxPacketBufPtr = rxPacket->data; 1599 1600#if TRACING_ON 1601 if (DTRACE(Ethernet)) { 1602 IpPtr ip(rxPacket); 1603 if (ip) { 1604 DPRINTF(Ethernet, "ID is %d\n", ip->id()); 1605 TcpPtr tcp(ip); 1606 if (tcp) { 1607 DPRINTF(Ethernet, 1608 "Src Port=%d, Dest Port=%d, Seq=%d, Ack=%d\n", 1609 tcp->sport(), tcp->dport(), tcp->seq(), 1610 tcp->ack()); 1611 } 1612 } 1613 } 1614#endif 1615 1616 // sanity check - i think the driver behaves like this 1617 assert(rxDescCnt >= rxPktBytes); 1618 rxFifo.pop(); 1619 } 1620 1621 1622 // dont' need the && rxDescCnt > 0 if driver sanity check 1623 // above holds 1624 if (rxPktBytes > 0) { 1625 rxState = rxFragWrite; 1626 // don't need min<>(rxPktBytes,rxDescCnt) if above sanity 1627 // check holds 1628 rxXferLen = rxPktBytes; 1629 1630 rxDmaAddr = rxFragPtr & 0x3fffffff; 1631 rxDmaData = rxPacketBufPtr; 1632 rxDmaLen = rxXferLen; 1633 rxDmaFree = dmaDataFree; 1634 1635 if (doRxDmaWrite()) 1636 goto exit; 1637 1638 } else { 1639 rxState = rxDescWrite; 1640 1641 //if (rxPktBytes == 0) { /* packet is done */ 1642 assert(rxPktBytes == 0); 1643 DPRINTF(EthernetSM, "done with receiving packet\n"); 1644 1645 rxDescCache.cmdsts |= CMDSTS_OWN; 1646 rxDescCache.cmdsts &= ~CMDSTS_MORE; 1647 rxDescCache.cmdsts |= CMDSTS_OK; 1648 rxDescCache.cmdsts &= 0xffff0000; 1649 rxDescCache.cmdsts += rxPacket->length; //i.e. set CMDSTS_SIZE 1650 1651#if 0 1652 /* 1653 * all the driver uses these are for its own stats keeping 1654 * which we don't care about, aren't necessary for 1655 * functionality and doing this would just slow us down. 1656 * if they end up using this in a later version for 1657 * functional purposes, just undef 1658 */ 1659 if (rxFilterEnable) { 1660 rxDescCache.cmdsts &= ~CMDSTS_DEST_MASK; 1661 const EthAddr &dst = rxFifoFront()->dst(); 1662 if (dst->unicast()) 1663 rxDescCache.cmdsts |= CMDSTS_DEST_SELF; 1664 if (dst->multicast()) 1665 rxDescCache.cmdsts |= CMDSTS_DEST_MULTI; 1666 if (dst->broadcast()) 1667 rxDescCache.cmdsts |= CMDSTS_DEST_MASK; 1668 } 1669#endif 1670 1671 IpPtr ip(rxPacket); 1672 if (extstsEnable && ip) { 1673 rxDescCache.extsts |= EXTSTS_IPPKT; 1674 rxIpChecksums++; 1675 if (cksum(ip) != 0) { 1676 DPRINTF(EthernetCksum, "Rx IP Checksum Error\n"); 1677 rxDescCache.extsts |= EXTSTS_IPERR; 1678 } 1679 TcpPtr tcp(ip); 1680 UdpPtr udp(ip); 1681 if (tcp) { 1682 rxDescCache.extsts |= EXTSTS_TCPPKT; 1683 rxTcpChecksums++; 1684 if (cksum(tcp) != 0) { 1685 DPRINTF(EthernetCksum, "Rx TCP Checksum Error\n"); 1686 rxDescCache.extsts |= EXTSTS_TCPERR; 1687 1688 } 1689 } else if (udp) { 1690 rxDescCache.extsts |= EXTSTS_UDPPKT; 1691 rxUdpChecksums++; 1692 if (cksum(udp) != 0) { 1693 DPRINTF(EthernetCksum, "Rx UDP Checksum Error\n"); 1694 rxDescCache.extsts |= EXTSTS_UDPERR; 1695 } 1696 } 1697 } 1698 rxPacket = 0; 1699 1700 /* 1701 * the driver seems to always receive into desc buffers 1702 * of size 1514, so you never have a pkt that is split 1703 * into multiple descriptors on the receive side, so 1704 * i don't implement that case, hence the assert above. 1705 */ 1706 1707 DPRINTF(EthernetDesc, 1708 "rxDescCache: addr=%08x writeback cmdsts extsts\n", 1709 regs.rxdp & 0x3fffffff); 1710 DPRINTF(EthernetDesc, 1711 "rxDescCache: link=%08x bufptr=%08x cmdsts=%08x extsts=%08x\n", 1712 rxDescCache.link, rxDescCache.bufptr, rxDescCache.cmdsts, 1713 rxDescCache.extsts); 1714 1715 rxDmaAddr = (regs.rxdp + offsetof(ns_desc, cmdsts)) & 0x3fffffff; 1716 rxDmaData = &(rxDescCache.cmdsts); 1717 rxDmaLen = sizeof(rxDescCache.cmdsts) + sizeof(rxDescCache.extsts); 1718 rxDmaFree = dmaDescFree; 1719 1720 descDmaWrites++; 1721 descDmaWrBytes += rxDmaLen; 1722 1723 if (doRxDmaWrite()) 1724 goto exit; 1725 } 1726 break; 1727 1728 case rxFragWrite: 1729 if (rxDmaState != dmaIdle) 1730 goto exit; 1731 1732 rxPacketBufPtr += rxXferLen; 1733 rxFragPtr += rxXferLen; 1734 rxPktBytes -= rxXferLen; 1735 1736 rxState = rxFifoBlock; 1737 break; 1738 1739 case rxDescWrite: 1740 if (rxDmaState != dmaIdle) 1741 goto exit; 1742 1743 assert(rxDescCache.cmdsts & CMDSTS_OWN); 1744 1745 assert(rxPacket == 0); 1746 devIntrPost(ISR_RXOK); 1747 1748 if (rxDescCache.cmdsts & CMDSTS_INTR) 1749 devIntrPost(ISR_RXDESC); 1750 1751 if (!rxEnable) { 1752 DPRINTF(EthernetSM, "Halting the RX state machine\n"); 1753 rxState = rxIdle; 1754 goto exit; 1755 } else 1756 rxState = rxAdvance; 1757 break; 1758 1759 case rxAdvance: 1760 if (rxDescCache.link == 0) { 1761 devIntrPost(ISR_RXIDLE); 1762 rxState = rxIdle; 1763 CRDD = true; 1764 goto exit; 1765 } else { 1766 rxState = rxDescRead; 1767 regs.rxdp = rxDescCache.link; 1768 CRDD = false; 1769 1770 rxDmaAddr = regs.rxdp & 0x3fffffff; 1771 rxDmaData = &rxDescCache; 1772 rxDmaLen = sizeof(ns_desc); 1773 rxDmaFree = dmaDescFree; 1774 1775 if (doRxDmaRead()) 1776 goto exit; 1777 } 1778 break; 1779 1780 default: 1781 panic("Invalid rxState!"); 1782 } 1783 1784 DPRINTF(EthernetSM, "entering next rxState=%s\n", 1785 NsRxStateStrings[rxState]); 1786 1787 goto next; 1788 1789 exit: 1790 /** 1791 * @todo do we want to schedule a future kick? 1792 */ 1793 DPRINTF(EthernetSM, "rx state machine exited rxState=%s\n", 1794 NsRxStateStrings[rxState]); 1795} 1796 1797void 1798NSGigE::transmit() 1799{ 1800 if (txFifo.empty()) { 1801 DPRINTF(Ethernet, "nothing to transmit\n"); 1802 return; 1803 } 1804 1805 DPRINTF(Ethernet, "Attempt Pkt Transmit: txFifo length=%d\n", 1806 txFifo.size()); 1807 if (interface->sendPacket(txFifo.front())) { 1808#if TRACING_ON 1809 if (DTRACE(Ethernet)) { 1810 IpPtr ip(txFifo.front()); 1811 if (ip) { 1812 DPRINTF(Ethernet, "ID is %d\n", ip->id()); 1813 TcpPtr tcp(ip); 1814 if (tcp) { 1815 DPRINTF(Ethernet, 1816 "Src Port=%d, Dest Port=%d, Seq=%d, Ack=%d\n", 1817 tcp->sport(), tcp->dport(), tcp->seq(), tcp->ack()); 1818 } 1819 } 1820 } 1821#endif 1822 1823 DDUMP(EthernetData, txFifo.front()->data, txFifo.front()->length); 1824 txBytes += txFifo.front()->length; 1825 txPackets++; 1826 1827 DPRINTF(Ethernet, "Successful Xmit! now txFifoAvail is %d\n", 1828 txFifo.avail()); 1829 txFifo.pop(); 1830 1831 /* 1832 * normally do a writeback of the descriptor here, and ONLY 1833 * after that is done, send this interrupt. but since our 1834 * stuff never actually fails, just do this interrupt here, 1835 * otherwise the code has to stray from this nice format. 1836 * besides, it's functionally the same. 1837 */ 1838 devIntrPost(ISR_TXOK); 1839 } 1840 1841 if (!txFifo.empty() && !txEvent.scheduled()) { 1842 DPRINTF(Ethernet, "reschedule transmit\n"); 1843 txEvent.schedule(curTick + retryTime); 1844 } 1845} 1846 1847void 1848NSGigE::txDmaReadCopy() 1849{ 1850 assert(txDmaState == dmaReading); 1851 1852 physmem->dma_read((uint8_t *)txDmaData, txDmaAddr, txDmaLen); 1853 txDmaState = dmaIdle; 1854 1855 DPRINTF(EthernetDMA, "tx dma read paddr=%#x len=%d\n", 1856 txDmaAddr, txDmaLen); 1857 DDUMP(EthernetDMA, txDmaData, txDmaLen); 1858} 1859 1860bool 1861NSGigE::doTxDmaRead() 1862{ 1863 assert(txDmaState == dmaIdle || txDmaState == dmaReadWaiting); 1864 txDmaState = dmaReading; 1865 1866 if (dmaInterface && !txDmaFree) { 1867 if (dmaInterface->busy()) 1868 txDmaState = dmaReadWaiting; 1869 else 1870 dmaInterface->doDMA(Read, txDmaAddr, txDmaLen, curTick, 1871 &txDmaReadEvent, true); 1872 return true; 1873 } 1874 1875 if (dmaReadDelay == 0 && dmaReadFactor == 0.0) { 1876 txDmaReadCopy(); 1877 return false; 1878 } 1879 1880 Tick factor = ((txDmaLen + ULL(63)) >> ULL(6)) * dmaReadFactor; 1881 Tick start = curTick + dmaReadDelay + factor; 1882 txDmaReadEvent.schedule(start); 1883 return true; 1884} 1885 1886void 1887NSGigE::txDmaReadDone() 1888{ 1889 assert(txDmaState == dmaReading); 1890 txDmaReadCopy(); 1891 1892 // If the receive state machine has a pending DMA, let it go first 1893 if (rxDmaState == dmaReadWaiting || rxDmaState == dmaWriteWaiting) 1894 rxKick(); 1895 1896 txKick(); 1897} 1898 1899void 1900NSGigE::txDmaWriteCopy() 1901{ 1902 assert(txDmaState == dmaWriting); 1903 1904 physmem->dma_write(txDmaAddr, (uint8_t *)txDmaData, txDmaLen); 1905 txDmaState = dmaIdle; 1906 1907 DPRINTF(EthernetDMA, "tx dma write paddr=%#x len=%d\n", 1908 txDmaAddr, txDmaLen); 1909 DDUMP(EthernetDMA, txDmaData, txDmaLen); 1910} 1911 1912bool 1913NSGigE::doTxDmaWrite() 1914{ 1915 assert(txDmaState == dmaIdle || txDmaState == dmaWriteWaiting); 1916 txDmaState = dmaWriting; 1917 1918 if (dmaInterface && !txDmaFree) { 1919 if (dmaInterface->busy()) 1920 txDmaState = dmaWriteWaiting; 1921 else 1922 dmaInterface->doDMA(WriteInvalidate, txDmaAddr, txDmaLen, curTick, 1923 &txDmaWriteEvent, true); 1924 return true; 1925 } 1926 1927 if (dmaWriteDelay == 0 && dmaWriteFactor == 0.0) { 1928 txDmaWriteCopy(); 1929 return false; 1930 } 1931 1932 Tick factor = ((txDmaLen + ULL(63)) >> ULL(6)) * dmaWriteFactor; 1933 Tick start = curTick + dmaWriteDelay + factor; 1934 txDmaWriteEvent.schedule(start); 1935 return true; 1936} 1937 1938void 1939NSGigE::txDmaWriteDone() 1940{ 1941 assert(txDmaState == dmaWriting); 1942 txDmaWriteCopy(); 1943 1944 // If the receive state machine has a pending DMA, let it go first 1945 if (rxDmaState == dmaReadWaiting || rxDmaState == dmaWriteWaiting) 1946 rxKick(); 1947 1948 txKick(); 1949} 1950 1951void 1952NSGigE::txKick() 1953{ 1954 DPRINTF(EthernetSM, "transmit kick txState=%s\n", 1955 NsTxStateStrings[txState]); 1956 1957 if (txKickTick > curTick) { 1958 DPRINTF(EthernetSM, "transmit kick exiting, can't run till %d\n", 1959 txKickTick); 1960 1961 return; 1962 } 1963 1964 next: 1965 switch(txDmaState) { 1966 case dmaReadWaiting: 1967 if (doTxDmaRead()) 1968 goto exit; 1969 break; 1970 case dmaWriteWaiting: 1971 if (doTxDmaWrite()) 1972 goto exit; 1973 break; 1974 default: 1975 break; 1976 } 1977 1978 switch (txState) { 1979 case txIdle: 1980 if (!txEnable) { 1981 DPRINTF(EthernetSM, "Transmit disabled. Nothing to do.\n"); 1982 goto exit; 1983 } 1984 1985 if (CTDD) { 1986 txState = txDescRefr; 1987 1988 txDmaAddr = regs.txdp & 0x3fffffff; 1989 txDmaData = &txDescCache + offsetof(ns_desc, link); 1990 txDmaLen = sizeof(txDescCache.link); 1991 txDmaFree = dmaDescFree; 1992 1993 descDmaReads++; 1994 descDmaRdBytes += txDmaLen; 1995 1996 if (doTxDmaRead()) 1997 goto exit; 1998 1999 } else { 2000 txState = txDescRead; 2001 2002 txDmaAddr = regs.txdp & 0x3fffffff; 2003 txDmaData = &txDescCache; 2004 txDmaLen = sizeof(ns_desc); 2005 txDmaFree = dmaDescFree; 2006 2007 descDmaReads++; 2008 descDmaRdBytes += txDmaLen; 2009 2010 if (doTxDmaRead()) 2011 goto exit; 2012 } 2013 break; 2014 2015 case txDescRefr: 2016 if (txDmaState != dmaIdle) 2017 goto exit; 2018 2019 txState = txAdvance; 2020 break; 2021 2022 case txDescRead: 2023 if (txDmaState != dmaIdle) 2024 goto exit; 2025 2026 DPRINTF(EthernetDesc, 2027 "txDescCache: link=%08x bufptr=%08x cmdsts=%08x extsts=%08x\n", 2028 txDescCache.link, txDescCache.bufptr, txDescCache.cmdsts, 2029 txDescCache.extsts); 2030 2031 if (txDescCache.cmdsts & CMDSTS_OWN) { 2032 txState = txFifoBlock; 2033 txFragPtr = txDescCache.bufptr; 2034 txDescCnt = txDescCache.cmdsts & CMDSTS_LEN_MASK; 2035 } else { 2036 devIntrPost(ISR_TXIDLE); 2037 txState = txIdle; 2038 goto exit; 2039 } 2040 break; 2041 2042 case txFifoBlock: 2043 if (!txPacket) { 2044 DPRINTF(EthernetSM, "****starting the tx of a new packet****\n"); 2045 txPacket = new PacketData(16384); 2046 txPacketBufPtr = txPacket->data; 2047 } 2048 2049 if (txDescCnt == 0) { 2050 DPRINTF(EthernetSM, "the txDescCnt == 0, done with descriptor\n"); 2051 if (txDescCache.cmdsts & CMDSTS_MORE) { 2052 DPRINTF(EthernetSM, "there are more descriptors to come\n"); 2053 txState = txDescWrite; 2054 2055 txDescCache.cmdsts &= ~CMDSTS_OWN; 2056 2057 txDmaAddr = regs.txdp + offsetof(ns_desc, cmdsts); 2058 txDmaAddr &= 0x3fffffff; 2059 txDmaData = &(txDescCache.cmdsts); 2060 txDmaLen = sizeof(txDescCache.cmdsts); 2061 txDmaFree = dmaDescFree; 2062 2063 if (doTxDmaWrite()) 2064 goto exit; 2065 2066 } else { /* this packet is totally done */ 2067 DPRINTF(EthernetSM, "This packet is done, let's wrap it up\n"); 2068 /* deal with the the packet that just finished */ 2069 if ((regs.vtcr & VTCR_PPCHK) && extstsEnable) { 2070 IpPtr ip(txPacket); 2071 if (txDescCache.extsts & EXTSTS_UDPPKT) { 2072 UdpPtr udp(ip); 2073 udp->sum(0); 2074 udp->sum(cksum(udp)); 2075 txUdpChecksums++; 2076 } else if (txDescCache.extsts & EXTSTS_TCPPKT) { 2077 TcpPtr tcp(ip); 2078 tcp->sum(0); 2079 tcp->sum(cksum(tcp)); 2080 txTcpChecksums++; 2081 } 2082 if (txDescCache.extsts & EXTSTS_IPPKT) { 2083 ip->sum(0); 2084 ip->sum(cksum(ip)); 2085 txIpChecksums++; 2086 } 2087 } 2088 2089 txPacket->length = txPacketBufPtr - txPacket->data; 2090 // this is just because the receive can't handle a 2091 // packet bigger want to make sure 2092 assert(txPacket->length <= 1514); 2093#ifndef NDEBUG 2094 bool success = 2095#endif 2096 txFifo.push(txPacket); 2097 assert(success); 2098 2099 /* 2100 * this following section is not tqo spec, but 2101 * functionally shouldn't be any different. normally, 2102 * the chip will wait til the transmit has occurred 2103 * before writing back the descriptor because it has 2104 * to wait to see that it was successfully transmitted 2105 * to decide whether to set CMDSTS_OK or not. 2106 * however, in the simulator since it is always 2107 * successfully transmitted, and writing it exactly to 2108 * spec would complicate the code, we just do it here 2109 */ 2110 2111 txDescCache.cmdsts &= ~CMDSTS_OWN; 2112 txDescCache.cmdsts |= CMDSTS_OK; 2113 2114 DPRINTF(EthernetDesc, 2115 "txDesc writeback: cmdsts=%08x extsts=%08x\n", 2116 txDescCache.cmdsts, txDescCache.extsts); 2117 2118 txDmaAddr = regs.txdp + offsetof(ns_desc, cmdsts); 2119 txDmaAddr &= 0x3fffffff; 2120 txDmaData = &(txDescCache.cmdsts); 2121 txDmaLen = sizeof(txDescCache.cmdsts) + 2122 sizeof(txDescCache.extsts); 2123 txDmaFree = dmaDescFree; 2124 2125 descDmaWrites++; 2126 descDmaWrBytes += txDmaLen; 2127 2128 transmit(); 2129 txPacket = 0; 2130 2131 if (!txEnable) { 2132 DPRINTF(EthernetSM, "halting TX state machine\n"); 2133 txState = txIdle; 2134 goto exit; 2135 } else 2136 txState = txAdvance; 2137 2138 if (doTxDmaWrite()) 2139 goto exit; 2140 } 2141 } else { 2142 DPRINTF(EthernetSM, "this descriptor isn't done yet\n"); 2143 if (!txFifo.full()) { 2144 txState = txFragRead; 2145 2146 /* 2147 * The number of bytes transferred is either whatever 2148 * is left in the descriptor (txDescCnt), or if there 2149 * is not enough room in the fifo, just whatever room 2150 * is left in the fifo 2151 */ 2152 txXferLen = min<uint32_t>(txDescCnt, txFifo.avail()); 2153 2154 txDmaAddr = txFragPtr & 0x3fffffff; 2155 txDmaData = txPacketBufPtr; 2156 txDmaLen = txXferLen; 2157 txDmaFree = dmaDataFree; 2158 2159 if (doTxDmaRead()) 2160 goto exit; 2161 } else { 2162 txState = txFifoBlock; 2163 transmit(); 2164 2165 goto exit; 2166 } 2167 2168 } 2169 break; 2170 2171 case txFragRead: 2172 if (txDmaState != dmaIdle) 2173 goto exit; 2174 2175 txPacketBufPtr += txXferLen; 2176 txFragPtr += txXferLen; 2177 txDescCnt -= txXferLen; 2178 txFifo.reserve(txXferLen); 2179 2180 txState = txFifoBlock; 2181 break; 2182 2183 case txDescWrite: 2184 if (txDmaState != dmaIdle) 2185 goto exit; 2186 2187 if (txDescCache.cmdsts & CMDSTS_INTR) 2188 devIntrPost(ISR_TXDESC); 2189 2190 txState = txAdvance; 2191 break; 2192 2193 case txAdvance: 2194 if (txDescCache.link == 0) { 2195 devIntrPost(ISR_TXIDLE); 2196 txState = txIdle; 2197 goto exit; 2198 } else { 2199 txState = txDescRead; 2200 regs.txdp = txDescCache.link; 2201 CTDD = false; 2202 2203 txDmaAddr = txDescCache.link & 0x3fffffff; 2204 txDmaData = &txDescCache; 2205 txDmaLen = sizeof(ns_desc); 2206 txDmaFree = dmaDescFree; 2207 2208 if (doTxDmaRead()) 2209 goto exit; 2210 } 2211 break; 2212 2213 default: 2214 panic("invalid state"); 2215 } 2216 2217 DPRINTF(EthernetSM, "entering next txState=%s\n", 2218 NsTxStateStrings[txState]); 2219 2220 goto next; 2221 2222 exit: 2223 /** 2224 * @todo do we want to schedule a future kick? 2225 */ 2226 DPRINTF(EthernetSM, "tx state machine exited txState=%s\n", 2227 NsTxStateStrings[txState]); 2228} 2229 2230void 2231NSGigE::transferDone() 2232{ 2233 if (txFifo.empty()) { 2234 DPRINTF(Ethernet, "transfer complete: txFifo empty...nothing to do\n"); 2235 return; 2236 } 2237 2238 DPRINTF(Ethernet, "transfer complete: data in txFifo...schedule xmit\n"); 2239 2240 if (txEvent.scheduled()) 2241 txEvent.reschedule(curTick + cycles(1)); 2242 else 2243 txEvent.schedule(curTick + cycles(1)); 2244} 2245 2246bool 2247NSGigE::rxFilter(const PacketPtr &packet) 2248{ 2249 EthPtr eth = packet; 2250 bool drop = true; 2251 string type; 2252 2253 const EthAddr &dst = eth->dst(); 2254 if (dst.unicast()) { 2255 // If we're accepting all unicast addresses 2256 if (acceptUnicast) 2257 drop = false; 2258 2259 // If we make a perfect match 2260 if (acceptPerfect && dst == rom.perfectMatch) 2261 drop = false; 2262 2263 if (acceptArp && eth->type() == ETH_TYPE_ARP) 2264 drop = false; 2265 2266 } else if (dst.broadcast()) { 2267 // if we're accepting broadcasts 2268 if (acceptBroadcast) 2269 drop = false; 2270 2271 } else if (dst.multicast()) { 2272 // if we're accepting all multicasts 2273 if (acceptMulticast) 2274 drop = false; 2275 2276 } 2277 2278 if (drop) { 2279 DPRINTF(Ethernet, "rxFilter drop\n"); 2280 DDUMP(EthernetData, packet->data, packet->length); 2281 } 2282 2283 return drop; 2284} 2285 2286bool 2287NSGigE::recvPacket(PacketPtr packet) 2288{ 2289 rxBytes += packet->length; 2290 rxPackets++; 2291 2292 DPRINTF(Ethernet, "Receiving packet from wire, rxFifoAvail=%d\n", 2293 rxFifo.avail()); 2294 2295 if (!rxEnable) { 2296 DPRINTF(Ethernet, "receive disabled...packet dropped\n"); 2297 debug_break(); 2298 interface->recvDone(); 2299 return true; 2300 } 2301 2302 if (rxFilterEnable && rxFilter(packet)) { 2303 DPRINTF(Ethernet, "packet filtered...dropped\n"); 2304 interface->recvDone(); 2305 return true; 2306 } 2307 2308 if (rxFifo.avail() < packet->length) { 2309#if TRACING_ON 2310 IpPtr ip(packet); 2311 TcpPtr tcp(ip); 2312 if (ip) { 2313 DPRINTF(Ethernet, 2314 "packet won't fit in receive buffer...pkt ID %d dropped\n", 2315 ip->id()); 2316 if (tcp) { 2317 DPRINTF(Ethernet, "Seq=%d\n", tcp->seq()); 2318 } 2319 } 2320#endif 2321 droppedPackets++; 2322 devIntrPost(ISR_RXORN); 2323 return false; 2324 } 2325 2326 rxFifo.push(packet); 2327 interface->recvDone(); 2328 2329 rxKick(); 2330 return true; 2331} 2332 2333//===================================================================== 2334// 2335// 2336void 2337NSGigE::serialize(ostream &os) 2338{ 2339 // Serialize the PciDev base class 2340 PciDev::serialize(os); 2341 2342 /* 2343 * Finalize any DMA events now. 2344 */ 2345 if (rxDmaReadEvent.scheduled()) 2346 rxDmaReadCopy(); 2347 if (rxDmaWriteEvent.scheduled()) 2348 rxDmaWriteCopy(); 2349 if (txDmaReadEvent.scheduled()) 2350 txDmaReadCopy(); 2351 if (txDmaWriteEvent.scheduled()) 2352 txDmaWriteCopy(); 2353 2354 /* 2355 * Serialize the device registers 2356 */ 2357 SERIALIZE_SCALAR(regs.command); 2358 SERIALIZE_SCALAR(regs.config); 2359 SERIALIZE_SCALAR(regs.mear); 2360 SERIALIZE_SCALAR(regs.ptscr); 2361 SERIALIZE_SCALAR(regs.isr); 2362 SERIALIZE_SCALAR(regs.imr); 2363 SERIALIZE_SCALAR(regs.ier); 2364 SERIALIZE_SCALAR(regs.ihr); 2365 SERIALIZE_SCALAR(regs.txdp); 2366 SERIALIZE_SCALAR(regs.txdp_hi); 2367 SERIALIZE_SCALAR(regs.txcfg); 2368 SERIALIZE_SCALAR(regs.gpior); 2369 SERIALIZE_SCALAR(regs.rxdp); 2370 SERIALIZE_SCALAR(regs.rxdp_hi); 2371 SERIALIZE_SCALAR(regs.rxcfg); 2372 SERIALIZE_SCALAR(regs.pqcr); 2373 SERIALIZE_SCALAR(regs.wcsr); 2374 SERIALIZE_SCALAR(regs.pcr); 2375 SERIALIZE_SCALAR(regs.rfcr); 2376 SERIALIZE_SCALAR(regs.rfdr); 2377 SERIALIZE_SCALAR(regs.srr); 2378 SERIALIZE_SCALAR(regs.mibc); 2379 SERIALIZE_SCALAR(regs.vrcr); 2380 SERIALIZE_SCALAR(regs.vtcr); 2381 SERIALIZE_SCALAR(regs.vdr); 2382 SERIALIZE_SCALAR(regs.ccsr); 2383 SERIALIZE_SCALAR(regs.tbicr); 2384 SERIALIZE_SCALAR(regs.tbisr); 2385 SERIALIZE_SCALAR(regs.tanar); 2386 SERIALIZE_SCALAR(regs.tanlpar); 2387 SERIALIZE_SCALAR(regs.taner); 2388 SERIALIZE_SCALAR(regs.tesr); 2389 2390 SERIALIZE_ARRAY(rom.perfectMatch, ETH_ADDR_LEN); 2391 2392 SERIALIZE_SCALAR(ioEnable); 2393 2394 /* 2395 * Serialize the data Fifos 2396 */ 2397 rxFifo.serialize("rxFifo", os); 2398 txFifo.serialize("txFifo", os); 2399 2400 /* 2401 * Serialize the various helper variables 2402 */ 2403 bool txPacketExists = txPacket; 2404 SERIALIZE_SCALAR(txPacketExists); 2405 if (txPacketExists) { 2406 txPacket->length = txPacketBufPtr - txPacket->data; 2407 txPacket->serialize("txPacket", os); 2408 uint32_t txPktBufPtr = (uint32_t) (txPacketBufPtr - txPacket->data); 2409 SERIALIZE_SCALAR(txPktBufPtr); 2410 } 2411 2412 bool rxPacketExists = rxPacket; 2413 SERIALIZE_SCALAR(rxPacketExists); 2414 if (rxPacketExists) { 2415 rxPacket->serialize("rxPacket", os); 2416 uint32_t rxPktBufPtr = (uint32_t) (rxPacketBufPtr - rxPacket->data); 2417 SERIALIZE_SCALAR(rxPktBufPtr); 2418 } 2419 2420 SERIALIZE_SCALAR(txXferLen); 2421 SERIALIZE_SCALAR(rxXferLen); 2422 2423 /* 2424 * Serialize DescCaches 2425 */ 2426 SERIALIZE_SCALAR(txDescCache.link); 2427 SERIALIZE_SCALAR(txDescCache.bufptr); 2428 SERIALIZE_SCALAR(txDescCache.cmdsts); 2429 SERIALIZE_SCALAR(txDescCache.extsts); 2430 SERIALIZE_SCALAR(rxDescCache.link); 2431 SERIALIZE_SCALAR(rxDescCache.bufptr); 2432 SERIALIZE_SCALAR(rxDescCache.cmdsts); 2433 SERIALIZE_SCALAR(rxDescCache.extsts); 2434 2435 /* 2436 * Serialize tx state machine 2437 */ 2438 int txState = this->txState; 2439 SERIALIZE_SCALAR(txState); 2440 SERIALIZE_SCALAR(txEnable); 2441 SERIALIZE_SCALAR(CTDD); 2442 SERIALIZE_SCALAR(txFragPtr); 2443 SERIALIZE_SCALAR(txDescCnt); 2444 int txDmaState = this->txDmaState; 2445 SERIALIZE_SCALAR(txDmaState); 2446 2447 /* 2448 * Serialize rx state machine 2449 */ 2450 int rxState = this->rxState; 2451 SERIALIZE_SCALAR(rxState); 2452 SERIALIZE_SCALAR(rxEnable); 2453 SERIALIZE_SCALAR(CRDD); 2454 SERIALIZE_SCALAR(rxPktBytes); 2455 SERIALIZE_SCALAR(rxFragPtr); 2456 SERIALIZE_SCALAR(rxDescCnt); 2457 int rxDmaState = this->rxDmaState; 2458 SERIALIZE_SCALAR(rxDmaState); 2459 2460 SERIALIZE_SCALAR(extstsEnable); 2461 2462 /* 2463 * If there's a pending transmit, store the time so we can 2464 * reschedule it later 2465 */ 2466 Tick transmitTick = txEvent.scheduled() ? txEvent.when() - curTick : 0; 2467 SERIALIZE_SCALAR(transmitTick); 2468 2469 /* 2470 * receive address filter settings 2471 */ 2472 SERIALIZE_SCALAR(rxFilterEnable); 2473 SERIALIZE_SCALAR(acceptBroadcast); 2474 SERIALIZE_SCALAR(acceptMulticast); 2475 SERIALIZE_SCALAR(acceptUnicast); 2476 SERIALIZE_SCALAR(acceptPerfect); 2477 SERIALIZE_SCALAR(acceptArp); 2478 2479 /* 2480 * Keep track of pending interrupt status. 2481 */ 2482 SERIALIZE_SCALAR(intrTick); 2483 SERIALIZE_SCALAR(cpuPendingIntr); 2484 Tick intrEventTick = 0; 2485 if (intrEvent) 2486 intrEventTick = intrEvent->when(); 2487 SERIALIZE_SCALAR(intrEventTick); 2488 2489} 2490 2491void 2492NSGigE::unserialize(Checkpoint *cp, const std::string §ion) 2493{ 2494 // Unserialize the PciDev base class 2495 PciDev::unserialize(cp, section); 2496 2497 UNSERIALIZE_SCALAR(regs.command); 2498 UNSERIALIZE_SCALAR(regs.config); 2499 UNSERIALIZE_SCALAR(regs.mear); 2500 UNSERIALIZE_SCALAR(regs.ptscr); 2501 UNSERIALIZE_SCALAR(regs.isr); 2502 UNSERIALIZE_SCALAR(regs.imr); 2503 UNSERIALIZE_SCALAR(regs.ier); 2504 UNSERIALIZE_SCALAR(regs.ihr); 2505 UNSERIALIZE_SCALAR(regs.txdp); 2506 UNSERIALIZE_SCALAR(regs.txdp_hi); 2507 UNSERIALIZE_SCALAR(regs.txcfg); 2508 UNSERIALIZE_SCALAR(regs.gpior); 2509 UNSERIALIZE_SCALAR(regs.rxdp); 2510 UNSERIALIZE_SCALAR(regs.rxdp_hi); 2511 UNSERIALIZE_SCALAR(regs.rxcfg); 2512 UNSERIALIZE_SCALAR(regs.pqcr); 2513 UNSERIALIZE_SCALAR(regs.wcsr); 2514 UNSERIALIZE_SCALAR(regs.pcr); 2515 UNSERIALIZE_SCALAR(regs.rfcr); 2516 UNSERIALIZE_SCALAR(regs.rfdr); 2517 UNSERIALIZE_SCALAR(regs.srr); 2518 UNSERIALIZE_SCALAR(regs.mibc); 2519 UNSERIALIZE_SCALAR(regs.vrcr); 2520 UNSERIALIZE_SCALAR(regs.vtcr); 2521 UNSERIALIZE_SCALAR(regs.vdr); 2522 UNSERIALIZE_SCALAR(regs.ccsr); 2523 UNSERIALIZE_SCALAR(regs.tbicr); 2524 UNSERIALIZE_SCALAR(regs.tbisr); 2525 UNSERIALIZE_SCALAR(regs.tanar); 2526 UNSERIALIZE_SCALAR(regs.tanlpar); 2527 UNSERIALIZE_SCALAR(regs.taner); 2528 UNSERIALIZE_SCALAR(regs.tesr); 2529 2530 UNSERIALIZE_ARRAY(rom.perfectMatch, ETH_ADDR_LEN); 2531 2532 UNSERIALIZE_SCALAR(ioEnable); 2533 2534 /* 2535 * unserialize the data fifos 2536 */ 2537 rxFifo.unserialize("rxFifo", cp, section); 2538 txFifo.unserialize("txFifo", cp, section); 2539 2540 /* 2541 * unserialize the various helper variables 2542 */ 2543 bool txPacketExists; 2544 UNSERIALIZE_SCALAR(txPacketExists); 2545 if (txPacketExists) { 2546 txPacket = new PacketData(16384); 2547 txPacket->unserialize("txPacket", cp, section); 2548 uint32_t txPktBufPtr; 2549 UNSERIALIZE_SCALAR(txPktBufPtr); 2550 txPacketBufPtr = (uint8_t *) txPacket->data + txPktBufPtr; 2551 } else 2552 txPacket = 0; 2553 2554 bool rxPacketExists; 2555 UNSERIALIZE_SCALAR(rxPacketExists); 2556 rxPacket = 0; 2557 if (rxPacketExists) { 2558 rxPacket = new PacketData(16384); 2559 rxPacket->unserialize("rxPacket", cp, section); 2560 uint32_t rxPktBufPtr; 2561 UNSERIALIZE_SCALAR(rxPktBufPtr); 2562 rxPacketBufPtr = (uint8_t *) rxPacket->data + rxPktBufPtr; 2563 } else 2564 rxPacket = 0; 2565 2566 UNSERIALIZE_SCALAR(txXferLen); 2567 UNSERIALIZE_SCALAR(rxXferLen); 2568 2569 /* 2570 * Unserialize DescCaches 2571 */ 2572 UNSERIALIZE_SCALAR(txDescCache.link); 2573 UNSERIALIZE_SCALAR(txDescCache.bufptr); 2574 UNSERIALIZE_SCALAR(txDescCache.cmdsts); 2575 UNSERIALIZE_SCALAR(txDescCache.extsts); 2576 UNSERIALIZE_SCALAR(rxDescCache.link); 2577 UNSERIALIZE_SCALAR(rxDescCache.bufptr); 2578 UNSERIALIZE_SCALAR(rxDescCache.cmdsts); 2579 UNSERIALIZE_SCALAR(rxDescCache.extsts); 2580 2581 /* 2582 * unserialize tx state machine 2583 */ 2584 int txState; 2585 UNSERIALIZE_SCALAR(txState); 2586 this->txState = (TxState) txState; 2587 UNSERIALIZE_SCALAR(txEnable); 2588 UNSERIALIZE_SCALAR(CTDD); 2589 UNSERIALIZE_SCALAR(txFragPtr); 2590 UNSERIALIZE_SCALAR(txDescCnt); 2591 int txDmaState; 2592 UNSERIALIZE_SCALAR(txDmaState); 2593 this->txDmaState = (DmaState) txDmaState; 2594 2595 /* 2596 * unserialize rx state machine 2597 */ 2598 int rxState; 2599 UNSERIALIZE_SCALAR(rxState); 2600 this->rxState = (RxState) rxState; 2601 UNSERIALIZE_SCALAR(rxEnable); 2602 UNSERIALIZE_SCALAR(CRDD); 2603 UNSERIALIZE_SCALAR(rxPktBytes); 2604 UNSERIALIZE_SCALAR(rxFragPtr); 2605 UNSERIALIZE_SCALAR(rxDescCnt); 2606 int rxDmaState; 2607 UNSERIALIZE_SCALAR(rxDmaState); 2608 this->rxDmaState = (DmaState) rxDmaState; 2609 2610 UNSERIALIZE_SCALAR(extstsEnable); 2611 2612 /* 2613 * If there's a pending transmit, reschedule it now 2614 */ 2615 Tick transmitTick; 2616 UNSERIALIZE_SCALAR(transmitTick); 2617 if (transmitTick) 2618 txEvent.schedule(curTick + transmitTick); 2619 2620 /* 2621 * unserialize receive address filter settings 2622 */ 2623 UNSERIALIZE_SCALAR(rxFilterEnable); 2624 UNSERIALIZE_SCALAR(acceptBroadcast); 2625 UNSERIALIZE_SCALAR(acceptMulticast); 2626 UNSERIALIZE_SCALAR(acceptUnicast); 2627 UNSERIALIZE_SCALAR(acceptPerfect); 2628 UNSERIALIZE_SCALAR(acceptArp); 2629 2630 /* 2631 * Keep track of pending interrupt status. 2632 */ 2633 UNSERIALIZE_SCALAR(intrTick); 2634 UNSERIALIZE_SCALAR(cpuPendingIntr); 2635 Tick intrEventTick; 2636 UNSERIALIZE_SCALAR(intrEventTick); 2637 if (intrEventTick) { 2638 intrEvent = new IntrEvent(this, true); 2639 intrEvent->schedule(intrEventTick); 2640 } 2641 2642 /* 2643 * re-add addrRanges to bus bridges 2644 */ 2645 if (pioInterface) { 2646 pioInterface->addAddrRange(RangeSize(BARAddrs[0], BARSize[0])); 2647 pioInterface->addAddrRange(RangeSize(BARAddrs[1], BARSize[1])); 2648 } 2649} 2650 2651Tick 2652NSGigE::cacheAccess(MemReqPtr &req) 2653{ 2654 DPRINTF(EthernetPIO, "timing access to paddr=%#x (daddr=%#x)\n", 2655 req->paddr, req->paddr - addr); 2656 return curTick + pioLatency; 2657} 2658 2659BEGIN_DECLARE_SIM_OBJECT_PARAMS(NSGigEInt) 2660 2661 SimObjectParam<EtherInt *> peer; 2662 SimObjectParam<NSGigE *> device; 2663 2664END_DECLARE_SIM_OBJECT_PARAMS(NSGigEInt) 2665 2666BEGIN_INIT_SIM_OBJECT_PARAMS(NSGigEInt) 2667 2668 INIT_PARAM_DFLT(peer, "peer interface", NULL), 2669 INIT_PARAM(device, "Ethernet device of this interface") 2670 2671END_INIT_SIM_OBJECT_PARAMS(NSGigEInt) 2672 2673CREATE_SIM_OBJECT(NSGigEInt) 2674{ 2675 NSGigEInt *dev_int = new NSGigEInt(getInstanceName(), device); 2676 2677 EtherInt *p = (EtherInt *)peer; 2678 if (p) { 2679 dev_int->setPeer(p); 2680 p->setPeer(dev_int); 2681 } 2682 2683 return dev_int; 2684} 2685 2686REGISTER_SIM_OBJECT("NSGigEInt", NSGigEInt) 2687 2688 2689BEGIN_DECLARE_SIM_OBJECT_PARAMS(NSGigE) 2690 2691 Param<Addr> addr; 2692 Param<Tick> clock; 2693 Param<Tick> tx_delay; 2694 Param<Tick> rx_delay; 2695 Param<Tick> intr_delay; 2696 SimObjectParam<MemoryController *> mmu; 2697 SimObjectParam<PhysicalMemory *> physmem; 2698 Param<bool> rx_filter; 2699 Param<string> hardware_address; 2700 SimObjectParam<Bus*> io_bus; 2701 SimObjectParam<Bus*> payload_bus; 2702 SimObjectParam<HierParams *> hier; 2703 Param<Tick> pio_latency; 2704 Param<bool> dma_desc_free; 2705 Param<bool> dma_data_free; 2706 Param<Tick> dma_read_delay; 2707 Param<Tick> dma_write_delay; 2708 Param<Tick> dma_read_factor; 2709 Param<Tick> dma_write_factor; 2710 SimObjectParam<PciConfigAll *> configspace; 2711 SimObjectParam<PciConfigData *> configdata; 2712 SimObjectParam<Platform *> platform; 2713 Param<uint32_t> pci_bus; 2714 Param<uint32_t> pci_dev; 2715 Param<uint32_t> pci_func; 2716 Param<uint32_t> tx_fifo_size; 2717 Param<uint32_t> rx_fifo_size; 2718 Param<uint32_t> m5reg; 2719 Param<bool> dma_no_allocate; 2720 2721END_DECLARE_SIM_OBJECT_PARAMS(NSGigE) 2722 2723BEGIN_INIT_SIM_OBJECT_PARAMS(NSGigE) 2724 2725 INIT_PARAM(addr, "Device Address"), 2726 INIT_PARAM(clock, "State machine processor frequency"), 2727 INIT_PARAM(tx_delay, "Transmit Delay"), 2728 INIT_PARAM(rx_delay, "Receive Delay"), 2729 INIT_PARAM(intr_delay, "Interrupt Delay in microseconds"), 2730 INIT_PARAM(mmu, "Memory Controller"), 2731 INIT_PARAM(physmem, "Physical Memory"), 2732 INIT_PARAM_DFLT(rx_filter, "Enable Receive Filter", true), 2733 INIT_PARAM_DFLT(hardware_address, "Ethernet Hardware Address", 2734 "00:99:00:00:00:01"), 2735 INIT_PARAM_DFLT(io_bus, "The IO Bus to attach to for headers", NULL), 2736 INIT_PARAM_DFLT(payload_bus, "The IO Bus to attach to for payload", NULL), 2737 INIT_PARAM_DFLT(hier, "Hierarchy global variables", &defaultHierParams), 2738 INIT_PARAM_DFLT(pio_latency, "Programmed IO latency in bus cycles", 1), 2739 INIT_PARAM_DFLT(dma_desc_free, "DMA of Descriptors is free", false), 2740 INIT_PARAM_DFLT(dma_data_free, "DMA of Data is free", false), 2741 INIT_PARAM_DFLT(dma_read_delay, "fixed delay for dma reads", 0), 2742 INIT_PARAM_DFLT(dma_write_delay, "fixed delay for dma writes", 0), 2743 INIT_PARAM_DFLT(dma_read_factor, "multiplier for dma reads", 0), 2744 INIT_PARAM_DFLT(dma_write_factor, "multiplier for dma writes", 0), 2745 INIT_PARAM(configspace, "PCI Configspace"), 2746 INIT_PARAM(configdata, "PCI Config data"), 2747 INIT_PARAM(platform, "Platform"), 2748 INIT_PARAM(pci_bus, "PCI bus"), 2749 INIT_PARAM(pci_dev, "PCI device number"), 2750 INIT_PARAM(pci_func, "PCI function code"), 2751 INIT_PARAM_DFLT(tx_fifo_size, "max size in bytes of txFifo", 131072), 2752 INIT_PARAM_DFLT(rx_fifo_size, "max size in bytes of rxFifo", 131072), 2753 INIT_PARAM(m5reg, "m5 register"), 2754 INIT_PARAM_DFLT(dma_no_allocate, "Should DMA reads allocate cache lines", true) 2755 2756END_INIT_SIM_OBJECT_PARAMS(NSGigE) 2757 2758 2759CREATE_SIM_OBJECT(NSGigE) 2760{ 2761 NSGigE::Params *params = new NSGigE::Params; 2762 2763 params->name = getInstanceName(); 2764 params->mmu = mmu; 2765 params->configSpace = configspace; 2766 params->configData = configdata; 2767 params->plat = platform; 2768 params->busNum = pci_bus; 2769 params->deviceNum = pci_dev; 2770 params->functionNum = pci_func; 2771 2772 params->clock = clock; 2773 params->intr_delay = intr_delay; 2774 params->pmem = physmem; 2775 params->tx_delay = tx_delay; 2776 params->rx_delay = rx_delay; 2777 params->hier = hier; 2778 params->header_bus = io_bus; 2779 params->payload_bus = payload_bus; 2780 params->pio_latency = pio_latency; 2781 params->dma_desc_free = dma_desc_free; 2782 params->dma_data_free = dma_data_free; 2783 params->dma_read_delay = dma_read_delay; 2784 params->dma_write_delay = dma_write_delay; 2785 params->dma_read_factor = dma_read_factor; 2786 params->dma_write_factor = dma_write_factor; 2787 params->rx_filter = rx_filter; 2788 params->eaddr = hardware_address; 2789 params->tx_fifo_size = tx_fifo_size; 2790 params->rx_fifo_size = rx_fifo_size; 2791 params->m5reg = m5reg; 2792 params->dma_no_allocate = dma_no_allocate; 2793 return new NSGigE(params); 2794} 2795 2796REGISTER_SIM_OBJECT("NSGigE", NSGigE) 2797