ns_gige.cc revision 3349
17322Sgblack@eecs.umich.edu/*
27322Sgblack@eecs.umich.edu * Copyright (c) 2004-2005 The Regents of The University of Michigan
37322Sgblack@eecs.umich.edu * All rights reserved.
47322Sgblack@eecs.umich.edu *
57322Sgblack@eecs.umich.edu * Redistribution and use in source and binary forms, with or without
67322Sgblack@eecs.umich.edu * modification, are permitted provided that the following conditions are
77322Sgblack@eecs.umich.edu * met: redistributions of source code must retain the above copyright
87322Sgblack@eecs.umich.edu * notice, this list of conditions and the following disclaimer;
97322Sgblack@eecs.umich.edu * redistributions in binary form must reproduce the above copyright
107322Sgblack@eecs.umich.edu * notice, this list of conditions and the following disclaimer in the
117322Sgblack@eecs.umich.edu * documentation and/or other materials provided with the distribution;
127322Sgblack@eecs.umich.edu * neither the name of the copyright holders nor the names of its
137322Sgblack@eecs.umich.edu * contributors may be used to endorse or promote products derived from
147322Sgblack@eecs.umich.edu * this software without specific prior written permission.
157322Sgblack@eecs.umich.edu *
167322Sgblack@eecs.umich.edu * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
177322Sgblack@eecs.umich.edu * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
187322Sgblack@eecs.umich.edu * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
197322Sgblack@eecs.umich.edu * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
207322Sgblack@eecs.umich.edu * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
217322Sgblack@eecs.umich.edu * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
227322Sgblack@eecs.umich.edu * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
237322Sgblack@eecs.umich.edu * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
247322Sgblack@eecs.umich.edu * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
257322Sgblack@eecs.umich.edu * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
267322Sgblack@eecs.umich.edu * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
277322Sgblack@eecs.umich.edu *
287322Sgblack@eecs.umich.edu * Authors: Nathan Binkert
297322Sgblack@eecs.umich.edu *          Lisa Hsu
307322Sgblack@eecs.umich.edu */
317322Sgblack@eecs.umich.edu
327322Sgblack@eecs.umich.edu/** @file
337322Sgblack@eecs.umich.edu * Device module for modelling the National Semiconductor
347322Sgblack@eecs.umich.edu * DP83820 ethernet controller.  Does not support priority queueing
357322Sgblack@eecs.umich.edu */
367322Sgblack@eecs.umich.edu#include <deque>
377322Sgblack@eecs.umich.edu#include <string>
387322Sgblack@eecs.umich.edu
397322Sgblack@eecs.umich.edu#include "arch/alpha/ev5.hh"
407376Sgblack@eecs.umich.edu#include "base/inet.hh"
417376Sgblack@eecs.umich.edu#include "cpu/thread_context.hh"
427376Sgblack@eecs.umich.edu#include "dev/etherlink.hh"
437376Sgblack@eecs.umich.edu#include "dev/ns_gige.hh"
447376Sgblack@eecs.umich.edu#include "dev/pciconfigall.hh"
457376Sgblack@eecs.umich.edu#include "mem/packet.hh"
467376Sgblack@eecs.umich.edu#include "mem/packet_access.hh"
477376Sgblack@eecs.umich.edu#include "sim/builder.hh"
487376Sgblack@eecs.umich.edu#include "sim/debug.hh"
497376Sgblack@eecs.umich.edu#include "sim/host.hh"
507376Sgblack@eecs.umich.edu#include "sim/stats.hh"
517376Sgblack@eecs.umich.edu#include "sim/system.hh"
527376Sgblack@eecs.umich.edu
537376Sgblack@eecs.umich.educonst char *NsRxStateStrings[] =
547376Sgblack@eecs.umich.edu{
557376Sgblack@eecs.umich.edu    "rxIdle",
567376Sgblack@eecs.umich.edu    "rxDescRefr",
577376Sgblack@eecs.umich.edu    "rxDescRead",
587376Sgblack@eecs.umich.edu    "rxFifoBlock",
597376Sgblack@eecs.umich.edu    "rxFragWrite",
607376Sgblack@eecs.umich.edu    "rxDescWrite",
617376Sgblack@eecs.umich.edu    "rxAdvance"
627376Sgblack@eecs.umich.edu};
637376Sgblack@eecs.umich.edu
647376Sgblack@eecs.umich.educonst char *NsTxStateStrings[] =
657376Sgblack@eecs.umich.edu{
667376Sgblack@eecs.umich.edu    "txIdle",
677376Sgblack@eecs.umich.edu    "txDescRefr",
687376Sgblack@eecs.umich.edu    "txDescRead",
697376Sgblack@eecs.umich.edu    "txFifoBlock",
707376Sgblack@eecs.umich.edu    "txFragRead",
717376Sgblack@eecs.umich.edu    "txDescWrite",
727376Sgblack@eecs.umich.edu    "txAdvance"
737376Sgblack@eecs.umich.edu};
747376Sgblack@eecs.umich.edu
757376Sgblack@eecs.umich.educonst char *NsDmaState[] =
767376Sgblack@eecs.umich.edu{
777376Sgblack@eecs.umich.edu    "dmaIdle",
787376Sgblack@eecs.umich.edu    "dmaReading",
797376Sgblack@eecs.umich.edu    "dmaWriting",
807376Sgblack@eecs.umich.edu    "dmaReadWaiting",
817376Sgblack@eecs.umich.edu    "dmaWriteWaiting"
827376Sgblack@eecs.umich.edu};
837376Sgblack@eecs.umich.edu
847376Sgblack@eecs.umich.eduusing namespace std;
857376Sgblack@eecs.umich.eduusing namespace Net;
867376Sgblack@eecs.umich.eduusing namespace TheISA;
877376Sgblack@eecs.umich.edu
887376Sgblack@eecs.umich.edu///////////////////////////////////////////////////////////////////////
897376Sgblack@eecs.umich.edu//
907376Sgblack@eecs.umich.edu// NSGigE PCI Device
917376Sgblack@eecs.umich.edu//
927376Sgblack@eecs.umich.eduNSGigE::NSGigE(Params *p)
937376Sgblack@eecs.umich.edu    : PciDev(p), ioEnable(false),
947376Sgblack@eecs.umich.edu      txFifo(p->tx_fifo_size), rxFifo(p->rx_fifo_size),
957376Sgblack@eecs.umich.edu      txPacket(0), rxPacket(0), txPacketBufPtr(NULL), rxPacketBufPtr(NULL),
967376Sgblack@eecs.umich.edu      txXferLen(0), rxXferLen(0), clock(p->clock),
977376Sgblack@eecs.umich.edu      txState(txIdle), txEnable(false), CTDD(false),
987376Sgblack@eecs.umich.edu      txFragPtr(0), txDescCnt(0), txDmaState(dmaIdle), rxState(rxIdle),
997376Sgblack@eecs.umich.edu      rxEnable(false), CRDD(false), rxPktBytes(0),
1007376Sgblack@eecs.umich.edu      rxFragPtr(0), rxDescCnt(0), rxDmaState(dmaIdle), extstsEnable(false),
1017376Sgblack@eecs.umich.edu      eepromState(eepromStart), rxDmaReadEvent(this), rxDmaWriteEvent(this),
1027376Sgblack@eecs.umich.edu      txDmaReadEvent(this), txDmaWriteEvent(this),
1037376Sgblack@eecs.umich.edu      dmaDescFree(p->dma_desc_free), dmaDataFree(p->dma_data_free),
1047376Sgblack@eecs.umich.edu      txDelay(p->tx_delay), rxDelay(p->rx_delay),
1057376Sgblack@eecs.umich.edu      rxKickTick(0), rxKickEvent(this), txKickTick(0), txKickEvent(this),
1067376Sgblack@eecs.umich.edu      txEvent(this), rxFilterEnable(p->rx_filter), acceptBroadcast(false),
1077376Sgblack@eecs.umich.edu      acceptMulticast(false), acceptUnicast(false),
1087376Sgblack@eecs.umich.edu      acceptPerfect(false), acceptArp(false), multicastHashEnable(false),
1097376Sgblack@eecs.umich.edu      intrTick(0), cpuPendingIntr(false),
1107376Sgblack@eecs.umich.edu      intrEvent(0), interface(0)
1117376Sgblack@eecs.umich.edu{
1127376Sgblack@eecs.umich.edu
1137376Sgblack@eecs.umich.edu    intrDelay = p->intr_delay;
1147376Sgblack@eecs.umich.edu    dmaReadDelay = p->dma_read_delay;
1157376Sgblack@eecs.umich.edu    dmaWriteDelay = p->dma_write_delay;
1167376Sgblack@eecs.umich.edu    dmaReadFactor = p->dma_read_factor;
1177376Sgblack@eecs.umich.edu    dmaWriteFactor = p->dma_write_factor;
1187376Sgblack@eecs.umich.edu
1197376Sgblack@eecs.umich.edu    regsReset();
1207376Sgblack@eecs.umich.edu    memcpy(&rom.perfectMatch, p->eaddr.bytes(), ETH_ADDR_LEN);
1217376Sgblack@eecs.umich.edu
1227376Sgblack@eecs.umich.edu    memset(&rxDesc32, 0, sizeof(rxDesc32));
1237376Sgblack@eecs.umich.edu    memset(&txDesc32, 0, sizeof(txDesc32));
1247376Sgblack@eecs.umich.edu    memset(&rxDesc64, 0, sizeof(rxDesc64));
1257376Sgblack@eecs.umich.edu    memset(&txDesc64, 0, sizeof(txDesc64));
1267376Sgblack@eecs.umich.edu}
1277376Sgblack@eecs.umich.edu
1287376Sgblack@eecs.umich.eduNSGigE::~NSGigE()
1297376Sgblack@eecs.umich.edu{}
1307376Sgblack@eecs.umich.edu
1317376Sgblack@eecs.umich.eduvoid
1327376Sgblack@eecs.umich.eduNSGigE::regStats()
1337376Sgblack@eecs.umich.edu{
1347376Sgblack@eecs.umich.edu    txBytes
1357376Sgblack@eecs.umich.edu        .name(name() + ".txBytes")
1367376Sgblack@eecs.umich.edu        .desc("Bytes Transmitted")
1377376Sgblack@eecs.umich.edu        .prereq(txBytes)
1387376Sgblack@eecs.umich.edu        ;
1397376Sgblack@eecs.umich.edu
1407376Sgblack@eecs.umich.edu    rxBytes
1417376Sgblack@eecs.umich.edu        .name(name() + ".rxBytes")
1427376Sgblack@eecs.umich.edu        .desc("Bytes Received")
1437376Sgblack@eecs.umich.edu        .prereq(rxBytes)
1447376Sgblack@eecs.umich.edu        ;
1457376Sgblack@eecs.umich.edu
1467376Sgblack@eecs.umich.edu    txPackets
1477376Sgblack@eecs.umich.edu        .name(name() + ".txPackets")
1487376Sgblack@eecs.umich.edu        .desc("Number of Packets Transmitted")
1497376Sgblack@eecs.umich.edu        .prereq(txBytes)
1507376Sgblack@eecs.umich.edu        ;
1517376Sgblack@eecs.umich.edu
1527376Sgblack@eecs.umich.edu    rxPackets
1537376Sgblack@eecs.umich.edu        .name(name() + ".rxPackets")
1547376Sgblack@eecs.umich.edu        .desc("Number of Packets Received")
1557376Sgblack@eecs.umich.edu        .prereq(rxBytes)
1567376Sgblack@eecs.umich.edu        ;
1577376Sgblack@eecs.umich.edu
1587376Sgblack@eecs.umich.edu    txIpChecksums
1597376Sgblack@eecs.umich.edu        .name(name() + ".txIpChecksums")
1607376Sgblack@eecs.umich.edu        .desc("Number of tx IP Checksums done by device")
1617376Sgblack@eecs.umich.edu        .precision(0)
1627376Sgblack@eecs.umich.edu        .prereq(txBytes)
1637376Sgblack@eecs.umich.edu        ;
1647376Sgblack@eecs.umich.edu
1657376Sgblack@eecs.umich.edu    rxIpChecksums
1667376Sgblack@eecs.umich.edu        .name(name() + ".rxIpChecksums")
1677376Sgblack@eecs.umich.edu        .desc("Number of rx IP Checksums done by device")
1687376Sgblack@eecs.umich.edu        .precision(0)
1697376Sgblack@eecs.umich.edu        .prereq(rxBytes)
1707376Sgblack@eecs.umich.edu        ;
1717376Sgblack@eecs.umich.edu
1727376Sgblack@eecs.umich.edu    txTcpChecksums
1737376Sgblack@eecs.umich.edu        .name(name() + ".txTcpChecksums")
1747376Sgblack@eecs.umich.edu        .desc("Number of tx TCP Checksums done by device")
1757376Sgblack@eecs.umich.edu        .precision(0)
1767376Sgblack@eecs.umich.edu        .prereq(txBytes)
1777376Sgblack@eecs.umich.edu        ;
1787376Sgblack@eecs.umich.edu
1797376Sgblack@eecs.umich.edu    rxTcpChecksums
1807376Sgblack@eecs.umich.edu        .name(name() + ".rxTcpChecksums")
1817376Sgblack@eecs.umich.edu        .desc("Number of rx TCP Checksums done by device")
1827376Sgblack@eecs.umich.edu        .precision(0)
1837376Sgblack@eecs.umich.edu        .prereq(rxBytes)
1847376Sgblack@eecs.umich.edu        ;
1857376Sgblack@eecs.umich.edu
1867376Sgblack@eecs.umich.edu    txUdpChecksums
1877376Sgblack@eecs.umich.edu        .name(name() + ".txUdpChecksums")
1887322Sgblack@eecs.umich.edu        .desc("Number of tx UDP Checksums done by device")
1897322Sgblack@eecs.umich.edu        .precision(0)
1907322Sgblack@eecs.umich.edu        .prereq(txBytes)
1917322Sgblack@eecs.umich.edu        ;
1927322Sgblack@eecs.umich.edu
1937322Sgblack@eecs.umich.edu    rxUdpChecksums
1947375Sgblack@eecs.umich.edu        .name(name() + ".rxUdpChecksums")
1957322Sgblack@eecs.umich.edu        .desc("Number of rx UDP Checksums done by device")
1967322Sgblack@eecs.umich.edu        .precision(0)
1977375Sgblack@eecs.umich.edu        .prereq(rxBytes)
1987375Sgblack@eecs.umich.edu        ;
1997322Sgblack@eecs.umich.edu
2007324Sgblack@eecs.umich.edu    descDmaReads
2017375Sgblack@eecs.umich.edu        .name(name() + ".descDMAReads")
2027324Sgblack@eecs.umich.edu        .desc("Number of descriptors the device read w/ DMA")
2037324Sgblack@eecs.umich.edu        .precision(0)
2047375Sgblack@eecs.umich.edu        ;
2057375Sgblack@eecs.umich.edu
2067324Sgblack@eecs.umich.edu    descDmaWrites
2077333Sgblack@eecs.umich.edu        .name(name() + ".descDMAWrites")
2087333Sgblack@eecs.umich.edu        .desc("Number of descriptors the device wrote w/ DMA")
2097333Sgblack@eecs.umich.edu        .precision(0)
2107333Sgblack@eecs.umich.edu        ;
2117375Sgblack@eecs.umich.edu
2127333Sgblack@eecs.umich.edu    descDmaRdBytes
2137333Sgblack@eecs.umich.edu        .name(name() + ".descDmaReadBytes")
2147375Sgblack@eecs.umich.edu        .desc("number of descriptor bytes read w/ DMA")
2157375Sgblack@eecs.umich.edu        .precision(0)
2167333Sgblack@eecs.umich.edu        ;
2177333Sgblack@eecs.umich.edu
2187333Sgblack@eecs.umich.edu   descDmaWrBytes
2197333Sgblack@eecs.umich.edu        .name(name() + ".descDmaWriteBytes")
2207333Sgblack@eecs.umich.edu        .desc("number of descriptor bytes write w/ DMA")
2217333Sgblack@eecs.umich.edu        .precision(0)
2227375Sgblack@eecs.umich.edu        ;
2237333Sgblack@eecs.umich.edu
2247333Sgblack@eecs.umich.edu    txBandwidth
2257375Sgblack@eecs.umich.edu        .name(name() + ".txBandwidth")
2267375Sgblack@eecs.umich.edu        .desc("Transmit Bandwidth (bits/s)")
2277333Sgblack@eecs.umich.edu        .precision(0)
2287333Sgblack@eecs.umich.edu        .prereq(txBytes)
2297333Sgblack@eecs.umich.edu        ;
2307333Sgblack@eecs.umich.edu
2317333Sgblack@eecs.umich.edu    rxBandwidth
2327333Sgblack@eecs.umich.edu        .name(name() + ".rxBandwidth")
2337333Sgblack@eecs.umich.edu        .desc("Receive Bandwidth (bits/s)")
2347333Sgblack@eecs.umich.edu        .precision(0)
2357375Sgblack@eecs.umich.edu        .prereq(rxBytes)
2367333Sgblack@eecs.umich.edu        ;
2377333Sgblack@eecs.umich.edu
2387375Sgblack@eecs.umich.edu    totBandwidth
2397375Sgblack@eecs.umich.edu        .name(name() + ".totBandwidth")
2407333Sgblack@eecs.umich.edu        .desc("Total Bandwidth (bits/s)")
2417333Sgblack@eecs.umich.edu        .precision(0)
2427333Sgblack@eecs.umich.edu        .prereq(totBytes)
2437333Sgblack@eecs.umich.edu        ;
2447333Sgblack@eecs.umich.edu
2457375Sgblack@eecs.umich.edu    totPackets
2467333Sgblack@eecs.umich.edu        .name(name() + ".totPackets")
2477333Sgblack@eecs.umich.edu        .desc("Total Packets")
2487375Sgblack@eecs.umich.edu        .precision(0)
2497375Sgblack@eecs.umich.edu        .prereq(totBytes)
2507333Sgblack@eecs.umich.edu        ;
2517333Sgblack@eecs.umich.edu
2527333Sgblack@eecs.umich.edu    totBytes
2537333Sgblack@eecs.umich.edu        .name(name() + ".totBytes")
2547333Sgblack@eecs.umich.edu        .desc("Total Bytes")
2557333Sgblack@eecs.umich.edu        .precision(0)
2567375Sgblack@eecs.umich.edu        .prereq(totBytes)
2577333Sgblack@eecs.umich.edu        ;
2587333Sgblack@eecs.umich.edu
2597375Sgblack@eecs.umich.edu    totPacketRate
2607375Sgblack@eecs.umich.edu        .name(name() + ".totPPS")
2617333Sgblack@eecs.umich.edu        .desc("Total Tranmission Rate (packets/s)")
2627333Sgblack@eecs.umich.edu        .precision(0)
2637333Sgblack@eecs.umich.edu        .prereq(totBytes)
2647333Sgblack@eecs.umich.edu        ;
2657333Sgblack@eecs.umich.edu
2667333Sgblack@eecs.umich.edu    txPacketRate
2677333Sgblack@eecs.umich.edu        .name(name() + ".txPPS")
2687333Sgblack@eecs.umich.edu        .desc("Packet Tranmission Rate (packets/s)")
2697375Sgblack@eecs.umich.edu        .precision(0)
2707333Sgblack@eecs.umich.edu        .prereq(txBytes)
2717333Sgblack@eecs.umich.edu        ;
2727375Sgblack@eecs.umich.edu
2737375Sgblack@eecs.umich.edu    rxPacketRate
2747333Sgblack@eecs.umich.edu        .name(name() + ".rxPPS")
2757333Sgblack@eecs.umich.edu        .desc("Packet Reception Rate (packets/s)")
2767333Sgblack@eecs.umich.edu        .precision(0)
2777333Sgblack@eecs.umich.edu        .prereq(rxBytes)
2787333Sgblack@eecs.umich.edu        ;
2797375Sgblack@eecs.umich.edu
2807333Sgblack@eecs.umich.edu    postedSwi
2817333Sgblack@eecs.umich.edu        .name(name() + ".postedSwi")
2827375Sgblack@eecs.umich.edu        .desc("number of software interrupts posted to CPU")
2837375Sgblack@eecs.umich.edu        .precision(0)
2847333Sgblack@eecs.umich.edu        ;
2857333Sgblack@eecs.umich.edu
2867333Sgblack@eecs.umich.edu    totalSwi
2877333Sgblack@eecs.umich.edu        .name(name() + ".totalSwi")
2887333Sgblack@eecs.umich.edu        .desc("total number of Swi written to ISR")
2897375Sgblack@eecs.umich.edu        .precision(0)
2907333Sgblack@eecs.umich.edu        ;
2917333Sgblack@eecs.umich.edu
2927375Sgblack@eecs.umich.edu    coalescedSwi
2937375Sgblack@eecs.umich.edu        .name(name() + ".coalescedSwi")
2947333Sgblack@eecs.umich.edu        .desc("average number of Swi's coalesced into each post")
2957333Sgblack@eecs.umich.edu        .precision(0)
2967333Sgblack@eecs.umich.edu        ;
2977333Sgblack@eecs.umich.edu
2987333Sgblack@eecs.umich.edu    postedRxIdle
2997375Sgblack@eecs.umich.edu        .name(name() + ".postedRxIdle")
3007333Sgblack@eecs.umich.edu        .desc("number of rxIdle interrupts posted to CPU")
3017333Sgblack@eecs.umich.edu        .precision(0)
3027375Sgblack@eecs.umich.edu        ;
3037375Sgblack@eecs.umich.edu
3047333Sgblack@eecs.umich.edu    totalRxIdle
3057333Sgblack@eecs.umich.edu        .name(name() + ".totalRxIdle")
3067333Sgblack@eecs.umich.edu        .desc("total number of RxIdle written to ISR")
3077333Sgblack@eecs.umich.edu        .precision(0)
3087333Sgblack@eecs.umich.edu        ;
3097375Sgblack@eecs.umich.edu
3107333Sgblack@eecs.umich.edu    coalescedRxIdle
3117333Sgblack@eecs.umich.edu        .name(name() + ".coalescedRxIdle")
3127375Sgblack@eecs.umich.edu        .desc("average number of RxIdle's coalesced into each post")
3137375Sgblack@eecs.umich.edu        .precision(0)
3147333Sgblack@eecs.umich.edu        ;
3157333Sgblack@eecs.umich.edu
3167333Sgblack@eecs.umich.edu    postedRxOk
3177333Sgblack@eecs.umich.edu        .name(name() + ".postedRxOk")
3187333Sgblack@eecs.umich.edu        .desc("number of RxOk interrupts posted to CPU")
3197375Sgblack@eecs.umich.edu        .precision(0)
3207333Sgblack@eecs.umich.edu        ;
3217333Sgblack@eecs.umich.edu
3227375Sgblack@eecs.umich.edu    totalRxOk
3237375Sgblack@eecs.umich.edu        .name(name() + ".totalRxOk")
3247333Sgblack@eecs.umich.edu        .desc("total number of RxOk written to ISR")
3257333Sgblack@eecs.umich.edu        .precision(0)
3267333Sgblack@eecs.umich.edu        ;
3277333Sgblack@eecs.umich.edu
3287333Sgblack@eecs.umich.edu    coalescedRxOk
3297375Sgblack@eecs.umich.edu        .name(name() + ".coalescedRxOk")
3307333Sgblack@eecs.umich.edu        .desc("average number of RxOk's coalesced into each post")
3317333Sgblack@eecs.umich.edu        .precision(0)
3327375Sgblack@eecs.umich.edu        ;
3337375Sgblack@eecs.umich.edu
3347333Sgblack@eecs.umich.edu    postedRxDesc
3357333Sgblack@eecs.umich.edu        .name(name() + ".postedRxDesc")
3367333Sgblack@eecs.umich.edu        .desc("number of RxDesc interrupts posted to CPU")
3377333Sgblack@eecs.umich.edu        .precision(0)
3387333Sgblack@eecs.umich.edu        ;
3397375Sgblack@eecs.umich.edu
3407333Sgblack@eecs.umich.edu    totalRxDesc
3417333Sgblack@eecs.umich.edu        .name(name() + ".totalRxDesc")
3427375Sgblack@eecs.umich.edu        .desc("total number of RxDesc written to ISR")
3437375Sgblack@eecs.umich.edu        .precision(0)
3447333Sgblack@eecs.umich.edu        ;
3457333Sgblack@eecs.umich.edu
3467333Sgblack@eecs.umich.edu    coalescedRxDesc
3477333Sgblack@eecs.umich.edu        .name(name() + ".coalescedRxDesc")
3487333Sgblack@eecs.umich.edu        .desc("average number of RxDesc's coalesced into each post")
3497375Sgblack@eecs.umich.edu        .precision(0)
3507333Sgblack@eecs.umich.edu        ;
3517333Sgblack@eecs.umich.edu
3527375Sgblack@eecs.umich.edu    postedTxOk
3537375Sgblack@eecs.umich.edu        .name(name() + ".postedTxOk")
3547333Sgblack@eecs.umich.edu        .desc("number of TxOk interrupts posted to CPU")
3557333Sgblack@eecs.umich.edu        .precision(0)
3567333Sgblack@eecs.umich.edu        ;
3577333Sgblack@eecs.umich.edu
3587333Sgblack@eecs.umich.edu    totalTxOk
3597333Sgblack@eecs.umich.edu        .name(name() + ".totalTxOk")
3607375Sgblack@eecs.umich.edu        .desc("total number of TxOk written to ISR")
3617333Sgblack@eecs.umich.edu        .precision(0)
3627333Sgblack@eecs.umich.edu        ;
3637375Sgblack@eecs.umich.edu
3647375Sgblack@eecs.umich.edu    coalescedTxOk
3657333Sgblack@eecs.umich.edu        .name(name() + ".coalescedTxOk")
3667333Sgblack@eecs.umich.edu        .desc("average number of TxOk's coalesced into each post")
3677333Sgblack@eecs.umich.edu        .precision(0)
3687333Sgblack@eecs.umich.edu        ;
3697333Sgblack@eecs.umich.edu
3707333Sgblack@eecs.umich.edu    postedTxIdle
3717375Sgblack@eecs.umich.edu        .name(name() + ".postedTxIdle")
3727333Sgblack@eecs.umich.edu        .desc("number of TxIdle interrupts posted to CPU")
3737333Sgblack@eecs.umich.edu        .precision(0)
3747375Sgblack@eecs.umich.edu        ;
3757375Sgblack@eecs.umich.edu
3767333Sgblack@eecs.umich.edu    totalTxIdle
3777364Sgblack@eecs.umich.edu        .name(name() + ".totalTxIdle")
3787364Sgblack@eecs.umich.edu        .desc("total number of TxIdle written to ISR")
3797378Sgblack@eecs.umich.edu        .precision(0)
3807364Sgblack@eecs.umich.edu        ;
3817378Sgblack@eecs.umich.edu
3827364Sgblack@eecs.umich.edu    coalescedTxIdle
3837364Sgblack@eecs.umich.edu        .name(name() + ".coalescedTxIdle")
3847364Sgblack@eecs.umich.edu        .desc("average number of TxIdle's coalesced into each post")
3857364Sgblack@eecs.umich.edu        .precision(0)
3867375Sgblack@eecs.umich.edu        ;
3877364Sgblack@eecs.umich.edu
3887364Sgblack@eecs.umich.edu    postedTxDesc
3897375Sgblack@eecs.umich.edu        .name(name() + ".postedTxDesc")
3907375Sgblack@eecs.umich.edu        .desc("number of TxDesc interrupts posted to CPU")
3917364Sgblack@eecs.umich.edu        .precision(0)
3927364Sgblack@eecs.umich.edu        ;
3937364Sgblack@eecs.umich.edu
3947364Sgblack@eecs.umich.edu    totalTxDesc
3957364Sgblack@eecs.umich.edu        .name(name() + ".totalTxDesc")
3967364Sgblack@eecs.umich.edu        .desc("total number of TxDesc written to ISR")
3977378Sgblack@eecs.umich.edu        .precision(0)
3987364Sgblack@eecs.umich.edu        ;
3997378Sgblack@eecs.umich.edu
4007364Sgblack@eecs.umich.edu    coalescedTxDesc
4017364Sgblack@eecs.umich.edu        .name(name() + ".coalescedTxDesc")
4027364Sgblack@eecs.umich.edu        .desc("average number of TxDesc's coalesced into each post")
4037364Sgblack@eecs.umich.edu        .precision(0)
4047364Sgblack@eecs.umich.edu        ;
4057364Sgblack@eecs.umich.edu
4067364Sgblack@eecs.umich.edu    postedRxOrn
4077375Sgblack@eecs.umich.edu        .name(name() + ".postedRxOrn")
4087364Sgblack@eecs.umich.edu        .desc("number of RxOrn posted to CPU")
4097364Sgblack@eecs.umich.edu        .precision(0)
4107375Sgblack@eecs.umich.edu        ;
4117375Sgblack@eecs.umich.edu
4127364Sgblack@eecs.umich.edu    totalRxOrn
4137365Sgblack@eecs.umich.edu        .name(name() + ".totalRxOrn")
4147365Sgblack@eecs.umich.edu        .desc("total number of RxOrn written to ISR")
4157365Sgblack@eecs.umich.edu        .precision(0)
4167365Sgblack@eecs.umich.edu        ;
4177375Sgblack@eecs.umich.edu
4187365Sgblack@eecs.umich.edu    coalescedRxOrn
4197365Sgblack@eecs.umich.edu        .name(name() + ".coalescedRxOrn")
4207375Sgblack@eecs.umich.edu        .desc("average number of RxOrn's coalesced into each post")
4217375Sgblack@eecs.umich.edu        .precision(0)
4227365Sgblack@eecs.umich.edu        ;
4237365Sgblack@eecs.umich.edu
4247365Sgblack@eecs.umich.edu    coalescedTotal
4257365Sgblack@eecs.umich.edu        .name(name() + ".coalescedTotal")
4267365Sgblack@eecs.umich.edu        .desc("average number of interrupts coalesced into each post")
4277365Sgblack@eecs.umich.edu        .precision(0)
4287365Sgblack@eecs.umich.edu        ;
4297365Sgblack@eecs.umich.edu
4307365Sgblack@eecs.umich.edu    postedInterrupts
4317375Sgblack@eecs.umich.edu        .name(name() + ".postedInterrupts")
4327365Sgblack@eecs.umich.edu        .desc("number of posts to CPU")
4337365Sgblack@eecs.umich.edu        .precision(0)
4347375Sgblack@eecs.umich.edu        ;
4357375Sgblack@eecs.umich.edu
4367365Sgblack@eecs.umich.edu    droppedPackets
4377366Sgblack@eecs.umich.edu        .name(name() + ".droppedPackets")
4387366Sgblack@eecs.umich.edu        .desc("number of packets dropped")
4397366Sgblack@eecs.umich.edu        .precision(0)
4407366Sgblack@eecs.umich.edu        ;
4417375Sgblack@eecs.umich.edu
4427366Sgblack@eecs.umich.edu    coalescedSwi = totalSwi / postedInterrupts;
4437366Sgblack@eecs.umich.edu    coalescedRxIdle = totalRxIdle / postedInterrupts;
4447375Sgblack@eecs.umich.edu    coalescedRxOk = totalRxOk / postedInterrupts;
4457375Sgblack@eecs.umich.edu    coalescedRxDesc = totalRxDesc / postedInterrupts;
4467366Sgblack@eecs.umich.edu    coalescedTxOk = totalTxOk / postedInterrupts;
4477366Sgblack@eecs.umich.edu    coalescedTxIdle = totalTxIdle / postedInterrupts;
4487366Sgblack@eecs.umich.edu    coalescedTxDesc = totalTxDesc / postedInterrupts;
4497366Sgblack@eecs.umich.edu    coalescedRxOrn = totalRxOrn / postedInterrupts;
4507366Sgblack@eecs.umich.edu
4517366Sgblack@eecs.umich.edu    coalescedTotal = (totalSwi + totalRxIdle + totalRxOk + totalRxDesc +
4527366Sgblack@eecs.umich.edu                      totalTxOk + totalTxIdle + totalTxDesc +
4537366Sgblack@eecs.umich.edu                      totalRxOrn) / postedInterrupts;
4547366Sgblack@eecs.umich.edu
4557375Sgblack@eecs.umich.edu    txBandwidth = txBytes * Stats::constant(8) / simSeconds;
4567366Sgblack@eecs.umich.edu    rxBandwidth = rxBytes * Stats::constant(8) / simSeconds;
4577366Sgblack@eecs.umich.edu    totBandwidth = txBandwidth + rxBandwidth;
4587375Sgblack@eecs.umich.edu    totBytes = txBytes + rxBytes;
4597375Sgblack@eecs.umich.edu    totPackets = txPackets + rxPackets;
4607366Sgblack@eecs.umich.edu
4617367Sgblack@eecs.umich.edu    txPacketRate = txPackets / simSeconds;
4627367Sgblack@eecs.umich.edu    rxPacketRate = rxPackets / simSeconds;
4637378Sgblack@eecs.umich.edu}
4647367Sgblack@eecs.umich.edu
4657378Sgblack@eecs.umich.edu
4667367Sgblack@eecs.umich.edu/**
4677375Sgblack@eecs.umich.edu * This is to write to the PCI general configuration registers
4687367Sgblack@eecs.umich.edu */
4697367Sgblack@eecs.umich.eduTick
4707375Sgblack@eecs.umich.eduNSGigE::writeConfig(PacketPtr pkt)
4717375Sgblack@eecs.umich.edu{
4727367Sgblack@eecs.umich.edu    int offset = pkt->getAddr() & PCI_CONFIG_SIZE;
4737367Sgblack@eecs.umich.edu    if (offset < PCI_DEVICE_SPECIFIC)
4747367Sgblack@eecs.umich.edu        PciDev::writeConfig(pkt);
4757367Sgblack@eecs.umich.edu    else
4767367Sgblack@eecs.umich.edu        panic("Device specific PCI config space not implemented!\n");
4777367Sgblack@eecs.umich.edu
4787378Sgblack@eecs.umich.edu    switch (offset) {
4797367Sgblack@eecs.umich.edu        // seems to work fine without all these PCI settings, but i
4807378Sgblack@eecs.umich.edu        // put in the IO to double check, an assertion will fail if we
4817367Sgblack@eecs.umich.edu        // need to properly implement it
4827367Sgblack@eecs.umich.edu      case PCI_COMMAND:
4837367Sgblack@eecs.umich.edu        if (config.data[offset] & PCI_CMD_IOSE)
4847375Sgblack@eecs.umich.edu            ioEnable = true;
4857367Sgblack@eecs.umich.edu        else
4867367Sgblack@eecs.umich.edu            ioEnable = false;
4877375Sgblack@eecs.umich.edu        break;
4887375Sgblack@eecs.umich.edu    }
4897367Sgblack@eecs.umich.edu    pkt->result = Packet::Success;
4907368Sgblack@eecs.umich.edu    return configDelay;
4917368Sgblack@eecs.umich.edu}
4927378Sgblack@eecs.umich.edu
4937368Sgblack@eecs.umich.edu/**
4947378Sgblack@eecs.umich.edu * This reads the device registers, which are detailed in the NS83820
4957368Sgblack@eecs.umich.edu * spec sheet
4967375Sgblack@eecs.umich.edu */
4977368Sgblack@eecs.umich.eduTick
4987368Sgblack@eecs.umich.eduNSGigE::read(PacketPtr pkt)
4997375Sgblack@eecs.umich.edu{
5007375Sgblack@eecs.umich.edu    assert(ioEnable);
5017368Sgblack@eecs.umich.edu
5027368Sgblack@eecs.umich.edu    pkt->allocate();
5037368Sgblack@eecs.umich.edu
5047368Sgblack@eecs.umich.edu    //The mask is to give you only the offset into the device register file
5057368Sgblack@eecs.umich.edu    Addr daddr = pkt->getAddr() & 0xfff;
5067368Sgblack@eecs.umich.edu    DPRINTF(EthernetPIO, "read  da=%#x pa=%#x size=%d\n",
5077378Sgblack@eecs.umich.edu            daddr, pkt->getAddr(), pkt->getSize());
5087368Sgblack@eecs.umich.edu
5097378Sgblack@eecs.umich.edu
5107368Sgblack@eecs.umich.edu    // there are some reserved registers, you can see ns_gige_reg.h and
5117368Sgblack@eecs.umich.edu    // the spec sheet for details
5127368Sgblack@eecs.umich.edu    if (daddr > LAST && daddr <=  RESERVED) {
5137375Sgblack@eecs.umich.edu        panic("Accessing reserved register");
5147368Sgblack@eecs.umich.edu    } else if (daddr > RESERVED && daddr <= 0x3FC) {
5157368Sgblack@eecs.umich.edu        return readConfig(pkt);
5167375Sgblack@eecs.umich.edu    } else if (daddr >= MIB_START && daddr <= MIB_END) {
5177375Sgblack@eecs.umich.edu        // don't implement all the MIB's.  hopefully the kernel
5187368Sgblack@eecs.umich.edu        // doesn't actually DEPEND upon their values
5197369Sgblack@eecs.umich.edu        // MIB are just hardware stats keepers
5207369Sgblack@eecs.umich.edu        pkt->set<uint32_t>(0);
5217378Sgblack@eecs.umich.edu        pkt->result = Packet::Success;
5227369Sgblack@eecs.umich.edu        return pioDelay;
5237378Sgblack@eecs.umich.edu    } else if (daddr > 0x3FC)
5247369Sgblack@eecs.umich.edu        panic("Something is messed up!\n");
5257375Sgblack@eecs.umich.edu
5267369Sgblack@eecs.umich.edu    assert(pkt->getSize() == sizeof(uint32_t));
5277369Sgblack@eecs.umich.edu        uint32_t &reg = *pkt->getPtr<uint32_t>();
5287375Sgblack@eecs.umich.edu        uint16_t rfaddr;
5297375Sgblack@eecs.umich.edu
5307369Sgblack@eecs.umich.edu        switch (daddr) {
5317369Sgblack@eecs.umich.edu          case CR:
5327369Sgblack@eecs.umich.edu            reg = regs.command;
5337369Sgblack@eecs.umich.edu            //these are supposed to be cleared on a read
5347369Sgblack@eecs.umich.edu            reg &= ~(CR_RXD | CR_TXD | CR_TXR | CR_RXR);
5357369Sgblack@eecs.umich.edu            break;
5367378Sgblack@eecs.umich.edu
5377369Sgblack@eecs.umich.edu          case CFGR:
5387378Sgblack@eecs.umich.edu            reg = regs.config;
5397369Sgblack@eecs.umich.edu            break;
5407369Sgblack@eecs.umich.edu
5417369Sgblack@eecs.umich.edu          case MEAR:
5427375Sgblack@eecs.umich.edu            reg = regs.mear;
5437369Sgblack@eecs.umich.edu            break;
5447369Sgblack@eecs.umich.edu
5457375Sgblack@eecs.umich.edu          case PTSCR:
5467375Sgblack@eecs.umich.edu            reg = regs.ptscr;
5477369Sgblack@eecs.umich.edu            break;
5487369Sgblack@eecs.umich.edu
5497369Sgblack@eecs.umich.edu          case ISR:
5507378Sgblack@eecs.umich.edu            reg = regs.isr;
5517369Sgblack@eecs.umich.edu            devIntrClear(ISR_ALL);
5527378Sgblack@eecs.umich.edu            break;
5537369Sgblack@eecs.umich.edu
5547369Sgblack@eecs.umich.edu          case IMR:
5557369Sgblack@eecs.umich.edu            reg = regs.imr;
5567369Sgblack@eecs.umich.edu            break;
5577375Sgblack@eecs.umich.edu
5587369Sgblack@eecs.umich.edu          case IER:
5597369Sgblack@eecs.umich.edu            reg = regs.ier;
5607375Sgblack@eecs.umich.edu            break;
5617375Sgblack@eecs.umich.edu
5627369Sgblack@eecs.umich.edu          case IHR:
5637369Sgblack@eecs.umich.edu            reg = regs.ihr;
5647369Sgblack@eecs.umich.edu            break;
5657369Sgblack@eecs.umich.edu
5667369Sgblack@eecs.umich.edu          case TXDP:
5677378Sgblack@eecs.umich.edu            reg = regs.txdp;
5687369Sgblack@eecs.umich.edu            break;
5697378Sgblack@eecs.umich.edu
5707369Sgblack@eecs.umich.edu          case TXDP_HI:
5717369Sgblack@eecs.umich.edu            reg = regs.txdp_hi;
5727369Sgblack@eecs.umich.edu            break;
5737369Sgblack@eecs.umich.edu
5747369Sgblack@eecs.umich.edu          case TX_CFG:
5757369Sgblack@eecs.umich.edu            reg = regs.txcfg;
5767375Sgblack@eecs.umich.edu            break;
5777369Sgblack@eecs.umich.edu
5787369Sgblack@eecs.umich.edu          case GPIOR:
5797375Sgblack@eecs.umich.edu            reg = regs.gpior;
5807375Sgblack@eecs.umich.edu            break;
5817369Sgblack@eecs.umich.edu
5827370Sgblack@eecs.umich.edu          case RXDP:
5837370Sgblack@eecs.umich.edu            reg = regs.rxdp;
5847378Sgblack@eecs.umich.edu            break;
5857370Sgblack@eecs.umich.edu
5867370Sgblack@eecs.umich.edu          case RXDP_HI:
5877370Sgblack@eecs.umich.edu            reg = regs.rxdp_hi;
5887370Sgblack@eecs.umich.edu            break;
5897370Sgblack@eecs.umich.edu
5907378Sgblack@eecs.umich.edu          case RX_CFG:
5917370Sgblack@eecs.umich.edu            reg = regs.rxcfg;
5927375Sgblack@eecs.umich.edu            break;
5937370Sgblack@eecs.umich.edu
5947370Sgblack@eecs.umich.edu          case PQCR:
5957375Sgblack@eecs.umich.edu            reg = regs.pqcr;
5967375Sgblack@eecs.umich.edu            break;
5977370Sgblack@eecs.umich.edu
5987370Sgblack@eecs.umich.edu          case WCSR:
5997370Sgblack@eecs.umich.edu            reg = regs.wcsr;
6007370Sgblack@eecs.umich.edu            break;
6017370Sgblack@eecs.umich.edu
6027370Sgblack@eecs.umich.edu          case PCR:
6037370Sgblack@eecs.umich.edu            reg = regs.pcr;
6047378Sgblack@eecs.umich.edu            break;
6057370Sgblack@eecs.umich.edu
6067370Sgblack@eecs.umich.edu            // see the spec sheet for how RFCR and RFDR work
6077370Sgblack@eecs.umich.edu            // basically, you write to RFCR to tell the machine
6087370Sgblack@eecs.umich.edu            // what you want to do next, then you act upon RFDR,
6097370Sgblack@eecs.umich.edu            // and the device will be prepared b/c of what you
6107370Sgblack@eecs.umich.edu            // wrote to RFCR
6117378Sgblack@eecs.umich.edu          case RFCR:
6127370Sgblack@eecs.umich.edu            reg = regs.rfcr;
6137370Sgblack@eecs.umich.edu            break;
6147370Sgblack@eecs.umich.edu
6157375Sgblack@eecs.umich.edu          case RFDR:
6167370Sgblack@eecs.umich.edu            rfaddr = (uint16_t)(regs.rfcr & RFCR_RFADDR);
6177370Sgblack@eecs.umich.edu            switch (rfaddr) {
6187375Sgblack@eecs.umich.edu              // Read from perfect match ROM octets
6197375Sgblack@eecs.umich.edu              case 0x000:
6207370Sgblack@eecs.umich.edu                reg = rom.perfectMatch[1];
6217370Sgblack@eecs.umich.edu                reg = reg << 8;
6227370Sgblack@eecs.umich.edu                reg += rom.perfectMatch[0];
6237378Sgblack@eecs.umich.edu                break;
6247370Sgblack@eecs.umich.edu              case 0x002:
6257370Sgblack@eecs.umich.edu                reg = rom.perfectMatch[3] << 8;
6267370Sgblack@eecs.umich.edu                reg += rom.perfectMatch[2];
6277370Sgblack@eecs.umich.edu                break;
6287370Sgblack@eecs.umich.edu              case 0x004:
6297378Sgblack@eecs.umich.edu                reg = rom.perfectMatch[5] << 8;
6307370Sgblack@eecs.umich.edu                reg += rom.perfectMatch[4];
6317375Sgblack@eecs.umich.edu                break;
6327370Sgblack@eecs.umich.edu              default:
6337370Sgblack@eecs.umich.edu                // Read filter hash table
6347375Sgblack@eecs.umich.edu                if (rfaddr >= FHASH_ADDR &&
6357375Sgblack@eecs.umich.edu                    rfaddr < FHASH_ADDR + FHASH_SIZE) {
6367370Sgblack@eecs.umich.edu
6377370Sgblack@eecs.umich.edu                    // Only word-aligned reads supported
6387370Sgblack@eecs.umich.edu                    if (rfaddr % 2)
6397370Sgblack@eecs.umich.edu                        panic("unaligned read from filter hash table!");
6407370Sgblack@eecs.umich.edu
6417370Sgblack@eecs.umich.edu                    reg = rom.filterHash[rfaddr - FHASH_ADDR + 1] << 8;
6427370Sgblack@eecs.umich.edu                    reg += rom.filterHash[rfaddr - FHASH_ADDR];
6437378Sgblack@eecs.umich.edu                    break;
6447370Sgblack@eecs.umich.edu                }
6457370Sgblack@eecs.umich.edu
6467370Sgblack@eecs.umich.edu                panic("reading RFDR for something other than pattern"
6477370Sgblack@eecs.umich.edu                      " matching or hashing! %#x\n", rfaddr);
6487370Sgblack@eecs.umich.edu            }
6497370Sgblack@eecs.umich.edu            break;
6507378Sgblack@eecs.umich.edu
6517370Sgblack@eecs.umich.edu          case SRR:
6527370Sgblack@eecs.umich.edu            reg = regs.srr;
6537370Sgblack@eecs.umich.edu            break;
6547375Sgblack@eecs.umich.edu
6557370Sgblack@eecs.umich.edu          case MIBC:
6567370Sgblack@eecs.umich.edu            reg = regs.mibc;
6577375Sgblack@eecs.umich.edu            reg &= ~(MIBC_MIBS | MIBC_ACLR);
6587375Sgblack@eecs.umich.edu            break;
6597370Sgblack@eecs.umich.edu
6607371Sgblack@eecs.umich.edu          case VRCR:
6617371Sgblack@eecs.umich.edu            reg = regs.vrcr;
6627378Sgblack@eecs.umich.edu            break;
6637371Sgblack@eecs.umich.edu
6647371Sgblack@eecs.umich.edu          case VTCR:
6657371Sgblack@eecs.umich.edu            reg = regs.vtcr;
6667371Sgblack@eecs.umich.edu            break;
6677371Sgblack@eecs.umich.edu
6687378Sgblack@eecs.umich.edu          case VDR:
6697371Sgblack@eecs.umich.edu            reg = regs.vdr;
6707375Sgblack@eecs.umich.edu            break;
6717371Sgblack@eecs.umich.edu
6727371Sgblack@eecs.umich.edu          case CCSR:
6737375Sgblack@eecs.umich.edu            reg = regs.ccsr;
6747375Sgblack@eecs.umich.edu            break;
6757371Sgblack@eecs.umich.edu
6767371Sgblack@eecs.umich.edu          case TBICR:
6777371Sgblack@eecs.umich.edu            reg = regs.tbicr;
6787371Sgblack@eecs.umich.edu            break;
6797371Sgblack@eecs.umich.edu
6807371Sgblack@eecs.umich.edu          case TBISR:
6817371Sgblack@eecs.umich.edu            reg = regs.tbisr;
6827378Sgblack@eecs.umich.edu            break;
6837371Sgblack@eecs.umich.edu
6847371Sgblack@eecs.umich.edu          case TANAR:
6857371Sgblack@eecs.umich.edu            reg = regs.tanar;
6867371Sgblack@eecs.umich.edu            break;
6877371Sgblack@eecs.umich.edu
6887371Sgblack@eecs.umich.edu          case TANLPAR:
6897378Sgblack@eecs.umich.edu            reg = regs.tanlpar;
6907371Sgblack@eecs.umich.edu            break;
6917371Sgblack@eecs.umich.edu
6927371Sgblack@eecs.umich.edu          case TANER:
6937375Sgblack@eecs.umich.edu            reg = regs.taner;
6947371Sgblack@eecs.umich.edu            break;
6957371Sgblack@eecs.umich.edu
6967375Sgblack@eecs.umich.edu          case TESR:
6977375Sgblack@eecs.umich.edu            reg = regs.tesr;
6987371Sgblack@eecs.umich.edu            break;
6997371Sgblack@eecs.umich.edu
7007371Sgblack@eecs.umich.edu          case M5REG:
7017378Sgblack@eecs.umich.edu            reg = 0;
7027371Sgblack@eecs.umich.edu            if (params()->rx_thread)
7037371Sgblack@eecs.umich.edu                reg |= M5REG_RX_THREAD;
7047371Sgblack@eecs.umich.edu            if (params()->tx_thread)
7057371Sgblack@eecs.umich.edu                reg |= M5REG_TX_THREAD;
7067371Sgblack@eecs.umich.edu            if (params()->rss)
7077378Sgblack@eecs.umich.edu                reg |= M5REG_RSS;
7087371Sgblack@eecs.umich.edu            break;
7097375Sgblack@eecs.umich.edu
7107371Sgblack@eecs.umich.edu          default:
7117371Sgblack@eecs.umich.edu            panic("reading unimplemented register: addr=%#x", daddr);
7127375Sgblack@eecs.umich.edu        }
7137375Sgblack@eecs.umich.edu
7147371Sgblack@eecs.umich.edu        DPRINTF(EthernetPIO, "read from %#x: data=%d data=%#x\n",
7157371Sgblack@eecs.umich.edu                daddr, reg, reg);
7167371Sgblack@eecs.umich.edu
7177371Sgblack@eecs.umich.edu    pkt->result = Packet::Success;
7187371Sgblack@eecs.umich.edu    return pioDelay;
7197371Sgblack@eecs.umich.edu}
7207371Sgblack@eecs.umich.edu
7217378Sgblack@eecs.umich.eduTick
7227371Sgblack@eecs.umich.eduNSGigE::write(PacketPtr pkt)
7237371Sgblack@eecs.umich.edu{
7247371Sgblack@eecs.umich.edu    assert(ioEnable);
7257371Sgblack@eecs.umich.edu
7267371Sgblack@eecs.umich.edu    Addr daddr = pkt->getAddr() & 0xfff;
7277371Sgblack@eecs.umich.edu    DPRINTF(EthernetPIO, "write da=%#x pa=%#x size=%d\n",
7287378Sgblack@eecs.umich.edu            daddr, pkt->getAddr(), pkt->getSize());
7297371Sgblack@eecs.umich.edu
7307371Sgblack@eecs.umich.edu    if (daddr > LAST && daddr <=  RESERVED) {
7317371Sgblack@eecs.umich.edu        panic("Accessing reserved register");
7327375Sgblack@eecs.umich.edu    } else if (daddr > RESERVED && daddr <= 0x3FC) {
7337371Sgblack@eecs.umich.edu        return writeConfig(pkt);
7347371Sgblack@eecs.umich.edu    } else if (daddr > 0x3FC)
7357375Sgblack@eecs.umich.edu        panic("Something is messed up!\n");
7367375Sgblack@eecs.umich.edu
7377371Sgblack@eecs.umich.edu    if (pkt->getSize() == sizeof(uint32_t)) {
7387371Sgblack@eecs.umich.edu        uint32_t reg = pkt->get<uint32_t>();
7397371Sgblack@eecs.umich.edu        uint16_t rfaddr;
7407378Sgblack@eecs.umich.edu
7417371Sgblack@eecs.umich.edu        DPRINTF(EthernetPIO, "write data=%d data=%#x\n", reg, reg);
7427371Sgblack@eecs.umich.edu
7437371Sgblack@eecs.umich.edu        switch (daddr) {
7447371Sgblack@eecs.umich.edu          case CR:
7457371Sgblack@eecs.umich.edu            regs.command = reg;
7467378Sgblack@eecs.umich.edu            if (reg & CR_TXD) {
7477371Sgblack@eecs.umich.edu                txEnable = false;
7487375Sgblack@eecs.umich.edu            } else if (reg & CR_TXE) {
7497371Sgblack@eecs.umich.edu                txEnable = true;
7507371Sgblack@eecs.umich.edu
7517375Sgblack@eecs.umich.edu                // the kernel is enabling the transmit machine
7527375Sgblack@eecs.umich.edu                if (txState == txIdle)
7537371Sgblack@eecs.umich.edu                    txKick();
7547371Sgblack@eecs.umich.edu            }
7557371Sgblack@eecs.umich.edu
7567371Sgblack@eecs.umich.edu            if (reg & CR_RXD) {
7577371Sgblack@eecs.umich.edu                rxEnable = false;
7587371Sgblack@eecs.umich.edu            } else if (reg & CR_RXE) {
7597371Sgblack@eecs.umich.edu                rxEnable = true;
7607378Sgblack@eecs.umich.edu
7617371Sgblack@eecs.umich.edu                if (rxState == rxIdle)
7627371Sgblack@eecs.umich.edu                    rxKick();
7637371Sgblack@eecs.umich.edu            }
7647371Sgblack@eecs.umich.edu
7657371Sgblack@eecs.umich.edu            if (reg & CR_TXR)
7667371Sgblack@eecs.umich.edu                txReset();
7677378Sgblack@eecs.umich.edu
7687371Sgblack@eecs.umich.edu            if (reg & CR_RXR)
7697371Sgblack@eecs.umich.edu                rxReset();
7707371Sgblack@eecs.umich.edu
7717375Sgblack@eecs.umich.edu            if (reg & CR_SWI)
7727371Sgblack@eecs.umich.edu                devIntrPost(ISR_SWI);
7737371Sgblack@eecs.umich.edu
7747375Sgblack@eecs.umich.edu            if (reg & CR_RST) {
7757375Sgblack@eecs.umich.edu                txReset();
7767371Sgblack@eecs.umich.edu                rxReset();
7777373Sgblack@eecs.umich.edu
7787373Sgblack@eecs.umich.edu                regsReset();
7797378Sgblack@eecs.umich.edu            }
7807373Sgblack@eecs.umich.edu            break;
7817378Sgblack@eecs.umich.edu
7827373Sgblack@eecs.umich.edu          case CFGR:
7837375Sgblack@eecs.umich.edu            if (reg & CFGR_LNKSTS ||
7847373Sgblack@eecs.umich.edu                reg & CFGR_SPDSTS ||
7857373Sgblack@eecs.umich.edu                reg & CFGR_DUPSTS ||
7867375Sgblack@eecs.umich.edu                reg & CFGR_RESERVED ||
7877375Sgblack@eecs.umich.edu                reg & CFGR_T64ADDR ||
7887373Sgblack@eecs.umich.edu                reg & CFGR_PCI64_DET)
7897373Sgblack@eecs.umich.edu
7907373Sgblack@eecs.umich.edu            // First clear all writable bits
7917373Sgblack@eecs.umich.edu            regs.config &= CFGR_LNKSTS | CFGR_SPDSTS | CFGR_DUPSTS |
7927378Sgblack@eecs.umich.edu                                   CFGR_RESERVED | CFGR_T64ADDR |
7937373Sgblack@eecs.umich.edu                                   CFGR_PCI64_DET;
7947378Sgblack@eecs.umich.edu            // Now set the appropriate writable bits
7957373Sgblack@eecs.umich.edu            regs.config |= reg & ~(CFGR_LNKSTS | CFGR_SPDSTS | CFGR_DUPSTS |
7967373Sgblack@eecs.umich.edu                                   CFGR_RESERVED | CFGR_T64ADDR |
7977373Sgblack@eecs.umich.edu                                   CFGR_PCI64_DET);
7987375Sgblack@eecs.umich.edu
7997373Sgblack@eecs.umich.edu// all these #if 0's are because i don't THINK the kernel needs to
8007373Sgblack@eecs.umich.edu// have these implemented. if there is a problem relating to one of
8017375Sgblack@eecs.umich.edu// these, you may need to add functionality in.
8027375Sgblack@eecs.umich.edu            if (reg & CFGR_TBI_EN) ;
8037373Sgblack@eecs.umich.edu            if (reg & CFGR_MODE_1000) ;
8047373Sgblack@eecs.umich.edu
8057373Sgblack@eecs.umich.edu            if (reg & CFGR_AUTO_1000)
8067378Sgblack@eecs.umich.edu                panic("CFGR_AUTO_1000 not implemented!\n");
8077373Sgblack@eecs.umich.edu
8087378Sgblack@eecs.umich.edu            if (reg & CFGR_PINT_DUPSTS ||
8097373Sgblack@eecs.umich.edu                reg & CFGR_PINT_LNKSTS ||
8107375Sgblack@eecs.umich.edu                reg & CFGR_PINT_SPDSTS)
8117373Sgblack@eecs.umich.edu                ;
8127373Sgblack@eecs.umich.edu
8137375Sgblack@eecs.umich.edu            if (reg & CFGR_TMRTEST) ;
8147375Sgblack@eecs.umich.edu            if (reg & CFGR_MRM_DIS) ;
8157373Sgblack@eecs.umich.edu            if (reg & CFGR_MWI_DIS) ;
8167373Sgblack@eecs.umich.edu
8177373Sgblack@eecs.umich.edu            if (reg & CFGR_T64ADDR) ;
8187373Sgblack@eecs.umich.edu            // panic("CFGR_T64ADDR is read only register!\n");
8197378Sgblack@eecs.umich.edu
8207373Sgblack@eecs.umich.edu            if (reg & CFGR_PCI64_DET)
8217378Sgblack@eecs.umich.edu                panic("CFGR_PCI64_DET is read only register!\n");
8227373Sgblack@eecs.umich.edu
8237373Sgblack@eecs.umich.edu            if (reg & CFGR_DATA64_EN) ;
8247373Sgblack@eecs.umich.edu            if (reg & CFGR_M64ADDR) ;
8257375Sgblack@eecs.umich.edu            if (reg & CFGR_PHY_RST) ;
8267373Sgblack@eecs.umich.edu            if (reg & CFGR_PHY_DIS) ;
8277373Sgblack@eecs.umich.edu
8287375Sgblack@eecs.umich.edu            if (reg & CFGR_EXTSTS_EN)
8297375Sgblack@eecs.umich.edu                extstsEnable = true;
8307373Sgblack@eecs.umich.edu            else
8317373Sgblack@eecs.umich.edu                extstsEnable = false;
8327380Sgblack@eecs.umich.edu
8337380Sgblack@eecs.umich.edu            if (reg & CFGR_REQALG) ;
8347380Sgblack@eecs.umich.edu            if (reg & CFGR_SB) ;
8357380Sgblack@eecs.umich.edu            if (reg & CFGR_POW) ;
8367380Sgblack@eecs.umich.edu            if (reg & CFGR_EXD) ;
8377380Sgblack@eecs.umich.edu            if (reg & CFGR_PESEL) ;
8387380Sgblack@eecs.umich.edu            if (reg & CFGR_BROM_DIS) ;
8397380Sgblack@eecs.umich.edu            if (reg & CFGR_EXT_125) ;
8407380Sgblack@eecs.umich.edu            if (reg & CFGR_BEM) ;
8417380Sgblack@eecs.umich.edu            break;
8427380Sgblack@eecs.umich.edu
8437380Sgblack@eecs.umich.edu          case MEAR:
8447380Sgblack@eecs.umich.edu            // Clear writable bits
8457380Sgblack@eecs.umich.edu            regs.mear &= MEAR_EEDO;
8467380Sgblack@eecs.umich.edu            // Set appropriate writable bits
8477380Sgblack@eecs.umich.edu            regs.mear |= reg & ~MEAR_EEDO;
8487380Sgblack@eecs.umich.edu
8497380Sgblack@eecs.umich.edu            // FreeBSD uses the EEPROM to read PMATCH (for the MAC address)
8507380Sgblack@eecs.umich.edu            // even though it could get it through RFDR
8517380Sgblack@eecs.umich.edu            if (reg & MEAR_EESEL) {
8527380Sgblack@eecs.umich.edu                // Rising edge of clock
8537380Sgblack@eecs.umich.edu                if (reg & MEAR_EECLK && !eepromClk)
8547380Sgblack@eecs.umich.edu                    eepromKick();
8557380Sgblack@eecs.umich.edu            }
8567380Sgblack@eecs.umich.edu            else {
8577380Sgblack@eecs.umich.edu                eepromState = eepromStart;
8587380Sgblack@eecs.umich.edu                regs.mear &= ~MEAR_EEDI;
8597380Sgblack@eecs.umich.edu            }
8607380Sgblack@eecs.umich.edu
8617380Sgblack@eecs.umich.edu            eepromClk = reg & MEAR_EECLK;
8627380Sgblack@eecs.umich.edu
8637380Sgblack@eecs.umich.edu            // since phy is completely faked, MEAR_MD* don't matter
8647380Sgblack@eecs.umich.edu            if (reg & MEAR_MDIO) ;
8657380Sgblack@eecs.umich.edu            if (reg & MEAR_MDDIR) ;
8667380Sgblack@eecs.umich.edu            if (reg & MEAR_MDC) ;
8677380Sgblack@eecs.umich.edu            break;
8687380Sgblack@eecs.umich.edu
8697380Sgblack@eecs.umich.edu          case PTSCR:
8707380Sgblack@eecs.umich.edu            regs.ptscr = reg & ~(PTSCR_RBIST_RDONLY);
8717380Sgblack@eecs.umich.edu            // these control BISTs for various parts of chip - we
8727380Sgblack@eecs.umich.edu            // don't care or do just fake that the BIST is done
8737380Sgblack@eecs.umich.edu            if (reg & PTSCR_RBIST_EN)
8747380Sgblack@eecs.umich.edu                regs.ptscr |= PTSCR_RBIST_DONE;
8757380Sgblack@eecs.umich.edu            if (reg & PTSCR_EEBIST_EN)
8767380Sgblack@eecs.umich.edu                regs.ptscr &= ~PTSCR_EEBIST_EN;
8777380Sgblack@eecs.umich.edu            if (reg & PTSCR_EELOAD_EN)
8787380Sgblack@eecs.umich.edu                regs.ptscr &= ~PTSCR_EELOAD_EN;
8797380Sgblack@eecs.umich.edu            break;
8807380Sgblack@eecs.umich.edu
8817380Sgblack@eecs.umich.edu          case ISR: /* writing to the ISR has no effect */
8827380Sgblack@eecs.umich.edu            panic("ISR is a read only register!\n");
8837380Sgblack@eecs.umich.edu
8847380Sgblack@eecs.umich.edu          case IMR:
8857380Sgblack@eecs.umich.edu            regs.imr = reg;
8867373Sgblack@eecs.umich.edu            devIntrChangeMask();
8877378Sgblack@eecs.umich.edu            break;
8887380Sgblack@eecs.umich.edu
8897373Sgblack@eecs.umich.edu          case IER:
8907378Sgblack@eecs.umich.edu            regs.ier = reg;
8917373Sgblack@eecs.umich.edu            break;
8927375Sgblack@eecs.umich.edu
8937373Sgblack@eecs.umich.edu          case IHR:
8947373Sgblack@eecs.umich.edu            regs.ihr = reg;
8957375Sgblack@eecs.umich.edu            /* not going to implement real interrupt holdoff */
8967375Sgblack@eecs.umich.edu            break;
8977373Sgblack@eecs.umich.edu
8987373Sgblack@eecs.umich.edu          case TXDP:
8997373Sgblack@eecs.umich.edu            regs.txdp = (reg & 0xFFFFFFFC);
9007373Sgblack@eecs.umich.edu            assert(txState == txIdle);
9017373Sgblack@eecs.umich.edu            CTDD = false;
9027378Sgblack@eecs.umich.edu            break;
9037380Sgblack@eecs.umich.edu
9047373Sgblack@eecs.umich.edu          case TXDP_HI:
9057378Sgblack@eecs.umich.edu            regs.txdp_hi = reg;
9067373Sgblack@eecs.umich.edu            break;
9077373Sgblack@eecs.umich.edu
9087375Sgblack@eecs.umich.edu          case TX_CFG:
9097373Sgblack@eecs.umich.edu            regs.txcfg = reg;
9107373Sgblack@eecs.umich.edu#if 0
9117375Sgblack@eecs.umich.edu            if (reg & TX_CFG_CSI) ;
9127375Sgblack@eecs.umich.edu            if (reg & TX_CFG_HBI) ;
9137373Sgblack@eecs.umich.edu            if (reg & TX_CFG_MLB) ;
9147373Sgblack@eecs.umich.edu            if (reg & TX_CFG_ATP) ;
9157373Sgblack@eecs.umich.edu            if (reg & TX_CFG_ECRETRY) {
9167378Sgblack@eecs.umich.edu                /*
9177380Sgblack@eecs.umich.edu                 * this could easily be implemented, but considering
9187373Sgblack@eecs.umich.edu                 * the network is just a fake pipe, wouldn't make
9197378Sgblack@eecs.umich.edu                 * sense to do this
9207373Sgblack@eecs.umich.edu                 */
9217375Sgblack@eecs.umich.edu            }
9227373Sgblack@eecs.umich.edu
9237373Sgblack@eecs.umich.edu            if (reg & TX_CFG_BRST_DIS) ;
9247375Sgblack@eecs.umich.edu#endif
9257375Sgblack@eecs.umich.edu
9267373Sgblack@eecs.umich.edu#if 0
9277373Sgblack@eecs.umich.edu            /* we handle our own DMA, ignore the kernel's exhortations */
9287373Sgblack@eecs.umich.edu            if (reg & TX_CFG_MXDMA) ;
9297373Sgblack@eecs.umich.edu#endif
9307373Sgblack@eecs.umich.edu
9317378Sgblack@eecs.umich.edu            // also, we currently don't care about fill/drain
9327380Sgblack@eecs.umich.edu            // thresholds though this may change in the future with
9337373Sgblack@eecs.umich.edu            // more realistic networks or a driver which changes it
9347378Sgblack@eecs.umich.edu            // according to feedback
9357373Sgblack@eecs.umich.edu
9367373Sgblack@eecs.umich.edu            break;
9377375Sgblack@eecs.umich.edu
9387373Sgblack@eecs.umich.edu          case GPIOR:
9397373Sgblack@eecs.umich.edu            // Only write writable bits
9407375Sgblack@eecs.umich.edu            regs.gpior &= GPIOR_UNUSED | GPIOR_GP5_IN | GPIOR_GP4_IN
9417375Sgblack@eecs.umich.edu                        | GPIOR_GP3_IN | GPIOR_GP2_IN | GPIOR_GP1_IN;
9427373Sgblack@eecs.umich.edu            regs.gpior |= reg & ~(GPIOR_UNUSED | GPIOR_GP5_IN | GPIOR_GP4_IN
9437374Sgblack@eecs.umich.edu                                | GPIOR_GP3_IN | GPIOR_GP2_IN | GPIOR_GP1_IN);
9447374Sgblack@eecs.umich.edu            /* these just control general purpose i/o pins, don't matter */
9457374Sgblack@eecs.umich.edu            break;
9467378Sgblack@eecs.umich.edu
9477374Sgblack@eecs.umich.edu          case RXDP:
9487378Sgblack@eecs.umich.edu            regs.rxdp = reg;
9497374Sgblack@eecs.umich.edu            CRDD = false;
9507374Sgblack@eecs.umich.edu            break;
9517374Sgblack@eecs.umich.edu
9527375Sgblack@eecs.umich.edu          case RXDP_HI:
9537374Sgblack@eecs.umich.edu            regs.rxdp_hi = reg;
9547374Sgblack@eecs.umich.edu            break;
9557375Sgblack@eecs.umich.edu
9567375Sgblack@eecs.umich.edu          case RX_CFG:
9577374Sgblack@eecs.umich.edu            regs.rxcfg = reg;
9587374Sgblack@eecs.umich.edu#if 0
9597374Sgblack@eecs.umich.edu            if (reg & RX_CFG_AEP) ;
9607374Sgblack@eecs.umich.edu            if (reg & RX_CFG_ARP) ;
9617374Sgblack@eecs.umich.edu            if (reg & RX_CFG_STRIPCRC) ;
9627378Sgblack@eecs.umich.edu            if (reg & RX_CFG_RX_RD) ;
9637374Sgblack@eecs.umich.edu            if (reg & RX_CFG_ALP) ;
9647378Sgblack@eecs.umich.edu            if (reg & RX_CFG_AIRL) ;
9657374Sgblack@eecs.umich.edu
9667375Sgblack@eecs.umich.edu            /* we handle our own DMA, ignore what kernel says about it */
9677374Sgblack@eecs.umich.edu            if (reg & RX_CFG_MXDMA) ;
9687374Sgblack@eecs.umich.edu
9697375Sgblack@eecs.umich.edu            //also, we currently don't care about fill/drain thresholds
9707375Sgblack@eecs.umich.edu            //though this may change in the future with more realistic
9717374Sgblack@eecs.umich.edu            //networks or a driver which changes it according to feedback
9727377Sgblack@eecs.umich.edu            if (reg & (RX_CFG_DRTH | RX_CFG_DRTH0)) ;
9737377Sgblack@eecs.umich.edu#endif
9747377Sgblack@eecs.umich.edu            break;
9757377Sgblack@eecs.umich.edu
9767377Sgblack@eecs.umich.edu          case PQCR:
9777377Sgblack@eecs.umich.edu            /* there is no priority queueing used in the linux 2.6 driver */
9787377Sgblack@eecs.umich.edu            regs.pqcr = reg;
9797377Sgblack@eecs.umich.edu            break;
9807377Sgblack@eecs.umich.edu
9817377Sgblack@eecs.umich.edu          case WCSR:
9827377Sgblack@eecs.umich.edu            /* not going to implement wake on LAN */
9837377Sgblack@eecs.umich.edu            regs.wcsr = reg;
9847377Sgblack@eecs.umich.edu            break;
9857377Sgblack@eecs.umich.edu
9867377Sgblack@eecs.umich.edu          case PCR:
9877377Sgblack@eecs.umich.edu            /* not going to implement pause control */
9887377Sgblack@eecs.umich.edu            regs.pcr = reg;
9897377Sgblack@eecs.umich.edu            break;
9907377Sgblack@eecs.umich.edu
9917377Sgblack@eecs.umich.edu          case RFCR:
9927377Sgblack@eecs.umich.edu            regs.rfcr = reg;
9937377Sgblack@eecs.umich.edu
9947377Sgblack@eecs.umich.edu            rxFilterEnable = (reg & RFCR_RFEN) ? true : false;
9957377Sgblack@eecs.umich.edu            acceptBroadcast = (reg & RFCR_AAB) ? true : false;
9967377Sgblack@eecs.umich.edu            acceptMulticast = (reg & RFCR_AAM) ? true : false;
9977377Sgblack@eecs.umich.edu            acceptUnicast = (reg & RFCR_AAU) ? true : false;
9987377Sgblack@eecs.umich.edu            acceptPerfect = (reg & RFCR_APM) ? true : false;
9997377Sgblack@eecs.umich.edu            acceptArp = (reg & RFCR_AARP) ? true : false;
10007377Sgblack@eecs.umich.edu            multicastHashEnable = (reg & RFCR_MHEN) ? true : false;
10017377Sgblack@eecs.umich.edu
10027377Sgblack@eecs.umich.edu#if 0
10037377Sgblack@eecs.umich.edu            if (reg & RFCR_APAT)
10047377Sgblack@eecs.umich.edu                panic("RFCR_APAT not implemented!\n");
10057377Sgblack@eecs.umich.edu#endif
10067377Sgblack@eecs.umich.edu            if (reg & RFCR_UHEN)
10077377Sgblack@eecs.umich.edu                panic("Unicast hash filtering not used by drivers!\n");
10087377Sgblack@eecs.umich.edu
10097377Sgblack@eecs.umich.edu            if (reg & RFCR_ULM)
10107377Sgblack@eecs.umich.edu                panic("RFCR_ULM not implemented!\n");
10117377Sgblack@eecs.umich.edu
10127377Sgblack@eecs.umich.edu            break;
10137377Sgblack@eecs.umich.edu
10147377Sgblack@eecs.umich.edu          case RFDR:
10157377Sgblack@eecs.umich.edu            rfaddr = (uint16_t)(regs.rfcr & RFCR_RFADDR);
10167377Sgblack@eecs.umich.edu            switch (rfaddr) {
10177377Sgblack@eecs.umich.edu              case 0x000:
10187377Sgblack@eecs.umich.edu                rom.perfectMatch[0] = (uint8_t)reg;
10197377Sgblack@eecs.umich.edu                rom.perfectMatch[1] = (uint8_t)(reg >> 8);
10207377Sgblack@eecs.umich.edu                break;
10217377Sgblack@eecs.umich.edu              case 0x002:
10227377Sgblack@eecs.umich.edu                rom.perfectMatch[2] = (uint8_t)reg;
10237377Sgblack@eecs.umich.edu                rom.perfectMatch[3] = (uint8_t)(reg >> 8);
10247377Sgblack@eecs.umich.edu                break;
10257377Sgblack@eecs.umich.edu              case 0x004:
10267377Sgblack@eecs.umich.edu                rom.perfectMatch[4] = (uint8_t)reg;
10277377Sgblack@eecs.umich.edu                rom.perfectMatch[5] = (uint8_t)(reg >> 8);
10287377Sgblack@eecs.umich.edu                break;
10297377Sgblack@eecs.umich.edu              default:
10307377Sgblack@eecs.umich.edu
10317377Sgblack@eecs.umich.edu                if (rfaddr >= FHASH_ADDR &&
10327377Sgblack@eecs.umich.edu                    rfaddr < FHASH_ADDR + FHASH_SIZE) {
10337377Sgblack@eecs.umich.edu
10347377Sgblack@eecs.umich.edu                    // Only word-aligned writes supported
10357377Sgblack@eecs.umich.edu                    if (rfaddr % 2)
10367377Sgblack@eecs.umich.edu                        panic("unaligned write to filter hash table!");
10377377Sgblack@eecs.umich.edu
10387377Sgblack@eecs.umich.edu                    rom.filterHash[rfaddr - FHASH_ADDR] = (uint8_t)reg;
10397377Sgblack@eecs.umich.edu                    rom.filterHash[rfaddr - FHASH_ADDR + 1]
10407377Sgblack@eecs.umich.edu                        = (uint8_t)(reg >> 8);
10417377Sgblack@eecs.umich.edu                    break;
10427377Sgblack@eecs.umich.edu                }
10437377Sgblack@eecs.umich.edu                panic("writing RFDR for something other than pattern matching\
10447377Sgblack@eecs.umich.edu                    or hashing! %#x\n", rfaddr);
10457377Sgblack@eecs.umich.edu            }
10467377Sgblack@eecs.umich.edu
10477377Sgblack@eecs.umich.edu          case BRAR:
10487377Sgblack@eecs.umich.edu            regs.brar = reg;
10497377Sgblack@eecs.umich.edu            break;
10507377Sgblack@eecs.umich.edu
10517377Sgblack@eecs.umich.edu          case BRDR:
10527377Sgblack@eecs.umich.edu            panic("the driver never uses BRDR, something is wrong!\n");
10537377Sgblack@eecs.umich.edu
10547377Sgblack@eecs.umich.edu          case SRR:
10557377Sgblack@eecs.umich.edu            panic("SRR is read only register!\n");
10567377Sgblack@eecs.umich.edu
10577322Sgblack@eecs.umich.edu          case MIBC:
10587379Sgblack@eecs.umich.edu            panic("the driver never uses MIBC, something is wrong!\n");
10597379Sgblack@eecs.umich.edu
10607379Sgblack@eecs.umich.edu          case VRCR:
10617379Sgblack@eecs.umich.edu            regs.vrcr = reg;
10627379Sgblack@eecs.umich.edu            break;
10637379Sgblack@eecs.umich.edu
10647379Sgblack@eecs.umich.edu          case VTCR:
10657379Sgblack@eecs.umich.edu            regs.vtcr = reg;
10667379Sgblack@eecs.umich.edu            break;
10677379Sgblack@eecs.umich.edu
10687379Sgblack@eecs.umich.edu          case VDR:
10697379Sgblack@eecs.umich.edu            panic("the driver never uses VDR, something is wrong!\n");
10707379Sgblack@eecs.umich.edu
10717379Sgblack@eecs.umich.edu          case CCSR:
10727379Sgblack@eecs.umich.edu            /* not going to implement clockrun stuff */
10737379Sgblack@eecs.umich.edu            regs.ccsr = reg;
10747379Sgblack@eecs.umich.edu            break;
10757379Sgblack@eecs.umich.edu
10767379Sgblack@eecs.umich.edu          case TBICR:
10777379Sgblack@eecs.umich.edu            regs.tbicr = reg;
10787379Sgblack@eecs.umich.edu            if (reg & TBICR_MR_LOOPBACK)
10797379Sgblack@eecs.umich.edu                panic("TBICR_MR_LOOPBACK never used, something wrong!\n");
10807379Sgblack@eecs.umich.edu
10817379Sgblack@eecs.umich.edu            if (reg & TBICR_MR_AN_ENABLE) {
10827379Sgblack@eecs.umich.edu                regs.tanlpar = regs.tanar;
10837379Sgblack@eecs.umich.edu                regs.tbisr |= (TBISR_MR_AN_COMPLETE | TBISR_MR_LINK_STATUS);
10847379Sgblack@eecs.umich.edu            }
10857379Sgblack@eecs.umich.edu
10867379Sgblack@eecs.umich.edu#if 0
10877379Sgblack@eecs.umich.edu            if (reg & TBICR_MR_RESTART_AN) ;
10887379Sgblack@eecs.umich.edu#endif
10897379Sgblack@eecs.umich.edu
10907379Sgblack@eecs.umich.edu            break;
10917379Sgblack@eecs.umich.edu
10927379Sgblack@eecs.umich.edu          case TBISR:
10937379Sgblack@eecs.umich.edu            panic("TBISR is read only register!\n");
10947379Sgblack@eecs.umich.edu
10957379Sgblack@eecs.umich.edu          case TANAR:
10967379Sgblack@eecs.umich.edu            // Only write the writable bits
10977379Sgblack@eecs.umich.edu            regs.tanar &= TANAR_RF1 | TANAR_RF2 | TANAR_UNUSED;
10987379Sgblack@eecs.umich.edu            regs.tanar |= reg & ~(TANAR_RF1 | TANAR_RF2 | TANAR_UNUSED);
10997379Sgblack@eecs.umich.edu
11007379Sgblack@eecs.umich.edu            // Pause capability unimplemented
11017379Sgblack@eecs.umich.edu#if 0
11027379Sgblack@eecs.umich.edu            if (reg & TANAR_PS2) ;
11037379Sgblack@eecs.umich.edu            if (reg & TANAR_PS1) ;
11047379Sgblack@eecs.umich.edu#endif
11057379Sgblack@eecs.umich.edu
11067379Sgblack@eecs.umich.edu            break;
11077379Sgblack@eecs.umich.edu
11087379Sgblack@eecs.umich.edu          case TANLPAR:
11097379Sgblack@eecs.umich.edu            panic("this should only be written to by the fake phy!\n");
11107379Sgblack@eecs.umich.edu
11117379Sgblack@eecs.umich.edu          case TANER:
11127379Sgblack@eecs.umich.edu            panic("TANER is read only register!\n");
11137379Sgblack@eecs.umich.edu
11147379Sgblack@eecs.umich.edu          case TESR:
11157379Sgblack@eecs.umich.edu            regs.tesr = reg;
11167379Sgblack@eecs.umich.edu            break;
11177379Sgblack@eecs.umich.edu
11187379Sgblack@eecs.umich.edu          default:
11197379Sgblack@eecs.umich.edu            panic("invalid register access daddr=%#x", daddr);
11207379Sgblack@eecs.umich.edu        }
11217379Sgblack@eecs.umich.edu    } else {
11227379Sgblack@eecs.umich.edu        panic("Invalid Request Size");
11237380Sgblack@eecs.umich.edu    }
11247379Sgblack@eecs.umich.edu    pkt->result = Packet::Success;
11257379Sgblack@eecs.umich.edu    return pioDelay;
11267379Sgblack@eecs.umich.edu}
11277379Sgblack@eecs.umich.edu
11287379Sgblack@eecs.umich.eduvoid
11297379Sgblack@eecs.umich.eduNSGigE::devIntrPost(uint32_t interrupts)
11307379Sgblack@eecs.umich.edu{
11317379Sgblack@eecs.umich.edu    if (interrupts & ISR_RESERVE)
11327379Sgblack@eecs.umich.edu        panic("Cannot set a reserved interrupt");
11337379Sgblack@eecs.umich.edu
11347379Sgblack@eecs.umich.edu    if (interrupts & ISR_NOIMPL)
11357379Sgblack@eecs.umich.edu        warn("interrupt not implemented %#x\n", interrupts);
11367379Sgblack@eecs.umich.edu
11377380Sgblack@eecs.umich.edu    interrupts &= ISR_IMPL;
11387379Sgblack@eecs.umich.edu    regs.isr |= interrupts;
11397379Sgblack@eecs.umich.edu
11407379Sgblack@eecs.umich.edu    if (interrupts & regs.imr) {
11417379Sgblack@eecs.umich.edu        if (interrupts & ISR_SWI) {
11427379Sgblack@eecs.umich.edu            totalSwi++;
11437379Sgblack@eecs.umich.edu        }
11447379Sgblack@eecs.umich.edu        if (interrupts & ISR_RXIDLE) {
11457379Sgblack@eecs.umich.edu            totalRxIdle++;
11467379Sgblack@eecs.umich.edu        }
11477379Sgblack@eecs.umich.edu        if (interrupts & ISR_RXOK) {
11487379Sgblack@eecs.umich.edu            totalRxOk++;
11497379Sgblack@eecs.umich.edu        }
11507379Sgblack@eecs.umich.edu        if (interrupts & ISR_RXDESC) {
11517379Sgblack@eecs.umich.edu            totalRxDesc++;
11527379Sgblack@eecs.umich.edu        }
11537379Sgblack@eecs.umich.edu        if (interrupts & ISR_TXOK) {
11547379Sgblack@eecs.umich.edu            totalTxOk++;
11557379Sgblack@eecs.umich.edu        }
11567379Sgblack@eecs.umich.edu        if (interrupts & ISR_TXIDLE) {
11577379Sgblack@eecs.umich.edu            totalTxIdle++;
11587379Sgblack@eecs.umich.edu        }
11597379Sgblack@eecs.umich.edu        if (interrupts & ISR_TXDESC) {
11607379Sgblack@eecs.umich.edu            totalTxDesc++;
11617379Sgblack@eecs.umich.edu        }
11627379Sgblack@eecs.umich.edu        if (interrupts & ISR_RXORN) {
11637379Sgblack@eecs.umich.edu            totalRxOrn++;
11647379Sgblack@eecs.umich.edu        }
11657379Sgblack@eecs.umich.edu    }
11667379Sgblack@eecs.umich.edu
11677379Sgblack@eecs.umich.edu    DPRINTF(EthernetIntr,
11687379Sgblack@eecs.umich.edu            "interrupt written to ISR: intr=%#x isr=%#x imr=%#x\n",
11697379Sgblack@eecs.umich.edu            interrupts, regs.isr, regs.imr);
11707379Sgblack@eecs.umich.edu
11717379Sgblack@eecs.umich.edu    if ((regs.isr & regs.imr)) {
11727379Sgblack@eecs.umich.edu        Tick when = curTick;
11737379Sgblack@eecs.umich.edu        if ((regs.isr & regs.imr & ISR_NODELAY) == 0)
11747379Sgblack@eecs.umich.edu            when += intrDelay;
11757379Sgblack@eecs.umich.edu        cpuIntrPost(when);
11767379Sgblack@eecs.umich.edu    }
11777379Sgblack@eecs.umich.edu}
11787379Sgblack@eecs.umich.edu
11797379Sgblack@eecs.umich.edu/* writing this interrupt counting stats inside this means that this function
11807379Sgblack@eecs.umich.edu   is now limited to being used to clear all interrupts upon the kernel
11817379Sgblack@eecs.umich.edu   reading isr and servicing.  just telling you in case you were thinking
11827379Sgblack@eecs.umich.edu   of expanding use.
11837379Sgblack@eecs.umich.edu*/
11847379Sgblack@eecs.umich.eduvoid
11857379Sgblack@eecs.umich.eduNSGigE::devIntrClear(uint32_t interrupts)
11867379Sgblack@eecs.umich.edu{
11877379Sgblack@eecs.umich.edu    if (interrupts & ISR_RESERVE)
11887379Sgblack@eecs.umich.edu        panic("Cannot clear a reserved interrupt");
11897379Sgblack@eecs.umich.edu
11907379Sgblack@eecs.umich.edu    if (regs.isr & regs.imr & ISR_SWI) {
11917379Sgblack@eecs.umich.edu        postedSwi++;
11927379Sgblack@eecs.umich.edu    }
11937379Sgblack@eecs.umich.edu    if (regs.isr & regs.imr & ISR_RXIDLE) {
11947379Sgblack@eecs.umich.edu        postedRxIdle++;
11957379Sgblack@eecs.umich.edu    }
11967379Sgblack@eecs.umich.edu    if (regs.isr & regs.imr & ISR_RXOK) {
11977379Sgblack@eecs.umich.edu        postedRxOk++;
11987379Sgblack@eecs.umich.edu    }
11997379Sgblack@eecs.umich.edu    if (regs.isr & regs.imr & ISR_RXDESC) {
12007379Sgblack@eecs.umich.edu            postedRxDesc++;
12017379Sgblack@eecs.umich.edu    }
12027379Sgblack@eecs.umich.edu    if (regs.isr & regs.imr & ISR_TXOK) {
12037379Sgblack@eecs.umich.edu        postedTxOk++;
12047379Sgblack@eecs.umich.edu    }
12057379Sgblack@eecs.umich.edu    if (regs.isr & regs.imr & ISR_TXIDLE) {
12067379Sgblack@eecs.umich.edu        postedTxIdle++;
12077379Sgblack@eecs.umich.edu    }
12087379Sgblack@eecs.umich.edu    if (regs.isr & regs.imr & ISR_TXDESC) {
12097379Sgblack@eecs.umich.edu        postedTxDesc++;
12107379Sgblack@eecs.umich.edu    }
12117379Sgblack@eecs.umich.edu    if (regs.isr & regs.imr & ISR_RXORN) {
12127379Sgblack@eecs.umich.edu        postedRxOrn++;
12137379Sgblack@eecs.umich.edu    }
12147379Sgblack@eecs.umich.edu
12157379Sgblack@eecs.umich.edu    if (regs.isr & regs.imr & ISR_IMPL)
12167379Sgblack@eecs.umich.edu        postedInterrupts++;
12177379Sgblack@eecs.umich.edu
12187379Sgblack@eecs.umich.edu    interrupts &= ~ISR_NOIMPL;
12197379Sgblack@eecs.umich.edu    regs.isr &= ~interrupts;
12207379Sgblack@eecs.umich.edu
12217379Sgblack@eecs.umich.edu    DPRINTF(EthernetIntr,
12227379Sgblack@eecs.umich.edu            "interrupt cleared from ISR: intr=%x isr=%x imr=%x\n",
12237379Sgblack@eecs.umich.edu            interrupts, regs.isr, regs.imr);
12247379Sgblack@eecs.umich.edu
12257379Sgblack@eecs.umich.edu    if (!(regs.isr & regs.imr))
12267379Sgblack@eecs.umich.edu        cpuIntrClear();
12277379Sgblack@eecs.umich.edu}
12287379Sgblack@eecs.umich.edu
12297379Sgblack@eecs.umich.eduvoid
12307379Sgblack@eecs.umich.eduNSGigE::devIntrChangeMask()
12317379Sgblack@eecs.umich.edu{
12327379Sgblack@eecs.umich.edu    DPRINTF(EthernetIntr, "interrupt mask changed: isr=%x imr=%x masked=%x\n",
12337379Sgblack@eecs.umich.edu            regs.isr, regs.imr, regs.isr & regs.imr);
12347379Sgblack@eecs.umich.edu
12357379Sgblack@eecs.umich.edu    if (regs.isr & regs.imr)
12367379Sgblack@eecs.umich.edu        cpuIntrPost(curTick);
12377379Sgblack@eecs.umich.edu    else
12387379Sgblack@eecs.umich.edu        cpuIntrClear();
12397379Sgblack@eecs.umich.edu}
12407379Sgblack@eecs.umich.edu
12417379Sgblack@eecs.umich.eduvoid
12427379Sgblack@eecs.umich.eduNSGigE::cpuIntrPost(Tick when)
12437379Sgblack@eecs.umich.edu{
12447379Sgblack@eecs.umich.edu    // If the interrupt you want to post is later than an interrupt
12457379Sgblack@eecs.umich.edu    // already scheduled, just let it post in the coming one and don't
12467379Sgblack@eecs.umich.edu    // schedule another.
12477379Sgblack@eecs.umich.edu    // HOWEVER, must be sure that the scheduled intrTick is in the
12487379Sgblack@eecs.umich.edu    // future (this was formerly the source of a bug)
12497379Sgblack@eecs.umich.edu    /**
12507379Sgblack@eecs.umich.edu     * @todo this warning should be removed and the intrTick code should
12517379Sgblack@eecs.umich.edu     * be fixed.
12527379Sgblack@eecs.umich.edu     */
12537379Sgblack@eecs.umich.edu    assert(when >= curTick);
12547379Sgblack@eecs.umich.edu    assert(intrTick >= curTick || intrTick == 0);
12557379Sgblack@eecs.umich.edu    if (when > intrTick && intrTick != 0) {
12567379Sgblack@eecs.umich.edu        DPRINTF(EthernetIntr, "don't need to schedule event...intrTick=%d\n",
12577379Sgblack@eecs.umich.edu                intrTick);
12587379Sgblack@eecs.umich.edu        return;
12597379Sgblack@eecs.umich.edu    }
12607379Sgblack@eecs.umich.edu
12617379Sgblack@eecs.umich.edu    intrTick = when;
12627379Sgblack@eecs.umich.edu    if (intrTick < curTick) {
12637379Sgblack@eecs.umich.edu        debug_break();
12647379Sgblack@eecs.umich.edu        intrTick = curTick;
12657379Sgblack@eecs.umich.edu    }
12667379Sgblack@eecs.umich.edu
12677379Sgblack@eecs.umich.edu    DPRINTF(EthernetIntr, "going to schedule an interrupt for intrTick=%d\n",
12687379Sgblack@eecs.umich.edu            intrTick);
12697379Sgblack@eecs.umich.edu
12707379Sgblack@eecs.umich.edu    if (intrEvent)
12717379Sgblack@eecs.umich.edu        intrEvent->squash();
12727379Sgblack@eecs.umich.edu    intrEvent = new IntrEvent(this, true);
12737379Sgblack@eecs.umich.edu    intrEvent->schedule(intrTick);
12747379Sgblack@eecs.umich.edu}
12757379Sgblack@eecs.umich.edu
12767379Sgblack@eecs.umich.eduvoid
12777379Sgblack@eecs.umich.eduNSGigE::cpuInterrupt()
12787379Sgblack@eecs.umich.edu{
12797379Sgblack@eecs.umich.edu    assert(intrTick == curTick);
12807379Sgblack@eecs.umich.edu
12817379Sgblack@eecs.umich.edu    // Whether or not there's a pending interrupt, we don't care about
12827379Sgblack@eecs.umich.edu    // it anymore
12837379Sgblack@eecs.umich.edu    intrEvent = 0;
12847379Sgblack@eecs.umich.edu    intrTick = 0;
12857379Sgblack@eecs.umich.edu
12867379Sgblack@eecs.umich.edu    // Don't send an interrupt if there's already one
12877379Sgblack@eecs.umich.edu    if (cpuPendingIntr) {
12887379Sgblack@eecs.umich.edu        DPRINTF(EthernetIntr,
12897379Sgblack@eecs.umich.edu                "would send an interrupt now, but there's already pending\n");
12907379Sgblack@eecs.umich.edu    } else {
12917379Sgblack@eecs.umich.edu        // Send interrupt
12927379Sgblack@eecs.umich.edu        cpuPendingIntr = true;
12937379Sgblack@eecs.umich.edu
12947379Sgblack@eecs.umich.edu        DPRINTF(EthernetIntr, "posting interrupt\n");
12957379Sgblack@eecs.umich.edu        intrPost();
12967379Sgblack@eecs.umich.edu    }
1297}
1298
1299void
1300NSGigE::cpuIntrClear()
1301{
1302    if (!cpuPendingIntr)
1303        return;
1304
1305    if (intrEvent) {
1306        intrEvent->squash();
1307        intrEvent = 0;
1308    }
1309
1310    intrTick = 0;
1311
1312    cpuPendingIntr = false;
1313
1314    DPRINTF(EthernetIntr, "clearing interrupt\n");
1315    intrClear();
1316}
1317
1318bool
1319NSGigE::cpuIntrPending() const
1320{ return cpuPendingIntr; }
1321
1322void
1323NSGigE::txReset()
1324{
1325
1326    DPRINTF(Ethernet, "transmit reset\n");
1327
1328    CTDD = false;
1329    txEnable = false;;
1330    txFragPtr = 0;
1331    assert(txDescCnt == 0);
1332    txFifo.clear();
1333    txState = txIdle;
1334    assert(txDmaState == dmaIdle);
1335}
1336
1337void
1338NSGigE::rxReset()
1339{
1340    DPRINTF(Ethernet, "receive reset\n");
1341
1342    CRDD = false;
1343    assert(rxPktBytes == 0);
1344    rxEnable = false;
1345    rxFragPtr = 0;
1346    assert(rxDescCnt == 0);
1347    assert(rxDmaState == dmaIdle);
1348    rxFifo.clear();
1349    rxState = rxIdle;
1350}
1351
1352void
1353NSGigE::regsReset()
1354{
1355    memset(&regs, 0, sizeof(regs));
1356    regs.config = (CFGR_LNKSTS | CFGR_TBI_EN | CFGR_MODE_1000);
1357    regs.mear = 0x12;
1358    regs.txcfg = 0x120; // set drain threshold to 1024 bytes and
1359                        // fill threshold to 32 bytes
1360    regs.rxcfg = 0x4;   // set drain threshold to 16 bytes
1361    regs.srr = 0x0103;  // set the silicon revision to rev B or 0x103
1362    regs.mibc = MIBC_FRZ;
1363    regs.vdr = 0x81;    // set the vlan tag type to 802.1q
1364    regs.tesr = 0xc000; // TBI capable of both full and half duplex
1365    regs.brar = 0xffffffff;
1366
1367    extstsEnable = false;
1368    acceptBroadcast = false;
1369    acceptMulticast = false;
1370    acceptUnicast = false;
1371    acceptPerfect = false;
1372    acceptArp = false;
1373}
1374
1375bool
1376NSGigE::doRxDmaRead()
1377{
1378    assert(rxDmaState == dmaIdle || rxDmaState == dmaReadWaiting);
1379    rxDmaState = dmaReading;
1380
1381    if (dmaPending() || getState() != Running)
1382        rxDmaState = dmaReadWaiting;
1383    else
1384        dmaRead(rxDmaAddr, rxDmaLen, &rxDmaReadEvent, (uint8_t*)rxDmaData);
1385
1386    return true;
1387}
1388
1389void
1390NSGigE::rxDmaReadDone()
1391{
1392    assert(rxDmaState == dmaReading);
1393    rxDmaState = dmaIdle;
1394
1395    DPRINTF(EthernetDMA, "rx dma read  paddr=%#x len=%d\n",
1396            rxDmaAddr, rxDmaLen);
1397    DDUMP(EthernetDMA, rxDmaData, rxDmaLen);
1398
1399    // If the transmit state machine has a pending DMA, let it go first
1400    if (txDmaState == dmaReadWaiting || txDmaState == dmaWriteWaiting)
1401        txKick();
1402
1403    rxKick();
1404}
1405
1406bool
1407NSGigE::doRxDmaWrite()
1408{
1409    assert(rxDmaState == dmaIdle || rxDmaState == dmaWriteWaiting);
1410    rxDmaState = dmaWriting;
1411
1412    if (dmaPending() || getState() != Running)
1413        rxDmaState = dmaWriteWaiting;
1414    else
1415        dmaWrite(rxDmaAddr, rxDmaLen, &rxDmaWriteEvent, (uint8_t*)rxDmaData);
1416    return true;
1417}
1418
1419void
1420NSGigE::rxDmaWriteDone()
1421{
1422    assert(rxDmaState == dmaWriting);
1423    rxDmaState = dmaIdle;
1424
1425    DPRINTF(EthernetDMA, "rx dma write paddr=%#x len=%d\n",
1426            rxDmaAddr, rxDmaLen);
1427    DDUMP(EthernetDMA, rxDmaData, rxDmaLen);
1428
1429    // If the transmit state machine has a pending DMA, let it go first
1430    if (txDmaState == dmaReadWaiting || txDmaState == dmaWriteWaiting)
1431        txKick();
1432
1433    rxKick();
1434}
1435
1436void
1437NSGigE::rxKick()
1438{
1439    bool is64bit = (bool)(regs.config & CFGR_M64ADDR);
1440
1441    DPRINTF(EthernetSM,
1442            "receive kick rxState=%s (rxBuf.size=%d) %d-bit\n",
1443            NsRxStateStrings[rxState], rxFifo.size(), is64bit ? 64 : 32);
1444
1445    Addr link, bufptr;
1446    uint32_t &cmdsts = is64bit ? rxDesc64.cmdsts : rxDesc32.cmdsts;
1447    uint32_t &extsts = is64bit ? rxDesc64.extsts : rxDesc32.extsts;
1448
1449  next:
1450    if (clock) {
1451        if (rxKickTick > curTick) {
1452            DPRINTF(EthernetSM, "receive kick exiting, can't run till %d\n",
1453                    rxKickTick);
1454
1455            goto exit;
1456        }
1457
1458        // Go to the next state machine clock tick.
1459        rxKickTick = curTick + cycles(1);
1460    }
1461
1462    switch(rxDmaState) {
1463      case dmaReadWaiting:
1464        if (doRxDmaRead())
1465            goto exit;
1466        break;
1467      case dmaWriteWaiting:
1468        if (doRxDmaWrite())
1469            goto exit;
1470        break;
1471      default:
1472        break;
1473    }
1474
1475    link = is64bit ? (Addr)rxDesc64.link : (Addr)rxDesc32.link;
1476    bufptr = is64bit ? (Addr)rxDesc64.bufptr : (Addr)rxDesc32.bufptr;
1477
1478    // see state machine from spec for details
1479    // the way this works is, if you finish work on one state and can
1480    // go directly to another, you do that through jumping to the
1481    // label "next".  however, if you have intermediate work, like DMA
1482    // so that you can't go to the next state yet, you go to exit and
1483    // exit the loop.  however, when the DMA is done it will trigger
1484    // an event and come back to this loop.
1485    switch (rxState) {
1486      case rxIdle:
1487        if (!rxEnable) {
1488            DPRINTF(EthernetSM, "Receive Disabled! Nothing to do.\n");
1489            goto exit;
1490        }
1491
1492        if (CRDD) {
1493            rxState = rxDescRefr;
1494
1495            rxDmaAddr = regs.rxdp & 0x3fffffff;
1496            rxDmaData =
1497                is64bit ? (void *)&rxDesc64.link : (void *)&rxDesc32.link;
1498            rxDmaLen = is64bit ? sizeof(rxDesc64.link) : sizeof(rxDesc32.link);
1499            rxDmaFree = dmaDescFree;
1500
1501            descDmaReads++;
1502            descDmaRdBytes += rxDmaLen;
1503
1504            if (doRxDmaRead())
1505                goto exit;
1506        } else {
1507            rxState = rxDescRead;
1508
1509            rxDmaAddr = regs.rxdp & 0x3fffffff;
1510            rxDmaData = is64bit ? (void *)&rxDesc64 : (void *)&rxDesc32;
1511            rxDmaLen = is64bit ? sizeof(rxDesc64) : sizeof(rxDesc32);
1512            rxDmaFree = dmaDescFree;
1513
1514            descDmaReads++;
1515            descDmaRdBytes += rxDmaLen;
1516
1517            if (doRxDmaRead())
1518                goto exit;
1519        }
1520        break;
1521
1522      case rxDescRefr:
1523        if (rxDmaState != dmaIdle)
1524            goto exit;
1525
1526        rxState = rxAdvance;
1527        break;
1528
1529     case rxDescRead:
1530        if (rxDmaState != dmaIdle)
1531            goto exit;
1532
1533        DPRINTF(EthernetDesc, "rxDesc: addr=%08x read descriptor\n",
1534                regs.rxdp & 0x3fffffff);
1535        DPRINTF(EthernetDesc,
1536                "rxDesc: link=%#x bufptr=%#x cmdsts=%08x extsts=%08x\n",
1537                link, bufptr, cmdsts, extsts);
1538
1539        if (cmdsts & CMDSTS_OWN) {
1540            devIntrPost(ISR_RXIDLE);
1541            rxState = rxIdle;
1542            goto exit;
1543        } else {
1544            rxState = rxFifoBlock;
1545            rxFragPtr = bufptr;
1546            rxDescCnt = cmdsts & CMDSTS_LEN_MASK;
1547        }
1548        break;
1549
1550      case rxFifoBlock:
1551        if (!rxPacket) {
1552            /**
1553             * @todo in reality, we should be able to start processing
1554             * the packet as it arrives, and not have to wait for the
1555             * full packet ot be in the receive fifo.
1556             */
1557            if (rxFifo.empty())
1558                goto exit;
1559
1560            DPRINTF(EthernetSM, "****processing receive of new packet****\n");
1561
1562            // If we don't have a packet, grab a new one from the fifo.
1563            rxPacket = rxFifo.front();
1564            rxPktBytes = rxPacket->length;
1565            rxPacketBufPtr = rxPacket->data;
1566
1567#if TRACING_ON
1568            if (DTRACE(Ethernet)) {
1569                IpPtr ip(rxPacket);
1570                if (ip) {
1571                    DPRINTF(Ethernet, "ID is %d\n", ip->id());
1572                    TcpPtr tcp(ip);
1573                    if (tcp) {
1574                        DPRINTF(Ethernet,
1575                                "Src Port=%d, Dest Port=%d, Seq=%d, Ack=%d\n",
1576                                tcp->sport(), tcp->dport(), tcp->seq(),
1577                                tcp->ack());
1578                    }
1579                }
1580            }
1581#endif
1582
1583            // sanity check - i think the driver behaves like this
1584            assert(rxDescCnt >= rxPktBytes);
1585            rxFifo.pop();
1586        }
1587
1588
1589        // dont' need the && rxDescCnt > 0 if driver sanity check
1590        // above holds
1591        if (rxPktBytes > 0) {
1592            rxState = rxFragWrite;
1593            // don't need min<>(rxPktBytes,rxDescCnt) if above sanity
1594            // check holds
1595            rxXferLen = rxPktBytes;
1596
1597            rxDmaAddr = rxFragPtr & 0x3fffffff;
1598            rxDmaData = rxPacketBufPtr;
1599            rxDmaLen = rxXferLen;
1600            rxDmaFree = dmaDataFree;
1601
1602            if (doRxDmaWrite())
1603                goto exit;
1604
1605        } else {
1606            rxState = rxDescWrite;
1607
1608            //if (rxPktBytes == 0) {  /* packet is done */
1609            assert(rxPktBytes == 0);
1610            DPRINTF(EthernetSM, "done with receiving packet\n");
1611
1612            cmdsts |= CMDSTS_OWN;
1613            cmdsts &= ~CMDSTS_MORE;
1614            cmdsts |= CMDSTS_OK;
1615            cmdsts &= 0xffff0000;
1616            cmdsts += rxPacket->length;   //i.e. set CMDSTS_SIZE
1617
1618#if 0
1619            /*
1620             * all the driver uses these are for its own stats keeping
1621             * which we don't care about, aren't necessary for
1622             * functionality and doing this would just slow us down.
1623             * if they end up using this in a later version for
1624             * functional purposes, just undef
1625             */
1626            if (rxFilterEnable) {
1627                cmdsts &= ~CMDSTS_DEST_MASK;
1628                const EthAddr &dst = rxFifoFront()->dst();
1629                if (dst->unicast())
1630                    cmdsts |= CMDSTS_DEST_SELF;
1631                if (dst->multicast())
1632                    cmdsts |= CMDSTS_DEST_MULTI;
1633                if (dst->broadcast())
1634                    cmdsts |= CMDSTS_DEST_MASK;
1635            }
1636#endif
1637
1638            IpPtr ip(rxPacket);
1639            if (extstsEnable && ip) {
1640                extsts |= EXTSTS_IPPKT;
1641                rxIpChecksums++;
1642                if (cksum(ip) != 0) {
1643                    DPRINTF(EthernetCksum, "Rx IP Checksum Error\n");
1644                    extsts |= EXTSTS_IPERR;
1645                }
1646                TcpPtr tcp(ip);
1647                UdpPtr udp(ip);
1648                if (tcp) {
1649                    extsts |= EXTSTS_TCPPKT;
1650                    rxTcpChecksums++;
1651                    if (cksum(tcp) != 0) {
1652                        DPRINTF(EthernetCksum, "Rx TCP Checksum Error\n");
1653                        extsts |= EXTSTS_TCPERR;
1654
1655                    }
1656                } else if (udp) {
1657                    extsts |= EXTSTS_UDPPKT;
1658                    rxUdpChecksums++;
1659                    if (cksum(udp) != 0) {
1660                        DPRINTF(EthernetCksum, "Rx UDP Checksum Error\n");
1661                        extsts |= EXTSTS_UDPERR;
1662                    }
1663                }
1664            }
1665            rxPacket = 0;
1666
1667            /*
1668             * the driver seems to always receive into desc buffers
1669             * of size 1514, so you never have a pkt that is split
1670             * into multiple descriptors on the receive side, so
1671             * i don't implement that case, hence the assert above.
1672             */
1673
1674            DPRINTF(EthernetDesc,
1675                    "rxDesc: addr=%08x writeback cmdsts extsts\n",
1676                    regs.rxdp & 0x3fffffff);
1677            DPRINTF(EthernetDesc,
1678                    "rxDesc: link=%#x bufptr=%#x cmdsts=%08x extsts=%08x\n",
1679                    link, bufptr, cmdsts, extsts);
1680
1681            rxDmaAddr = regs.rxdp & 0x3fffffff;
1682            rxDmaData = &cmdsts;
1683            if (is64bit) {
1684                rxDmaAddr += offsetof(ns_desc64, cmdsts);
1685                rxDmaLen = sizeof(rxDesc64.cmdsts) + sizeof(rxDesc64.extsts);
1686            } else {
1687                rxDmaAddr += offsetof(ns_desc32, cmdsts);
1688                rxDmaLen = sizeof(rxDesc32.cmdsts) + sizeof(rxDesc32.extsts);
1689            }
1690            rxDmaFree = dmaDescFree;
1691
1692            descDmaWrites++;
1693            descDmaWrBytes += rxDmaLen;
1694
1695            if (doRxDmaWrite())
1696                goto exit;
1697        }
1698        break;
1699
1700      case rxFragWrite:
1701        if (rxDmaState != dmaIdle)
1702            goto exit;
1703
1704        rxPacketBufPtr += rxXferLen;
1705        rxFragPtr += rxXferLen;
1706        rxPktBytes -= rxXferLen;
1707
1708        rxState = rxFifoBlock;
1709        break;
1710
1711      case rxDescWrite:
1712        if (rxDmaState != dmaIdle)
1713            goto exit;
1714
1715        assert(cmdsts & CMDSTS_OWN);
1716
1717        assert(rxPacket == 0);
1718        devIntrPost(ISR_RXOK);
1719
1720        if (cmdsts & CMDSTS_INTR)
1721            devIntrPost(ISR_RXDESC);
1722
1723        if (!rxEnable) {
1724            DPRINTF(EthernetSM, "Halting the RX state machine\n");
1725            rxState = rxIdle;
1726            goto exit;
1727        } else
1728            rxState = rxAdvance;
1729        break;
1730
1731      case rxAdvance:
1732        if (link == 0) {
1733            devIntrPost(ISR_RXIDLE);
1734            rxState = rxIdle;
1735            CRDD = true;
1736            goto exit;
1737        } else {
1738            if (rxDmaState != dmaIdle)
1739                goto exit;
1740            rxState = rxDescRead;
1741            regs.rxdp = link;
1742            CRDD = false;
1743
1744            rxDmaAddr = regs.rxdp & 0x3fffffff;
1745            rxDmaData = is64bit ? (void *)&rxDesc64 : (void *)&rxDesc32;
1746            rxDmaLen = is64bit ? sizeof(rxDesc64) : sizeof(rxDesc32);
1747            rxDmaFree = dmaDescFree;
1748
1749            if (doRxDmaRead())
1750                goto exit;
1751        }
1752        break;
1753
1754      default:
1755        panic("Invalid rxState!");
1756    }
1757
1758    DPRINTF(EthernetSM, "entering next rxState=%s\n",
1759            NsRxStateStrings[rxState]);
1760    goto next;
1761
1762  exit:
1763    /**
1764     * @todo do we want to schedule a future kick?
1765     */
1766    DPRINTF(EthernetSM, "rx state machine exited rxState=%s\n",
1767            NsRxStateStrings[rxState]);
1768
1769    if (clock && !rxKickEvent.scheduled())
1770        rxKickEvent.schedule(rxKickTick);
1771}
1772
1773void
1774NSGigE::transmit()
1775{
1776    if (txFifo.empty()) {
1777        DPRINTF(Ethernet, "nothing to transmit\n");
1778        return;
1779    }
1780
1781    DPRINTF(Ethernet, "Attempt Pkt Transmit: txFifo length=%d\n",
1782            txFifo.size());
1783    if (interface->sendPacket(txFifo.front())) {
1784#if TRACING_ON
1785        if (DTRACE(Ethernet)) {
1786            IpPtr ip(txFifo.front());
1787            if (ip) {
1788                DPRINTF(Ethernet, "ID is %d\n", ip->id());
1789                TcpPtr tcp(ip);
1790                if (tcp) {
1791                    DPRINTF(Ethernet,
1792                            "Src Port=%d, Dest Port=%d, Seq=%d, Ack=%d\n",
1793                            tcp->sport(), tcp->dport(), tcp->seq(),
1794                            tcp->ack());
1795                }
1796            }
1797        }
1798#endif
1799
1800        DDUMP(EthernetData, txFifo.front()->data, txFifo.front()->length);
1801        txBytes += txFifo.front()->length;
1802        txPackets++;
1803
1804        DPRINTF(Ethernet, "Successful Xmit! now txFifoAvail is %d\n",
1805                txFifo.avail());
1806        txFifo.pop();
1807
1808        /*
1809         * normally do a writeback of the descriptor here, and ONLY
1810         * after that is done, send this interrupt.  but since our
1811         * stuff never actually fails, just do this interrupt here,
1812         * otherwise the code has to stray from this nice format.
1813         * besides, it's functionally the same.
1814         */
1815        devIntrPost(ISR_TXOK);
1816    }
1817
1818   if (!txFifo.empty() && !txEvent.scheduled()) {
1819       DPRINTF(Ethernet, "reschedule transmit\n");
1820       txEvent.schedule(curTick + retryTime);
1821   }
1822}
1823
1824bool
1825NSGigE::doTxDmaRead()
1826{
1827    assert(txDmaState == dmaIdle || txDmaState == dmaReadWaiting);
1828    txDmaState = dmaReading;
1829
1830    if (dmaPending() || getState() != Running)
1831        txDmaState = dmaReadWaiting;
1832    else
1833        dmaRead(txDmaAddr, txDmaLen, &txDmaReadEvent, (uint8_t*)txDmaData);
1834
1835    return true;
1836}
1837
1838void
1839NSGigE::txDmaReadDone()
1840{
1841    assert(txDmaState == dmaReading);
1842    txDmaState = dmaIdle;
1843
1844    DPRINTF(EthernetDMA, "tx dma read  paddr=%#x len=%d\n",
1845            txDmaAddr, txDmaLen);
1846    DDUMP(EthernetDMA, txDmaData, txDmaLen);
1847
1848    // If the receive state machine  has a pending DMA, let it go first
1849    if (rxDmaState == dmaReadWaiting || rxDmaState == dmaWriteWaiting)
1850        rxKick();
1851
1852    txKick();
1853}
1854
1855bool
1856NSGigE::doTxDmaWrite()
1857{
1858    assert(txDmaState == dmaIdle || txDmaState == dmaWriteWaiting);
1859    txDmaState = dmaWriting;
1860
1861    if (dmaPending() || getState() != Running)
1862        txDmaState = dmaWriteWaiting;
1863    else
1864        dmaWrite(txDmaAddr, txDmaLen, &txDmaWriteEvent, (uint8_t*)txDmaData);
1865    return true;
1866}
1867
1868void
1869NSGigE::txDmaWriteDone()
1870{
1871    assert(txDmaState == dmaWriting);
1872    txDmaState = dmaIdle;
1873
1874    DPRINTF(EthernetDMA, "tx dma write paddr=%#x len=%d\n",
1875            txDmaAddr, txDmaLen);
1876    DDUMP(EthernetDMA, txDmaData, txDmaLen);
1877
1878    // If the receive state machine  has a pending DMA, let it go first
1879    if (rxDmaState == dmaReadWaiting || rxDmaState == dmaWriteWaiting)
1880        rxKick();
1881
1882    txKick();
1883}
1884
1885void
1886NSGigE::txKick()
1887{
1888    bool is64bit = (bool)(regs.config & CFGR_M64ADDR);
1889
1890    DPRINTF(EthernetSM, "transmit kick txState=%s %d-bit\n",
1891            NsTxStateStrings[txState], is64bit ? 64 : 32);
1892
1893    Addr link, bufptr;
1894    uint32_t &cmdsts = is64bit ? txDesc64.cmdsts : txDesc32.cmdsts;
1895    uint32_t &extsts = is64bit ? txDesc64.extsts : txDesc32.extsts;
1896
1897  next:
1898    if (clock) {
1899        if (txKickTick > curTick) {
1900            DPRINTF(EthernetSM, "transmit kick exiting, can't run till %d\n",
1901                    txKickTick);
1902            goto exit;
1903        }
1904
1905        // Go to the next state machine clock tick.
1906        txKickTick = curTick + cycles(1);
1907    }
1908
1909    switch(txDmaState) {
1910      case dmaReadWaiting:
1911        if (doTxDmaRead())
1912            goto exit;
1913        break;
1914      case dmaWriteWaiting:
1915        if (doTxDmaWrite())
1916            goto exit;
1917        break;
1918      default:
1919        break;
1920    }
1921
1922    link = is64bit ? (Addr)txDesc64.link : (Addr)txDesc32.link;
1923    bufptr = is64bit ? (Addr)txDesc64.bufptr : (Addr)txDesc32.bufptr;
1924    switch (txState) {
1925      case txIdle:
1926        if (!txEnable) {
1927            DPRINTF(EthernetSM, "Transmit disabled.  Nothing to do.\n");
1928            goto exit;
1929        }
1930
1931        if (CTDD) {
1932            txState = txDescRefr;
1933
1934            txDmaAddr = regs.txdp & 0x3fffffff;
1935            txDmaData =
1936                is64bit ? (void *)&txDesc64.link : (void *)&txDesc32.link;
1937            txDmaLen = is64bit ? sizeof(txDesc64.link) : sizeof(txDesc32.link);
1938            txDmaFree = dmaDescFree;
1939
1940            descDmaReads++;
1941            descDmaRdBytes += txDmaLen;
1942
1943            if (doTxDmaRead())
1944                goto exit;
1945
1946        } else {
1947            txState = txDescRead;
1948
1949            txDmaAddr = regs.txdp & 0x3fffffff;
1950            txDmaData = is64bit ? (void *)&txDesc64 : (void *)&txDesc32;
1951            txDmaLen = is64bit ? sizeof(txDesc64) : sizeof(txDesc32);
1952            txDmaFree = dmaDescFree;
1953
1954            descDmaReads++;
1955            descDmaRdBytes += txDmaLen;
1956
1957            if (doTxDmaRead())
1958                goto exit;
1959        }
1960        break;
1961
1962      case txDescRefr:
1963        if (txDmaState != dmaIdle)
1964            goto exit;
1965
1966        txState = txAdvance;
1967        break;
1968
1969      case txDescRead:
1970        if (txDmaState != dmaIdle)
1971            goto exit;
1972
1973        DPRINTF(EthernetDesc, "txDesc: addr=%08x read descriptor\n",
1974                regs.txdp & 0x3fffffff);
1975        DPRINTF(EthernetDesc,
1976                "txDesc: link=%#x bufptr=%#x cmdsts=%#08x extsts=%#08x\n",
1977                link, bufptr, cmdsts, extsts);
1978
1979        if (cmdsts & CMDSTS_OWN) {
1980            txState = txFifoBlock;
1981            txFragPtr = bufptr;
1982            txDescCnt = cmdsts & CMDSTS_LEN_MASK;
1983        } else {
1984            devIntrPost(ISR_TXIDLE);
1985            txState = txIdle;
1986            goto exit;
1987        }
1988        break;
1989
1990      case txFifoBlock:
1991        if (!txPacket) {
1992            DPRINTF(EthernetSM, "****starting the tx of a new packet****\n");
1993            txPacket = new EthPacketData(16384);
1994            txPacketBufPtr = txPacket->data;
1995        }
1996
1997        if (txDescCnt == 0) {
1998            DPRINTF(EthernetSM, "the txDescCnt == 0, done with descriptor\n");
1999            if (cmdsts & CMDSTS_MORE) {
2000                DPRINTF(EthernetSM, "there are more descriptors to come\n");
2001                txState = txDescWrite;
2002
2003                cmdsts &= ~CMDSTS_OWN;
2004
2005                txDmaAddr = regs.txdp & 0x3fffffff;
2006                txDmaData = &cmdsts;
2007                if (is64bit) {
2008                    txDmaAddr += offsetof(ns_desc64, cmdsts);
2009                    txDmaLen = sizeof(txDesc64.cmdsts);
2010                } else {
2011                    txDmaAddr += offsetof(ns_desc32, cmdsts);
2012                    txDmaLen = sizeof(txDesc32.cmdsts);
2013                }
2014                txDmaFree = dmaDescFree;
2015
2016                if (doTxDmaWrite())
2017                    goto exit;
2018
2019            } else { /* this packet is totally done */
2020                DPRINTF(EthernetSM, "This packet is done, let's wrap it up\n");
2021                /* deal with the the packet that just finished */
2022                if ((regs.vtcr & VTCR_PPCHK) && extstsEnable) {
2023                    IpPtr ip(txPacket);
2024                    if (extsts & EXTSTS_UDPPKT) {
2025                        UdpPtr udp(ip);
2026                        udp->sum(0);
2027                        udp->sum(cksum(udp));
2028                        txUdpChecksums++;
2029                    } else if (extsts & EXTSTS_TCPPKT) {
2030                        TcpPtr tcp(ip);
2031                        tcp->sum(0);
2032                        tcp->sum(cksum(tcp));
2033                        txTcpChecksums++;
2034                    }
2035                    if (extsts & EXTSTS_IPPKT) {
2036                        ip->sum(0);
2037                        ip->sum(cksum(ip));
2038                        txIpChecksums++;
2039                    }
2040                }
2041
2042                txPacket->length = txPacketBufPtr - txPacket->data;
2043                // this is just because the receive can't handle a
2044                // packet bigger want to make sure
2045                if (txPacket->length > 1514)
2046                    panic("transmit packet too large, %s > 1514\n",
2047                          txPacket->length);
2048
2049#ifndef NDEBUG
2050                bool success =
2051#endif
2052                    txFifo.push(txPacket);
2053                assert(success);
2054
2055                /*
2056                 * this following section is not tqo spec, but
2057                 * functionally shouldn't be any different.  normally,
2058                 * the chip will wait til the transmit has occurred
2059                 * before writing back the descriptor because it has
2060                 * to wait to see that it was successfully transmitted
2061                 * to decide whether to set CMDSTS_OK or not.
2062                 * however, in the simulator since it is always
2063                 * successfully transmitted, and writing it exactly to
2064                 * spec would complicate the code, we just do it here
2065                 */
2066
2067                cmdsts &= ~CMDSTS_OWN;
2068                cmdsts |= CMDSTS_OK;
2069
2070                DPRINTF(EthernetDesc,
2071                        "txDesc writeback: cmdsts=%08x extsts=%08x\n",
2072                        cmdsts, extsts);
2073
2074                txDmaFree = dmaDescFree;
2075                txDmaAddr = regs.txdp & 0x3fffffff;
2076                txDmaData = &cmdsts;
2077                if (is64bit) {
2078                    txDmaAddr += offsetof(ns_desc64, cmdsts);
2079                    txDmaLen =
2080                        sizeof(txDesc64.cmdsts) + sizeof(txDesc64.extsts);
2081                } else {
2082                    txDmaAddr += offsetof(ns_desc32, cmdsts);
2083                    txDmaLen =
2084                        sizeof(txDesc32.cmdsts) + sizeof(txDesc32.extsts);
2085                }
2086
2087                descDmaWrites++;
2088                descDmaWrBytes += txDmaLen;
2089
2090                transmit();
2091                txPacket = 0;
2092
2093                if (!txEnable) {
2094                    DPRINTF(EthernetSM, "halting TX state machine\n");
2095                    txState = txIdle;
2096                    goto exit;
2097                } else
2098                    txState = txAdvance;
2099
2100                if (doTxDmaWrite())
2101                    goto exit;
2102            }
2103        } else {
2104            DPRINTF(EthernetSM, "this descriptor isn't done yet\n");
2105            if (!txFifo.full()) {
2106                txState = txFragRead;
2107
2108                /*
2109                 * The number of bytes transferred is either whatever
2110                 * is left in the descriptor (txDescCnt), or if there
2111                 * is not enough room in the fifo, just whatever room
2112                 * is left in the fifo
2113                 */
2114                txXferLen = min<uint32_t>(txDescCnt, txFifo.avail());
2115
2116                txDmaAddr = txFragPtr & 0x3fffffff;
2117                txDmaData = txPacketBufPtr;
2118                txDmaLen = txXferLen;
2119                txDmaFree = dmaDataFree;
2120
2121                if (doTxDmaRead())
2122                    goto exit;
2123            } else {
2124                txState = txFifoBlock;
2125                transmit();
2126
2127                goto exit;
2128            }
2129
2130        }
2131        break;
2132
2133      case txFragRead:
2134        if (txDmaState != dmaIdle)
2135            goto exit;
2136
2137        txPacketBufPtr += txXferLen;
2138        txFragPtr += txXferLen;
2139        txDescCnt -= txXferLen;
2140        txFifo.reserve(txXferLen);
2141
2142        txState = txFifoBlock;
2143        break;
2144
2145      case txDescWrite:
2146        if (txDmaState != dmaIdle)
2147            goto exit;
2148
2149        if (cmdsts & CMDSTS_INTR)
2150            devIntrPost(ISR_TXDESC);
2151
2152        if (!txEnable) {
2153            DPRINTF(EthernetSM, "halting TX state machine\n");
2154            txState = txIdle;
2155            goto exit;
2156        } else
2157            txState = txAdvance;
2158        break;
2159
2160      case txAdvance:
2161        if (link == 0) {
2162            devIntrPost(ISR_TXIDLE);
2163            txState = txIdle;
2164            goto exit;
2165        } else {
2166            if (txDmaState != dmaIdle)
2167                goto exit;
2168            txState = txDescRead;
2169            regs.txdp = link;
2170            CTDD = false;
2171
2172            txDmaAddr = link & 0x3fffffff;
2173            txDmaData = is64bit ? (void *)&txDesc64 : (void *)&txDesc32;
2174            txDmaLen = is64bit ? sizeof(txDesc64) : sizeof(txDesc32);
2175            txDmaFree = dmaDescFree;
2176
2177            if (doTxDmaRead())
2178                goto exit;
2179        }
2180        break;
2181
2182      default:
2183        panic("invalid state");
2184    }
2185
2186    DPRINTF(EthernetSM, "entering next txState=%s\n",
2187            NsTxStateStrings[txState]);
2188    goto next;
2189
2190  exit:
2191    /**
2192     * @todo do we want to schedule a future kick?
2193     */
2194    DPRINTF(EthernetSM, "tx state machine exited txState=%s\n",
2195            NsTxStateStrings[txState]);
2196
2197    if (clock && !txKickEvent.scheduled())
2198        txKickEvent.schedule(txKickTick);
2199}
2200
2201/**
2202 * Advance the EEPROM state machine
2203 * Called on rising edge of EEPROM clock bit in MEAR
2204 */
2205void
2206NSGigE::eepromKick()
2207{
2208    switch (eepromState) {
2209
2210      case eepromStart:
2211
2212        // Wait for start bit
2213        if (regs.mear & MEAR_EEDI) {
2214            // Set up to get 2 opcode bits
2215            eepromState = eepromGetOpcode;
2216            eepromBitsToRx = 2;
2217            eepromOpcode = 0;
2218        }
2219        break;
2220
2221      case eepromGetOpcode:
2222        eepromOpcode <<= 1;
2223        eepromOpcode += (regs.mear & MEAR_EEDI) ? 1 : 0;
2224        --eepromBitsToRx;
2225
2226        // Done getting opcode
2227        if (eepromBitsToRx == 0) {
2228            if (eepromOpcode != EEPROM_READ)
2229                panic("only EEPROM reads are implemented!");
2230
2231            // Set up to get address
2232            eepromState = eepromGetAddress;
2233            eepromBitsToRx = 6;
2234            eepromAddress = 0;
2235        }
2236        break;
2237
2238      case eepromGetAddress:
2239        eepromAddress <<= 1;
2240        eepromAddress += (regs.mear & MEAR_EEDI) ? 1 : 0;
2241        --eepromBitsToRx;
2242
2243        // Done getting address
2244        if (eepromBitsToRx == 0) {
2245
2246            if (eepromAddress >= EEPROM_SIZE)
2247                panic("EEPROM read access out of range!");
2248
2249            switch (eepromAddress) {
2250
2251              case EEPROM_PMATCH2_ADDR:
2252                eepromData = rom.perfectMatch[5];
2253                eepromData <<= 8;
2254                eepromData += rom.perfectMatch[4];
2255                break;
2256
2257              case EEPROM_PMATCH1_ADDR:
2258                eepromData = rom.perfectMatch[3];
2259                eepromData <<= 8;
2260                eepromData += rom.perfectMatch[2];
2261                break;
2262
2263              case EEPROM_PMATCH0_ADDR:
2264                eepromData = rom.perfectMatch[1];
2265                eepromData <<= 8;
2266                eepromData += rom.perfectMatch[0];
2267                break;
2268
2269              default:
2270                panic("FreeBSD driver only uses EEPROM to read PMATCH!");
2271            }
2272            // Set up to read data
2273            eepromState = eepromRead;
2274            eepromBitsToRx = 16;
2275
2276            // Clear data in bit
2277            regs.mear &= ~MEAR_EEDI;
2278        }
2279        break;
2280
2281      case eepromRead:
2282        // Clear Data Out bit
2283        regs.mear &= ~MEAR_EEDO;
2284        // Set bit to value of current EEPROM bit
2285        regs.mear |= (eepromData & 0x8000) ? MEAR_EEDO : 0x0;
2286
2287        eepromData <<= 1;
2288        --eepromBitsToRx;
2289
2290        // All done
2291        if (eepromBitsToRx == 0) {
2292            eepromState = eepromStart;
2293        }
2294        break;
2295
2296      default:
2297        panic("invalid EEPROM state");
2298    }
2299
2300}
2301
2302void
2303NSGigE::transferDone()
2304{
2305    if (txFifo.empty()) {
2306        DPRINTF(Ethernet, "transfer complete: txFifo empty...nothing to do\n");
2307        return;
2308    }
2309
2310    DPRINTF(Ethernet, "transfer complete: data in txFifo...schedule xmit\n");
2311
2312    if (txEvent.scheduled())
2313        txEvent.reschedule(curTick + cycles(1));
2314    else
2315        txEvent.schedule(curTick + cycles(1));
2316}
2317
2318bool
2319NSGigE::rxFilter(const EthPacketPtr &packet)
2320{
2321    EthPtr eth = packet;
2322    bool drop = true;
2323    string type;
2324
2325    const EthAddr &dst = eth->dst();
2326    if (dst.unicast()) {
2327        // If we're accepting all unicast addresses
2328        if (acceptUnicast)
2329            drop = false;
2330
2331        // If we make a perfect match
2332        if (acceptPerfect && dst == rom.perfectMatch)
2333            drop = false;
2334
2335        if (acceptArp && eth->type() == ETH_TYPE_ARP)
2336            drop = false;
2337
2338    } else if (dst.broadcast()) {
2339        // if we're accepting broadcasts
2340        if (acceptBroadcast)
2341            drop = false;
2342
2343    } else if (dst.multicast()) {
2344        // if we're accepting all multicasts
2345        if (acceptMulticast)
2346            drop = false;
2347
2348        // Multicast hashing faked - all packets accepted
2349        if (multicastHashEnable)
2350            drop = false;
2351    }
2352
2353    if (drop) {
2354        DPRINTF(Ethernet, "rxFilter drop\n");
2355        DDUMP(EthernetData, packet->data, packet->length);
2356    }
2357
2358    return drop;
2359}
2360
2361bool
2362NSGigE::recvPacket(EthPacketPtr packet)
2363{
2364    rxBytes += packet->length;
2365    rxPackets++;
2366
2367    DPRINTF(Ethernet, "Receiving packet from wire, rxFifoAvail=%d\n",
2368            rxFifo.avail());
2369
2370    if (!rxEnable) {
2371        DPRINTF(Ethernet, "receive disabled...packet dropped\n");
2372        return true;
2373    }
2374
2375    if (!rxFilterEnable) {
2376        DPRINTF(Ethernet,
2377            "receive packet filtering disabled . . . packet dropped\n");
2378        return true;
2379    }
2380
2381    if (rxFilter(packet)) {
2382        DPRINTF(Ethernet, "packet filtered...dropped\n");
2383        return true;
2384    }
2385
2386    if (rxFifo.avail() < packet->length) {
2387#if TRACING_ON
2388        IpPtr ip(packet);
2389        TcpPtr tcp(ip);
2390        if (ip) {
2391            DPRINTF(Ethernet,
2392                    "packet won't fit in receive buffer...pkt ID %d dropped\n",
2393                    ip->id());
2394            if (tcp) {
2395                DPRINTF(Ethernet, "Seq=%d\n", tcp->seq());
2396            }
2397        }
2398#endif
2399        droppedPackets++;
2400        devIntrPost(ISR_RXORN);
2401        return false;
2402    }
2403
2404    rxFifo.push(packet);
2405
2406    rxKick();
2407    return true;
2408}
2409
2410
2411void
2412NSGigE::resume()
2413{
2414    SimObject::resume();
2415
2416    // During drain we could have left the state machines in a waiting state and
2417    // they wouldn't get out until some other event occured to kick them.
2418    // This way they'll get out immediately
2419    txKick();
2420    rxKick();
2421}
2422
2423
2424//=====================================================================
2425//
2426//
2427void
2428NSGigE::serialize(ostream &os)
2429{
2430    // Serialize the PciDev base class
2431    PciDev::serialize(os);
2432
2433    /*
2434     * Finalize any DMA events now.
2435     */
2436    // @todo will mem system save pending dma?
2437
2438    /*
2439     * Serialize the device registers
2440     */
2441    SERIALIZE_SCALAR(regs.command);
2442    SERIALIZE_SCALAR(regs.config);
2443    SERIALIZE_SCALAR(regs.mear);
2444    SERIALIZE_SCALAR(regs.ptscr);
2445    SERIALIZE_SCALAR(regs.isr);
2446    SERIALIZE_SCALAR(regs.imr);
2447    SERIALIZE_SCALAR(regs.ier);
2448    SERIALIZE_SCALAR(regs.ihr);
2449    SERIALIZE_SCALAR(regs.txdp);
2450    SERIALIZE_SCALAR(regs.txdp_hi);
2451    SERIALIZE_SCALAR(regs.txcfg);
2452    SERIALIZE_SCALAR(regs.gpior);
2453    SERIALIZE_SCALAR(regs.rxdp);
2454    SERIALIZE_SCALAR(regs.rxdp_hi);
2455    SERIALIZE_SCALAR(regs.rxcfg);
2456    SERIALIZE_SCALAR(regs.pqcr);
2457    SERIALIZE_SCALAR(regs.wcsr);
2458    SERIALIZE_SCALAR(regs.pcr);
2459    SERIALIZE_SCALAR(regs.rfcr);
2460    SERIALIZE_SCALAR(regs.rfdr);
2461    SERIALIZE_SCALAR(regs.brar);
2462    SERIALIZE_SCALAR(regs.brdr);
2463    SERIALIZE_SCALAR(regs.srr);
2464    SERIALIZE_SCALAR(regs.mibc);
2465    SERIALIZE_SCALAR(regs.vrcr);
2466    SERIALIZE_SCALAR(regs.vtcr);
2467    SERIALIZE_SCALAR(regs.vdr);
2468    SERIALIZE_SCALAR(regs.ccsr);
2469    SERIALIZE_SCALAR(regs.tbicr);
2470    SERIALIZE_SCALAR(regs.tbisr);
2471    SERIALIZE_SCALAR(regs.tanar);
2472    SERIALIZE_SCALAR(regs.tanlpar);
2473    SERIALIZE_SCALAR(regs.taner);
2474    SERIALIZE_SCALAR(regs.tesr);
2475
2476    SERIALIZE_ARRAY(rom.perfectMatch, ETH_ADDR_LEN);
2477    SERIALIZE_ARRAY(rom.filterHash, FHASH_SIZE);
2478
2479    SERIALIZE_SCALAR(ioEnable);
2480
2481    /*
2482     * Serialize the data Fifos
2483     */
2484    rxFifo.serialize("rxFifo", os);
2485    txFifo.serialize("txFifo", os);
2486
2487    /*
2488     * Serialize the various helper variables
2489     */
2490    bool txPacketExists = txPacket;
2491    SERIALIZE_SCALAR(txPacketExists);
2492    if (txPacketExists) {
2493        txPacket->length = txPacketBufPtr - txPacket->data;
2494        txPacket->serialize("txPacket", os);
2495        uint32_t txPktBufPtr = (uint32_t) (txPacketBufPtr - txPacket->data);
2496        SERIALIZE_SCALAR(txPktBufPtr);
2497    }
2498
2499    bool rxPacketExists = rxPacket;
2500    SERIALIZE_SCALAR(rxPacketExists);
2501    if (rxPacketExists) {
2502        rxPacket->serialize("rxPacket", os);
2503        uint32_t rxPktBufPtr = (uint32_t) (rxPacketBufPtr - rxPacket->data);
2504        SERIALIZE_SCALAR(rxPktBufPtr);
2505    }
2506
2507    SERIALIZE_SCALAR(txXferLen);
2508    SERIALIZE_SCALAR(rxXferLen);
2509
2510    /*
2511     * Serialize Cached Descriptors
2512     */
2513    SERIALIZE_SCALAR(rxDesc64.link);
2514    SERIALIZE_SCALAR(rxDesc64.bufptr);
2515    SERIALIZE_SCALAR(rxDesc64.cmdsts);
2516    SERIALIZE_SCALAR(rxDesc64.extsts);
2517    SERIALIZE_SCALAR(txDesc64.link);
2518    SERIALIZE_SCALAR(txDesc64.bufptr);
2519    SERIALIZE_SCALAR(txDesc64.cmdsts);
2520    SERIALIZE_SCALAR(txDesc64.extsts);
2521    SERIALIZE_SCALAR(rxDesc32.link);
2522    SERIALIZE_SCALAR(rxDesc32.bufptr);
2523    SERIALIZE_SCALAR(rxDesc32.cmdsts);
2524    SERIALIZE_SCALAR(rxDesc32.extsts);
2525    SERIALIZE_SCALAR(txDesc32.link);
2526    SERIALIZE_SCALAR(txDesc32.bufptr);
2527    SERIALIZE_SCALAR(txDesc32.cmdsts);
2528    SERIALIZE_SCALAR(txDesc32.extsts);
2529    SERIALIZE_SCALAR(extstsEnable);
2530
2531    /*
2532     * Serialize tx state machine
2533     */
2534    int txState = this->txState;
2535    SERIALIZE_SCALAR(txState);
2536    SERIALIZE_SCALAR(txEnable);
2537    SERIALIZE_SCALAR(CTDD);
2538    SERIALIZE_SCALAR(txFragPtr);
2539    SERIALIZE_SCALAR(txDescCnt);
2540    int txDmaState = this->txDmaState;
2541    SERIALIZE_SCALAR(txDmaState);
2542    SERIALIZE_SCALAR(txKickTick);
2543
2544    /*
2545     * Serialize rx state machine
2546     */
2547    int rxState = this->rxState;
2548    SERIALIZE_SCALAR(rxState);
2549    SERIALIZE_SCALAR(rxEnable);
2550    SERIALIZE_SCALAR(CRDD);
2551    SERIALIZE_SCALAR(rxPktBytes);
2552    SERIALIZE_SCALAR(rxFragPtr);
2553    SERIALIZE_SCALAR(rxDescCnt);
2554    int rxDmaState = this->rxDmaState;
2555    SERIALIZE_SCALAR(rxDmaState);
2556    SERIALIZE_SCALAR(rxKickTick);
2557
2558    /*
2559     * Serialize EEPROM state machine
2560     */
2561    int eepromState = this->eepromState;
2562    SERIALIZE_SCALAR(eepromState);
2563    SERIALIZE_SCALAR(eepromClk);
2564    SERIALIZE_SCALAR(eepromBitsToRx);
2565    SERIALIZE_SCALAR(eepromOpcode);
2566    SERIALIZE_SCALAR(eepromAddress);
2567    SERIALIZE_SCALAR(eepromData);
2568
2569    /*
2570     * If there's a pending transmit, store the time so we can
2571     * reschedule it later
2572     */
2573    Tick transmitTick = txEvent.scheduled() ? txEvent.when() - curTick : 0;
2574    SERIALIZE_SCALAR(transmitTick);
2575
2576    /*
2577     * receive address filter settings
2578     */
2579    SERIALIZE_SCALAR(rxFilterEnable);
2580    SERIALIZE_SCALAR(acceptBroadcast);
2581    SERIALIZE_SCALAR(acceptMulticast);
2582    SERIALIZE_SCALAR(acceptUnicast);
2583    SERIALIZE_SCALAR(acceptPerfect);
2584    SERIALIZE_SCALAR(acceptArp);
2585    SERIALIZE_SCALAR(multicastHashEnable);
2586
2587    /*
2588     * Keep track of pending interrupt status.
2589     */
2590    SERIALIZE_SCALAR(intrTick);
2591    SERIALIZE_SCALAR(cpuPendingIntr);
2592    Tick intrEventTick = 0;
2593    if (intrEvent)
2594        intrEventTick = intrEvent->when();
2595    SERIALIZE_SCALAR(intrEventTick);
2596
2597}
2598
2599void
2600NSGigE::unserialize(Checkpoint *cp, const std::string &section)
2601{
2602    // Unserialize the PciDev base class
2603    PciDev::unserialize(cp, section);
2604
2605    UNSERIALIZE_SCALAR(regs.command);
2606    UNSERIALIZE_SCALAR(regs.config);
2607    UNSERIALIZE_SCALAR(regs.mear);
2608    UNSERIALIZE_SCALAR(regs.ptscr);
2609    UNSERIALIZE_SCALAR(regs.isr);
2610    UNSERIALIZE_SCALAR(regs.imr);
2611    UNSERIALIZE_SCALAR(regs.ier);
2612    UNSERIALIZE_SCALAR(regs.ihr);
2613    UNSERIALIZE_SCALAR(regs.txdp);
2614    UNSERIALIZE_SCALAR(regs.txdp_hi);
2615    UNSERIALIZE_SCALAR(regs.txcfg);
2616    UNSERIALIZE_SCALAR(regs.gpior);
2617    UNSERIALIZE_SCALAR(regs.rxdp);
2618    UNSERIALIZE_SCALAR(regs.rxdp_hi);
2619    UNSERIALIZE_SCALAR(regs.rxcfg);
2620    UNSERIALIZE_SCALAR(regs.pqcr);
2621    UNSERIALIZE_SCALAR(regs.wcsr);
2622    UNSERIALIZE_SCALAR(regs.pcr);
2623    UNSERIALIZE_SCALAR(regs.rfcr);
2624    UNSERIALIZE_SCALAR(regs.rfdr);
2625    UNSERIALIZE_SCALAR(regs.brar);
2626    UNSERIALIZE_SCALAR(regs.brdr);
2627    UNSERIALIZE_SCALAR(regs.srr);
2628    UNSERIALIZE_SCALAR(regs.mibc);
2629    UNSERIALIZE_SCALAR(regs.vrcr);
2630    UNSERIALIZE_SCALAR(regs.vtcr);
2631    UNSERIALIZE_SCALAR(regs.vdr);
2632    UNSERIALIZE_SCALAR(regs.ccsr);
2633    UNSERIALIZE_SCALAR(regs.tbicr);
2634    UNSERIALIZE_SCALAR(regs.tbisr);
2635    UNSERIALIZE_SCALAR(regs.tanar);
2636    UNSERIALIZE_SCALAR(regs.tanlpar);
2637    UNSERIALIZE_SCALAR(regs.taner);
2638    UNSERIALIZE_SCALAR(regs.tesr);
2639
2640    UNSERIALIZE_ARRAY(rom.perfectMatch, ETH_ADDR_LEN);
2641    UNSERIALIZE_ARRAY(rom.filterHash, FHASH_SIZE);
2642
2643    UNSERIALIZE_SCALAR(ioEnable);
2644
2645    /*
2646     * unserialize the data fifos
2647     */
2648    rxFifo.unserialize("rxFifo", cp, section);
2649    txFifo.unserialize("txFifo", cp, section);
2650
2651    /*
2652     * unserialize the various helper variables
2653     */
2654    bool txPacketExists;
2655    UNSERIALIZE_SCALAR(txPacketExists);
2656    if (txPacketExists) {
2657        txPacket = new EthPacketData(16384);
2658        txPacket->unserialize("txPacket", cp, section);
2659        uint32_t txPktBufPtr;
2660        UNSERIALIZE_SCALAR(txPktBufPtr);
2661        txPacketBufPtr = (uint8_t *) txPacket->data + txPktBufPtr;
2662    } else
2663        txPacket = 0;
2664
2665    bool rxPacketExists;
2666    UNSERIALIZE_SCALAR(rxPacketExists);
2667    rxPacket = 0;
2668    if (rxPacketExists) {
2669        rxPacket = new EthPacketData(16384);
2670        rxPacket->unserialize("rxPacket", cp, section);
2671        uint32_t rxPktBufPtr;
2672        UNSERIALIZE_SCALAR(rxPktBufPtr);
2673        rxPacketBufPtr = (uint8_t *) rxPacket->data + rxPktBufPtr;
2674    } else
2675        rxPacket = 0;
2676
2677    UNSERIALIZE_SCALAR(txXferLen);
2678    UNSERIALIZE_SCALAR(rxXferLen);
2679
2680    /*
2681     * Unserialize Cached Descriptors
2682     */
2683    UNSERIALIZE_SCALAR(rxDesc64.link);
2684    UNSERIALIZE_SCALAR(rxDesc64.bufptr);
2685    UNSERIALIZE_SCALAR(rxDesc64.cmdsts);
2686    UNSERIALIZE_SCALAR(rxDesc64.extsts);
2687    UNSERIALIZE_SCALAR(txDesc64.link);
2688    UNSERIALIZE_SCALAR(txDesc64.bufptr);
2689    UNSERIALIZE_SCALAR(txDesc64.cmdsts);
2690    UNSERIALIZE_SCALAR(txDesc64.extsts);
2691    UNSERIALIZE_SCALAR(rxDesc32.link);
2692    UNSERIALIZE_SCALAR(rxDesc32.bufptr);
2693    UNSERIALIZE_SCALAR(rxDesc32.cmdsts);
2694    UNSERIALIZE_SCALAR(rxDesc32.extsts);
2695    UNSERIALIZE_SCALAR(txDesc32.link);
2696    UNSERIALIZE_SCALAR(txDesc32.bufptr);
2697    UNSERIALIZE_SCALAR(txDesc32.cmdsts);
2698    UNSERIALIZE_SCALAR(txDesc32.extsts);
2699    UNSERIALIZE_SCALAR(extstsEnable);
2700
2701    /*
2702     * unserialize tx state machine
2703     */
2704    int txState;
2705    UNSERIALIZE_SCALAR(txState);
2706    this->txState = (TxState) txState;
2707    UNSERIALIZE_SCALAR(txEnable);
2708    UNSERIALIZE_SCALAR(CTDD);
2709    UNSERIALIZE_SCALAR(txFragPtr);
2710    UNSERIALIZE_SCALAR(txDescCnt);
2711    int txDmaState;
2712    UNSERIALIZE_SCALAR(txDmaState);
2713    this->txDmaState = (DmaState) txDmaState;
2714    UNSERIALIZE_SCALAR(txKickTick);
2715    if (txKickTick)
2716        txKickEvent.schedule(txKickTick);
2717
2718    /*
2719     * unserialize rx state machine
2720     */
2721    int rxState;
2722    UNSERIALIZE_SCALAR(rxState);
2723    this->rxState = (RxState) rxState;
2724    UNSERIALIZE_SCALAR(rxEnable);
2725    UNSERIALIZE_SCALAR(CRDD);
2726    UNSERIALIZE_SCALAR(rxPktBytes);
2727    UNSERIALIZE_SCALAR(rxFragPtr);
2728    UNSERIALIZE_SCALAR(rxDescCnt);
2729    int rxDmaState;
2730    UNSERIALIZE_SCALAR(rxDmaState);
2731    this->rxDmaState = (DmaState) rxDmaState;
2732    UNSERIALIZE_SCALAR(rxKickTick);
2733    if (rxKickTick)
2734        rxKickEvent.schedule(rxKickTick);
2735
2736    /*
2737     * Unserialize EEPROM state machine
2738     */
2739    int eepromState;
2740    UNSERIALIZE_SCALAR(eepromState);
2741    this->eepromState = (EEPROMState) eepromState;
2742    UNSERIALIZE_SCALAR(eepromClk);
2743    UNSERIALIZE_SCALAR(eepromBitsToRx);
2744    UNSERIALIZE_SCALAR(eepromOpcode);
2745    UNSERIALIZE_SCALAR(eepromAddress);
2746    UNSERIALIZE_SCALAR(eepromData);
2747
2748    /*
2749     * If there's a pending transmit, reschedule it now
2750     */
2751    Tick transmitTick;
2752    UNSERIALIZE_SCALAR(transmitTick);
2753    if (transmitTick)
2754        txEvent.schedule(curTick + transmitTick);
2755
2756    /*
2757     * unserialize receive address filter settings
2758     */
2759    UNSERIALIZE_SCALAR(rxFilterEnable);
2760    UNSERIALIZE_SCALAR(acceptBroadcast);
2761    UNSERIALIZE_SCALAR(acceptMulticast);
2762    UNSERIALIZE_SCALAR(acceptUnicast);
2763    UNSERIALIZE_SCALAR(acceptPerfect);
2764    UNSERIALIZE_SCALAR(acceptArp);
2765    UNSERIALIZE_SCALAR(multicastHashEnable);
2766
2767    /*
2768     * Keep track of pending interrupt status.
2769     */
2770    UNSERIALIZE_SCALAR(intrTick);
2771    UNSERIALIZE_SCALAR(cpuPendingIntr);
2772    Tick intrEventTick;
2773    UNSERIALIZE_SCALAR(intrEventTick);
2774    if (intrEventTick) {
2775        intrEvent = new IntrEvent(this, true);
2776        intrEvent->schedule(intrEventTick);
2777    }
2778}
2779
2780BEGIN_DECLARE_SIM_OBJECT_PARAMS(NSGigEInt)
2781
2782    SimObjectParam<EtherInt *> peer;
2783    SimObjectParam<NSGigE *> device;
2784
2785END_DECLARE_SIM_OBJECT_PARAMS(NSGigEInt)
2786
2787BEGIN_INIT_SIM_OBJECT_PARAMS(NSGigEInt)
2788
2789    INIT_PARAM_DFLT(peer, "peer interface", NULL),
2790    INIT_PARAM(device, "Ethernet device of this interface")
2791
2792END_INIT_SIM_OBJECT_PARAMS(NSGigEInt)
2793
2794CREATE_SIM_OBJECT(NSGigEInt)
2795{
2796    NSGigEInt *dev_int = new NSGigEInt(getInstanceName(), device);
2797
2798    EtherInt *p = (EtherInt *)peer;
2799    if (p) {
2800        dev_int->setPeer(p);
2801        p->setPeer(dev_int);
2802    }
2803
2804    return dev_int;
2805}
2806
2807REGISTER_SIM_OBJECT("NSGigEInt", NSGigEInt)
2808
2809
2810BEGIN_DECLARE_SIM_OBJECT_PARAMS(NSGigE)
2811
2812    SimObjectParam<System *> system;
2813    SimObjectParam<Platform *> platform;
2814    SimObjectParam<PciConfigData *> configdata;
2815    Param<uint32_t> pci_bus;
2816    Param<uint32_t> pci_dev;
2817    Param<uint32_t> pci_func;
2818    Param<Tick> pio_latency;
2819    Param<Tick> config_latency;
2820
2821    Param<Tick> clock;
2822    Param<bool> dma_desc_free;
2823    Param<bool> dma_data_free;
2824    Param<Tick> dma_read_delay;
2825    Param<Tick> dma_write_delay;
2826    Param<Tick> dma_read_factor;
2827    Param<Tick> dma_write_factor;
2828    Param<bool> dma_no_allocate;
2829    Param<Tick> intr_delay;
2830
2831    Param<Tick> rx_delay;
2832    Param<Tick> tx_delay;
2833    Param<uint32_t> rx_fifo_size;
2834    Param<uint32_t> tx_fifo_size;
2835
2836    Param<bool> rx_filter;
2837    Param<string> hardware_address;
2838    Param<bool> rx_thread;
2839    Param<bool> tx_thread;
2840    Param<bool> rss;
2841
2842END_DECLARE_SIM_OBJECT_PARAMS(NSGigE)
2843
2844BEGIN_INIT_SIM_OBJECT_PARAMS(NSGigE)
2845
2846    INIT_PARAM(system, "System pointer"),
2847    INIT_PARAM(platform, "Platform pointer"),
2848    INIT_PARAM(configdata, "PCI Config data"),
2849    INIT_PARAM(pci_bus, "PCI bus ID"),
2850    INIT_PARAM(pci_dev, "PCI device number"),
2851    INIT_PARAM(pci_func, "PCI function code"),
2852    INIT_PARAM_DFLT(pio_latency, "Programmed IO latency in bus cycles", 1),
2853    INIT_PARAM(config_latency, "Number of cycles for a config read or write"),
2854    INIT_PARAM(clock, "State machine cycle time"),
2855
2856    INIT_PARAM(dma_desc_free, "DMA of Descriptors is free"),
2857    INIT_PARAM(dma_data_free, "DMA of Data is free"),
2858    INIT_PARAM(dma_read_delay, "fixed delay for dma reads"),
2859    INIT_PARAM(dma_write_delay, "fixed delay for dma writes"),
2860    INIT_PARAM(dma_read_factor, "multiplier for dma reads"),
2861    INIT_PARAM(dma_write_factor, "multiplier for dma writes"),
2862    INIT_PARAM(dma_no_allocate, "Should DMA reads allocate cache lines"),
2863    INIT_PARAM(intr_delay, "Interrupt Delay in microseconds"),
2864
2865    INIT_PARAM(rx_delay, "Receive Delay"),
2866    INIT_PARAM(tx_delay, "Transmit Delay"),
2867    INIT_PARAM(rx_fifo_size, "max size in bytes of rxFifo"),
2868    INIT_PARAM(tx_fifo_size, "max size in bytes of txFifo"),
2869
2870    INIT_PARAM(rx_filter, "Enable Receive Filter"),
2871    INIT_PARAM(hardware_address, "Ethernet Hardware Address"),
2872    INIT_PARAM(rx_thread, ""),
2873    INIT_PARAM(tx_thread, ""),
2874    INIT_PARAM(rss, "")
2875
2876END_INIT_SIM_OBJECT_PARAMS(NSGigE)
2877
2878
2879CREATE_SIM_OBJECT(NSGigE)
2880{
2881    NSGigE::Params *params = new NSGigE::Params;
2882
2883    params->name = getInstanceName();
2884    params->platform = platform;
2885    params->system = system;
2886    params->configData = configdata;
2887    params->busNum = pci_bus;
2888    params->deviceNum = pci_dev;
2889    params->functionNum = pci_func;
2890    params->pio_delay = pio_latency;
2891    params->config_delay = config_latency;
2892
2893    params->clock = clock;
2894    params->dma_desc_free = dma_desc_free;
2895    params->dma_data_free = dma_data_free;
2896    params->dma_read_delay = dma_read_delay;
2897    params->dma_write_delay = dma_write_delay;
2898    params->dma_read_factor = dma_read_factor;
2899    params->dma_write_factor = dma_write_factor;
2900    params->dma_no_allocate = dma_no_allocate;
2901    params->pio_delay = pio_latency;
2902    params->intr_delay = intr_delay;
2903
2904    params->rx_delay = rx_delay;
2905    params->tx_delay = tx_delay;
2906    params->rx_fifo_size = rx_fifo_size;
2907    params->tx_fifo_size = tx_fifo_size;
2908
2909    params->rx_filter = rx_filter;
2910    params->eaddr = hardware_address;
2911    params->rx_thread = rx_thread;
2912    params->tx_thread = tx_thread;
2913    params->rss = rss;
2914
2915    return new NSGigE(params);
2916}
2917
2918REGISTER_SIM_OBJECT("NSGigE", NSGigE)
2919