ns_gige.cc revision 2641
16657Snate@binkert.org/*
26657Snate@binkert.org * Copyright (c) 2004-2005 The Regents of The University of Michigan
36657Snate@binkert.org * All rights reserved.
46657Snate@binkert.org *
56657Snate@binkert.org * Redistribution and use in source and binary forms, with or without
66657Snate@binkert.org * modification, are permitted provided that the following conditions are
76657Snate@binkert.org * met: redistributions of source code must retain the above copyright
86657Snate@binkert.org * notice, this list of conditions and the following disclaimer;
96657Snate@binkert.org * redistributions in binary form must reproduce the above copyright
106657Snate@binkert.org * notice, this list of conditions and the following disclaimer in the
116657Snate@binkert.org * documentation and/or other materials provided with the distribution;
126657Snate@binkert.org * neither the name of the copyright holders nor the names of its
136657Snate@binkert.org * contributors may be used to endorse or promote products derived from
146657Snate@binkert.org * this software without specific prior written permission.
156657Snate@binkert.org *
166657Snate@binkert.org * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
176657Snate@binkert.org * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
186657Snate@binkert.org * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
196657Snate@binkert.org * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
206657Snate@binkert.org * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
216657Snate@binkert.org * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
226657Snate@binkert.org * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
236657Snate@binkert.org * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
246657Snate@binkert.org * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
256657Snate@binkert.org * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
266657Snate@binkert.org * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
276657Snate@binkert.org */
286999Snate@binkert.org
296657Snate@binkert.org/** @file
306657Snate@binkert.org * Device module for modelling the National Semiconductor
316657Snate@binkert.org * DP83820 ethernet controller.  Does not support priority queueing
326657Snate@binkert.org */
338189SLisa.Hsu@amd.com#include <deque>
346657Snate@binkert.org#include <string>
356882SBrad.Beckmann@amd.com
367055Snate@binkert.org#include "arch/alpha/ev5.hh"
376882SBrad.Beckmann@amd.com#include "base/inet.hh"
386882SBrad.Beckmann@amd.com#include "cpu/exec_context.hh"
398191SLisa.Hsu@amd.com#include "dev/etherlink.hh"
406882SBrad.Beckmann@amd.com#include "dev/ns_gige.hh"
416882SBrad.Beckmann@amd.com#include "dev/pciconfigall.hh"
429102SNuwan.Jayasena@amd.com#include "mem/packet.hh"
436888SBrad.Beckmann@amd.com#include "sim/builder.hh"
446882SBrad.Beckmann@amd.com#include "sim/debug.hh"
456882SBrad.Beckmann@amd.com#include "sim/host.hh"
466657Snate@binkert.org#include "sim/stats.hh"
476657Snate@binkert.org#include "sim/system.hh"
486657Snate@binkert.org
496657Snate@binkert.orgconst char *NsRxStateStrings[] =
506657Snate@binkert.org{
517839Snilay@cs.wisc.edu    "rxIdle",
526657Snate@binkert.org    "rxDescRefr",
536882SBrad.Beckmann@amd.com    "rxDescRead",
546882SBrad.Beckmann@amd.com    "rxFifoBlock",
556882SBrad.Beckmann@amd.com    "rxFragWrite",
566882SBrad.Beckmann@amd.com    "rxDescWrite",
576882SBrad.Beckmann@amd.com    "rxAdvance"
586882SBrad.Beckmann@amd.com};
596657Snate@binkert.org
606657Snate@binkert.orgconst char *NsTxStateStrings[] =
616657Snate@binkert.org{
626657Snate@binkert.org    "txIdle",
636657Snate@binkert.org    "txDescRefr",
649104Shestness@cs.utexas.edu    "txDescRead",
656657Snate@binkert.org    "txFifoBlock",
666657Snate@binkert.org    "txFragRead",
676657Snate@binkert.org    "txDescWrite",
686657Snate@binkert.org    "txAdvance"
697839Snilay@cs.wisc.edu};
707839Snilay@cs.wisc.edu
716657Snate@binkert.orgconst char *NsDmaState[] =
726657Snate@binkert.org{
736657Snate@binkert.org    "dmaIdle",
746657Snate@binkert.org    "dmaReading",
756657Snate@binkert.org    "dmaWriting",
766657Snate@binkert.org    "dmaReadWaiting",
776657Snate@binkert.org    "dmaWriteWaiting"
786657Snate@binkert.org};
796657Snate@binkert.org
806657Snate@binkert.orgusing namespace std;
816657Snate@binkert.orgusing namespace Net;
826657Snate@binkert.orgusing namespace TheISA;
836657Snate@binkert.org
846657Snate@binkert.org///////////////////////////////////////////////////////////////////////
856657Snate@binkert.org//
866657Snate@binkert.org// NSGigE PCI Device
876657Snate@binkert.org//
886657Snate@binkert.orgNSGigE::NSGigE(Params *p)
896657Snate@binkert.org    : PciDev(p), ioEnable(false),
906657Snate@binkert.org      txFifo(p->tx_fifo_size), rxFifo(p->rx_fifo_size),
916779SBrad.Beckmann@amd.com      txPacket(0), rxPacket(0), txPacketBufPtr(NULL), rxPacketBufPtr(NULL),
926657Snate@binkert.org      txXferLen(0), rxXferLen(0), clock(p->clock),
936657Snate@binkert.org      txState(txIdle), txEnable(false), CTDD(false),
946657Snate@binkert.org      txFragPtr(0), txDescCnt(0), txDmaState(dmaIdle), rxState(rxIdle),
956657Snate@binkert.org      rxEnable(false), CRDD(false), rxPktBytes(0),
966657Snate@binkert.org      rxFragPtr(0), rxDescCnt(0), rxDmaState(dmaIdle), extstsEnable(false),
976657Snate@binkert.org      eepromState(eepromStart), rxDmaReadEvent(this), rxDmaWriteEvent(this),
986657Snate@binkert.org      txDmaReadEvent(this), txDmaWriteEvent(this),
996657Snate@binkert.org      dmaDescFree(p->dma_desc_free), dmaDataFree(p->dma_data_free),
1006657Snate@binkert.org      txDelay(p->tx_delay), rxDelay(p->rx_delay),
1019104Shestness@cs.utexas.edu      rxKickTick(0), rxKickEvent(this), txKickTick(0), txKickEvent(this),
1029104Shestness@cs.utexas.edu      txEvent(this), rxFilterEnable(p->rx_filter), acceptBroadcast(false),
1039104Shestness@cs.utexas.edu      acceptMulticast(false), acceptUnicast(false),
1049104Shestness@cs.utexas.edu      acceptPerfect(false), acceptArp(false), multicastHashEnable(false),
1056657Snate@binkert.org      intrTick(0), cpuPendingIntr(false),
1066657Snate@binkert.org      intrEvent(0), interface(0)
1076657Snate@binkert.org{
1086657Snate@binkert.org
1096657Snate@binkert.org    intrDelay = p->intr_delay;
1106657Snate@binkert.org    dmaReadDelay = p->dma_read_delay;
1116657Snate@binkert.org    dmaWriteDelay = p->dma_write_delay;
1126657Snate@binkert.org    dmaReadFactor = p->dma_read_factor;
1136657Snate@binkert.org    dmaWriteFactor = p->dma_write_factor;
1146657Snate@binkert.org
1156657Snate@binkert.org    regsReset();
1166657Snate@binkert.org    memcpy(&rom.perfectMatch, p->eaddr.bytes(), ETH_ADDR_LEN);
1176657Snate@binkert.org
1186657Snate@binkert.org    memset(&rxDesc32, 0, sizeof(rxDesc32));
1196657Snate@binkert.org    memset(&txDesc32, 0, sizeof(txDesc32));
1207839Snilay@cs.wisc.edu    memset(&rxDesc64, 0, sizeof(rxDesc64));
1217839Snilay@cs.wisc.edu    memset(&txDesc64, 0, sizeof(txDesc64));
1227839Snilay@cs.wisc.edu}
1237839Snilay@cs.wisc.edu
1247839Snilay@cs.wisc.eduNSGigE::~NSGigE()
1257839Snilay@cs.wisc.edu{}
1267839Snilay@cs.wisc.edu
1277839Snilay@cs.wisc.eduvoid
1287839Snilay@cs.wisc.eduNSGigE::regStats()
1297839Snilay@cs.wisc.edu{
1307839Snilay@cs.wisc.edu    txBytes
1317839Snilay@cs.wisc.edu        .name(name() + ".txBytes")
1327839Snilay@cs.wisc.edu        .desc("Bytes Transmitted")
1337839Snilay@cs.wisc.edu        .prereq(txBytes)
1347839Snilay@cs.wisc.edu        ;
1356657Snate@binkert.org
1366657Snate@binkert.org    rxBytes
1376657Snate@binkert.org        .name(name() + ".rxBytes")
1386657Snate@binkert.org        .desc("Bytes Received")
1396657Snate@binkert.org        .prereq(rxBytes)
1406657Snate@binkert.org        ;
1416657Snate@binkert.org
1426657Snate@binkert.org    txPackets
1436657Snate@binkert.org        .name(name() + ".txPackets")
1446657Snate@binkert.org        .desc("Number of Packets Transmitted")
1456657Snate@binkert.org        .prereq(txBytes)
1466657Snate@binkert.org        ;
1476657Snate@binkert.org
1486657Snate@binkert.org    rxPackets
1496657Snate@binkert.org        .name(name() + ".rxPackets")
1506657Snate@binkert.org        .desc("Number of Packets Received")
1516657Snate@binkert.org        .prereq(rxBytes)
1526657Snate@binkert.org        ;
1536657Snate@binkert.org
1546657Snate@binkert.org    txIpChecksums
1556657Snate@binkert.org        .name(name() + ".txIpChecksums")
1566657Snate@binkert.org        .desc("Number of tx IP Checksums done by device")
1576657Snate@binkert.org        .precision(0)
1586657Snate@binkert.org        .prereq(txBytes)
1596657Snate@binkert.org        ;
1606657Snate@binkert.org
1616657Snate@binkert.org    rxIpChecksums
1626657Snate@binkert.org        .name(name() + ".rxIpChecksums")
1636657Snate@binkert.org        .desc("Number of rx IP Checksums done by device")
1646657Snate@binkert.org        .precision(0)
1656657Snate@binkert.org        .prereq(rxBytes)
1666877Ssteve.reinhardt@amd.com        ;
1676657Snate@binkert.org
1686657Snate@binkert.org    txTcpChecksums
1696657Snate@binkert.org        .name(name() + ".txTcpChecksums")
1706657Snate@binkert.org        .desc("Number of tx TCP Checksums done by device")
1716657Snate@binkert.org        .precision(0)
1726657Snate@binkert.org        .prereq(txBytes)
1737542SBrad.Beckmann@amd.com        ;
1747542SBrad.Beckmann@amd.com
1756657Snate@binkert.org    rxTcpChecksums
1766877Ssteve.reinhardt@amd.com        .name(name() + ".rxTcpChecksums")
1776999Snate@binkert.org        .desc("Number of rx TCP Checksums done by device")
1786877Ssteve.reinhardt@amd.com        .precision(0)
1796877Ssteve.reinhardt@amd.com        .prereq(rxBytes)
1806877Ssteve.reinhardt@amd.com        ;
1816877Ssteve.reinhardt@amd.com
1826877Ssteve.reinhardt@amd.com    txUdpChecksums
1836877Ssteve.reinhardt@amd.com        .name(name() + ".txUdpChecksums")
1846877Ssteve.reinhardt@amd.com        .desc("Number of tx UDP Checksums done by device")
1856877Ssteve.reinhardt@amd.com        .precision(0)
1866877Ssteve.reinhardt@amd.com        .prereq(txBytes)
1876877Ssteve.reinhardt@amd.com        ;
1886877Ssteve.reinhardt@amd.com
1896877Ssteve.reinhardt@amd.com    rxUdpChecksums
1906877Ssteve.reinhardt@amd.com        .name(name() + ".rxUdpChecksums")
1916877Ssteve.reinhardt@amd.com        .desc("Number of rx UDP Checksums done by device")
1926877Ssteve.reinhardt@amd.com        .precision(0)
1936877Ssteve.reinhardt@amd.com        .prereq(rxBytes)
1946882SBrad.Beckmann@amd.com        ;
1956882SBrad.Beckmann@amd.com
1966882SBrad.Beckmann@amd.com    descDmaReads
1976882SBrad.Beckmann@amd.com        .name(name() + ".descDMAReads")
1986882SBrad.Beckmann@amd.com        .desc("Number of descriptors the device read w/ DMA")
1996882SBrad.Beckmann@amd.com        .precision(0)
2006882SBrad.Beckmann@amd.com        ;
2016877Ssteve.reinhardt@amd.com
2026877Ssteve.reinhardt@amd.com    descDmaWrites
2036877Ssteve.reinhardt@amd.com        .name(name() + ".descDMAWrites")
2046877Ssteve.reinhardt@amd.com        .desc("Number of descriptors the device wrote w/ DMA")
2056657Snate@binkert.org        .precision(0)
2066657Snate@binkert.org        ;
2076999Snate@binkert.org
2086657Snate@binkert.org    descDmaRdBytes
2096657Snate@binkert.org        .name(name() + ".descDmaReadBytes")
2106657Snate@binkert.org        .desc("number of descriptor bytes read w/ DMA")
2116657Snate@binkert.org        .precision(0)
2126657Snate@binkert.org        ;
2136657Snate@binkert.org
2147007Snate@binkert.org   descDmaWrBytes
2156657Snate@binkert.org        .name(name() + ".descDmaWriteBytes")
2166657Snate@binkert.org        .desc("number of descriptor bytes write w/ DMA")
2176657Snate@binkert.org        .precision(0)
2186657Snate@binkert.org        ;
2196657Snate@binkert.org
2207007Snate@binkert.org    txBandwidth
2217007Snate@binkert.org        .name(name() + ".txBandwidth")
2226657Snate@binkert.org        .desc("Transmit Bandwidth (bits/s)")
2237002Snate@binkert.org        .precision(0)
2247002Snate@binkert.org        .prereq(txBytes)
2257002Snate@binkert.org        ;
2267002Snate@binkert.org
2278229Snate@binkert.org    rxBandwidth
2288229Snate@binkert.org        .name(name() + ".rxBandwidth")
2296657Snate@binkert.org        .desc("Receive Bandwidth (bits/s)")
2306657Snate@binkert.org        .precision(0)
2318229Snate@binkert.org        .prereq(rxBytes)
2328229Snate@binkert.org        ;
2338229Snate@binkert.org
2348229Snate@binkert.org    totBandwidth
2356657Snate@binkert.org        .name(name() + ".totBandwidth")
2366657Snate@binkert.org        .desc("Total Bandwidth (bits/s)")
2376657Snate@binkert.org        .precision(0)
2386657Snate@binkert.org        .prereq(totBytes)
2396793SBrad.Beckmann@amd.com        ;
2406657Snate@binkert.org
2416657Snate@binkert.org    totPackets
2426657Snate@binkert.org        .name(name() + ".totPackets")
2436657Snate@binkert.org        .desc("Total Packets")
2446657Snate@binkert.org        .precision(0)
2457002Snate@binkert.org        .prereq(totBytes)
2466657Snate@binkert.org        ;
2477007Snate@binkert.org
2487007Snate@binkert.org    totBytes
2497007Snate@binkert.org        .name(name() + ".totBytes")
2507007Snate@binkert.org        .desc("Total Bytes")
2517007Snate@binkert.org        .precision(0)
2526657Snate@binkert.org        .prereq(totBytes)
2536877Ssteve.reinhardt@amd.com        ;
2546877Ssteve.reinhardt@amd.com
2556657Snate@binkert.org    totPacketRate
2566877Ssteve.reinhardt@amd.com        .name(name() + ".totPPS")
2576657Snate@binkert.org        .desc("Total Tranmission Rate (packets/s)")
2586657Snate@binkert.org        .precision(0)
2597002Snate@binkert.org        .prereq(totBytes)
2607002Snate@binkert.org        ;
2617567SBrad.Beckmann@amd.com
2627567SBrad.Beckmann@amd.com    txPacketRate
2637922SBrad.Beckmann@amd.com        .name(name() + ".txPPS")
2646881SBrad.Beckmann@amd.com        .desc("Packet Tranmission Rate (packets/s)")
2657002Snate@binkert.org        .precision(0)
2667002Snate@binkert.org        .prereq(txBytes)
2676657Snate@binkert.org        ;
2687002Snate@binkert.org
2696902SBrad.Beckmann@amd.com    rxPacketRate
2706863Sdrh5@cs.wisc.edu        .name(name() + ".rxPPS")
2716863Sdrh5@cs.wisc.edu        .desc("Packet Reception Rate (packets/s)")
2728683Snilay@cs.wisc.edu        .precision(0)
2738683Snilay@cs.wisc.edu        .prereq(rxBytes)
2747007Snate@binkert.org        ;
2756657Snate@binkert.org
2766657Snate@binkert.org    postedSwi
2776657Snate@binkert.org        .name(name() + ".postedSwi")
2786657Snate@binkert.org        .desc("number of software interrupts posted to CPU")
2796657Snate@binkert.org        .precision(0)
2806657Snate@binkert.org        ;
2816882SBrad.Beckmann@amd.com
2826882SBrad.Beckmann@amd.com    totalSwi
2836882SBrad.Beckmann@amd.com        .name(name() + ".totalSwi")
2846882SBrad.Beckmann@amd.com        .desc("total number of Swi written to ISR")
2856657Snate@binkert.org        .precision(0)
2866657Snate@binkert.org        ;
2876657Snate@binkert.org
2886657Snate@binkert.org    coalescedSwi
2897007Snate@binkert.org        .name(name() + ".coalescedSwi")
2907839Snilay@cs.wisc.edu        .desc("average number of Swi's coalesced into each post")
2917839Snilay@cs.wisc.edu        .precision(0)
2927839Snilay@cs.wisc.edu        ;
2937839Snilay@cs.wisc.edu
2947839Snilay@cs.wisc.edu    postedRxIdle
2957839Snilay@cs.wisc.edu        .name(name() + ".postedRxIdle")
2967839Snilay@cs.wisc.edu        .desc("number of rxIdle interrupts posted to CPU")
2977839Snilay@cs.wisc.edu        .precision(0)
2987839Snilay@cs.wisc.edu        ;
2997839Snilay@cs.wisc.edu
3007839Snilay@cs.wisc.edu    totalRxIdle
3017839Snilay@cs.wisc.edu        .name(name() + ".totalRxIdle")
3027007Snate@binkert.org        .desc("total number of RxIdle written to ISR")
3037007Snate@binkert.org        .precision(0)
3047007Snate@binkert.org        ;
3057007Snate@binkert.org
3067007Snate@binkert.org    coalescedRxIdle
3077839Snilay@cs.wisc.edu        .name(name() + ".coalescedRxIdle")
3087839Snilay@cs.wisc.edu        .desc("average number of RxIdle's coalesced into each post")
3097839Snilay@cs.wisc.edu        .precision(0)
3107839Snilay@cs.wisc.edu        ;
3117839Snilay@cs.wisc.edu
3127839Snilay@cs.wisc.edu    postedRxOk
3137839Snilay@cs.wisc.edu        .name(name() + ".postedRxOk")
3147839Snilay@cs.wisc.edu        .desc("number of RxOk interrupts posted to CPU")
3157839Snilay@cs.wisc.edu        .precision(0)
3167839Snilay@cs.wisc.edu        ;
3177839Snilay@cs.wisc.edu
3187839Snilay@cs.wisc.edu    totalRxOk
3197007Snate@binkert.org        .name(name() + ".totalRxOk")
3207007Snate@binkert.org        .desc("total number of RxOk written to ISR")
3217002Snate@binkert.org        .precision(0)
3226657Snate@binkert.org        ;
3236657Snate@binkert.org
3246657Snate@binkert.org    coalescedRxOk
3257055Snate@binkert.org        .name(name() + ".coalescedRxOk")
3266657Snate@binkert.org        .desc("average number of RxOk's coalesced into each post")
3276657Snate@binkert.org        .precision(0)
3286657Snate@binkert.org        ;
3296863Sdrh5@cs.wisc.edu
3307055Snate@binkert.org    postedRxDesc
3317567SBrad.Beckmann@amd.com        .name(name() + ".postedRxDesc")
3328943Sandreas.hansson@arm.com        .desc("number of RxDesc interrupts posted to CPU")
3337567SBrad.Beckmann@amd.com        .precision(0)
3347567SBrad.Beckmann@amd.com        ;
3357567SBrad.Beckmann@amd.com
3367542SBrad.Beckmann@amd.com    totalRxDesc
3377542SBrad.Beckmann@amd.com        .name(name() + ".totalRxDesc")
3386657Snate@binkert.org        .desc("total number of RxDesc written to ISR")
3397007Snate@binkert.org        .precision(0)
3406657Snate@binkert.org        ;
3416657Snate@binkert.org
3426657Snate@binkert.org    coalescedRxDesc
3436657Snate@binkert.org        .name(name() + ".coalescedRxDesc")
3446657Snate@binkert.org        .desc("average number of RxDesc's coalesced into each post")
3456657Snate@binkert.org        .precision(0)
3466657Snate@binkert.org        ;
3476657Snate@binkert.org
3487839Snilay@cs.wisc.edu    postedTxOk
3497839Snilay@cs.wisc.edu        .name(name() + ".postedTxOk")
3507839Snilay@cs.wisc.edu        .desc("number of TxOk interrupts posted to CPU")
3517839Snilay@cs.wisc.edu        .precision(0)
3527839Snilay@cs.wisc.edu        ;
3537839Snilay@cs.wisc.edu
3547839Snilay@cs.wisc.edu    totalTxOk
3557839Snilay@cs.wisc.edu        .name(name() + ".totalTxOk")
3567839Snilay@cs.wisc.edu        .desc("total number of TxOk written to ISR")
3577839Snilay@cs.wisc.edu        .precision(0)
3587839Snilay@cs.wisc.edu        ;
3597839Snilay@cs.wisc.edu
3607839Snilay@cs.wisc.edu    coalescedTxOk
3617839Snilay@cs.wisc.edu        .name(name() + ".coalescedTxOk")
3627839Snilay@cs.wisc.edu        .desc("average number of TxOk's coalesced into each post")
3637839Snilay@cs.wisc.edu        .precision(0)
3646657Snate@binkert.org        ;
3656657Snate@binkert.org
3666657Snate@binkert.org    postedTxIdle
3676657Snate@binkert.org        .name(name() + ".postedTxIdle")
3687839Snilay@cs.wisc.edu        .desc("number of TxIdle interrupts posted to CPU")
3697839Snilay@cs.wisc.edu        .precision(0)
3707839Snilay@cs.wisc.edu        ;
3717839Snilay@cs.wisc.edu
3727839Snilay@cs.wisc.edu    totalTxIdle
3737839Snilay@cs.wisc.edu        .name(name() + ".totalTxIdle")
3747839Snilay@cs.wisc.edu        .desc("total number of TxIdle written to ISR")
3757839Snilay@cs.wisc.edu        .precision(0)
3767839Snilay@cs.wisc.edu        ;
3777839Snilay@cs.wisc.edu
3787839Snilay@cs.wisc.edu    coalescedTxIdle
3797839Snilay@cs.wisc.edu        .name(name() + ".coalescedTxIdle")
3807839Snilay@cs.wisc.edu        .desc("average number of TxIdle's coalesced into each post")
3817839Snilay@cs.wisc.edu        .precision(0)
3827839Snilay@cs.wisc.edu        ;
3837839Snilay@cs.wisc.edu
3846657Snate@binkert.org    postedTxDesc
3856657Snate@binkert.org        .name(name() + ".postedTxDesc")
3866657Snate@binkert.org        .desc("number of TxDesc interrupts posted to CPU")
3876657Snate@binkert.org        .precision(0)
3887007Snate@binkert.org        ;
3896657Snate@binkert.org
3906657Snate@binkert.org    totalTxDesc
3916657Snate@binkert.org        .name(name() + ".totalTxDesc")
3926657Snate@binkert.org        .desc("total number of TxDesc written to ISR")
3936657Snate@binkert.org        .precision(0)
3946657Snate@binkert.org        ;
3956657Snate@binkert.org
3966657Snate@binkert.org    coalescedTxDesc
3976657Snate@binkert.org        .name(name() + ".coalescedTxDesc")
3986657Snate@binkert.org        .desc("average number of TxDesc's coalesced into each post")
3997007Snate@binkert.org        .precision(0)
4006657Snate@binkert.org        ;
4016657Snate@binkert.org
4026657Snate@binkert.org    postedRxOrn
4036657Snate@binkert.org        .name(name() + ".postedRxOrn")
4046657Snate@binkert.org        .desc("number of RxOrn posted to CPU")
4056999Snate@binkert.org        .precision(0)
4066657Snate@binkert.org        ;
4076657Snate@binkert.org
4086657Snate@binkert.org    totalRxOrn
4096657Snate@binkert.org        .name(name() + ".totalRxOrn")
4107007Snate@binkert.org        .desc("total number of RxOrn written to ISR")
4116657Snate@binkert.org        .precision(0)
4126657Snate@binkert.org        ;
4136657Snate@binkert.org
4146657Snate@binkert.org    coalescedRxOrn
4156657Snate@binkert.org        .name(name() + ".coalescedRxOrn")
4168946Sandreas.hansson@arm.com        .desc("average number of RxOrn's coalesced into each post")
4178946Sandreas.hansson@arm.com        .precision(0)
4188946Sandreas.hansson@arm.com        ;
4197832Snate@binkert.org
4207002Snate@binkert.org    coalescedTotal
4217002Snate@binkert.org        .name(name() + ".coalescedTotal")
4227002Snate@binkert.org        .desc("average number of interrupts coalesced into each post")
4238641Snate@binkert.org        .precision(0)
4247056Snate@binkert.org        ;
4258232Snate@binkert.org
4268232Snate@binkert.org    postedInterrupts
4276657Snate@binkert.org        .name(name() + ".postedInterrupts")
4288229Snate@binkert.org        .desc("number of posts to CPU")
4296657Snate@binkert.org        .precision(0)
4306657Snate@binkert.org        ;
4317056Snate@binkert.org
4327056Snate@binkert.org    droppedPackets
4336657Snate@binkert.org        .name(name() + ".droppedPackets")
4347002Snate@binkert.org        .desc("number of packets dropped")
4357002Snate@binkert.org        .precision(0)
4366657Snate@binkert.org        ;
4376657Snate@binkert.org
4386657Snate@binkert.org    coalescedSwi = totalSwi / postedInterrupts;
4396657Snate@binkert.org    coalescedRxIdle = totalRxIdle / postedInterrupts;
4406657Snate@binkert.org    coalescedRxOk = totalRxOk / postedInterrupts;
4416793SBrad.Beckmann@amd.com    coalescedRxDesc = totalRxDesc / postedInterrupts;
4426657Snate@binkert.org    coalescedTxOk = totalTxOk / postedInterrupts;
4436657Snate@binkert.org    coalescedTxIdle = totalTxIdle / postedInterrupts;
4446657Snate@binkert.org    coalescedTxDesc = totalTxDesc / postedInterrupts;
4456657Snate@binkert.org    coalescedRxOrn = totalRxOrn / postedInterrupts;
4466877Ssteve.reinhardt@amd.com
4476877Ssteve.reinhardt@amd.com    coalescedTotal = (totalSwi + totalRxIdle + totalRxOk + totalRxDesc +
4486877Ssteve.reinhardt@amd.com                      totalTxOk + totalTxIdle + totalTxDesc +
4496877Ssteve.reinhardt@amd.com                      totalRxOrn) / postedInterrupts;
4506877Ssteve.reinhardt@amd.com
4516877Ssteve.reinhardt@amd.com    txBandwidth = txBytes * Stats::constant(8) / simSeconds;
4526657Snate@binkert.org    rxBandwidth = rxBytes * Stats::constant(8) / simSeconds;
4537542SBrad.Beckmann@amd.com    totBandwidth = txBandwidth + rxBandwidth;
4546657Snate@binkert.org    totBytes = txBytes + rxBytes;
4557007Snate@binkert.org    totPackets = txPackets + rxPackets;
4566657Snate@binkert.org
4576657Snate@binkert.org    txPacketRate = txPackets / simSeconds;
4587007Snate@binkert.org    rxPacketRate = rxPackets / simSeconds;
4596657Snate@binkert.org}
4606877Ssteve.reinhardt@amd.com
4616877Ssteve.reinhardt@amd.com
4626657Snate@binkert.org/**
4636877Ssteve.reinhardt@amd.com * This is to write to the PCI general configuration registers
4646877Ssteve.reinhardt@amd.com */
4656877Ssteve.reinhardt@amd.comvoid
4666877Ssteve.reinhardt@amd.comNSGigE::writeConfig(int offset, const uint16_t data)
4676877Ssteve.reinhardt@amd.com{
4686969SBrad.Beckmann@amd.com    if (offset < PCI_DEVICE_SPECIFIC)
4698532SLisa.Hsu@amd.com        PciDev::writeConfig(offset,  data);
4706657Snate@binkert.org    else
4717567SBrad.Beckmann@amd.com        panic("Device specific PCI config space not implemented!\n");
4727567SBrad.Beckmann@amd.com
4737567SBrad.Beckmann@amd.com    switch (offset) {
4747567SBrad.Beckmann@amd.com        // seems to work fine without all these PCI settings, but i
4757567SBrad.Beckmann@amd.com        // put in the IO to double check, an assertion will fail if we
4767567SBrad.Beckmann@amd.com        // need to properly implement it
4776657Snate@binkert.org      case PCI_COMMAND:
4786882SBrad.Beckmann@amd.com        if (config.data[offset] & PCI_CMD_IOSE)
4796882SBrad.Beckmann@amd.com            ioEnable = true;
4806882SBrad.Beckmann@amd.com        else
4816882SBrad.Beckmann@amd.com            ioEnable = false;
4826882SBrad.Beckmann@amd.com        break;
4836882SBrad.Beckmann@amd.com    }
4846882SBrad.Beckmann@amd.com}
4858189SLisa.Hsu@amd.com
4868189SLisa.Hsu@amd.com/**
4876877Ssteve.reinhardt@amd.com * This reads the device registers, which are detailed in the NS83820
4888189SLisa.Hsu@amd.com * spec sheet
4898189SLisa.Hsu@amd.com */
4908189SLisa.Hsu@amd.comTick
4918189SLisa.Hsu@amd.comNSGigE::read(Packet *pkt)
4926882SBrad.Beckmann@amd.com{
4936882SBrad.Beckmann@amd.com    assert(ioEnable);
4946882SBrad.Beckmann@amd.com
4956882SBrad.Beckmann@amd.com    pkt->time += pioDelay;
4966882SBrad.Beckmann@amd.com    pkt->allocate();
4976882SBrad.Beckmann@amd.com
4986882SBrad.Beckmann@amd.com    //The mask is to give you only the offset into the device register file
4996882SBrad.Beckmann@amd.com    Addr daddr = pkt->getAddr() & 0xfff;
5006882SBrad.Beckmann@amd.com    DPRINTF(EthernetPIO, "read  da=%#x pa=%#x size=%d\n",
5016882SBrad.Beckmann@amd.com            daddr, pkt->getAddr(), pkt->getSize());
5028189SLisa.Hsu@amd.com
5036882SBrad.Beckmann@amd.com
5046882SBrad.Beckmann@amd.com    // there are some reserved registers, you can see ns_gige_reg.h and
5056882SBrad.Beckmann@amd.com    // the spec sheet for details
5068189SLisa.Hsu@amd.com    if (daddr > LAST && daddr <=  RESERVED) {
5078189SLisa.Hsu@amd.com        panic("Accessing reserved register");
5088189SLisa.Hsu@amd.com    } else if (daddr > RESERVED && daddr <= 0x3FC) {
5098189SLisa.Hsu@amd.com        if (pkt->getSize() == sizeof(uint8_t))
5108938SLisa.Hsu@amd.com            readConfig(daddr & 0xff, pkt->getPtr<uint8_t>());
5118938SLisa.Hsu@amd.com        if (pkt->getSize() == sizeof(uint16_t))
5128938SLisa.Hsu@amd.com            readConfig(daddr & 0xff, pkt->getPtr<uint16_t>());
5138938SLisa.Hsu@amd.com        if (pkt->getSize() == sizeof(uint32_t))
5148938SLisa.Hsu@amd.com            readConfig(daddr & 0xff, pkt->getPtr<uint32_t>());
5158938SLisa.Hsu@amd.com        pkt->result = Packet::Success;
5168938SLisa.Hsu@amd.com        return pioDelay;
5176888SBrad.Beckmann@amd.com    } else if (daddr >= MIB_START && daddr <= MIB_END) {
5186888SBrad.Beckmann@amd.com        // don't implement all the MIB's.  hopefully the kernel
5196888SBrad.Beckmann@amd.com        // doesn't actually DEPEND upon their values
5206888SBrad.Beckmann@amd.com        // MIB are just hardware stats keepers
5216888SBrad.Beckmann@amd.com        pkt->set<uint32_t>(0);
5228189SLisa.Hsu@amd.com        pkt->result = Packet::Success;
5236888SBrad.Beckmann@amd.com        return pioDelay;
5246888SBrad.Beckmann@amd.com    } else if (daddr > 0x3FC)
5256657Snate@binkert.org        panic("Something is messed up!\n");
5266888SBrad.Beckmann@amd.com
5276888SBrad.Beckmann@amd.com    assert(pkt->getSize() == sizeof(uint32_t));
5286888SBrad.Beckmann@amd.com        uint32_t &reg = *pkt->getPtr<uint32_t>();
5296888SBrad.Beckmann@amd.com        uint16_t rfaddr;
5306657Snate@binkert.org
5316657Snate@binkert.org        switch (daddr) {
5326657Snate@binkert.org          case CR:
5336657Snate@binkert.org            reg = regs.command;
5346657Snate@binkert.org            //these are supposed to be cleared on a read
5356657Snate@binkert.org            reg &= ~(CR_RXD | CR_TXD | CR_TXR | CR_RXR);
5366657Snate@binkert.org            break;
5376657Snate@binkert.org
5386657Snate@binkert.org          case CFGR:
5397007Snate@binkert.org            reg = regs.config;
5407007Snate@binkert.org            break;
5416657Snate@binkert.org
5427007Snate@binkert.org          case MEAR:
5437007Snate@binkert.org            reg = regs.mear;
5447007Snate@binkert.org            break;
5456657Snate@binkert.org
5466657Snate@binkert.org          case PTSCR:
5476657Snate@binkert.org            reg = regs.ptscr;
5487007Snate@binkert.org            break;
5497542SBrad.Beckmann@amd.com
5507542SBrad.Beckmann@amd.com          case ISR:
5517007Snate@binkert.org            reg = regs.isr;
5526657Snate@binkert.org            devIntrClear(ISR_ALL);
5536657Snate@binkert.org            break;
5546657Snate@binkert.org
5556657Snate@binkert.org          case IMR:
5566657Snate@binkert.org            reg = regs.imr;
5576657Snate@binkert.org            break;
5586657Snate@binkert.org
5596657Snate@binkert.org          case IER:
5606657Snate@binkert.org            reg = regs.ier;
5616657Snate@binkert.org            break;
5626657Snate@binkert.org
5636657Snate@binkert.org          case IHR:
5646657Snate@binkert.org            reg = regs.ihr;
5656657Snate@binkert.org            break;
5666657Snate@binkert.org
5676657Snate@binkert.org          case TXDP:
5686657Snate@binkert.org            reg = regs.txdp;
5696657Snate@binkert.org            break;
5706657Snate@binkert.org
5716657Snate@binkert.org          case TXDP_HI:
5726657Snate@binkert.org            reg = regs.txdp_hi;
5736657Snate@binkert.org            break;
5746657Snate@binkert.org
5756657Snate@binkert.org          case TX_CFG:
5766657Snate@binkert.org            reg = regs.txcfg;
5776657Snate@binkert.org            break;
5786657Snate@binkert.org
5796657Snate@binkert.org          case GPIOR:
5807007Snate@binkert.org            reg = regs.gpior;
5816657Snate@binkert.org            break;
5826657Snate@binkert.org
5836657Snate@binkert.org          case RXDP:
5846657Snate@binkert.org            reg = regs.rxdp;
5857007Snate@binkert.org            break;
5866657Snate@binkert.org
5877007Snate@binkert.org          case RXDP_HI:
5887007Snate@binkert.org            reg = regs.rxdp_hi;
5896657Snate@binkert.org            break;
5906657Snate@binkert.org
5916657Snate@binkert.org          case RX_CFG:
5926657Snate@binkert.org            reg = regs.rxcfg;
5936657Snate@binkert.org            break;
5946657Snate@binkert.org
5956657Snate@binkert.org          case PQCR:
5966657Snate@binkert.org            reg = regs.pqcr;
5976657Snate@binkert.org            break;
5986657Snate@binkert.org
5996657Snate@binkert.org          case WCSR:
6006657Snate@binkert.org            reg = regs.wcsr;
6016657Snate@binkert.org            break;
6026657Snate@binkert.org
6036657Snate@binkert.org          case PCR:
6047566SBrad.Beckmann@amd.com            reg = regs.pcr;
6056657Snate@binkert.org            break;
6066657Snate@binkert.org
6076657Snate@binkert.org            // see the spec sheet for how RFCR and RFDR work
6086657Snate@binkert.org            // basically, you write to RFCR to tell the machine
6096657Snate@binkert.org            // what you want to do next, then you act upon RFDR,
6108308Stushar@csail.mit.edu            // and the device will be prepared b/c of what you
6116657Snate@binkert.org            // wrote to RFCR
6126657Snate@binkert.org          case RFCR:
6136657Snate@binkert.org            reg = regs.rfcr;
6147007Snate@binkert.org            break;
6157007Snate@binkert.org
6168308Stushar@csail.mit.edu          case RFDR:
6176657Snate@binkert.org            rfaddr = (uint16_t)(regs.rfcr & RFCR_RFADDR);
6186657Snate@binkert.org            switch (rfaddr) {
6196657Snate@binkert.org              // Read from perfect match ROM octets
6206657Snate@binkert.org              case 0x000:
6216657Snate@binkert.org                reg = rom.perfectMatch[1];
6226657Snate@binkert.org                reg = reg << 8;
6236657Snate@binkert.org                reg += rom.perfectMatch[0];
6246657Snate@binkert.org                break;
6256657Snate@binkert.org              case 0x002:
6266657Snate@binkert.org                reg = rom.perfectMatch[3] << 8;
6276657Snate@binkert.org                reg += rom.perfectMatch[2];
6286657Snate@binkert.org                break;
6298187SLisa.Hsu@amd.com              case 0x004:
6306657Snate@binkert.org                reg = rom.perfectMatch[5] << 8;
6316657Snate@binkert.org                reg += rom.perfectMatch[4];
6326657Snate@binkert.org                break;
6336657Snate@binkert.org              default:
6346657Snate@binkert.org                // Read filter hash table
6356657Snate@binkert.org                if (rfaddr >= FHASH_ADDR &&
6366657Snate@binkert.org                    rfaddr < FHASH_ADDR + FHASH_SIZE) {
6376657Snate@binkert.org
6386657Snate@binkert.org                    // Only word-aligned reads supported
6397454Snate@binkert.org                    if (rfaddr % 2)
6406657Snate@binkert.org                        panic("unaligned read from filter hash table!");
6416657Snate@binkert.org
6426657Snate@binkert.org                    reg = rom.filterHash[rfaddr - FHASH_ADDR + 1] << 8;
6436657Snate@binkert.org                    reg += rom.filterHash[rfaddr - FHASH_ADDR];
6447007Snate@binkert.org                    break;
6457056Snate@binkert.org                }
6467007Snate@binkert.org
6477007Snate@binkert.org                panic("reading RFDR for something other than pattern"
6486657Snate@binkert.org                      " matching or hashing! %#x\n", rfaddr);
6497566SBrad.Beckmann@amd.com            }
6507566SBrad.Beckmann@amd.com            break;
6517566SBrad.Beckmann@amd.com
6527566SBrad.Beckmann@amd.com          case SRR:
6537566SBrad.Beckmann@amd.com            reg = regs.srr;
6547566SBrad.Beckmann@amd.com            break;
6557566SBrad.Beckmann@amd.com
6566657Snate@binkert.org          case MIBC:
6577672Snate@binkert.org            reg = regs.mibc;
6586657Snate@binkert.org            reg &= ~(MIBC_MIBS | MIBC_ACLR);
6596657Snate@binkert.org            break;
6606657Snate@binkert.org
6616657Snate@binkert.org          case VRCR:
6627672Snate@binkert.org            reg = regs.vrcr;
6636657Snate@binkert.org            break;
6647056Snate@binkert.org
6656657Snate@binkert.org          case VTCR:
6666657Snate@binkert.org            reg = regs.vtcr;
6677672Snate@binkert.org            break;
6686657Snate@binkert.org
6696657Snate@binkert.org          case VDR:
6706657Snate@binkert.org            reg = regs.vdr;
6716657Snate@binkert.org            break;
6726657Snate@binkert.org
6736657Snate@binkert.org          case CCSR:
6746657Snate@binkert.org            reg = regs.ccsr;
6756657Snate@binkert.org            break;
6766657Snate@binkert.org
6776657Snate@binkert.org          case TBICR:
6786657Snate@binkert.org            reg = regs.tbicr;
6797542SBrad.Beckmann@amd.com            break;
6806657Snate@binkert.org
6816657Snate@binkert.org          case TBISR:
6826657Snate@binkert.org            reg = regs.tbisr;
6836657Snate@binkert.org            break;
6846657Snate@binkert.org
6856657Snate@binkert.org          case TANAR:
6866657Snate@binkert.org            reg = regs.tanar;
6876657Snate@binkert.org            break;
6886657Snate@binkert.org
6896657Snate@binkert.org          case TANLPAR:
6906657Snate@binkert.org            reg = regs.tanlpar;
6916657Snate@binkert.org            break;
6926657Snate@binkert.org
6936657Snate@binkert.org          case TANER:
6948683Snilay@cs.wisc.edu            reg = regs.taner;
6958683Snilay@cs.wisc.edu            break;
6968683Snilay@cs.wisc.edu
6978683Snilay@cs.wisc.edu          case TESR:
6988683Snilay@cs.wisc.edu            reg = regs.tesr;
6998683Snilay@cs.wisc.edu            break;
7006657Snate@binkert.org
7017007Snate@binkert.org          case M5REG:
7027007Snate@binkert.org            reg = 0;
7037007Snate@binkert.org            if (params()->rx_thread)
7046657Snate@binkert.org                reg |= M5REG_RX_THREAD;
7056657Snate@binkert.org            if (params()->tx_thread)
7066657Snate@binkert.org                reg |= M5REG_TX_THREAD;
7077007Snate@binkert.org            if (params()->rss)
7087007Snate@binkert.org                reg |= M5REG_RSS;
7097007Snate@binkert.org            break;
7106657Snate@binkert.org
7116657Snate@binkert.org          default:
7126657Snate@binkert.org            panic("reading unimplemented register: addr=%#x", daddr);
7138683Snilay@cs.wisc.edu        }
7148683Snilay@cs.wisc.edu
7158683Snilay@cs.wisc.edu        DPRINTF(EthernetPIO, "read from %#x: data=%d data=%#x\n",
7168683Snilay@cs.wisc.edu                daddr, reg, reg);
7178683Snilay@cs.wisc.edu
7188683Snilay@cs.wisc.edu    pkt->result = Packet::Success;
7197007Snate@binkert.org    return pioDelay;
7207007Snate@binkert.org}
7217007Snate@binkert.org
7226657Snate@binkert.orgTick
7236657Snate@binkert.orgNSGigE::write(Packet *pkt)
7246657Snate@binkert.org{
7257007Snate@binkert.org    assert(ioEnable);
7267007Snate@binkert.org
7277007Snate@binkert.org    Addr daddr = pkt->getAddr() & 0xfff;
7286657Snate@binkert.org    DPRINTF(EthernetPIO, "write da=%#x pa=%#x size=%d\n",
7296657Snate@binkert.org            daddr, pkt->getAddr(), pkt->getSize());
7306657Snate@binkert.org
7317007Snate@binkert.org    pkt->time += pioDelay;
7327007Snate@binkert.org
7337007Snate@binkert.org    if (daddr > LAST && daddr <=  RESERVED) {
7346657Snate@binkert.org        panic("Accessing reserved register");
7356657Snate@binkert.org    } else if (daddr > RESERVED && daddr <= 0x3FC) {
7367007Snate@binkert.org        if (pkt->getSize() == sizeof(uint8_t))
7377007Snate@binkert.org            writeConfig(daddr & 0xff, pkt->get<uint8_t>());
7387567SBrad.Beckmann@amd.com        if (pkt->getSize() == sizeof(uint16_t))
7397567SBrad.Beckmann@amd.com            writeConfig(daddr & 0xff, pkt->get<uint16_t>());
7407567SBrad.Beckmann@amd.com        if (pkt->getSize() == sizeof(uint32_t))
7417567SBrad.Beckmann@amd.com            writeConfig(daddr & 0xff, pkt->get<uint32_t>());
7427567SBrad.Beckmann@amd.com        pkt->result = Packet::Success;
7437567SBrad.Beckmann@amd.com        return pioDelay;
7447567SBrad.Beckmann@amd.com    } else if (daddr > 0x3FC)
7457567SBrad.Beckmann@amd.com        panic("Something is messed up!\n");
7467567SBrad.Beckmann@amd.com
7477567SBrad.Beckmann@amd.com    if (pkt->getSize() == sizeof(uint32_t)) {
7487567SBrad.Beckmann@amd.com        uint32_t reg = pkt->get<uint32_t>();
7497567SBrad.Beckmann@amd.com        uint16_t rfaddr;
7507567SBrad.Beckmann@amd.com
7518155Snilay@cs.wisc.edu        DPRINTF(EthernetPIO, "write data=%d data=%#x\n", reg, reg);
7528155Snilay@cs.wisc.edu
7538155Snilay@cs.wisc.edu        switch (daddr) {
7548155Snilay@cs.wisc.edu          case CR:
7558155Snilay@cs.wisc.edu            regs.command = reg;
7568155Snilay@cs.wisc.edu            if (reg & CR_TXD) {
7578155Snilay@cs.wisc.edu                txEnable = false;
7588155Snilay@cs.wisc.edu            } else if (reg & CR_TXE) {
7598155Snilay@cs.wisc.edu                txEnable = true;
7608155Snilay@cs.wisc.edu
7618155Snilay@cs.wisc.edu                // the kernel is enabling the transmit machine
7627567SBrad.Beckmann@amd.com                if (txState == txIdle)
7638155Snilay@cs.wisc.edu                    txKick();
7648155Snilay@cs.wisc.edu            }
7657567SBrad.Beckmann@amd.com
7667567SBrad.Beckmann@amd.com            if (reg & CR_RXD) {
7677567SBrad.Beckmann@amd.com                rxEnable = false;
7687567SBrad.Beckmann@amd.com            } else if (reg & CR_RXE) {
7697922SBrad.Beckmann@amd.com                rxEnable = true;
7707922SBrad.Beckmann@amd.com
7717922SBrad.Beckmann@amd.com                if (rxState == rxIdle)
7727922SBrad.Beckmann@amd.com                    rxKick();
7737922SBrad.Beckmann@amd.com            }
7747922SBrad.Beckmann@amd.com
7757922SBrad.Beckmann@amd.com            if (reg & CR_TXR)
7767922SBrad.Beckmann@amd.com                txReset();
7778154Snilay@cs.wisc.edu
7788154Snilay@cs.wisc.edu            if (reg & CR_RXR)
7798154Snilay@cs.wisc.edu                rxReset();
7808154Snilay@cs.wisc.edu
7818154Snilay@cs.wisc.edu            if (reg & CR_SWI)
7828154Snilay@cs.wisc.edu                devIntrPost(ISR_SWI);
7838154Snilay@cs.wisc.edu
7848154Snilay@cs.wisc.edu            if (reg & CR_RST) {
7858154Snilay@cs.wisc.edu                txReset();
7868154Snilay@cs.wisc.edu                rxReset();
7878154Snilay@cs.wisc.edu
7888154Snilay@cs.wisc.edu                regsReset();
7898154Snilay@cs.wisc.edu            }
7908154Snilay@cs.wisc.edu            break;
7918154Snilay@cs.wisc.edu
7928154Snilay@cs.wisc.edu          case CFGR:
7938154Snilay@cs.wisc.edu            if (reg & CFGR_LNKSTS ||
7948154Snilay@cs.wisc.edu                reg & CFGR_SPDSTS ||
7958154Snilay@cs.wisc.edu                reg & CFGR_DUPSTS ||
7968154Snilay@cs.wisc.edu                reg & CFGR_RESERVED ||
7978154Snilay@cs.wisc.edu                reg & CFGR_T64ADDR ||
7987922SBrad.Beckmann@amd.com                reg & CFGR_PCI64_DET)
7997922SBrad.Beckmann@amd.com
8007922SBrad.Beckmann@amd.com            // First clear all writable bits
8017922SBrad.Beckmann@amd.com            regs.config &= CFGR_LNKSTS | CFGR_SPDSTS | CFGR_DUPSTS |
8027007Snate@binkert.org                                   CFGR_RESERVED | CFGR_T64ADDR |
8037007Snate@binkert.org                                   CFGR_PCI64_DET;
8046863Sdrh5@cs.wisc.edu            // Now set the appropriate writable bits
8056863Sdrh5@cs.wisc.edu            regs.config |= reg & ~(CFGR_LNKSTS | CFGR_SPDSTS | CFGR_DUPSTS |
8066863Sdrh5@cs.wisc.edu                                   CFGR_RESERVED | CFGR_T64ADDR |
8077007Snate@binkert.org                                   CFGR_PCI64_DET);
8087007Snate@binkert.org
8097007Snate@binkert.org// all these #if 0's are because i don't THINK the kernel needs to
8107007Snate@binkert.org// have these implemented. if there is a problem relating to one of
8116863Sdrh5@cs.wisc.edu// these, you may need to add functionality in.
8126863Sdrh5@cs.wisc.edu            if (reg & CFGR_TBI_EN) ;
8136863Sdrh5@cs.wisc.edu            if (reg & CFGR_MODE_1000) ;
8146863Sdrh5@cs.wisc.edu
8156863Sdrh5@cs.wisc.edu            if (reg & CFGR_AUTO_1000)
8166863Sdrh5@cs.wisc.edu                panic("CFGR_AUTO_1000 not implemented!\n");
8177007Snate@binkert.org
8187007Snate@binkert.org            if (reg & CFGR_PINT_DUPSTS ||
8197007Snate@binkert.org                reg & CFGR_PINT_LNKSTS ||
8207007Snate@binkert.org                reg & CFGR_PINT_SPDSTS)
8217007Snate@binkert.org                ;
8226657Snate@binkert.org
8237007Snate@binkert.org            if (reg & CFGR_TMRTEST) ;
8247007Snate@binkert.org            if (reg & CFGR_MRM_DIS) ;
8257007Snate@binkert.org            if (reg & CFGR_MWI_DIS) ;
8266657Snate@binkert.org
8276657Snate@binkert.org            if (reg & CFGR_T64ADDR) ;
8287007Snate@binkert.org            // panic("CFGR_T64ADDR is read only register!\n");
8297007Snate@binkert.org
8307007Snate@binkert.org            if (reg & CFGR_PCI64_DET)
8316657Snate@binkert.org                panic("CFGR_PCI64_DET is read only register!\n");
8326657Snate@binkert.org
8337007Snate@binkert.org            if (reg & CFGR_DATA64_EN) ;
8347007Snate@binkert.org            if (reg & CFGR_M64ADDR) ;
8357007Snate@binkert.org            if (reg & CFGR_PHY_RST) ;
8366902SBrad.Beckmann@amd.com            if (reg & CFGR_PHY_DIS) ;
8376902SBrad.Beckmann@amd.com
8386902SBrad.Beckmann@amd.com            if (reg & CFGR_EXTSTS_EN)
8396902SBrad.Beckmann@amd.com                extstsEnable = true;
8406902SBrad.Beckmann@amd.com            else
8416902SBrad.Beckmann@amd.com                extstsEnable = false;
8426902SBrad.Beckmann@amd.com
8437025SBrad.Beckmann@amd.com            if (reg & CFGR_REQALG) ;
8446902SBrad.Beckmann@amd.com            if (reg & CFGR_SB) ;
8456902SBrad.Beckmann@amd.com            if (reg & CFGR_POW) ;
8466902SBrad.Beckmann@amd.com            if (reg & CFGR_EXD) ;
8476902SBrad.Beckmann@amd.com            if (reg & CFGR_PESEL) ;
8486902SBrad.Beckmann@amd.com            if (reg & CFGR_BROM_DIS) ;
8497542SBrad.Beckmann@amd.com            if (reg & CFGR_EXT_125) ;
8507542SBrad.Beckmann@amd.com            if (reg & CFGR_BEM) ;
8517542SBrad.Beckmann@amd.com            break;
8526902SBrad.Beckmann@amd.com
8536902SBrad.Beckmann@amd.com          case MEAR:
8546902SBrad.Beckmann@amd.com            // Clear writable bits
8556902SBrad.Beckmann@amd.com            regs.mear &= MEAR_EEDO;
8566902SBrad.Beckmann@amd.com            // Set appropriate writable bits
8576902SBrad.Beckmann@amd.com            regs.mear |= reg & ~MEAR_EEDO;
8586902SBrad.Beckmann@amd.com
8596902SBrad.Beckmann@amd.com            // FreeBSD uses the EEPROM to read PMATCH (for the MAC address)
8606902SBrad.Beckmann@amd.com            // even though it could get it through RFDR
8616902SBrad.Beckmann@amd.com            if (reg & MEAR_EESEL) {
8626902SBrad.Beckmann@amd.com                // Rising edge of clock
8636902SBrad.Beckmann@amd.com                if (reg & MEAR_EECLK && !eepromClk)
8646902SBrad.Beckmann@amd.com                    eepromKick();
8656902SBrad.Beckmann@amd.com            }
8666902SBrad.Beckmann@amd.com            else {
8677542SBrad.Beckmann@amd.com                eepromState = eepromStart;
8686902SBrad.Beckmann@amd.com                regs.mear &= ~MEAR_EEDI;
8697839Snilay@cs.wisc.edu            }
8707839Snilay@cs.wisc.edu
8717839Snilay@cs.wisc.edu            eepromClk = reg & MEAR_EECLK;
8727839Snilay@cs.wisc.edu
8737839Snilay@cs.wisc.edu            // since phy is completely faked, MEAR_MD* don't matter
8747839Snilay@cs.wisc.edu            if (reg & MEAR_MDIO) ;
8757839Snilay@cs.wisc.edu            if (reg & MEAR_MDDIR) ;
8767839Snilay@cs.wisc.edu            if (reg & MEAR_MDC) ;
8777839Snilay@cs.wisc.edu            break;
8787839Snilay@cs.wisc.edu
8797839Snilay@cs.wisc.edu          case PTSCR:
8807839Snilay@cs.wisc.edu            regs.ptscr = reg & ~(PTSCR_RBIST_RDONLY);
8817839Snilay@cs.wisc.edu            // these control BISTs for various parts of chip - we
8827839Snilay@cs.wisc.edu            // don't care or do just fake that the BIST is done
8837839Snilay@cs.wisc.edu            if (reg & PTSCR_RBIST_EN)
8847839Snilay@cs.wisc.edu                regs.ptscr |= PTSCR_RBIST_DONE;
8857839Snilay@cs.wisc.edu            if (reg & PTSCR_EEBIST_EN)
8867839Snilay@cs.wisc.edu                regs.ptscr &= ~PTSCR_EEBIST_EN;
8877839Snilay@cs.wisc.edu            if (reg & PTSCR_EELOAD_EN)
8887839Snilay@cs.wisc.edu                regs.ptscr &= ~PTSCR_EELOAD_EN;
8897839Snilay@cs.wisc.edu            break;
8907839Snilay@cs.wisc.edu
8917839Snilay@cs.wisc.edu          case ISR: /* writing to the ISR has no effect */
8927839Snilay@cs.wisc.edu            panic("ISR is a read only register!\n");
8937839Snilay@cs.wisc.edu
8947839Snilay@cs.wisc.edu          case IMR:
8957839Snilay@cs.wisc.edu            regs.imr = reg;
8967839Snilay@cs.wisc.edu            devIntrChangeMask();
8977839Snilay@cs.wisc.edu            break;
8987839Snilay@cs.wisc.edu
8997839Snilay@cs.wisc.edu          case IER:
9007839Snilay@cs.wisc.edu            regs.ier = reg;
9017839Snilay@cs.wisc.edu            break;
9027839Snilay@cs.wisc.edu
9037839Snilay@cs.wisc.edu          case IHR:
9047839Snilay@cs.wisc.edu            regs.ihr = reg;
9057839Snilay@cs.wisc.edu            /* not going to implement real interrupt holdoff */
9066902SBrad.Beckmann@amd.com            break;
9078683Snilay@cs.wisc.edu
9088683Snilay@cs.wisc.edu          case TXDP:
9098683Snilay@cs.wisc.edu            regs.txdp = (reg & 0xFFFFFFFC);
9108683Snilay@cs.wisc.edu            assert(txState == txIdle);
9118683Snilay@cs.wisc.edu            CTDD = false;
9128683Snilay@cs.wisc.edu            break;
9138683Snilay@cs.wisc.edu
9148683Snilay@cs.wisc.edu          case TXDP_HI:
9158683Snilay@cs.wisc.edu            regs.txdp_hi = reg;
9168683Snilay@cs.wisc.edu            break;
9178683Snilay@cs.wisc.edu
9188683Snilay@cs.wisc.edu          case TX_CFG:
9198683Snilay@cs.wisc.edu            regs.txcfg = reg;
9208683Snilay@cs.wisc.edu#if 0
9218683Snilay@cs.wisc.edu            if (reg & TX_CFG_CSI) ;
9228683Snilay@cs.wisc.edu            if (reg & TX_CFG_HBI) ;
9238683Snilay@cs.wisc.edu            if (reg & TX_CFG_MLB) ;
9246657Snate@binkert.org            if (reg & TX_CFG_ATP) ;
9256657Snate@binkert.org            if (reg & TX_CFG_ECRETRY) {
9267839Snilay@cs.wisc.edu                /*
9277839Snilay@cs.wisc.edu                 * this could easily be implemented, but considering
9287839Snilay@cs.wisc.edu                 * the network is just a fake pipe, wouldn't make
9297839Snilay@cs.wisc.edu                 * sense to do this
9306657Snate@binkert.org                 */
9317839Snilay@cs.wisc.edu            }
9327839Snilay@cs.wisc.edu
9337839Snilay@cs.wisc.edu            if (reg & TX_CFG_BRST_DIS) ;
9347839Snilay@cs.wisc.edu#endif
9357839Snilay@cs.wisc.edu
9368055Sksewell@umich.edu#if 0
9377839Snilay@cs.wisc.edu            /* we handle our own DMA, ignore the kernel's exhortations */
9387839Snilay@cs.wisc.edu            if (reg & TX_CFG_MXDMA) ;
9396657Snate@binkert.org#endif
9407839Snilay@cs.wisc.edu
9417839Snilay@cs.wisc.edu            // also, we currently don't care about fill/drain
9427839Snilay@cs.wisc.edu            // thresholds though this may change in the future with
9437839Snilay@cs.wisc.edu            // more realistic networks or a driver which changes it
9447839Snilay@cs.wisc.edu            // according to feedback
9457839Snilay@cs.wisc.edu
9467839Snilay@cs.wisc.edu            break;
9477839Snilay@cs.wisc.edu
9487839Snilay@cs.wisc.edu          case GPIOR:
9497839Snilay@cs.wisc.edu            // Only write writable bits
9507839Snilay@cs.wisc.edu            regs.gpior &= GPIOR_UNUSED | GPIOR_GP5_IN | GPIOR_GP4_IN
9518055Sksewell@umich.edu                        | GPIOR_GP3_IN | GPIOR_GP2_IN | GPIOR_GP1_IN;
9527839Snilay@cs.wisc.edu            regs.gpior |= reg & ~(GPIOR_UNUSED | GPIOR_GP5_IN | GPIOR_GP4_IN
9537839Snilay@cs.wisc.edu                                | GPIOR_GP3_IN | GPIOR_GP2_IN | GPIOR_GP1_IN);
9547839Snilay@cs.wisc.edu            /* these just control general purpose i/o pins, don't matter */
9557839Snilay@cs.wisc.edu            break;
9567839Snilay@cs.wisc.edu
9577839Snilay@cs.wisc.edu          case RXDP:
9587839Snilay@cs.wisc.edu            regs.rxdp = reg;
9597839Snilay@cs.wisc.edu            CRDD = false;
9607839Snilay@cs.wisc.edu            break;
9617839Snilay@cs.wisc.edu
9627839Snilay@cs.wisc.edu          case RXDP_HI:
9637839Snilay@cs.wisc.edu            regs.rxdp_hi = reg;
9647839Snilay@cs.wisc.edu            break;
9657839Snilay@cs.wisc.edu
9668055Sksewell@umich.edu          case RX_CFG:
9677839Snilay@cs.wisc.edu            regs.rxcfg = reg;
9687839Snilay@cs.wisc.edu#if 0
9697839Snilay@cs.wisc.edu            if (reg & RX_CFG_AEP) ;
9707839Snilay@cs.wisc.edu            if (reg & RX_CFG_ARP) ;
9717839Snilay@cs.wisc.edu            if (reg & RX_CFG_STRIPCRC) ;
9727839Snilay@cs.wisc.edu            if (reg & RX_CFG_RX_RD) ;
9737839Snilay@cs.wisc.edu            if (reg & RX_CFG_ALP) ;
9747839Snilay@cs.wisc.edu            if (reg & RX_CFG_AIRL) ;
9757839Snilay@cs.wisc.edu
9767839Snilay@cs.wisc.edu            /* we handle our own DMA, ignore what kernel says about it */
9776657Snate@binkert.org            if (reg & RX_CFG_MXDMA) ;
9787007Snate@binkert.org
9797007Snate@binkert.org            //also, we currently don't care about fill/drain thresholds
9806657Snate@binkert.org            //though this may change in the future with more realistic
9818055Sksewell@umich.edu            //networks or a driver which changes it according to feedback
9826657Snate@binkert.org            if (reg & (RX_CFG_DRTH | RX_CFG_DRTH0)) ;
9836657Snate@binkert.org#endif
9846657Snate@binkert.org            break;
9856657Snate@binkert.org
9868478Snilay@cs.wisc.edu          case PQCR:
9878478Snilay@cs.wisc.edu            /* there is no priority queueing used in the linux 2.6 driver */
9888478Snilay@cs.wisc.edu            regs.pqcr = reg;
9896657Snate@binkert.org            break;
9906657Snate@binkert.org
9916657Snate@binkert.org          case WCSR:
9926657Snate@binkert.org            /* not going to implement wake on LAN */
9936657Snate@binkert.org            regs.wcsr = reg;
9946999Snate@binkert.org            break;
9956657Snate@binkert.org
9966657Snate@binkert.org          case PCR:
9979104Shestness@cs.utexas.edu            /* not going to implement pause control */
9989104Shestness@cs.utexas.edu            regs.pcr = reg;
9999104Shestness@cs.utexas.edu            break;
10009104Shestness@cs.utexas.edu
10016657Snate@binkert.org          case RFCR:
10026657Snate@binkert.org            regs.rfcr = reg;
10036657Snate@binkert.org
10046657Snate@binkert.org            rxFilterEnable = (reg & RFCR_RFEN) ? true : false;
10058946Sandreas.hansson@arm.com            acceptBroadcast = (reg & RFCR_AAB) ? true : false;
10068946Sandreas.hansson@arm.com            acceptMulticast = (reg & RFCR_AAM) ? true : false;
10078946Sandreas.hansson@arm.com            acceptUnicast = (reg & RFCR_AAU) ? true : false;
10087832Snate@binkert.org            acceptPerfect = (reg & RFCR_APM) ? true : false;
10097832Snate@binkert.org            acceptArp = (reg & RFCR_AARP) ? true : false;
10107007Snate@binkert.org            multicastHashEnable = (reg & RFCR_MHEN) ? true : false;
10118232Snate@binkert.org
10128229Snate@binkert.org#if 0
10138229Snate@binkert.org            if (reg & RFCR_APAT)
10148229Snate@binkert.org                panic("RFCR_APAT not implemented!\n");
10159104Shestness@cs.utexas.edu#endif
10169104Shestness@cs.utexas.edu            if (reg & RFCR_UHEN)
10179104Shestness@cs.utexas.edu                panic("Unicast hash filtering not used by drivers!\n");
10189104Shestness@cs.utexas.edu
10199104Shestness@cs.utexas.edu            if (reg & RFCR_ULM)
10209104Shestness@cs.utexas.edu                panic("RFCR_ULM not implemented!\n");
10218229Snate@binkert.org
10226657Snate@binkert.org            break;
10236657Snate@binkert.org
10246657Snate@binkert.org          case RFDR:
10256657Snate@binkert.org            rfaddr = (uint16_t)(regs.rfcr & RFCR_RFADDR);
10267055Snate@binkert.org            switch (rfaddr) {
10277055Snate@binkert.org              case 0x000:
10287007Snate@binkert.org                rom.perfectMatch[0] = (uint8_t)reg;
10297007Snate@binkert.org                rom.perfectMatch[1] = (uint8_t)(reg >> 8);
10306657Snate@binkert.org                break;
10316657Snate@binkert.org              case 0x002:
10326657Snate@binkert.org                rom.perfectMatch[2] = (uint8_t)reg;
10336657Snate@binkert.org                rom.perfectMatch[3] = (uint8_t)(reg >> 8);
10346657Snate@binkert.org                break;
10356657Snate@binkert.org              case 0x004:
10367007Snate@binkert.org                rom.perfectMatch[4] = (uint8_t)reg;
10377007Snate@binkert.org                rom.perfectMatch[5] = (uint8_t)(reg >> 8);
10387007Snate@binkert.org                break;
10397007Snate@binkert.org              default:
10407007Snate@binkert.org
10416657Snate@binkert.org                if (rfaddr >= FHASH_ADDR &&
10426657Snate@binkert.org                    rfaddr < FHASH_ADDR + FHASH_SIZE) {
10436657Snate@binkert.org
10446657Snate@binkert.org                    // Only word-aligned writes supported
10456657Snate@binkert.org                    if (rfaddr % 2)
10466657Snate@binkert.org                        panic("unaligned write to filter hash table!");
10476657Snate@binkert.org
10486657Snate@binkert.org                    rom.filterHash[rfaddr - FHASH_ADDR] = (uint8_t)reg;
10496657Snate@binkert.org                    rom.filterHash[rfaddr - FHASH_ADDR + 1]
10506657Snate@binkert.org                        = (uint8_t)(reg >> 8);
10516657Snate@binkert.org                    break;
10526657Snate@binkert.org                }
10537567SBrad.Beckmann@amd.com                panic("writing RFDR for something other than pattern matching\
10547567SBrad.Beckmann@amd.com                    or hashing! %#x\n", rfaddr);
10557567SBrad.Beckmann@amd.com            }
10567567SBrad.Beckmann@amd.com
10576657Snate@binkert.org          case BRAR:
10586657Snate@binkert.org            regs.brar = reg;
10596657Snate@binkert.org            break;
10606657Snate@binkert.org
10616657Snate@binkert.org          case BRDR:
10626657Snate@binkert.org            panic("the driver never uses BRDR, something is wrong!\n");
10636657Snate@binkert.org
10646657Snate@binkert.org          case SRR:
10656657Snate@binkert.org            panic("SRR is read only register!\n");
10666657Snate@binkert.org
10677007Snate@binkert.org          case MIBC:
10686657Snate@binkert.org            panic("the driver never uses MIBC, something is wrong!\n");
10696657Snate@binkert.org
10706657Snate@binkert.org          case VRCR:
10716657Snate@binkert.org            regs.vrcr = reg;
10726657Snate@binkert.org            break;
10736657Snate@binkert.org
10746657Snate@binkert.org          case VTCR:
10756657Snate@binkert.org            regs.vtcr = reg;
10766999Snate@binkert.org            break;
10776657Snate@binkert.org
10786657Snate@binkert.org          case VDR:
10796657Snate@binkert.org            panic("the driver never uses VDR, something is wrong!\n");
10806657Snate@binkert.org
10816657Snate@binkert.org          case CCSR:
10826657Snate@binkert.org            /* not going to implement clockrun stuff */
10837832Snate@binkert.org            regs.ccsr = reg;
10847832Snate@binkert.org            break;
10857805Snilay@cs.wisc.edu
10867832Snate@binkert.org          case TBICR:
10878232Snate@binkert.org            regs.tbicr = reg;
10888232Snate@binkert.org            if (reg & TBICR_MR_LOOPBACK)
10898229Snate@binkert.org                panic("TBICR_MR_LOOPBACK never used, something wrong!\n");
10908229Snate@binkert.org
10918229Snate@binkert.org            if (reg & TBICR_MR_AN_ENABLE) {
10928229Snate@binkert.org                regs.tanlpar = regs.tanar;
10936657Snate@binkert.org                regs.tbisr |= (TBISR_MR_AN_COMPLETE | TBISR_MR_LINK_STATUS);
10946657Snate@binkert.org            }
10956657Snate@binkert.org
10966657Snate@binkert.org#if 0
10976657Snate@binkert.org            if (reg & TBICR_MR_RESTART_AN) ;
10986657Snate@binkert.org#endif
10996657Snate@binkert.org
11006657Snate@binkert.org            break;
11017007Snate@binkert.org
11027007Snate@binkert.org          case TBISR:
11037839Snilay@cs.wisc.edu            panic("TBISR is read only register!\n");
11047839Snilay@cs.wisc.edu
11057839Snilay@cs.wisc.edu          case TANAR:
11067839Snilay@cs.wisc.edu            // Only write the writable bits
11077839Snilay@cs.wisc.edu            regs.tanar &= TANAR_RF1 | TANAR_RF2 | TANAR_UNUSED;
11087839Snilay@cs.wisc.edu            regs.tanar |= reg & ~(TANAR_RF1 | TANAR_RF2 | TANAR_UNUSED);
11097839Snilay@cs.wisc.edu
11107839Snilay@cs.wisc.edu            // Pause capability unimplemented
11117839Snilay@cs.wisc.edu#if 0
11127839Snilay@cs.wisc.edu            if (reg & TANAR_PS2) ;
11137007Snate@binkert.org            if (reg & TANAR_PS1) ;
11146657Snate@binkert.org#endif
11157839Snilay@cs.wisc.edu
11167839Snilay@cs.wisc.edu            break;
11178337Snilay@cs.wisc.edu
11187839Snilay@cs.wisc.edu          case TANLPAR:
11198337Snilay@cs.wisc.edu            panic("this should only be written to by the fake phy!\n");
11207839Snilay@cs.wisc.edu
11218337Snilay@cs.wisc.edu          case TANER:
11227839Snilay@cs.wisc.edu            panic("TANER is read only register!\n");
11238337Snilay@cs.wisc.edu
11247839Snilay@cs.wisc.edu          case TESR:
11257839Snilay@cs.wisc.edu            regs.tesr = reg;
11266657Snate@binkert.org            break;
11276657Snate@binkert.org
11287780Snilay@cs.wisc.edu          default:
11297780Snilay@cs.wisc.edu            panic("invalid register access daddr=%#x", daddr);
11307780Snilay@cs.wisc.edu        }
11317780Snilay@cs.wisc.edu    } else {
11327780Snilay@cs.wisc.edu        panic("Invalid Request Size");
11337780Snilay@cs.wisc.edu    }
11346657Snate@binkert.org    pkt->result = Packet::Success;
11357007Snate@binkert.org    return pioDelay;
11367839Snilay@cs.wisc.edu}
11377839Snilay@cs.wisc.edu
11387839Snilay@cs.wisc.eduvoid
11397839Snilay@cs.wisc.eduNSGigE::devIntrPost(uint32_t interrupts)
11407839Snilay@cs.wisc.edu{
11417839Snilay@cs.wisc.edu    if (interrupts & ISR_RESERVE)
11427839Snilay@cs.wisc.edu        panic("Cannot set a reserved interrupt");
11437839Snilay@cs.wisc.edu
11447839Snilay@cs.wisc.edu    if (interrupts & ISR_NOIMPL)
11456657Snate@binkert.org        warn("interrupt not implemented %#x\n", interrupts);
11467839Snilay@cs.wisc.edu
11476657Snate@binkert.org    interrupts &= ISR_IMPL;
11487780Snilay@cs.wisc.edu    regs.isr |= interrupts;
11497780Snilay@cs.wisc.edu
11507542SBrad.Beckmann@amd.com    if (interrupts & regs.imr) {
11518266Sksewell@umich.edu        if (interrupts & ISR_SWI) {
11528266Sksewell@umich.edu            totalSwi++;
11538266Sksewell@umich.edu        }
11548266Sksewell@umich.edu        if (interrupts & ISR_RXIDLE) {
11558266Sksewell@umich.edu            totalRxIdle++;
11568266Sksewell@umich.edu        }
11576657Snate@binkert.org        if (interrupts & ISR_RXOK) {
11587832Snate@binkert.org            totalRxOk++;
11597839Snilay@cs.wisc.edu        }
11607839Snilay@cs.wisc.edu        if (interrupts & ISR_RXDESC) {
11618337Snilay@cs.wisc.edu            totalRxDesc++;
11628341Snilay@cs.wisc.edu        }
11637839Snilay@cs.wisc.edu        if (interrupts & ISR_TXOK) {
11648337Snilay@cs.wisc.edu            totalTxOk++;
11658341Snilay@cs.wisc.edu        }
11667839Snilay@cs.wisc.edu        if (interrupts & ISR_TXIDLE) {
11678337Snilay@cs.wisc.edu            totalTxIdle++;
11688341Snilay@cs.wisc.edu        }
11697839Snilay@cs.wisc.edu        if (interrupts & ISR_TXDESC) {
11708337Snilay@cs.wisc.edu            totalTxDesc++;
11718341Snilay@cs.wisc.edu        }
11727839Snilay@cs.wisc.edu        if (interrupts & ISR_RXORN) {
11737839Snilay@cs.wisc.edu            totalRxOrn++;
11746657Snate@binkert.org        }
11758266Sksewell@umich.edu    }
11768266Sksewell@umich.edu
11778266Sksewell@umich.edu    DPRINTF(EthernetIntr,
11788266Sksewell@umich.edu            "interrupt written to ISR: intr=%#x isr=%#x imr=%#x\n",
11798266Sksewell@umich.edu            interrupts, regs.isr, regs.imr);
11808266Sksewell@umich.edu
11816657Snate@binkert.org    if ((regs.isr & regs.imr)) {
11827780Snilay@cs.wisc.edu        Tick when = curTick;
11838266Sksewell@umich.edu        if ((regs.isr & regs.imr & ISR_NODELAY) == 0)
11848266Sksewell@umich.edu            when += intrDelay;
11858266Sksewell@umich.edu        cpuIntrPost(when);
11868266Sksewell@umich.edu    }
11878266Sksewell@umich.edu}
11888266Sksewell@umich.edu
11896657Snate@binkert.org/* writing this interrupt counting stats inside this means that this function
11906657Snate@binkert.org   is now limited to being used to clear all interrupts upon the kernel
11916657Snate@binkert.org   reading isr and servicing.  just telling you in case you were thinking
11926657Snate@binkert.org   of expanding use.
11936657Snate@binkert.org*/
11947007Snate@binkert.orgvoid
11957007Snate@binkert.orgNSGigE::devIntrClear(uint32_t interrupts)
11967007Snate@binkert.org{
11977007Snate@binkert.org    if (interrupts & ISR_RESERVE)
11987839Snilay@cs.wisc.edu        panic("Cannot clear a reserved interrupt");
11997839Snilay@cs.wisc.edu
12007839Snilay@cs.wisc.edu    if (regs.isr & regs.imr & ISR_SWI) {
12017839Snilay@cs.wisc.edu        postedSwi++;
12027839Snilay@cs.wisc.edu    }
12037839Snilay@cs.wisc.edu    if (regs.isr & regs.imr & ISR_RXIDLE) {
12047839Snilay@cs.wisc.edu        postedRxIdle++;
12057839Snilay@cs.wisc.edu    }
12067839Snilay@cs.wisc.edu    if (regs.isr & regs.imr & ISR_RXOK) {
12077839Snilay@cs.wisc.edu        postedRxOk++;
12087839Snilay@cs.wisc.edu    }
12097007Snate@binkert.org    if (regs.isr & regs.imr & ISR_RXDESC) {
12106657Snate@binkert.org            postedRxDesc++;
12116657Snate@binkert.org    }
12126657Snate@binkert.org    if (regs.isr & regs.imr & ISR_TXOK) {
12136657Snate@binkert.org        postedTxOk++;
12146657Snate@binkert.org    }
12156657Snate@binkert.org    if (regs.isr & regs.imr & ISR_TXIDLE) {
12166657Snate@binkert.org        postedTxIdle++;
12176657Snate@binkert.org    }
12186657Snate@binkert.org    if (regs.isr & regs.imr & ISR_TXDESC) {
12196657Snate@binkert.org        postedTxDesc++;
12206657Snate@binkert.org    }
12216999Snate@binkert.org    if (regs.isr & regs.imr & ISR_RXORN) {
12226657Snate@binkert.org        postedRxOrn++;
12236657Snate@binkert.org    }
12246657Snate@binkert.org
12256657Snate@binkert.org    if (regs.isr & regs.imr & ISR_IMPL)
12266657Snate@binkert.org        postedInterrupts++;
12276657Snate@binkert.org
12289104Shestness@cs.utexas.edu    interrupts &= ~ISR_NOIMPL;
12296657Snate@binkert.org    regs.isr &= ~interrupts;
12306657Snate@binkert.org
12316657Snate@binkert.org    DPRINTF(EthernetIntr,
12326657Snate@binkert.org            "interrupt cleared from ISR: intr=%x isr=%x imr=%x\n",
12336657Snate@binkert.org            interrupts, regs.isr, regs.imr);
12346657Snate@binkert.org
12356657Snate@binkert.org    if (!(regs.isr & regs.imr))
12367007Snate@binkert.org        cpuIntrClear();
12376657Snate@binkert.org}
12386657Snate@binkert.org
12396657Snate@binkert.orgvoid
12406657Snate@binkert.orgNSGigE::devIntrChangeMask()
12416657Snate@binkert.org{
12426657Snate@binkert.org    DPRINTF(EthernetIntr, "interrupt mask changed: isr=%x imr=%x masked=%x\n",
12436657Snate@binkert.org            regs.isr, regs.imr, regs.isr & regs.imr);
12446657Snate@binkert.org
12456657Snate@binkert.org    if (regs.isr & regs.imr)
12466657Snate@binkert.org        cpuIntrPost(curTick);
12476657Snate@binkert.org    else
12489104Shestness@cs.utexas.edu        cpuIntrClear();
12499104Shestness@cs.utexas.edu}
12509104Shestness@cs.utexas.edu
12519104Shestness@cs.utexas.eduvoid
12526657Snate@binkert.orgNSGigE::cpuIntrPost(Tick when)
12536657Snate@binkert.org{
12546657Snate@binkert.org    // If the interrupt you want to post is later than an interrupt
12556657Snate@binkert.org    // already scheduled, just let it post in the coming one and don't
12566657Snate@binkert.org    // schedule another.
12576657Snate@binkert.org    // HOWEVER, must be sure that the scheduled intrTick is in the
12586657Snate@binkert.org    // future (this was formerly the source of a bug)
12596657Snate@binkert.org    /**
12606657Snate@binkert.org     * @todo this warning should be removed and the intrTick code should
12616657Snate@binkert.org     * be fixed.
12627839Snilay@cs.wisc.edu     */
12637839Snilay@cs.wisc.edu    assert(when >= curTick);
12647839Snilay@cs.wisc.edu    assert(intrTick >= curTick || intrTick == 0);
12657839Snilay@cs.wisc.edu    if (when > intrTick && intrTick != 0) {
12667839Snilay@cs.wisc.edu        DPRINTF(EthernetIntr, "don't need to schedule event...intrTick=%d\n",
12677839Snilay@cs.wisc.edu                intrTick);
12687839Snilay@cs.wisc.edu        return;
12697839Snilay@cs.wisc.edu    }
12707839Snilay@cs.wisc.edu
12717839Snilay@cs.wisc.edu    intrTick = when;
12727839Snilay@cs.wisc.edu    if (intrTick < curTick) {
12737839Snilay@cs.wisc.edu        debug_break();
12746657Snate@binkert.org        intrTick = curTick;
12756657Snate@binkert.org    }
12766657Snate@binkert.org
12776657Snate@binkert.org    DPRINTF(EthernetIntr, "going to schedule an interrupt for intrTick=%d\n",
12786657Snate@binkert.org            intrTick);
12796657Snate@binkert.org
12806657Snate@binkert.org    if (intrEvent)
12816657Snate@binkert.org        intrEvent->squash();
12826657Snate@binkert.org    intrEvent = new IntrEvent(this, true);
12836657Snate@binkert.org    intrEvent->schedule(intrTick);
12846657Snate@binkert.org}
12856657Snate@binkert.org
12866657Snate@binkert.orgvoid
12876657Snate@binkert.orgNSGigE::cpuInterrupt()
12886657Snate@binkert.org{
12896657Snate@binkert.org    assert(intrTick == curTick);
12906657Snate@binkert.org
12916657Snate@binkert.org    // Whether or not there's a pending interrupt, we don't care about
12926657Snate@binkert.org    // it anymore
12936657Snate@binkert.org    intrEvent = 0;
12946657Snate@binkert.org    intrTick = 0;
12957805Snilay@cs.wisc.edu
12968159SBrad.Beckmann@amd.com    // Don't send an interrupt if there's already one
12978159SBrad.Beckmann@amd.com    if (cpuPendingIntr) {
12986657Snate@binkert.org        DPRINTF(EthernetIntr,
12996657Snate@binkert.org                "would send an interrupt now, but there's already pending\n");
13006657Snate@binkert.org    } else {
13016657Snate@binkert.org        // Send interrupt
13026657Snate@binkert.org        cpuPendingIntr = true;
13036657Snate@binkert.org
13047542SBrad.Beckmann@amd.com        DPRINTF(EthernetIntr, "posting interrupt\n");
13057542SBrad.Beckmann@amd.com        intrPost();
13067542SBrad.Beckmann@amd.com    }
13077542SBrad.Beckmann@amd.com}
13087542SBrad.Beckmann@amd.com
13097542SBrad.Beckmann@amd.comvoid
13107542SBrad.Beckmann@amd.comNSGigE::cpuIntrClear()
13117542SBrad.Beckmann@amd.com{
13127542SBrad.Beckmann@amd.com    if (!cpuPendingIntr)
13137542SBrad.Beckmann@amd.com        return;
13147542SBrad.Beckmann@amd.com
13157832Snate@binkert.org    if (intrEvent) {
13167542SBrad.Beckmann@amd.com        intrEvent->squash();
13177542SBrad.Beckmann@amd.com        intrEvent = 0;
13187542SBrad.Beckmann@amd.com    }
13198229Snate@binkert.org
13207542SBrad.Beckmann@amd.com    intrTick = 0;
13217542SBrad.Beckmann@amd.com
13227542SBrad.Beckmann@amd.com    cpuPendingIntr = false;
13237542SBrad.Beckmann@amd.com
13247542SBrad.Beckmann@amd.com    DPRINTF(EthernetIntr, "clearing interrupt\n");
13257542SBrad.Beckmann@amd.com    intrClear();
13267542SBrad.Beckmann@amd.com}
13277542SBrad.Beckmann@amd.com
13287542SBrad.Beckmann@amd.combool
13297542SBrad.Beckmann@amd.comNSGigE::cpuIntrPending() const
13307542SBrad.Beckmann@amd.com{ return cpuPendingIntr; }
13317542SBrad.Beckmann@amd.com
13327542SBrad.Beckmann@amd.comvoid
13337542SBrad.Beckmann@amd.comNSGigE::txReset()
13347542SBrad.Beckmann@amd.com{
13357542SBrad.Beckmann@amd.com
13367542SBrad.Beckmann@amd.com    DPRINTF(Ethernet, "transmit reset\n");
13377542SBrad.Beckmann@amd.com
13387542SBrad.Beckmann@amd.com    CTDD = false;
13397542SBrad.Beckmann@amd.com    txEnable = false;;
13407542SBrad.Beckmann@amd.com    txFragPtr = 0;
13417542SBrad.Beckmann@amd.com    assert(txDescCnt == 0);
13427542SBrad.Beckmann@amd.com    txFifo.clear();
13437542SBrad.Beckmann@amd.com    txState = txIdle;
13447542SBrad.Beckmann@amd.com    assert(txDmaState == dmaIdle);
13457542SBrad.Beckmann@amd.com}
13467542SBrad.Beckmann@amd.com
13477542SBrad.Beckmann@amd.comvoid
13487542SBrad.Beckmann@amd.comNSGigE::rxReset()
13497542SBrad.Beckmann@amd.com{
13507542SBrad.Beckmann@amd.com    DPRINTF(Ethernet, "receive reset\n");
13517542SBrad.Beckmann@amd.com
13527542SBrad.Beckmann@amd.com    CRDD = false;
13537542SBrad.Beckmann@amd.com    assert(rxPktBytes == 0);
13547542SBrad.Beckmann@amd.com    rxEnable = false;
13557542SBrad.Beckmann@amd.com    rxFragPtr = 0;
13567542SBrad.Beckmann@amd.com    assert(rxDescCnt == 0);
13577542SBrad.Beckmann@amd.com    assert(rxDmaState == dmaIdle);
13587542SBrad.Beckmann@amd.com    rxFifo.clear();
13597542SBrad.Beckmann@amd.com    rxState = rxIdle;
13607542SBrad.Beckmann@amd.com}
13617542SBrad.Beckmann@amd.com
13627542SBrad.Beckmann@amd.comvoid
13637542SBrad.Beckmann@amd.comNSGigE::regsReset()
13647542SBrad.Beckmann@amd.com{
13657542SBrad.Beckmann@amd.com    memset(&regs, 0, sizeof(regs));
13667542SBrad.Beckmann@amd.com    regs.config = (CFGR_LNKSTS | CFGR_TBI_EN | CFGR_MODE_1000);
13677542SBrad.Beckmann@amd.com    regs.mear = 0x12;
13687542SBrad.Beckmann@amd.com    regs.txcfg = 0x120; // set drain threshold to 1024 bytes and
13697542SBrad.Beckmann@amd.com                        // fill threshold to 32 bytes
13707542SBrad.Beckmann@amd.com    regs.rxcfg = 0x4;   // set drain threshold to 16 bytes
13717542SBrad.Beckmann@amd.com    regs.srr = 0x0103;  // set the silicon revision to rev B or 0x103
13727542SBrad.Beckmann@amd.com    regs.mibc = MIBC_FRZ;
13737542SBrad.Beckmann@amd.com    regs.vdr = 0x81;    // set the vlan tag type to 802.1q
13747542SBrad.Beckmann@amd.com    regs.tesr = 0xc000; // TBI capable of both full and half duplex
13757542SBrad.Beckmann@amd.com    regs.brar = 0xffffffff;
13767542SBrad.Beckmann@amd.com
13777542SBrad.Beckmann@amd.com    extstsEnable = false;
13787542SBrad.Beckmann@amd.com    acceptBroadcast = false;
13797542SBrad.Beckmann@amd.com    acceptMulticast = false;
13807542SBrad.Beckmann@amd.com    acceptUnicast = false;
13817542SBrad.Beckmann@amd.com    acceptPerfect = false;
13827542SBrad.Beckmann@amd.com    acceptArp = false;
13837542SBrad.Beckmann@amd.com}
13847542SBrad.Beckmann@amd.com
13857542SBrad.Beckmann@amd.combool
13867542SBrad.Beckmann@amd.comNSGigE::doRxDmaRead()
13877542SBrad.Beckmann@amd.com{
13887542SBrad.Beckmann@amd.com    assert(rxDmaState == dmaIdle || rxDmaState == dmaReadWaiting);
13897542SBrad.Beckmann@amd.com    rxDmaState = dmaReading;
13907542SBrad.Beckmann@amd.com
13917542SBrad.Beckmann@amd.com    if (dmaPending())
13927542SBrad.Beckmann@amd.com        rxDmaState = dmaReadWaiting;
13937542SBrad.Beckmann@amd.com    else
13947542SBrad.Beckmann@amd.com        dmaRead(rxDmaAddr, rxDmaLen, &rxDmaReadEvent, (uint8_t*)rxDmaData);
13957542SBrad.Beckmann@amd.com
13967542SBrad.Beckmann@amd.com    return true;
13977542SBrad.Beckmann@amd.com}
13987542SBrad.Beckmann@amd.com
13997542SBrad.Beckmann@amd.comvoid
14006657Snate@binkert.orgNSGigE::rxDmaReadDone()
14016999Snate@binkert.org{
14026657Snate@binkert.org    assert(rxDmaState == dmaReading);
14036657Snate@binkert.org    rxDmaState = dmaIdle;
14046657Snate@binkert.org
14056657Snate@binkert.org    DPRINTF(EthernetDMA, "rx dma read  paddr=%#x len=%d\n",
14066657Snate@binkert.org            rxDmaAddr, rxDmaLen);
14076657Snate@binkert.org    DDUMP(EthernetDMA, rxDmaData, rxDmaLen);
14087542SBrad.Beckmann@amd.com
14097542SBrad.Beckmann@amd.com    // If the transmit state machine has a pending DMA, let it go first
14106657Snate@binkert.org    if (txDmaState == dmaReadWaiting || txDmaState == dmaWriteWaiting)
14117832Snate@binkert.org        txKick();
14127002Snate@binkert.org
14137002Snate@binkert.org    rxKick();
14148229Snate@binkert.org}
14158229Snate@binkert.org
14168608Snilay@cs.wisc.edubool
14176657Snate@binkert.orgNSGigE::doRxDmaWrite()
14187007Snate@binkert.org{
14197007Snate@binkert.org    assert(rxDmaState == dmaIdle || rxDmaState == dmaWriteWaiting);
14206657Snate@binkert.org    rxDmaState = dmaWriting;
14216657Snate@binkert.org
14226657Snate@binkert.org    if (dmaPending())
14236657Snate@binkert.org        rxDmaState = dmaWriteWaiting;
14246657Snate@binkert.org    else
14257542SBrad.Beckmann@amd.com        dmaWrite(rxDmaAddr, rxDmaLen, &rxDmaWriteEvent, (uint8_t*)rxDmaData);
14267542SBrad.Beckmann@amd.com    return true;
14277542SBrad.Beckmann@amd.com}
14286657Snate@binkert.org
14296657Snate@binkert.orgvoid
14306657Snate@binkert.orgNSGigE::rxDmaWriteDone()
14316657Snate@binkert.org{
14326657Snate@binkert.org    assert(rxDmaState == dmaWriting);
14336657Snate@binkert.org    rxDmaState = dmaIdle;
14346657Snate@binkert.org
14356657Snate@binkert.org    DPRINTF(EthernetDMA, "rx dma write paddr=%#x len=%d\n",
14366657Snate@binkert.org            rxDmaAddr, rxDmaLen);
14377007Snate@binkert.org    DDUMP(EthernetDMA, rxDmaData, rxDmaLen);
14386657Snate@binkert.org
14396657Snate@binkert.org    // If the transmit state machine has a pending DMA, let it go first
14406657Snate@binkert.org    if (txDmaState == dmaReadWaiting || txDmaState == dmaWriteWaiting)
14416657Snate@binkert.org        txKick();
14426999Snate@binkert.org
14436657Snate@binkert.org    rxKick();
14446657Snate@binkert.org}
14456657Snate@binkert.org
14466657Snate@binkert.orgvoid
14476657Snate@binkert.orgNSGigE::rxKick()
14486657Snate@binkert.org{
14497832Snate@binkert.org    bool is64bit = (bool)(regs.config & CFGR_M64ADDR);
14507832Snate@binkert.org
14516657Snate@binkert.org    DPRINTF(EthernetSM,
14526657Snate@binkert.org            "receive kick rxState=%s (rxBuf.size=%d) %d-bit\n",
14536657Snate@binkert.org            NsRxStateStrings[rxState], rxFifo.size(), is64bit ? 64 : 32);
14546657Snate@binkert.org
14556657Snate@binkert.org    Addr link, bufptr;
14566657Snate@binkert.org    uint32_t &cmdsts = is64bit ? rxDesc64.cmdsts : rxDesc32.cmdsts;
14576657Snate@binkert.org    uint32_t &extsts = is64bit ? rxDesc64.extsts : rxDesc32.extsts;
14586657Snate@binkert.org
14596657Snate@binkert.org  next:
14606657Snate@binkert.org    if (clock) {
14616657Snate@binkert.org        if (rxKickTick > curTick) {
14626657Snate@binkert.org            DPRINTF(EthernetSM, "receive kick exiting, can't run till %d\n",
14636657Snate@binkert.org                    rxKickTick);
14646657Snate@binkert.org
14657007Snate@binkert.org            goto exit;
14667007Snate@binkert.org        }
14677007Snate@binkert.org
14686657Snate@binkert.org        // Go to the next state machine clock tick.
14696657Snate@binkert.org        rxKickTick = curTick + cycles(1);
14706657Snate@binkert.org    }
14717007Snate@binkert.org
14727007Snate@binkert.org    switch(rxDmaState) {
14737007Snate@binkert.org      case dmaReadWaiting:
14746657Snate@binkert.org        if (doRxDmaRead())
14756657Snate@binkert.org            goto exit;
14766657Snate@binkert.org        break;
14776657Snate@binkert.org      case dmaWriteWaiting:
14786657Snate@binkert.org        if (doRxDmaWrite())
14796657Snate@binkert.org            goto exit;
14806657Snate@binkert.org        break;
14816657Snate@binkert.org      default:
14826657Snate@binkert.org        break;
14836657Snate@binkert.org    }
14846657Snate@binkert.org
14857007Snate@binkert.org    link = is64bit ? (Addr)rxDesc64.link : (Addr)rxDesc32.link;
14867007Snate@binkert.org    bufptr = is64bit ? (Addr)rxDesc64.bufptr : (Addr)rxDesc32.bufptr;
14876657Snate@binkert.org
14886657Snate@binkert.org    // see state machine from spec for details
14896657Snate@binkert.org    // the way this works is, if you finish work on one state and can
14906657Snate@binkert.org    // go directly to another, you do that through jumping to the
14916657Snate@binkert.org    // label "next".  however, if you have intermediate work, like DMA
14927007Snate@binkert.org    // so that you can't go to the next state yet, you go to exit and
14937007Snate@binkert.org    // exit the loop.  however, when the DMA is done it will trigger
14947007Snate@binkert.org    // an event and come back to this loop.
14956657Snate@binkert.org    switch (rxState) {
14966657Snate@binkert.org      case rxIdle:
14976657Snate@binkert.org        if (!rxEnable) {
14987007Snate@binkert.org            DPRINTF(EthernetSM, "Receive Disabled! Nothing to do.\n");
14997542SBrad.Beckmann@amd.com            goto exit;
15007542SBrad.Beckmann@amd.com        }
15016657Snate@binkert.org
15027542SBrad.Beckmann@amd.com        if (CRDD) {
15037542SBrad.Beckmann@amd.com            rxState = rxDescRefr;
15047002Snate@binkert.org
15057542SBrad.Beckmann@amd.com            rxDmaAddr = regs.rxdp & 0x3fffffff;
15067542SBrad.Beckmann@amd.com            rxDmaData =
15077542SBrad.Beckmann@amd.com                is64bit ? (void *)&rxDesc64.link : (void *)&rxDesc32.link;
15087542SBrad.Beckmann@amd.com            rxDmaLen = is64bit ? sizeof(rxDesc64.link) : sizeof(rxDesc32.link);
15096657Snate@binkert.org            rxDmaFree = dmaDescFree;
15107542SBrad.Beckmann@amd.com
15117542SBrad.Beckmann@amd.com            descDmaReads++;
15127542SBrad.Beckmann@amd.com            descDmaRdBytes += rxDmaLen;
15137542SBrad.Beckmann@amd.com
15147542SBrad.Beckmann@amd.com            if (doRxDmaRead())
15157542SBrad.Beckmann@amd.com                goto exit;
15167542SBrad.Beckmann@amd.com        } else {
15177542SBrad.Beckmann@amd.com            rxState = rxDescRead;
15186657Snate@binkert.org
15196657Snate@binkert.org            rxDmaAddr = regs.rxdp & 0x3fffffff;
15206657Snate@binkert.org            rxDmaData = is64bit ? (void *)&rxDesc64 : (void *)&rxDesc32;
15216657Snate@binkert.org            rxDmaLen = is64bit ? sizeof(rxDesc64) : sizeof(rxDesc32);
15226657Snate@binkert.org            rxDmaFree = dmaDescFree;
15236657Snate@binkert.org
15247007Snate@binkert.org            descDmaReads++;
15256999Snate@binkert.org            descDmaRdBytes += rxDmaLen;
15267007Snate@binkert.org
15277007Snate@binkert.org            if (doRxDmaRead())
15287007Snate@binkert.org                goto exit;
15297007Snate@binkert.org        }
15307007Snate@binkert.org        break;
15317007Snate@binkert.org
15326657Snate@binkert.org      case rxDescRefr:
15336657Snate@binkert.org        if (rxDmaState != dmaIdle)
15346657Snate@binkert.org            goto exit;
15356657Snate@binkert.org
15366657Snate@binkert.org        rxState = rxAdvance;
15376657Snate@binkert.org        break;
15386657Snate@binkert.org
15396657Snate@binkert.org     case rxDescRead:
15406657Snate@binkert.org        if (rxDmaState != dmaIdle)
15416657Snate@binkert.org            goto exit;
15426657Snate@binkert.org
15436657Snate@binkert.org        DPRINTF(EthernetDesc, "rxDesc: addr=%08x read descriptor\n",
15446657Snate@binkert.org                regs.rxdp & 0x3fffffff);
15456657Snate@binkert.org        DPRINTF(EthernetDesc,
15466657Snate@binkert.org                "rxDesc: link=%#x bufptr=%#x cmdsts=%08x extsts=%08x\n",
15476657Snate@binkert.org                link, bufptr, cmdsts, extsts);
15486657Snate@binkert.org
15496657Snate@binkert.org        if (cmdsts & CMDSTS_OWN) {
15506657Snate@binkert.org            devIntrPost(ISR_RXIDLE);
15516657Snate@binkert.org            rxState = rxIdle;
15526657Snate@binkert.org            goto exit;
15536657Snate@binkert.org        } else {
15546657Snate@binkert.org            rxState = rxFifoBlock;
15556657Snate@binkert.org            rxFragPtr = bufptr;
15566657Snate@binkert.org            rxDescCnt = cmdsts & CMDSTS_LEN_MASK;
15576657Snate@binkert.org        }
15586657Snate@binkert.org        break;
15596657Snate@binkert.org
15606657Snate@binkert.org      case rxFifoBlock:
15616999Snate@binkert.org        if (!rxPacket) {
15626657Snate@binkert.org            /**
15636657Snate@binkert.org             * @todo in reality, we should be able to start processing
15647007Snate@binkert.org             * the packet as it arrives, and not have to wait for the
15657007Snate@binkert.org             * full packet ot be in the receive fifo.
15666657Snate@binkert.org             */
15676657Snate@binkert.org            if (rxFifo.empty())
15686657Snate@binkert.org                goto exit;
15696657Snate@binkert.org
15706657Snate@binkert.org            DPRINTF(EthernetSM, "****processing receive of new packet****\n");
15716657Snate@binkert.org
15726657Snate@binkert.org            // If we don't have a packet, grab a new one from the fifo.
15736657Snate@binkert.org            rxPacket = rxFifo.front();
15746657Snate@binkert.org            rxPktBytes = rxPacket->length;
15756657Snate@binkert.org            rxPacketBufPtr = rxPacket->data;
15766657Snate@binkert.org
15776657Snate@binkert.org#if TRACING_ON
15786657Snate@binkert.org            if (DTRACE(Ethernet)) {
15796657Snate@binkert.org                IpPtr ip(rxPacket);
15806657Snate@binkert.org                if (ip) {
15816657Snate@binkert.org                    DPRINTF(Ethernet, "ID is %d\n", ip->id());
15826657Snate@binkert.org                    TcpPtr tcp(ip);
15836657Snate@binkert.org                    if (tcp) {
15846657Snate@binkert.org                        DPRINTF(Ethernet,
15856657Snate@binkert.org                                "Src Port=%d, Dest Port=%d, Seq=%d, Ack=%d\n",
15866657Snate@binkert.org                                tcp->sport(), tcp->dport(), tcp->seq(),
15876657Snate@binkert.org                                tcp->ack());
15886657Snate@binkert.org                    }
15896657Snate@binkert.org                }
15906657Snate@binkert.org            }
15916657Snate@binkert.org#endif
15926657Snate@binkert.org
15936657Snate@binkert.org            // sanity check - i think the driver behaves like this
15946657Snate@binkert.org            assert(rxDescCnt >= rxPktBytes);
15956657Snate@binkert.org            rxFifo.pop();
15966657Snate@binkert.org        }
15976657Snate@binkert.org
15986657Snate@binkert.org
15996657Snate@binkert.org        // dont' need the && rxDescCnt > 0 if driver sanity check
16006657Snate@binkert.org        // above holds
16016657Snate@binkert.org        if (rxPktBytes > 0) {
16026657Snate@binkert.org            rxState = rxFragWrite;
16036657Snate@binkert.org            // don't need min<>(rxPktBytes,rxDescCnt) if above sanity
16046657Snate@binkert.org            // check holds
16056657Snate@binkert.org            rxXferLen = rxPktBytes;
16066657Snate@binkert.org
16076657Snate@binkert.org            rxDmaAddr = rxFragPtr & 0x3fffffff;
16086657Snate@binkert.org            rxDmaData = rxPacketBufPtr;
16096657Snate@binkert.org            rxDmaLen = rxXferLen;
16106657Snate@binkert.org            rxDmaFree = dmaDataFree;
16116657Snate@binkert.org
16126657Snate@binkert.org            if (doRxDmaWrite())
16136657Snate@binkert.org                goto exit;
16146657Snate@binkert.org
16156657Snate@binkert.org        } else {
16166657Snate@binkert.org            rxState = rxDescWrite;
16176657Snate@binkert.org
16186657Snate@binkert.org            //if (rxPktBytes == 0) {  /* packet is done */
16196657Snate@binkert.org            assert(rxPktBytes == 0);
16206657Snate@binkert.org            DPRINTF(EthernetSM, "done with receiving packet\n");
16216657Snate@binkert.org
16226657Snate@binkert.org            cmdsts |= CMDSTS_OWN;
16236657Snate@binkert.org            cmdsts &= ~CMDSTS_MORE;
16246657Snate@binkert.org            cmdsts |= CMDSTS_OK;
16256657Snate@binkert.org            cmdsts &= 0xffff0000;
16266657Snate@binkert.org            cmdsts += rxPacket->length;   //i.e. set CMDSTS_SIZE
16276657Snate@binkert.org
16286657Snate@binkert.org#if 0
16296657Snate@binkert.org            /*
16306657Snate@binkert.org             * all the driver uses these are for its own stats keeping
16316657Snate@binkert.org             * which we don't care about, aren't necessary for
16326657Snate@binkert.org             * functionality and doing this would just slow us down.
16336657Snate@binkert.org             * if they end up using this in a later version for
16346657Snate@binkert.org             * functional purposes, just undef
16356657Snate@binkert.org             */
16366657Snate@binkert.org            if (rxFilterEnable) {
16376657Snate@binkert.org                cmdsts &= ~CMDSTS_DEST_MASK;
16386657Snate@binkert.org                const EthAddr &dst = rxFifoFront()->dst();
16396657Snate@binkert.org                if (dst->unicast())
16406657Snate@binkert.org                    cmdsts |= CMDSTS_DEST_SELF;
16416657Snate@binkert.org                if (dst->multicast())
16426657Snate@binkert.org                    cmdsts |= CMDSTS_DEST_MULTI;
16436657Snate@binkert.org                if (dst->broadcast())
16446657Snate@binkert.org                    cmdsts |= CMDSTS_DEST_MASK;
16456657Snate@binkert.org            }
16466657Snate@binkert.org#endif
16476657Snate@binkert.org
16486657Snate@binkert.org            IpPtr ip(rxPacket);
16496657Snate@binkert.org            if (extstsEnable && ip) {
16506657Snate@binkert.org                extsts |= EXTSTS_IPPKT;
16516657Snate@binkert.org                rxIpChecksums++;
16526657Snate@binkert.org                if (cksum(ip) != 0) {
16536657Snate@binkert.org                    DPRINTF(EthernetCksum, "Rx IP Checksum Error\n");
16547007Snate@binkert.org                    extsts |= EXTSTS_IPERR;
16556657Snate@binkert.org                }
16566657Snate@binkert.org                TcpPtr tcp(ip);
16576657Snate@binkert.org                UdpPtr udp(ip);
16586657Snate@binkert.org                if (tcp) {
16596657Snate@binkert.org                    extsts |= EXTSTS_TCPPKT;
16606657Snate@binkert.org                    rxTcpChecksums++;
16616657Snate@binkert.org                    if (cksum(tcp) != 0) {
16627007Snate@binkert.org                        DPRINTF(EthernetCksum, "Rx TCP Checksum Error\n");
16636657Snate@binkert.org                        extsts |= EXTSTS_TCPERR;
16646657Snate@binkert.org
16656657Snate@binkert.org                    }
16666657Snate@binkert.org                } else if (udp) {
16676657Snate@binkert.org                    extsts |= EXTSTS_UDPPKT;
16686657Snate@binkert.org                    rxUdpChecksums++;
16696657Snate@binkert.org                    if (cksum(udp) != 0) {
16706657Snate@binkert.org                        DPRINTF(EthernetCksum, "Rx UDP Checksum Error\n");
16716657Snate@binkert.org                        extsts |= EXTSTS_UDPERR;
16726657Snate@binkert.org                    }
16736657Snate@binkert.org                }
16746657Snate@binkert.org            }
16756657Snate@binkert.org            rxPacket = 0;
16766657Snate@binkert.org
16776657Snate@binkert.org            /*
16787007Snate@binkert.org             * the driver seems to always receive into desc buffers
16796657Snate@binkert.org             * of size 1514, so you never have a pkt that is split
16806657Snate@binkert.org             * into multiple descriptors on the receive side, so
16816657Snate@binkert.org             * i don't implement that case, hence the assert above.
16826657Snate@binkert.org             */
16836657Snate@binkert.org
16846657Snate@binkert.org            DPRINTF(EthernetDesc,
16856657Snate@binkert.org                    "rxDesc: addr=%08x writeback cmdsts extsts\n",
16866657Snate@binkert.org                    regs.rxdp & 0x3fffffff);
16876657Snate@binkert.org            DPRINTF(EthernetDesc,
16886657Snate@binkert.org                    "rxDesc: link=%#x bufptr=%#x cmdsts=%08x extsts=%08x\n",
16896657Snate@binkert.org                    link, bufptr, cmdsts, extsts);
16906657Snate@binkert.org
16916657Snate@binkert.org            rxDmaAddr = regs.rxdp & 0x3fffffff;
16926657Snate@binkert.org            rxDmaData = &cmdsts;
16936657Snate@binkert.org            if (is64bit) {
16946657Snate@binkert.org                rxDmaAddr += offsetof(ns_desc64, cmdsts);
16956657Snate@binkert.org                rxDmaLen = sizeof(rxDesc64.cmdsts) + sizeof(rxDesc64.extsts);
16966657Snate@binkert.org            } else {
16976657Snate@binkert.org                rxDmaAddr += offsetof(ns_desc32, cmdsts);
16986657Snate@binkert.org                rxDmaLen = sizeof(rxDesc32.cmdsts) + sizeof(rxDesc32.extsts);
16996657Snate@binkert.org            }
17006657Snate@binkert.org            rxDmaFree = dmaDescFree;
1701
1702            descDmaWrites++;
1703            descDmaWrBytes += rxDmaLen;
1704
1705            if (doRxDmaWrite())
1706                goto exit;
1707        }
1708        break;
1709
1710      case rxFragWrite:
1711        if (rxDmaState != dmaIdle)
1712            goto exit;
1713
1714        rxPacketBufPtr += rxXferLen;
1715        rxFragPtr += rxXferLen;
1716        rxPktBytes -= rxXferLen;
1717
1718        rxState = rxFifoBlock;
1719        break;
1720
1721      case rxDescWrite:
1722        if (rxDmaState != dmaIdle)
1723            goto exit;
1724
1725        assert(cmdsts & CMDSTS_OWN);
1726
1727        assert(rxPacket == 0);
1728        devIntrPost(ISR_RXOK);
1729
1730        if (cmdsts & CMDSTS_INTR)
1731            devIntrPost(ISR_RXDESC);
1732
1733        if (!rxEnable) {
1734            DPRINTF(EthernetSM, "Halting the RX state machine\n");
1735            rxState = rxIdle;
1736            goto exit;
1737        } else
1738            rxState = rxAdvance;
1739        break;
1740
1741      case rxAdvance:
1742        if (link == 0) {
1743            devIntrPost(ISR_RXIDLE);
1744            rxState = rxIdle;
1745            CRDD = true;
1746            goto exit;
1747        } else {
1748            if (rxDmaState != dmaIdle)
1749                goto exit;
1750            rxState = rxDescRead;
1751            regs.rxdp = link;
1752            CRDD = false;
1753
1754            rxDmaAddr = regs.rxdp & 0x3fffffff;
1755            rxDmaData = is64bit ? (void *)&rxDesc64 : (void *)&rxDesc32;
1756            rxDmaLen = is64bit ? sizeof(rxDesc64) : sizeof(rxDesc32);
1757            rxDmaFree = dmaDescFree;
1758
1759            if (doRxDmaRead())
1760                goto exit;
1761        }
1762        break;
1763
1764      default:
1765        panic("Invalid rxState!");
1766    }
1767
1768    DPRINTF(EthernetSM, "entering next rxState=%s\n",
1769            NsRxStateStrings[rxState]);
1770    goto next;
1771
1772  exit:
1773    /**
1774     * @todo do we want to schedule a future kick?
1775     */
1776    DPRINTF(EthernetSM, "rx state machine exited rxState=%s\n",
1777            NsRxStateStrings[rxState]);
1778
1779    if (clock && !rxKickEvent.scheduled())
1780        rxKickEvent.schedule(rxKickTick);
1781}
1782
1783void
1784NSGigE::transmit()
1785{
1786    if (txFifo.empty()) {
1787        DPRINTF(Ethernet, "nothing to transmit\n");
1788        return;
1789    }
1790
1791    DPRINTF(Ethernet, "Attempt Pkt Transmit: txFifo length=%d\n",
1792            txFifo.size());
1793    if (interface->sendPacket(txFifo.front())) {
1794#if TRACING_ON
1795        if (DTRACE(Ethernet)) {
1796            IpPtr ip(txFifo.front());
1797            if (ip) {
1798                DPRINTF(Ethernet, "ID is %d\n", ip->id());
1799                TcpPtr tcp(ip);
1800                if (tcp) {
1801                    DPRINTF(Ethernet,
1802                            "Src Port=%d, Dest Port=%d, Seq=%d, Ack=%d\n",
1803                            tcp->sport(), tcp->dport(), tcp->seq(),
1804                            tcp->ack());
1805                }
1806            }
1807        }
1808#endif
1809
1810        DDUMP(EthernetData, txFifo.front()->data, txFifo.front()->length);
1811        txBytes += txFifo.front()->length;
1812        txPackets++;
1813
1814        DPRINTF(Ethernet, "Successful Xmit! now txFifoAvail is %d\n",
1815                txFifo.avail());
1816        txFifo.pop();
1817
1818        /*
1819         * normally do a writeback of the descriptor here, and ONLY
1820         * after that is done, send this interrupt.  but since our
1821         * stuff never actually fails, just do this interrupt here,
1822         * otherwise the code has to stray from this nice format.
1823         * besides, it's functionally the same.
1824         */
1825        devIntrPost(ISR_TXOK);
1826    }
1827
1828   if (!txFifo.empty() && !txEvent.scheduled()) {
1829       DPRINTF(Ethernet, "reschedule transmit\n");
1830       txEvent.schedule(curTick + retryTime);
1831   }
1832}
1833
1834bool
1835NSGigE::doTxDmaRead()
1836{
1837    assert(txDmaState == dmaIdle || txDmaState == dmaReadWaiting);
1838    txDmaState = dmaReading;
1839
1840    if (dmaPending())
1841        txDmaState = dmaReadWaiting;
1842    else
1843        dmaRead(txDmaAddr, txDmaLen, &txDmaReadEvent, (uint8_t*)txDmaData);
1844
1845    return true;
1846}
1847
1848void
1849NSGigE::txDmaReadDone()
1850{
1851    assert(txDmaState == dmaReading);
1852    txDmaState = dmaIdle;
1853
1854    DPRINTF(EthernetDMA, "tx dma read  paddr=%#x len=%d\n",
1855            txDmaAddr, txDmaLen);
1856    DDUMP(EthernetDMA, txDmaData, txDmaLen);
1857
1858    // If the receive state machine  has a pending DMA, let it go first
1859    if (rxDmaState == dmaReadWaiting || rxDmaState == dmaWriteWaiting)
1860        rxKick();
1861
1862    txKick();
1863}
1864
1865bool
1866NSGigE::doTxDmaWrite()
1867{
1868    assert(txDmaState == dmaIdle || txDmaState == dmaWriteWaiting);
1869    txDmaState = dmaWriting;
1870
1871    if (dmaPending())
1872        txDmaState = dmaWriteWaiting;
1873    else
1874        dmaWrite(txDmaAddr, txDmaLen, &txDmaWriteEvent, (uint8_t*)txDmaData);
1875    return true;
1876}
1877
1878void
1879NSGigE::txDmaWriteDone()
1880{
1881    assert(txDmaState == dmaWriting);
1882    txDmaState = dmaIdle;
1883
1884    DPRINTF(EthernetDMA, "tx dma write paddr=%#x len=%d\n",
1885            txDmaAddr, txDmaLen);
1886    DDUMP(EthernetDMA, txDmaData, txDmaLen);
1887
1888    // If the receive state machine  has a pending DMA, let it go first
1889    if (rxDmaState == dmaReadWaiting || rxDmaState == dmaWriteWaiting)
1890        rxKick();
1891
1892    txKick();
1893}
1894
1895void
1896NSGigE::txKick()
1897{
1898    bool is64bit = (bool)(regs.config & CFGR_M64ADDR);
1899
1900    DPRINTF(EthernetSM, "transmit kick txState=%s %d-bit\n",
1901            NsTxStateStrings[txState], is64bit ? 64 : 32);
1902
1903    Addr link, bufptr;
1904    uint32_t &cmdsts = is64bit ? txDesc64.cmdsts : txDesc32.cmdsts;
1905    uint32_t &extsts = is64bit ? txDesc64.extsts : txDesc32.extsts;
1906
1907  next:
1908    if (clock) {
1909        if (txKickTick > curTick) {
1910            DPRINTF(EthernetSM, "transmit kick exiting, can't run till %d\n",
1911                    txKickTick);
1912            goto exit;
1913        }
1914
1915        // Go to the next state machine clock tick.
1916        txKickTick = curTick + cycles(1);
1917    }
1918
1919    switch(txDmaState) {
1920      case dmaReadWaiting:
1921        if (doTxDmaRead())
1922            goto exit;
1923        break;
1924      case dmaWriteWaiting:
1925        if (doTxDmaWrite())
1926            goto exit;
1927        break;
1928      default:
1929        break;
1930    }
1931
1932    link = is64bit ? (Addr)txDesc64.link : (Addr)txDesc32.link;
1933    bufptr = is64bit ? (Addr)txDesc64.bufptr : (Addr)txDesc32.bufptr;
1934    switch (txState) {
1935      case txIdle:
1936        if (!txEnable) {
1937            DPRINTF(EthernetSM, "Transmit disabled.  Nothing to do.\n");
1938            goto exit;
1939        }
1940
1941        if (CTDD) {
1942            txState = txDescRefr;
1943
1944            txDmaAddr = regs.txdp & 0x3fffffff;
1945            txDmaData =
1946                is64bit ? (void *)&txDesc64.link : (void *)&txDesc32.link;
1947            txDmaLen = is64bit ? sizeof(txDesc64.link) : sizeof(txDesc32.link);
1948            txDmaFree = dmaDescFree;
1949
1950            descDmaReads++;
1951            descDmaRdBytes += txDmaLen;
1952
1953            if (doTxDmaRead())
1954                goto exit;
1955
1956        } else {
1957            txState = txDescRead;
1958
1959            txDmaAddr = regs.txdp & 0x3fffffff;
1960            txDmaData = is64bit ? (void *)&txDesc64 : (void *)&txDesc32;
1961            txDmaLen = is64bit ? sizeof(txDesc64) : sizeof(txDesc32);
1962            txDmaFree = dmaDescFree;
1963
1964            descDmaReads++;
1965            descDmaRdBytes += txDmaLen;
1966
1967            if (doTxDmaRead())
1968                goto exit;
1969        }
1970        break;
1971
1972      case txDescRefr:
1973        if (txDmaState != dmaIdle)
1974            goto exit;
1975
1976        txState = txAdvance;
1977        break;
1978
1979      case txDescRead:
1980        if (txDmaState != dmaIdle)
1981            goto exit;
1982
1983        DPRINTF(EthernetDesc, "txDesc: addr=%08x read descriptor\n",
1984                regs.txdp & 0x3fffffff);
1985        DPRINTF(EthernetDesc,
1986                "txDesc: link=%#x bufptr=%#x cmdsts=%#08x extsts=%#08x\n",
1987                link, bufptr, cmdsts, extsts);
1988
1989        if (cmdsts & CMDSTS_OWN) {
1990            txState = txFifoBlock;
1991            txFragPtr = bufptr;
1992            txDescCnt = cmdsts & CMDSTS_LEN_MASK;
1993        } else {
1994            devIntrPost(ISR_TXIDLE);
1995            txState = txIdle;
1996            goto exit;
1997        }
1998        break;
1999
2000      case txFifoBlock:
2001        if (!txPacket) {
2002            DPRINTF(EthernetSM, "****starting the tx of a new packet****\n");
2003            txPacket = new EthPacketData(16384);
2004            txPacketBufPtr = txPacket->data;
2005        }
2006
2007        if (txDescCnt == 0) {
2008            DPRINTF(EthernetSM, "the txDescCnt == 0, done with descriptor\n");
2009            if (cmdsts & CMDSTS_MORE) {
2010                DPRINTF(EthernetSM, "there are more descriptors to come\n");
2011                txState = txDescWrite;
2012
2013                cmdsts &= ~CMDSTS_OWN;
2014
2015                txDmaAddr = regs.txdp & 0x3fffffff;
2016                txDmaData = &cmdsts;
2017                if (is64bit) {
2018                    txDmaAddr += offsetof(ns_desc64, cmdsts);
2019                    txDmaLen = sizeof(txDesc64.cmdsts);
2020                } else {
2021                    txDmaAddr += offsetof(ns_desc32, cmdsts);
2022                    txDmaLen = sizeof(txDesc32.cmdsts);
2023                }
2024                txDmaFree = dmaDescFree;
2025
2026                if (doTxDmaWrite())
2027                    goto exit;
2028
2029            } else { /* this packet is totally done */
2030                DPRINTF(EthernetSM, "This packet is done, let's wrap it up\n");
2031                /* deal with the the packet that just finished */
2032                if ((regs.vtcr & VTCR_PPCHK) && extstsEnable) {
2033                    IpPtr ip(txPacket);
2034                    if (extsts & EXTSTS_UDPPKT) {
2035                        UdpPtr udp(ip);
2036                        udp->sum(0);
2037                        udp->sum(cksum(udp));
2038                        txUdpChecksums++;
2039                    } else if (extsts & EXTSTS_TCPPKT) {
2040                        TcpPtr tcp(ip);
2041                        tcp->sum(0);
2042                        tcp->sum(cksum(tcp));
2043                        txTcpChecksums++;
2044                    }
2045                    if (extsts & EXTSTS_IPPKT) {
2046                        ip->sum(0);
2047                        ip->sum(cksum(ip));
2048                        txIpChecksums++;
2049                    }
2050                }
2051
2052                txPacket->length = txPacketBufPtr - txPacket->data;
2053                // this is just because the receive can't handle a
2054                // packet bigger want to make sure
2055                if (txPacket->length > 1514)
2056                    panic("transmit packet too large, %s > 1514\n",
2057                          txPacket->length);
2058
2059#ifndef NDEBUG
2060                bool success =
2061#endif
2062                    txFifo.push(txPacket);
2063                assert(success);
2064
2065                /*
2066                 * this following section is not tqo spec, but
2067                 * functionally shouldn't be any different.  normally,
2068                 * the chip will wait til the transmit has occurred
2069                 * before writing back the descriptor because it has
2070                 * to wait to see that it was successfully transmitted
2071                 * to decide whether to set CMDSTS_OK or not.
2072                 * however, in the simulator since it is always
2073                 * successfully transmitted, and writing it exactly to
2074                 * spec would complicate the code, we just do it here
2075                 */
2076
2077                cmdsts &= ~CMDSTS_OWN;
2078                cmdsts |= CMDSTS_OK;
2079
2080                DPRINTF(EthernetDesc,
2081                        "txDesc writeback: cmdsts=%08x extsts=%08x\n",
2082                        cmdsts, extsts);
2083
2084                txDmaFree = dmaDescFree;
2085                txDmaAddr = regs.txdp & 0x3fffffff;
2086                txDmaData = &cmdsts;
2087                if (is64bit) {
2088                    txDmaAddr += offsetof(ns_desc64, cmdsts);
2089                    txDmaLen =
2090                        sizeof(txDesc64.cmdsts) + sizeof(txDesc64.extsts);
2091                } else {
2092                    txDmaAddr += offsetof(ns_desc32, cmdsts);
2093                    txDmaLen =
2094                        sizeof(txDesc32.cmdsts) + sizeof(txDesc32.extsts);
2095                }
2096
2097                descDmaWrites++;
2098                descDmaWrBytes += txDmaLen;
2099
2100                transmit();
2101                txPacket = 0;
2102
2103                if (!txEnable) {
2104                    DPRINTF(EthernetSM, "halting TX state machine\n");
2105                    txState = txIdle;
2106                    goto exit;
2107                } else
2108                    txState = txAdvance;
2109
2110                if (doTxDmaWrite())
2111                    goto exit;
2112            }
2113        } else {
2114            DPRINTF(EthernetSM, "this descriptor isn't done yet\n");
2115            if (!txFifo.full()) {
2116                txState = txFragRead;
2117
2118                /*
2119                 * The number of bytes transferred is either whatever
2120                 * is left in the descriptor (txDescCnt), or if there
2121                 * is not enough room in the fifo, just whatever room
2122                 * is left in the fifo
2123                 */
2124                txXferLen = min<uint32_t>(txDescCnt, txFifo.avail());
2125
2126                txDmaAddr = txFragPtr & 0x3fffffff;
2127                txDmaData = txPacketBufPtr;
2128                txDmaLen = txXferLen;
2129                txDmaFree = dmaDataFree;
2130
2131                if (doTxDmaRead())
2132                    goto exit;
2133            } else {
2134                txState = txFifoBlock;
2135                transmit();
2136
2137                goto exit;
2138            }
2139
2140        }
2141        break;
2142
2143      case txFragRead:
2144        if (txDmaState != dmaIdle)
2145            goto exit;
2146
2147        txPacketBufPtr += txXferLen;
2148        txFragPtr += txXferLen;
2149        txDescCnt -= txXferLen;
2150        txFifo.reserve(txXferLen);
2151
2152        txState = txFifoBlock;
2153        break;
2154
2155      case txDescWrite:
2156        if (txDmaState != dmaIdle)
2157            goto exit;
2158
2159        if (cmdsts & CMDSTS_INTR)
2160            devIntrPost(ISR_TXDESC);
2161
2162        if (!txEnable) {
2163            DPRINTF(EthernetSM, "halting TX state machine\n");
2164            txState = txIdle;
2165            goto exit;
2166        } else
2167            txState = txAdvance;
2168        break;
2169
2170      case txAdvance:
2171        if (link == 0) {
2172            devIntrPost(ISR_TXIDLE);
2173            txState = txIdle;
2174            goto exit;
2175        } else {
2176            if (txDmaState != dmaIdle)
2177                goto exit;
2178            txState = txDescRead;
2179            regs.txdp = link;
2180            CTDD = false;
2181
2182            txDmaAddr = link & 0x3fffffff;
2183            txDmaData = is64bit ? (void *)&txDesc64 : (void *)&txDesc32;
2184            txDmaLen = is64bit ? sizeof(txDesc64) : sizeof(txDesc32);
2185            txDmaFree = dmaDescFree;
2186
2187            if (doTxDmaRead())
2188                goto exit;
2189        }
2190        break;
2191
2192      default:
2193        panic("invalid state");
2194    }
2195
2196    DPRINTF(EthernetSM, "entering next txState=%s\n",
2197            NsTxStateStrings[txState]);
2198    goto next;
2199
2200  exit:
2201    /**
2202     * @todo do we want to schedule a future kick?
2203     */
2204    DPRINTF(EthernetSM, "tx state machine exited txState=%s\n",
2205            NsTxStateStrings[txState]);
2206
2207    if (clock && !txKickEvent.scheduled())
2208        txKickEvent.schedule(txKickTick);
2209}
2210
2211/**
2212 * Advance the EEPROM state machine
2213 * Called on rising edge of EEPROM clock bit in MEAR
2214 */
2215void
2216NSGigE::eepromKick()
2217{
2218    switch (eepromState) {
2219
2220      case eepromStart:
2221
2222        // Wait for start bit
2223        if (regs.mear & MEAR_EEDI) {
2224            // Set up to get 2 opcode bits
2225            eepromState = eepromGetOpcode;
2226            eepromBitsToRx = 2;
2227            eepromOpcode = 0;
2228        }
2229        break;
2230
2231      case eepromGetOpcode:
2232        eepromOpcode <<= 1;
2233        eepromOpcode += (regs.mear & MEAR_EEDI) ? 1 : 0;
2234        --eepromBitsToRx;
2235
2236        // Done getting opcode
2237        if (eepromBitsToRx == 0) {
2238            if (eepromOpcode != EEPROM_READ)
2239                panic("only EEPROM reads are implemented!");
2240
2241            // Set up to get address
2242            eepromState = eepromGetAddress;
2243            eepromBitsToRx = 6;
2244            eepromAddress = 0;
2245        }
2246        break;
2247
2248      case eepromGetAddress:
2249        eepromAddress <<= 1;
2250        eepromAddress += (regs.mear & MEAR_EEDI) ? 1 : 0;
2251        --eepromBitsToRx;
2252
2253        // Done getting address
2254        if (eepromBitsToRx == 0) {
2255
2256            if (eepromAddress >= EEPROM_SIZE)
2257                panic("EEPROM read access out of range!");
2258
2259            switch (eepromAddress) {
2260
2261              case EEPROM_PMATCH2_ADDR:
2262                eepromData = rom.perfectMatch[5];
2263                eepromData <<= 8;
2264                eepromData += rom.perfectMatch[4];
2265                break;
2266
2267              case EEPROM_PMATCH1_ADDR:
2268                eepromData = rom.perfectMatch[3];
2269                eepromData <<= 8;
2270                eepromData += rom.perfectMatch[2];
2271                break;
2272
2273              case EEPROM_PMATCH0_ADDR:
2274                eepromData = rom.perfectMatch[1];
2275                eepromData <<= 8;
2276                eepromData += rom.perfectMatch[0];
2277                break;
2278
2279              default:
2280                panic("FreeBSD driver only uses EEPROM to read PMATCH!");
2281            }
2282            // Set up to read data
2283            eepromState = eepromRead;
2284            eepromBitsToRx = 16;
2285
2286            // Clear data in bit
2287            regs.mear &= ~MEAR_EEDI;
2288        }
2289        break;
2290
2291      case eepromRead:
2292        // Clear Data Out bit
2293        regs.mear &= ~MEAR_EEDO;
2294        // Set bit to value of current EEPROM bit
2295        regs.mear |= (eepromData & 0x8000) ? MEAR_EEDO : 0x0;
2296
2297        eepromData <<= 1;
2298        --eepromBitsToRx;
2299
2300        // All done
2301        if (eepromBitsToRx == 0) {
2302            eepromState = eepromStart;
2303        }
2304        break;
2305
2306      default:
2307        panic("invalid EEPROM state");
2308    }
2309
2310}
2311
2312void
2313NSGigE::transferDone()
2314{
2315    if (txFifo.empty()) {
2316        DPRINTF(Ethernet, "transfer complete: txFifo empty...nothing to do\n");
2317        return;
2318    }
2319
2320    DPRINTF(Ethernet, "transfer complete: data in txFifo...schedule xmit\n");
2321
2322    if (txEvent.scheduled())
2323        txEvent.reschedule(curTick + cycles(1));
2324    else
2325        txEvent.schedule(curTick + cycles(1));
2326}
2327
2328bool
2329NSGigE::rxFilter(const EthPacketPtr &packet)
2330{
2331    EthPtr eth = packet;
2332    bool drop = true;
2333    string type;
2334
2335    const EthAddr &dst = eth->dst();
2336    if (dst.unicast()) {
2337        // If we're accepting all unicast addresses
2338        if (acceptUnicast)
2339            drop = false;
2340
2341        // If we make a perfect match
2342        if (acceptPerfect && dst == rom.perfectMatch)
2343            drop = false;
2344
2345        if (acceptArp && eth->type() == ETH_TYPE_ARP)
2346            drop = false;
2347
2348    } else if (dst.broadcast()) {
2349        // if we're accepting broadcasts
2350        if (acceptBroadcast)
2351            drop = false;
2352
2353    } else if (dst.multicast()) {
2354        // if we're accepting all multicasts
2355        if (acceptMulticast)
2356            drop = false;
2357
2358        // Multicast hashing faked - all packets accepted
2359        if (multicastHashEnable)
2360            drop = false;
2361    }
2362
2363    if (drop) {
2364        DPRINTF(Ethernet, "rxFilter drop\n");
2365        DDUMP(EthernetData, packet->data, packet->length);
2366    }
2367
2368    return drop;
2369}
2370
2371bool
2372NSGigE::recvPacket(EthPacketPtr packet)
2373{
2374    rxBytes += packet->length;
2375    rxPackets++;
2376
2377    DPRINTF(Ethernet, "Receiving packet from wire, rxFifoAvail=%d\n",
2378            rxFifo.avail());
2379
2380    if (!rxEnable) {
2381        DPRINTF(Ethernet, "receive disabled...packet dropped\n");
2382        return true;
2383    }
2384
2385    if (!rxFilterEnable) {
2386        DPRINTF(Ethernet,
2387            "receive packet filtering disabled . . . packet dropped\n");
2388        return true;
2389    }
2390
2391    if (rxFilter(packet)) {
2392        DPRINTF(Ethernet, "packet filtered...dropped\n");
2393        return true;
2394    }
2395
2396    if (rxFifo.avail() < packet->length) {
2397#if TRACING_ON
2398        IpPtr ip(packet);
2399        TcpPtr tcp(ip);
2400        if (ip) {
2401            DPRINTF(Ethernet,
2402                    "packet won't fit in receive buffer...pkt ID %d dropped\n",
2403                    ip->id());
2404            if (tcp) {
2405                DPRINTF(Ethernet, "Seq=%d\n", tcp->seq());
2406            }
2407        }
2408#endif
2409        droppedPackets++;
2410        devIntrPost(ISR_RXORN);
2411        return false;
2412    }
2413
2414    rxFifo.push(packet);
2415
2416    rxKick();
2417    return true;
2418}
2419
2420//=====================================================================
2421//
2422//
2423void
2424NSGigE::serialize(ostream &os)
2425{
2426    // Serialize the PciDev base class
2427    PciDev::serialize(os);
2428
2429    /*
2430     * Finalize any DMA events now.
2431     */
2432    // @todo will mem system save pending dma?
2433
2434    /*
2435     * Serialize the device registers
2436     */
2437    SERIALIZE_SCALAR(regs.command);
2438    SERIALIZE_SCALAR(regs.config);
2439    SERIALIZE_SCALAR(regs.mear);
2440    SERIALIZE_SCALAR(regs.ptscr);
2441    SERIALIZE_SCALAR(regs.isr);
2442    SERIALIZE_SCALAR(regs.imr);
2443    SERIALIZE_SCALAR(regs.ier);
2444    SERIALIZE_SCALAR(regs.ihr);
2445    SERIALIZE_SCALAR(regs.txdp);
2446    SERIALIZE_SCALAR(regs.txdp_hi);
2447    SERIALIZE_SCALAR(regs.txcfg);
2448    SERIALIZE_SCALAR(regs.gpior);
2449    SERIALIZE_SCALAR(regs.rxdp);
2450    SERIALIZE_SCALAR(regs.rxdp_hi);
2451    SERIALIZE_SCALAR(regs.rxcfg);
2452    SERIALIZE_SCALAR(regs.pqcr);
2453    SERIALIZE_SCALAR(regs.wcsr);
2454    SERIALIZE_SCALAR(regs.pcr);
2455    SERIALIZE_SCALAR(regs.rfcr);
2456    SERIALIZE_SCALAR(regs.rfdr);
2457    SERIALIZE_SCALAR(regs.brar);
2458    SERIALIZE_SCALAR(regs.brdr);
2459    SERIALIZE_SCALAR(regs.srr);
2460    SERIALIZE_SCALAR(regs.mibc);
2461    SERIALIZE_SCALAR(regs.vrcr);
2462    SERIALIZE_SCALAR(regs.vtcr);
2463    SERIALIZE_SCALAR(regs.vdr);
2464    SERIALIZE_SCALAR(regs.ccsr);
2465    SERIALIZE_SCALAR(regs.tbicr);
2466    SERIALIZE_SCALAR(regs.tbisr);
2467    SERIALIZE_SCALAR(regs.tanar);
2468    SERIALIZE_SCALAR(regs.tanlpar);
2469    SERIALIZE_SCALAR(regs.taner);
2470    SERIALIZE_SCALAR(regs.tesr);
2471
2472    SERIALIZE_ARRAY(rom.perfectMatch, ETH_ADDR_LEN);
2473    SERIALIZE_ARRAY(rom.filterHash, FHASH_SIZE);
2474
2475    SERIALIZE_SCALAR(ioEnable);
2476
2477    /*
2478     * Serialize the data Fifos
2479     */
2480    rxFifo.serialize("rxFifo", os);
2481    txFifo.serialize("txFifo", os);
2482
2483    /*
2484     * Serialize the various helper variables
2485     */
2486    bool txPacketExists = txPacket;
2487    SERIALIZE_SCALAR(txPacketExists);
2488    if (txPacketExists) {
2489        txPacket->length = txPacketBufPtr - txPacket->data;
2490        txPacket->serialize("txPacket", os);
2491        uint32_t txPktBufPtr = (uint32_t) (txPacketBufPtr - txPacket->data);
2492        SERIALIZE_SCALAR(txPktBufPtr);
2493    }
2494
2495    bool rxPacketExists = rxPacket;
2496    SERIALIZE_SCALAR(rxPacketExists);
2497    if (rxPacketExists) {
2498        rxPacket->serialize("rxPacket", os);
2499        uint32_t rxPktBufPtr = (uint32_t) (rxPacketBufPtr - rxPacket->data);
2500        SERIALIZE_SCALAR(rxPktBufPtr);
2501    }
2502
2503    SERIALIZE_SCALAR(txXferLen);
2504    SERIALIZE_SCALAR(rxXferLen);
2505
2506    /*
2507     * Serialize Cached Descriptors
2508     */
2509    SERIALIZE_SCALAR(rxDesc64.link);
2510    SERIALIZE_SCALAR(rxDesc64.bufptr);
2511    SERIALIZE_SCALAR(rxDesc64.cmdsts);
2512    SERIALIZE_SCALAR(rxDesc64.extsts);
2513    SERIALIZE_SCALAR(txDesc64.link);
2514    SERIALIZE_SCALAR(txDesc64.bufptr);
2515    SERIALIZE_SCALAR(txDesc64.cmdsts);
2516    SERIALIZE_SCALAR(txDesc64.extsts);
2517    SERIALIZE_SCALAR(rxDesc32.link);
2518    SERIALIZE_SCALAR(rxDesc32.bufptr);
2519    SERIALIZE_SCALAR(rxDesc32.cmdsts);
2520    SERIALIZE_SCALAR(rxDesc32.extsts);
2521    SERIALIZE_SCALAR(txDesc32.link);
2522    SERIALIZE_SCALAR(txDesc32.bufptr);
2523    SERIALIZE_SCALAR(txDesc32.cmdsts);
2524    SERIALIZE_SCALAR(txDesc32.extsts);
2525    SERIALIZE_SCALAR(extstsEnable);
2526
2527    /*
2528     * Serialize tx state machine
2529     */
2530    int txState = this->txState;
2531    SERIALIZE_SCALAR(txState);
2532    SERIALIZE_SCALAR(txEnable);
2533    SERIALIZE_SCALAR(CTDD);
2534    SERIALIZE_SCALAR(txFragPtr);
2535    SERIALIZE_SCALAR(txDescCnt);
2536    int txDmaState = this->txDmaState;
2537    SERIALIZE_SCALAR(txDmaState);
2538    SERIALIZE_SCALAR(txKickTick);
2539
2540    /*
2541     * Serialize rx state machine
2542     */
2543    int rxState = this->rxState;
2544    SERIALIZE_SCALAR(rxState);
2545    SERIALIZE_SCALAR(rxEnable);
2546    SERIALIZE_SCALAR(CRDD);
2547    SERIALIZE_SCALAR(rxPktBytes);
2548    SERIALIZE_SCALAR(rxFragPtr);
2549    SERIALIZE_SCALAR(rxDescCnt);
2550    int rxDmaState = this->rxDmaState;
2551    SERIALIZE_SCALAR(rxDmaState);
2552    SERIALIZE_SCALAR(rxKickTick);
2553
2554    /*
2555     * Serialize EEPROM state machine
2556     */
2557    int eepromState = this->eepromState;
2558    SERIALIZE_SCALAR(eepromState);
2559    SERIALIZE_SCALAR(eepromClk);
2560    SERIALIZE_SCALAR(eepromBitsToRx);
2561    SERIALIZE_SCALAR(eepromOpcode);
2562    SERIALIZE_SCALAR(eepromAddress);
2563    SERIALIZE_SCALAR(eepromData);
2564
2565    /*
2566     * If there's a pending transmit, store the time so we can
2567     * reschedule it later
2568     */
2569    Tick transmitTick = txEvent.scheduled() ? txEvent.when() - curTick : 0;
2570    SERIALIZE_SCALAR(transmitTick);
2571
2572    /*
2573     * receive address filter settings
2574     */
2575    SERIALIZE_SCALAR(rxFilterEnable);
2576    SERIALIZE_SCALAR(acceptBroadcast);
2577    SERIALIZE_SCALAR(acceptMulticast);
2578    SERIALIZE_SCALAR(acceptUnicast);
2579    SERIALIZE_SCALAR(acceptPerfect);
2580    SERIALIZE_SCALAR(acceptArp);
2581    SERIALIZE_SCALAR(multicastHashEnable);
2582
2583    /*
2584     * Keep track of pending interrupt status.
2585     */
2586    SERIALIZE_SCALAR(intrTick);
2587    SERIALIZE_SCALAR(cpuPendingIntr);
2588    Tick intrEventTick = 0;
2589    if (intrEvent)
2590        intrEventTick = intrEvent->when();
2591    SERIALIZE_SCALAR(intrEventTick);
2592
2593}
2594
2595void
2596NSGigE::unserialize(Checkpoint *cp, const std::string &section)
2597{
2598    // Unserialize the PciDev base class
2599    PciDev::unserialize(cp, section);
2600
2601    UNSERIALIZE_SCALAR(regs.command);
2602    UNSERIALIZE_SCALAR(regs.config);
2603    UNSERIALIZE_SCALAR(regs.mear);
2604    UNSERIALIZE_SCALAR(regs.ptscr);
2605    UNSERIALIZE_SCALAR(regs.isr);
2606    UNSERIALIZE_SCALAR(regs.imr);
2607    UNSERIALIZE_SCALAR(regs.ier);
2608    UNSERIALIZE_SCALAR(regs.ihr);
2609    UNSERIALIZE_SCALAR(regs.txdp);
2610    UNSERIALIZE_SCALAR(regs.txdp_hi);
2611    UNSERIALIZE_SCALAR(regs.txcfg);
2612    UNSERIALIZE_SCALAR(regs.gpior);
2613    UNSERIALIZE_SCALAR(regs.rxdp);
2614    UNSERIALIZE_SCALAR(regs.rxdp_hi);
2615    UNSERIALIZE_SCALAR(regs.rxcfg);
2616    UNSERIALIZE_SCALAR(regs.pqcr);
2617    UNSERIALIZE_SCALAR(regs.wcsr);
2618    UNSERIALIZE_SCALAR(regs.pcr);
2619    UNSERIALIZE_SCALAR(regs.rfcr);
2620    UNSERIALIZE_SCALAR(regs.rfdr);
2621    UNSERIALIZE_SCALAR(regs.brar);
2622    UNSERIALIZE_SCALAR(regs.brdr);
2623    UNSERIALIZE_SCALAR(regs.srr);
2624    UNSERIALIZE_SCALAR(regs.mibc);
2625    UNSERIALIZE_SCALAR(regs.vrcr);
2626    UNSERIALIZE_SCALAR(regs.vtcr);
2627    UNSERIALIZE_SCALAR(regs.vdr);
2628    UNSERIALIZE_SCALAR(regs.ccsr);
2629    UNSERIALIZE_SCALAR(regs.tbicr);
2630    UNSERIALIZE_SCALAR(regs.tbisr);
2631    UNSERIALIZE_SCALAR(regs.tanar);
2632    UNSERIALIZE_SCALAR(regs.tanlpar);
2633    UNSERIALIZE_SCALAR(regs.taner);
2634    UNSERIALIZE_SCALAR(regs.tesr);
2635
2636    UNSERIALIZE_ARRAY(rom.perfectMatch, ETH_ADDR_LEN);
2637    UNSERIALIZE_ARRAY(rom.filterHash, FHASH_SIZE);
2638
2639    UNSERIALIZE_SCALAR(ioEnable);
2640
2641    /*
2642     * unserialize the data fifos
2643     */
2644    rxFifo.unserialize("rxFifo", cp, section);
2645    txFifo.unserialize("txFifo", cp, section);
2646
2647    /*
2648     * unserialize the various helper variables
2649     */
2650    bool txPacketExists;
2651    UNSERIALIZE_SCALAR(txPacketExists);
2652    if (txPacketExists) {
2653        txPacket = new EthPacketData(16384);
2654        txPacket->unserialize("txPacket", cp, section);
2655        uint32_t txPktBufPtr;
2656        UNSERIALIZE_SCALAR(txPktBufPtr);
2657        txPacketBufPtr = (uint8_t *) txPacket->data + txPktBufPtr;
2658    } else
2659        txPacket = 0;
2660
2661    bool rxPacketExists;
2662    UNSERIALIZE_SCALAR(rxPacketExists);
2663    rxPacket = 0;
2664    if (rxPacketExists) {
2665        rxPacket = new EthPacketData(16384);
2666        rxPacket->unserialize("rxPacket", cp, section);
2667        uint32_t rxPktBufPtr;
2668        UNSERIALIZE_SCALAR(rxPktBufPtr);
2669        rxPacketBufPtr = (uint8_t *) rxPacket->data + rxPktBufPtr;
2670    } else
2671        rxPacket = 0;
2672
2673    UNSERIALIZE_SCALAR(txXferLen);
2674    UNSERIALIZE_SCALAR(rxXferLen);
2675
2676    /*
2677     * Unserialize Cached Descriptors
2678     */
2679    UNSERIALIZE_SCALAR(rxDesc64.link);
2680    UNSERIALIZE_SCALAR(rxDesc64.bufptr);
2681    UNSERIALIZE_SCALAR(rxDesc64.cmdsts);
2682    UNSERIALIZE_SCALAR(rxDesc64.extsts);
2683    UNSERIALIZE_SCALAR(txDesc64.link);
2684    UNSERIALIZE_SCALAR(txDesc64.bufptr);
2685    UNSERIALIZE_SCALAR(txDesc64.cmdsts);
2686    UNSERIALIZE_SCALAR(txDesc64.extsts);
2687    UNSERIALIZE_SCALAR(rxDesc32.link);
2688    UNSERIALIZE_SCALAR(rxDesc32.bufptr);
2689    UNSERIALIZE_SCALAR(rxDesc32.cmdsts);
2690    UNSERIALIZE_SCALAR(rxDesc32.extsts);
2691    UNSERIALIZE_SCALAR(txDesc32.link);
2692    UNSERIALIZE_SCALAR(txDesc32.bufptr);
2693    UNSERIALIZE_SCALAR(txDesc32.cmdsts);
2694    UNSERIALIZE_SCALAR(txDesc32.extsts);
2695    UNSERIALIZE_SCALAR(extstsEnable);
2696
2697    /*
2698     * unserialize tx state machine
2699     */
2700    int txState;
2701    UNSERIALIZE_SCALAR(txState);
2702    this->txState = (TxState) txState;
2703    UNSERIALIZE_SCALAR(txEnable);
2704    UNSERIALIZE_SCALAR(CTDD);
2705    UNSERIALIZE_SCALAR(txFragPtr);
2706    UNSERIALIZE_SCALAR(txDescCnt);
2707    int txDmaState;
2708    UNSERIALIZE_SCALAR(txDmaState);
2709    this->txDmaState = (DmaState) txDmaState;
2710    UNSERIALIZE_SCALAR(txKickTick);
2711    if (txKickTick)
2712        txKickEvent.schedule(txKickTick);
2713
2714    /*
2715     * unserialize rx state machine
2716     */
2717    int rxState;
2718    UNSERIALIZE_SCALAR(rxState);
2719    this->rxState = (RxState) rxState;
2720    UNSERIALIZE_SCALAR(rxEnable);
2721    UNSERIALIZE_SCALAR(CRDD);
2722    UNSERIALIZE_SCALAR(rxPktBytes);
2723    UNSERIALIZE_SCALAR(rxFragPtr);
2724    UNSERIALIZE_SCALAR(rxDescCnt);
2725    int rxDmaState;
2726    UNSERIALIZE_SCALAR(rxDmaState);
2727    this->rxDmaState = (DmaState) rxDmaState;
2728    UNSERIALIZE_SCALAR(rxKickTick);
2729    if (rxKickTick)
2730        rxKickEvent.schedule(rxKickTick);
2731
2732    /*
2733     * Unserialize EEPROM state machine
2734     */
2735    int eepromState;
2736    UNSERIALIZE_SCALAR(eepromState);
2737    this->eepromState = (EEPROMState) eepromState;
2738    UNSERIALIZE_SCALAR(eepromClk);
2739    UNSERIALIZE_SCALAR(eepromBitsToRx);
2740    UNSERIALIZE_SCALAR(eepromOpcode);
2741    UNSERIALIZE_SCALAR(eepromAddress);
2742    UNSERIALIZE_SCALAR(eepromData);
2743
2744    /*
2745     * If there's a pending transmit, reschedule it now
2746     */
2747    Tick transmitTick;
2748    UNSERIALIZE_SCALAR(transmitTick);
2749    if (transmitTick)
2750        txEvent.schedule(curTick + transmitTick);
2751
2752    /*
2753     * unserialize receive address filter settings
2754     */
2755    UNSERIALIZE_SCALAR(rxFilterEnable);
2756    UNSERIALIZE_SCALAR(acceptBroadcast);
2757    UNSERIALIZE_SCALAR(acceptMulticast);
2758    UNSERIALIZE_SCALAR(acceptUnicast);
2759    UNSERIALIZE_SCALAR(acceptPerfect);
2760    UNSERIALIZE_SCALAR(acceptArp);
2761    UNSERIALIZE_SCALAR(multicastHashEnable);
2762
2763    /*
2764     * Keep track of pending interrupt status.
2765     */
2766    UNSERIALIZE_SCALAR(intrTick);
2767    UNSERIALIZE_SCALAR(cpuPendingIntr);
2768    Tick intrEventTick;
2769    UNSERIALIZE_SCALAR(intrEventTick);
2770    if (intrEventTick) {
2771        intrEvent = new IntrEvent(this, true);
2772        intrEvent->schedule(intrEventTick);
2773    }
2774}
2775
2776BEGIN_DECLARE_SIM_OBJECT_PARAMS(NSGigEInt)
2777
2778    SimObjectParam<EtherInt *> peer;
2779    SimObjectParam<NSGigE *> device;
2780
2781END_DECLARE_SIM_OBJECT_PARAMS(NSGigEInt)
2782
2783BEGIN_INIT_SIM_OBJECT_PARAMS(NSGigEInt)
2784
2785    INIT_PARAM_DFLT(peer, "peer interface", NULL),
2786    INIT_PARAM(device, "Ethernet device of this interface")
2787
2788END_INIT_SIM_OBJECT_PARAMS(NSGigEInt)
2789
2790CREATE_SIM_OBJECT(NSGigEInt)
2791{
2792    NSGigEInt *dev_int = new NSGigEInt(getInstanceName(), device);
2793
2794    EtherInt *p = (EtherInt *)peer;
2795    if (p) {
2796        dev_int->setPeer(p);
2797        p->setPeer(dev_int);
2798    }
2799
2800    return dev_int;
2801}
2802
2803REGISTER_SIM_OBJECT("NSGigEInt", NSGigEInt)
2804
2805
2806BEGIN_DECLARE_SIM_OBJECT_PARAMS(NSGigE)
2807
2808    SimObjectParam<System *> system;
2809    SimObjectParam<Platform *> platform;
2810    SimObjectParam<PciConfigAll *> configspace;
2811    SimObjectParam<PciConfigData *> configdata;
2812    Param<uint32_t> pci_bus;
2813    Param<uint32_t> pci_dev;
2814    Param<uint32_t> pci_func;
2815    Param<Tick> pio_latency;
2816
2817    Param<Tick> clock;
2818    Param<bool> dma_desc_free;
2819    Param<bool> dma_data_free;
2820    Param<Tick> dma_read_delay;
2821    Param<Tick> dma_write_delay;
2822    Param<Tick> dma_read_factor;
2823    Param<Tick> dma_write_factor;
2824    Param<bool> dma_no_allocate;
2825    Param<Tick> intr_delay;
2826
2827    Param<Tick> rx_delay;
2828    Param<Tick> tx_delay;
2829    Param<uint32_t> rx_fifo_size;
2830    Param<uint32_t> tx_fifo_size;
2831
2832    Param<bool> rx_filter;
2833    Param<string> hardware_address;
2834    Param<bool> rx_thread;
2835    Param<bool> tx_thread;
2836    Param<bool> rss;
2837
2838END_DECLARE_SIM_OBJECT_PARAMS(NSGigE)
2839
2840BEGIN_INIT_SIM_OBJECT_PARAMS(NSGigE)
2841
2842    INIT_PARAM(system, "System pointer"),
2843    INIT_PARAM(platform, "Platform pointer"),
2844    INIT_PARAM(configspace, "PCI Configspace"),
2845    INIT_PARAM(configdata, "PCI Config data"),
2846    INIT_PARAM(pci_bus, "PCI bus ID"),
2847    INIT_PARAM(pci_dev, "PCI device number"),
2848    INIT_PARAM(pci_func, "PCI function code"),
2849    INIT_PARAM_DFLT(pio_latency, "Programmed IO latency in bus cycles", 1),
2850    INIT_PARAM(clock, "State machine cycle time"),
2851
2852    INIT_PARAM(dma_desc_free, "DMA of Descriptors is free"),
2853    INIT_PARAM(dma_data_free, "DMA of Data is free"),
2854    INIT_PARAM(dma_read_delay, "fixed delay for dma reads"),
2855    INIT_PARAM(dma_write_delay, "fixed delay for dma writes"),
2856    INIT_PARAM(dma_read_factor, "multiplier for dma reads"),
2857    INIT_PARAM(dma_write_factor, "multiplier for dma writes"),
2858    INIT_PARAM(dma_no_allocate, "Should DMA reads allocate cache lines"),
2859    INIT_PARAM(intr_delay, "Interrupt Delay in microseconds"),
2860
2861    INIT_PARAM(rx_delay, "Receive Delay"),
2862    INIT_PARAM(tx_delay, "Transmit Delay"),
2863    INIT_PARAM(rx_fifo_size, "max size in bytes of rxFifo"),
2864    INIT_PARAM(tx_fifo_size, "max size in bytes of txFifo"),
2865
2866    INIT_PARAM(rx_filter, "Enable Receive Filter"),
2867    INIT_PARAM(hardware_address, "Ethernet Hardware Address"),
2868    INIT_PARAM(rx_thread, ""),
2869    INIT_PARAM(tx_thread, ""),
2870    INIT_PARAM(rss, "")
2871
2872END_INIT_SIM_OBJECT_PARAMS(NSGigE)
2873
2874
2875CREATE_SIM_OBJECT(NSGigE)
2876{
2877    NSGigE::Params *params = new NSGigE::Params;
2878
2879    params->name = getInstanceName();
2880    params->platform = platform;
2881    params->system = system;
2882    params->configSpace = configspace;
2883    params->configData = configdata;
2884    params->busNum = pci_bus;
2885    params->deviceNum = pci_dev;
2886    params->functionNum = pci_func;
2887    params->pio_delay = pio_latency;
2888
2889    params->clock = clock;
2890    params->dma_desc_free = dma_desc_free;
2891    params->dma_data_free = dma_data_free;
2892    params->dma_read_delay = dma_read_delay;
2893    params->dma_write_delay = dma_write_delay;
2894    params->dma_read_factor = dma_read_factor;
2895    params->dma_write_factor = dma_write_factor;
2896    params->dma_no_allocate = dma_no_allocate;
2897    params->pio_delay = pio_latency;
2898    params->intr_delay = intr_delay;
2899
2900    params->rx_delay = rx_delay;
2901    params->tx_delay = tx_delay;
2902    params->rx_fifo_size = rx_fifo_size;
2903    params->tx_fifo_size = tx_fifo_size;
2904
2905    params->rx_filter = rx_filter;
2906    params->eaddr = hardware_address;
2907    params->rx_thread = rx_thread;
2908    params->tx_thread = tx_thread;
2909    params->rss = rss;
2910
2911    return new NSGigE(params);
2912}
2913
2914REGISTER_SIM_OBJECT("NSGigE", NSGigE)
2915