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 &reg = *(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 &reg = *(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(&regs, 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 &section)
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