ns_gige.cc revision 4875
12292SN/A/*
27597Sminkyu.jeong@arm.com * Copyright (c) 2004-2005 The Regents of The University of Michigan
37597Sminkyu.jeong@arm.com * All rights reserved.
47597Sminkyu.jeong@arm.com *
57597Sminkyu.jeong@arm.com * Redistribution and use in source and binary forms, with or without
67597Sminkyu.jeong@arm.com * modification, are permitted provided that the following conditions are
77597Sminkyu.jeong@arm.com * met: redistributions of source code must retain the above copyright
87597Sminkyu.jeong@arm.com * notice, this list of conditions and the following disclaimer;
97597Sminkyu.jeong@arm.com * redistributions in binary form must reproduce the above copyright
107597Sminkyu.jeong@arm.com * notice, this list of conditions and the following disclaimer in the
117597Sminkyu.jeong@arm.com * documentation and/or other materials provided with the distribution;
127597Sminkyu.jeong@arm.com * neither the name of the copyright holders nor the names of its
137597Sminkyu.jeong@arm.com * contributors may be used to endorse or promote products derived from
142292SN/A * this software without specific prior written permission.
152292SN/A *
162292SN/A * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
172292SN/A * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
182292SN/A * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
192292SN/A * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
202292SN/A * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
212292SN/A * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
222292SN/A * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
232292SN/A * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
242292SN/A * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
252292SN/A * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
262292SN/A * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
272292SN/A *
282292SN/A * Authors: Nathan Binkert
292292SN/A *          Lisa Hsu
302292SN/A */
312292SN/A
322292SN/A/** @file
332292SN/A * Device module for modelling the National Semiconductor
342292SN/A * DP83820 ethernet controller.  Does not support priority queueing
352292SN/A */
362292SN/A#include <deque>
372292SN/A#include <string>
382292SN/A
392689Sktlim@umich.edu#include "base/inet.hh"
402689Sktlim@umich.edu#include "cpu/thread_context.hh"
412689Sktlim@umich.edu#include "dev/etherlink.hh"
422292SN/A#include "dev/ns_gige.hh"
432292SN/A#include "dev/pciconfigall.hh"
443326Sktlim@umich.edu#include "mem/packet.hh"
456658Snate@binkert.org#include "mem/packet_access.hh"
462733Sktlim@umich.edu#include "sim/builder.hh"
472907Sktlim@umich.edu#include "sim/debug.hh"
482292SN/A#include "sim/host.hh"
492292SN/A#include "sim/stats.hh"
502722Sktlim@umich.edu#include "sim/system.hh"
512669Sktlim@umich.edu
522292SN/Aconst char *NsRxStateStrings[] =
532790Sktlim@umich.edu{
542790Sktlim@umich.edu    "rxIdle",
552790Sktlim@umich.edu    "rxDescRefr",
562790Sktlim@umich.edu    "rxDescRead",
572669Sktlim@umich.edu    "rxFifoBlock",
582678Sktlim@umich.edu    "rxFragWrite",
592678Sktlim@umich.edu    "rxDescWrite",
605606Snate@binkert.org    "rxAdvance"
612292SN/A};
622678Sktlim@umich.edu
632292SN/Aconst char *NsTxStateStrings[] =
642292SN/A{
652669Sktlim@umich.edu    "txIdle",
662292SN/A    "txDescRefr",
672678Sktlim@umich.edu    "txDescRead",
682292SN/A    "txFifoBlock",
692678Sktlim@umich.edu    "txFragRead",
702678Sktlim@umich.edu    "txDescWrite",
712678Sktlim@umich.edu    "txAdvance"
724319Sktlim@umich.edu};
734319Sktlim@umich.edu
744319Sktlim@umich.educonst char *NsDmaState[] =
754319Sktlim@umich.edu{
764319Sktlim@umich.edu    "dmaIdle",
772678Sktlim@umich.edu    "dmaReading",
782678Sktlim@umich.edu    "dmaWriting",
792292SN/A    "dmaReadWaiting",
802678Sktlim@umich.edu    "dmaWriteWaiting"
812678Sktlim@umich.edu};
825336Shines@cs.fsu.edu
832678Sktlim@umich.eduusing namespace std;
844873Sstever@eecs.umich.eduusing namespace Net;
852678Sktlim@umich.eduusing namespace TheISA;
862292SN/A
872678Sktlim@umich.edu///////////////////////////////////////////////////////////////////////
882678Sktlim@umich.edu//
892678Sktlim@umich.edu// NSGigE PCI Device
902678Sktlim@umich.edu//
912678Sktlim@umich.eduNSGigE::NSGigE(Params *p)
922678Sktlim@umich.edu    : PciDev(p), ioEnable(false),
932678Sktlim@umich.edu      txFifo(p->tx_fifo_size), rxFifo(p->rx_fifo_size),
942698Sktlim@umich.edu      txPacket(0), rxPacket(0), txPacketBufPtr(NULL), rxPacketBufPtr(NULL),
952344SN/A      txXferLen(0), rxXferLen(0), rxDmaFree(false), txDmaFree(false),
962678Sktlim@umich.edu      clock(p->clock),
972678Sktlim@umich.edu      txState(txIdle), txEnable(false), CTDD(false), txHalt(false),
984986Ssaidi@eecs.umich.edu      txFragPtr(0), txDescCnt(0), txDmaState(dmaIdle), rxState(rxIdle),
994986Ssaidi@eecs.umich.edu      rxEnable(false), CRDD(false), rxPktBytes(0), rxHalt(false),
1006974Stjones1@inf.ed.ac.uk      rxFragPtr(0), rxDescCnt(0), rxDmaState(dmaIdle), extstsEnable(false),
1016974Stjones1@inf.ed.ac.uk      eepromState(eepromStart), eepromClk(false), eepromBitsToRx(0),
1026974Stjones1@inf.ed.ac.uk      eepromOpcode(0), eepromAddress(0), eepromData(0),
1036974Stjones1@inf.ed.ac.uk      dmaReadDelay(p->dma_read_delay), dmaWriteDelay(p->dma_write_delay),
1046974Stjones1@inf.ed.ac.uk      dmaReadFactor(p->dma_read_factor), dmaWriteFactor(p->dma_write_factor),
1056974Stjones1@inf.ed.ac.uk      rxDmaData(NULL), rxDmaAddr(0), rxDmaLen(0),
1066974Stjones1@inf.ed.ac.uk      txDmaData(NULL), txDmaAddr(0), txDmaLen(0),
1072678Sktlim@umich.edu      rxDmaReadEvent(this), rxDmaWriteEvent(this),
1082820Sktlim@umich.edu      txDmaReadEvent(this), txDmaWriteEvent(this),
1092678Sktlim@umich.edu      dmaDescFree(p->dma_desc_free), dmaDataFree(p->dma_data_free),
1102678Sktlim@umich.edu      txDelay(p->tx_delay), rxDelay(p->rx_delay),
1116974Stjones1@inf.ed.ac.uk      rxKickTick(0), rxKickEvent(this), txKickTick(0), txKickEvent(this),
1126974Stjones1@inf.ed.ac.uk      txEvent(this), rxFilterEnable(p->rx_filter),
1136974Stjones1@inf.ed.ac.uk      acceptBroadcast(false), acceptMulticast(false), acceptUnicast(false),
1146974Stjones1@inf.ed.ac.uk      acceptPerfect(false), acceptArp(false), multicastHashEnable(false),
1156974Stjones1@inf.ed.ac.uk      intrDelay(p->intr_delay), intrTick(0), cpuPendingIntr(false),
1166974Stjones1@inf.ed.ac.uk      intrEvent(0), interface(0)
1172678Sktlim@umich.edu{
1182678Sktlim@umich.edu
1192678Sktlim@umich.edu
1202678Sktlim@umich.edu    regsReset();
1212678Sktlim@umich.edu    memcpy(&rom.perfectMatch, p->eaddr.bytes(), ETH_ADDR_LEN);
1222344SN/A
1232307SN/A    memset(&rxDesc32, 0, sizeof(rxDesc32));
1246974Stjones1@inf.ed.ac.uk    memset(&txDesc32, 0, sizeof(txDesc32));
1256974Stjones1@inf.ed.ac.uk    memset(&rxDesc64, 0, sizeof(rxDesc64));
1266974Stjones1@inf.ed.ac.uk    memset(&txDesc64, 0, sizeof(txDesc64));
1276974Stjones1@inf.ed.ac.uk}
1282678Sktlim@umich.edu
1294032Sktlim@umich.eduNSGigE::~NSGigE()
1302678Sktlim@umich.edu{}
1312292SN/A
1322292SN/Avoid
1332292SN/ANSGigE::regStats()
1342292SN/A{
1352678Sktlim@umich.edu    txBytes
1362678Sktlim@umich.edu        .name(name() + ".txBytes")
1376974Stjones1@inf.ed.ac.uk        .desc("Bytes Transmitted")
1382292SN/A        .prereq(txBytes)
1392292SN/A        ;
1402292SN/A
1412292SN/A    rxBytes
1422292SN/A        .name(name() + ".rxBytes")
1435529Snate@binkert.org        .desc("Bytes Received")
1445529Snate@binkert.org        .prereq(rxBytes)
1455529Snate@binkert.org        ;
1462292SN/A
1474329Sktlim@umich.edu    txPackets
1484329Sktlim@umich.edu        .name(name() + ".txPackets")
1494329Sktlim@umich.edu        .desc("Number of Packets Transmitted")
1504329Sktlim@umich.edu        .prereq(txBytes)
1512292SN/A        ;
1522307SN/A
1532307SN/A    rxPackets
1542907Sktlim@umich.edu        .name(name() + ".rxPackets")
1552907Sktlim@umich.edu        .desc("Number of Packets Received")
1562292SN/A        .prereq(rxBytes)
1572292SN/A        ;
1582329SN/A
1592329SN/A    txIpChecksums
1602329SN/A        .name(name() + ".txIpChecksums")
1612292SN/A        .desc("Number of tx IP Checksums done by device")
1622292SN/A        .precision(0)
1632292SN/A        .prereq(txBytes)
1642292SN/A        ;
1652292SN/A
1662292SN/A    rxIpChecksums
1672292SN/A        .name(name() + ".rxIpChecksums")
1682292SN/A        .desc("Number of rx IP Checksums done by device")
1692292SN/A        .precision(0)
1702292SN/A        .prereq(rxBytes)
1712292SN/A        ;
1723492Sktlim@umich.edu
1732329SN/A    txTcpChecksums
1742292SN/A        .name(name() + ".txTcpChecksums")
1752292SN/A        .desc("Number of tx TCP Checksums done by device")
1762292SN/A        .precision(0)
1772292SN/A        .prereq(txBytes)
1782292SN/A        ;
1792292SN/A
1802292SN/A    rxTcpChecksums
1812292SN/A        .name(name() + ".rxTcpChecksums")
1822292SN/A        .desc("Number of rx TCP Checksums done by device")
1832292SN/A        .precision(0)
1842292SN/A        .prereq(rxBytes)
1852292SN/A        ;
1862292SN/A
1872292SN/A    txUdpChecksums
1882292SN/A        .name(name() + ".txUdpChecksums")
1892292SN/A        .desc("Number of tx UDP Checksums done by device")
1902292SN/A        .precision(0)
1912727Sktlim@umich.edu        .prereq(txBytes)
1922727Sktlim@umich.edu        ;
1932727Sktlim@umich.edu
1942727Sktlim@umich.edu    rxUdpChecksums
1952727Sktlim@umich.edu        .name(name() + ".rxUdpChecksums")
1962727Sktlim@umich.edu        .desc("Number of rx UDP Checksums done by device")
1972727Sktlim@umich.edu        .precision(0)
1982727Sktlim@umich.edu        .prereq(rxBytes)
1992727Sktlim@umich.edu        ;
2002727Sktlim@umich.edu
2012727Sktlim@umich.edu    descDmaReads
2022727Sktlim@umich.edu        .name(name() + ".descDMAReads")
2032727Sktlim@umich.edu        .desc("Number of descriptors the device read w/ DMA")
2042727Sktlim@umich.edu        .precision(0)
2052727Sktlim@umich.edu        ;
2062727Sktlim@umich.edu
2072727Sktlim@umich.edu    descDmaWrites
2082727Sktlim@umich.edu        .name(name() + ".descDMAWrites")
2092361SN/A        .desc("Number of descriptors the device wrote w/ DMA")
2102361SN/A        .precision(0)
2112361SN/A        ;
2122361SN/A
2132727Sktlim@umich.edu    descDmaRdBytes
2142727Sktlim@umich.edu        .name(name() + ".descDmaReadBytes")
2152727Sktlim@umich.edu        .desc("number of descriptor bytes read w/ DMA")
2162727Sktlim@umich.edu        .precision(0)
2172727Sktlim@umich.edu        ;
2182727Sktlim@umich.edu
2192727Sktlim@umich.edu   descDmaWrBytes
2202727Sktlim@umich.edu        .name(name() + ".descDmaWriteBytes")
2212727Sktlim@umich.edu        .desc("number of descriptor bytes write w/ DMA")
2222727Sktlim@umich.edu        .precision(0)
2232727Sktlim@umich.edu        ;
2242727Sktlim@umich.edu
2252727Sktlim@umich.edu    txBandwidth
2262727Sktlim@umich.edu        .name(name() + ".txBandwidth")
2272727Sktlim@umich.edu        .desc("Transmit Bandwidth (bits/s)")
2282727Sktlim@umich.edu        .precision(0)
2292727Sktlim@umich.edu        .prereq(txBytes)
2302727Sktlim@umich.edu        ;
2312727Sktlim@umich.edu
2322727Sktlim@umich.edu    rxBandwidth
2332727Sktlim@umich.edu        .name(name() + ".rxBandwidth")
2342727Sktlim@umich.edu        .desc("Receive Bandwidth (bits/s)")
2352727Sktlim@umich.edu        .precision(0)
2364329Sktlim@umich.edu        .prereq(rxBytes)
2374329Sktlim@umich.edu        ;
2384329Sktlim@umich.edu
2394329Sktlim@umich.edu    totBandwidth
2404329Sktlim@umich.edu        .name(name() + ".totBandwidth")
2414329Sktlim@umich.edu        .desc("Total Bandwidth (bits/s)")
2424329Sktlim@umich.edu        .precision(0)
2434329Sktlim@umich.edu        .prereq(totBytes)
2444329Sktlim@umich.edu        ;
2454329Sktlim@umich.edu
2464329Sktlim@umich.edu    totPackets
2474329Sktlim@umich.edu        .name(name() + ".totPackets")
2484329Sktlim@umich.edu        .desc("Total Packets")
2492292SN/A        .precision(0)
2502292SN/A        .prereq(totBytes)
2512292SN/A        ;
2522292SN/A
2532292SN/A    totBytes
2542292SN/A        .name(name() + ".totBytes")
2552292SN/A        .desc("Total Bytes")
2562292SN/A        .precision(0)
2572292SN/A        .prereq(totBytes)
2582292SN/A        ;
2592292SN/A
2602292SN/A    totPacketRate
2612292SN/A        .name(name() + ".totPPS")
2622292SN/A        .desc("Total Tranmission Rate (packets/s)")
2632307SN/A        .precision(0)
2642307SN/A        .prereq(totBytes)
2652307SN/A        ;
2662367SN/A
2672367SN/A    txPacketRate
2682307SN/A        .name(name() + ".txPPS")
2692367SN/A        .desc("Packet Tranmission Rate (packets/s)")
2702307SN/A        .precision(0)
2712329SN/A        .prereq(txBytes)
2722307SN/A        ;
2732307SN/A
2742307SN/A    rxPacketRate
2752307SN/A        .name(name() + ".rxPPS")
2762307SN/A        .desc("Packet Reception Rate (packets/s)")
2772307SN/A        .precision(0)
2782307SN/A        .prereq(rxBytes)
2792307SN/A        ;
2802307SN/A
2812307SN/A    postedSwi
2822307SN/A        .name(name() + ".postedSwi")
2832307SN/A        .desc("number of software interrupts posted to CPU")
2842307SN/A        .precision(0)
2852307SN/A        ;
2862307SN/A
2872329SN/A    totalSwi
2882307SN/A        .name(name() + ".totalSwi")
2892307SN/A        .desc("total number of Swi written to ISR")
2902307SN/A        .precision(0)
2912307SN/A        ;
2922307SN/A
2932307SN/A    coalescedSwi
2942307SN/A        .name(name() + ".coalescedSwi")
2952307SN/A        .desc("average number of Swi's coalesced into each post")
2962307SN/A        .precision(0)
2972307SN/A        ;
2982292SN/A
2992292SN/A    postedRxIdle
3002329SN/A        .name(name() + ".postedRxIdle")
3012329SN/A        .desc("number of rxIdle interrupts posted to CPU")
3022292SN/A        .precision(0)
3032329SN/A        ;
3042329SN/A
3052292SN/A    totalRxIdle
3062292SN/A        .name(name() + ".totalRxIdle")
3072292SN/A        .desc("total number of RxIdle written to ISR")
3082292SN/A        .precision(0)
3092292SN/A        ;
3102329SN/A
3112292SN/A    coalescedRxIdle
3122292SN/A        .name(name() + ".coalescedRxIdle")
3132292SN/A        .desc("average number of RxIdle's coalesced into each post")
3142292SN/A        .precision(0)
3152292SN/A        ;
3162292SN/A
3172292SN/A    postedRxOk
3182292SN/A        .name(name() + ".postedRxOk")
3192329SN/A        .desc("number of RxOk interrupts posted to CPU")
3202329SN/A        .precision(0)
3212329SN/A        ;
3222292SN/A
3232292SN/A    totalRxOk
3242292SN/A        .name(name() + ".totalRxOk")
3252292SN/A        .desc("total number of RxOk written to ISR")
3262292SN/A        .precision(0)
3272329SN/A        ;
3282292SN/A
3292292SN/A    coalescedRxOk
3302292SN/A        .name(name() + ".coalescedRxOk")
3312292SN/A        .desc("average number of RxOk's coalesced into each post")
3322292SN/A        .precision(0)
3332292SN/A        ;
3342292SN/A
3352292SN/A    postedRxDesc
3362292SN/A        .name(name() + ".postedRxDesc")
3372292SN/A        .desc("number of RxDesc interrupts posted to CPU")
3382292SN/A        .precision(0)
3392292SN/A        ;
3402292SN/A
3412292SN/A    totalRxDesc
3422292SN/A        .name(name() + ".totalRxDesc")
3432292SN/A        .desc("total number of RxDesc written to ISR")
3442292SN/A        .precision(0)
3452292SN/A        ;
3462292SN/A
3472292SN/A    coalescedRxDesc
3482292SN/A        .name(name() + ".coalescedRxDesc")
3492292SN/A        .desc("average number of RxDesc's coalesced into each post")
3502292SN/A        .precision(0)
3512292SN/A        ;
3522329SN/A
3532329SN/A    postedTxOk
3542292SN/A        .name(name() + ".postedTxOk")
3557720Sgblack@eecs.umich.edu        .desc("number of TxOk interrupts posted to CPU")
3567720Sgblack@eecs.umich.edu        .precision(0)
3572292SN/A        ;
3582292SN/A
3592292SN/A    totalTxOk
3602292SN/A        .name(name() + ".totalTxOk")
3612292SN/A        .desc("total number of TxOk written to ISR")
3622292SN/A        .precision(0)
3632292SN/A        ;
3642292SN/A
3652292SN/A    coalescedTxOk
3662292SN/A        .name(name() + ".coalescedTxOk")
3672292SN/A        .desc("average number of TxOk's coalesced into each post")
3682292SN/A        .precision(0)
3692292SN/A        ;
3702292SN/A
3712292SN/A    postedTxIdle
3722292SN/A        .name(name() + ".postedTxIdle")
3732292SN/A        .desc("number of TxIdle interrupts posted to CPU")
3742292SN/A        .precision(0)
3752292SN/A        ;
3762292SN/A
3772292SN/A    totalTxIdle
3782292SN/A        .name(name() + ".totalTxIdle")
3792292SN/A        .desc("total number of TxIdle written to ISR")
3802292SN/A        .precision(0)
3817720Sgblack@eecs.umich.edu        ;
3827720Sgblack@eecs.umich.edu
3832292SN/A    coalescedTxIdle
3842292SN/A        .name(name() + ".coalescedTxIdle")
3852292SN/A        .desc("average number of TxIdle's coalesced into each post")
3862292SN/A        .precision(0)
3872292SN/A        ;
3882292SN/A
3892292SN/A    postedTxDesc
3902292SN/A        .name(name() + ".postedTxDesc")
3912292SN/A        .desc("number of TxDesc interrupts posted to CPU")
3922292SN/A        .precision(0)
3932292SN/A        ;
3942292SN/A
3952292SN/A    totalTxDesc
3962292SN/A        .name(name() + ".totalTxDesc")
3972292SN/A        .desc("total number of TxDesc written to ISR")
3982292SN/A        .precision(0)
3992292SN/A        ;
4002292SN/A
4012292SN/A    coalescedTxDesc
4022292SN/A        .name(name() + ".coalescedTxDesc")
4032292SN/A        .desc("average number of TxDesc's coalesced into each post")
4042292SN/A        .precision(0)
4052292SN/A        ;
4062292SN/A
4072292SN/A    postedRxOrn
4082292SN/A        .name(name() + ".postedRxOrn")
4092292SN/A        .desc("number of RxOrn posted to CPU")
4102292SN/A        .precision(0)
4112292SN/A        ;
4122292SN/A
4132292SN/A    totalRxOrn
4142292SN/A        .name(name() + ".totalRxOrn")
4152292SN/A        .desc("total number of RxOrn written to ISR")
4162292SN/A        .precision(0)
4172292SN/A        ;
4182292SN/A
4192292SN/A    coalescedRxOrn
4202292SN/A        .name(name() + ".coalescedRxOrn")
4212292SN/A        .desc("average number of RxOrn's coalesced into each post")
4222292SN/A        .precision(0)
4232292SN/A        ;
4242292SN/A
4252292SN/A    coalescedTotal
4262292SN/A        .name(name() + ".coalescedTotal")
4272292SN/A        .desc("average number of interrupts coalesced into each post")
4282292SN/A        .precision(0)
4292292SN/A        ;
4302292SN/A
4312292SN/A    postedInterrupts
4322292SN/A        .name(name() + ".postedInterrupts")
4332292SN/A        .desc("number of posts to CPU")
4342292SN/A        .precision(0)
4352292SN/A        ;
4362292SN/A
4372292SN/A    droppedPackets
4382292SN/A        .name(name() + ".droppedPackets")
4392292SN/A        .desc("number of packets dropped")
4402292SN/A        .precision(0)
4412292SN/A        ;
4422292SN/A
4434032Sktlim@umich.edu    coalescedSwi = totalSwi / postedInterrupts;
4442292SN/A    coalescedRxIdle = totalRxIdle / postedInterrupts;
4452292SN/A    coalescedRxOk = totalRxOk / postedInterrupts;
4462292SN/A    coalescedRxDesc = totalRxDesc / postedInterrupts;
4477720Sgblack@eecs.umich.edu    coalescedTxOk = totalTxOk / postedInterrupts;
4487720Sgblack@eecs.umich.edu    coalescedTxIdle = totalTxIdle / postedInterrupts;
4492292SN/A    coalescedTxDesc = totalTxDesc / postedInterrupts;
4504032Sktlim@umich.edu    coalescedRxOrn = totalRxOrn / postedInterrupts;
4514032Sktlim@umich.edu
4522669Sktlim@umich.edu    coalescedTotal = (totalSwi + totalRxIdle + totalRxOk + totalRxDesc +
4532292SN/A                      totalTxOk + totalTxIdle + totalTxDesc +
4547597Sminkyu.jeong@arm.com                      totalRxOrn) / postedInterrupts;
4557597Sminkyu.jeong@arm.com
4567597Sminkyu.jeong@arm.com    txBandwidth = txBytes * Stats::constant(8) / simSeconds;
4572329SN/A    rxBandwidth = rxBytes * Stats::constant(8) / simSeconds;
4582329SN/A    totBandwidth = txBandwidth + rxBandwidth;
4592367SN/A    totBytes = txBytes + rxBytes;
4602367SN/A    totPackets = txPackets + rxPackets;
4617600Sminkyu.jeong@arm.com
4627600Sminkyu.jeong@arm.com    txPacketRate = txPackets / simSeconds;
4637600Sminkyu.jeong@arm.com    rxPacketRate = rxPackets / simSeconds;
4644032Sktlim@umich.edu}
4653731Sktlim@umich.edu
4662367SN/A
4672367SN/A/**
4682292SN/A * This is to write to the PCI general configuration registers
4692292SN/A */
4704032Sktlim@umich.eduTick
4714032Sktlim@umich.eduNSGigE::writeConfig(PacketPtr pkt)
4724032Sktlim@umich.edu{
4734032Sktlim@umich.edu    int offset = pkt->getAddr() & PCI_CONFIG_SIZE;
4744032Sktlim@umich.edu    if (offset < PCI_DEVICE_SPECIFIC)
4754032Sktlim@umich.edu        PciDev::writeConfig(pkt);
4764032Sktlim@umich.edu    else
4774032Sktlim@umich.edu        panic("Device specific PCI config space not implemented!\n");
4784032Sktlim@umich.edu
4794032Sktlim@umich.edu    switch (offset) {
4804032Sktlim@umich.edu        // seems to work fine without all these PCI settings, but i
4814032Sktlim@umich.edu        // put in the IO to double check, an assertion will fail if we
4827616Sminkyu.jeong@arm.com        // need to properly implement it
4837616Sminkyu.jeong@arm.com      case PCI_COMMAND:
4847616Sminkyu.jeong@arm.com        if (config.data[offset] & PCI_CMD_IOSE)
4857616Sminkyu.jeong@arm.com            ioEnable = true;
4864032Sktlim@umich.edu        else
4877616Sminkyu.jeong@arm.com            ioEnable = false;
4887616Sminkyu.jeong@arm.com        break;
4897616Sminkyu.jeong@arm.com    }
4904032Sktlim@umich.edu
4914032Sktlim@umich.edu    return configDelay;
4924032Sktlim@umich.edu}
4934032Sktlim@umich.edu
4944032Sktlim@umich.edu/**
4954032Sktlim@umich.edu * This reads the device registers, which are detailed in the NS83820
4964032Sktlim@umich.edu * spec sheet
4974032Sktlim@umich.edu */
4984032Sktlim@umich.eduTick
4994032Sktlim@umich.eduNSGigE::read(PacketPtr pkt)
5004032Sktlim@umich.edu{
5014032Sktlim@umich.edu    assert(ioEnable);
5024032Sktlim@umich.edu
5034032Sktlim@umich.edu    pkt->allocate();
5044032Sktlim@umich.edu
5054032Sktlim@umich.edu    //The mask is to give you only the offset into the device register file
5064032Sktlim@umich.edu    Addr daddr = pkt->getAddr() & 0xfff;
5072292SN/A    DPRINTF(EthernetPIO, "read  da=%#x pa=%#x size=%d\n",
5082292SN/A            daddr, pkt->getAddr(), pkt->getSize());
5092292SN/A
5102292SN/A
5112292SN/A    // there are some reserved registers, you can see ns_gige_reg.h and
5122292SN/A    // the spec sheet for details
5132292SN/A    if (daddr > LAST && daddr <=  RESERVED) {
5142292SN/A        panic("Accessing reserved register");
5152292SN/A    } else if (daddr > RESERVED && daddr <= 0x3FC) {
5162292SN/A        return readConfig(pkt);
5172292SN/A    } else if (daddr >= MIB_START && daddr <= MIB_END) {
5182292SN/A        // don't implement all the MIB's.  hopefully the kernel
5192292SN/A        // doesn't actually DEPEND upon their values
5202292SN/A        // MIB are just hardware stats keepers
5212292SN/A        pkt->set<uint32_t>(0);
5227720Sgblack@eecs.umich.edu        pkt->makeAtomicResponse();
5237720Sgblack@eecs.umich.edu        return pioDelay;
5242292SN/A    } else if (daddr > 0x3FC)
5254032Sktlim@umich.edu        panic("Something is messed up!\n");
5264032Sktlim@umich.edu
5272292SN/A    assert(pkt->getSize() == sizeof(uint32_t));
5282292SN/A        uint32_t &reg = *pkt->getPtr<uint32_t>();
5292292SN/A        uint16_t rfaddr;
5302292SN/A
5312292SN/A        switch (daddr) {
5322292SN/A          case CR:
5332329SN/A            reg = regs.command;
5347720Sgblack@eecs.umich.edu            //these are supposed to be cleared on a read
5357720Sgblack@eecs.umich.edu            reg &= ~(CR_RXD | CR_TXD | CR_TXR | CR_RXR);
5362292SN/A            break;
5372292SN/A
5382292SN/A          case CFGR:
5392292SN/A            reg = regs.config;
5402292SN/A            break;
5412292SN/A
5422336SN/A          case MEAR:
5432336SN/A            reg = regs.mear;
5442336SN/A            break;
5452329SN/A
5462292SN/A          case PTSCR:
5472329SN/A            reg = regs.ptscr;
5482292SN/A            break;
5492292SN/A
5504032Sktlim@umich.edu          case ISR:
5514032Sktlim@umich.edu            reg = regs.isr;
5524032Sktlim@umich.edu            devIntrClear(ISR_ALL);
5534032Sktlim@umich.edu            break;
5544032Sktlim@umich.edu
5552292SN/A          case IMR:
5564032Sktlim@umich.edu            reg = regs.imr;
5574032Sktlim@umich.edu            break;
5584032Sktlim@umich.edu
5592329SN/A          case IER:
5604032Sktlim@umich.edu            reg = regs.ier;
5617616Sminkyu.jeong@arm.com            break;
5627616Sminkyu.jeong@arm.com
5637616Sminkyu.jeong@arm.com          case IHR:
5647616Sminkyu.jeong@arm.com            reg = regs.ihr;
5654032Sktlim@umich.edu            break;
5667616Sminkyu.jeong@arm.com
5677616Sminkyu.jeong@arm.com          case TXDP:
5687616Sminkyu.jeong@arm.com            reg = regs.txdp;
5694032Sktlim@umich.edu            break;
5704032Sktlim@umich.edu
5714032Sktlim@umich.edu          case TXDP_HI:
5724032Sktlim@umich.edu            reg = regs.txdp_hi;
5734032Sktlim@umich.edu            break;
5744032Sktlim@umich.edu
5754032Sktlim@umich.edu          case TX_CFG:
5764032Sktlim@umich.edu            reg = regs.txcfg;
5772292SN/A            break;
5782292SN/A
5794032Sktlim@umich.edu          case GPIOR:
5804032Sktlim@umich.edu            reg = regs.gpior;
5814032Sktlim@umich.edu            break;
5822292SN/A
5832292SN/A          case RXDP:
5844032Sktlim@umich.edu            reg = regs.rxdp;
5852292SN/A            break;
5862292SN/A
5872292SN/A          case RXDP_HI:
5882292SN/A            reg = regs.rxdp_hi;
5892292SN/A            break;
5902292SN/A
5912292SN/A          case RX_CFG:
5922292SN/A            reg = regs.rxcfg;
5932292SN/A            break;
5942292SN/A
5952292SN/A          case PQCR:
5967720Sgblack@eecs.umich.edu            reg = regs.pqcr;
5977720Sgblack@eecs.umich.edu            break;
5982292SN/A
5992292SN/A          case WCSR:
6002292SN/A            reg = regs.wcsr;
6012292SN/A            break;
6022292SN/A
6032292SN/A          case PCR:
6042292SN/A            reg = regs.pcr;
6052292SN/A            break;
6062292SN/A
6072292SN/A            // see the spec sheet for how RFCR and RFDR work
6082292SN/A            // basically, you write to RFCR to tell the machine
6092292SN/A            // what you want to do next, then you act upon RFDR,
6102292SN/A            // and the device will be prepared b/c of what you
6112292SN/A            // wrote to RFCR
6122292SN/A          case RFCR:
6132292SN/A            reg = regs.rfcr;
6142292SN/A            break;
6152292SN/A
6162292SN/A          case RFDR:
6172292SN/A            rfaddr = (uint16_t)(regs.rfcr & RFCR_RFADDR);
6182292SN/A            switch (rfaddr) {
6192292SN/A              // Read from perfect match ROM octets
6202292SN/A              case 0x000:
6212292SN/A                reg = rom.perfectMatch[1];
6222292SN/A                reg = reg << 8;
6232292SN/A                reg += rom.perfectMatch[0];
6242292SN/A                break;
6252292SN/A              case 0x002:
6262292SN/A                reg = rom.perfectMatch[3] << 8;
6272329SN/A                reg += rom.perfectMatch[2];
6282329SN/A                break;
6292292SN/A              case 0x004:
6302292SN/A                reg = rom.perfectMatch[5] << 8;
6312292SN/A                reg += rom.perfectMatch[4];
6322292SN/A                break;
6332292SN/A              default:
6347720Sgblack@eecs.umich.edu                // Read filter hash table
6357720Sgblack@eecs.umich.edu                if (rfaddr >= FHASH_ADDR &&
6362292SN/A                    rfaddr < FHASH_ADDR + FHASH_SIZE) {
6372292SN/A
6382292SN/A                    // Only word-aligned reads supported
6392292SN/A                    if (rfaddr % 2)
6402292SN/A                        panic("unaligned read from filter hash table!");
6412292SN/A
6422292SN/A                    reg = rom.filterHash[rfaddr - FHASH_ADDR + 1] << 8;
6432292SN/A                    reg += rom.filterHash[rfaddr - FHASH_ADDR];
6442292SN/A                    break;
6452292SN/A                }
6462292SN/A
6472292SN/A                panic("reading RFDR for something other than pattern"
6482292SN/A                      " matching or hashing! %#x\n", rfaddr);
6496974Stjones1@inf.ed.ac.uk            }
6506974Stjones1@inf.ed.ac.uk            break;
6516974Stjones1@inf.ed.ac.uk
6526974Stjones1@inf.ed.ac.uk          case SRR:
6536974Stjones1@inf.ed.ac.uk            reg = regs.srr;
6546974Stjones1@inf.ed.ac.uk            break;
6556974Stjones1@inf.ed.ac.uk
6566974Stjones1@inf.ed.ac.uk          case MIBC:
6576974Stjones1@inf.ed.ac.uk            reg = regs.mibc;
6586974Stjones1@inf.ed.ac.uk            reg &= ~(MIBC_MIBS | MIBC_ACLR);
6596974Stjones1@inf.ed.ac.uk            break;
6606974Stjones1@inf.ed.ac.uk
6616974Stjones1@inf.ed.ac.uk          case VRCR:
6626974Stjones1@inf.ed.ac.uk            reg = regs.vrcr;
6636974Stjones1@inf.ed.ac.uk            break;
6646974Stjones1@inf.ed.ac.uk
6652292SN/A          case VTCR:
6662292SN/A            reg = regs.vtcr;
6676974Stjones1@inf.ed.ac.uk            break;
6686974Stjones1@inf.ed.ac.uk
6696974Stjones1@inf.ed.ac.uk          case VDR:
6706974Stjones1@inf.ed.ac.uk            reg = regs.vdr;
6716974Stjones1@inf.ed.ac.uk            break;
6726974Stjones1@inf.ed.ac.uk
6732292SN/A          case CCSR:
6742292SN/A            reg = regs.ccsr;
6752292SN/A            break;
6762292SN/A
6772292SN/A          case TBICR:
6782292SN/A            reg = regs.tbicr;
6792907Sktlim@umich.edu            break;
6802678Sktlim@umich.edu
6812678Sktlim@umich.edu          case TBISR:
6822678Sktlim@umich.edu            reg = regs.tbisr;
6832678Sktlim@umich.edu            break;
6842678Sktlim@umich.edu
6852329SN/A          case TANAR:
6862329SN/A            reg = regs.tanar;
6872292SN/A            break;
6882292SN/A
6892292SN/A          case TANLPAR:
6902292SN/A            reg = regs.tanlpar;
6912292SN/A            break;
6922292SN/A
6932292SN/A          case TANER:
6942678Sktlim@umich.edu            reg = regs.taner;
6952292SN/A            break;
6962292SN/A
6972292SN/A          case TESR:
6982292SN/A            reg = regs.tesr;
6992292SN/A            break;
7002292SN/A
7012292SN/A          case M5REG:
7022292SN/A            reg = 0;
7032292SN/A            if (params()->rx_thread)
7042292SN/A                reg |= M5REG_RX_THREAD;
7052292SN/A            if (params()->tx_thread)
7066974Stjones1@inf.ed.ac.uk                reg |= M5REG_TX_THREAD;
7076974Stjones1@inf.ed.ac.uk            if (params()->rss)
7086974Stjones1@inf.ed.ac.uk                reg |= M5REG_RSS;
7096974Stjones1@inf.ed.ac.uk            break;
7106974Stjones1@inf.ed.ac.uk
7112669Sktlim@umich.edu          default:
7122669Sktlim@umich.edu            panic("reading unimplemented register: addr=%#x", daddr);
7132669Sktlim@umich.edu        }
7142292SN/A
7152292SN/A        DPRINTF(EthernetPIO, "read from %#x: data=%d data=%#x\n",
7162669Sktlim@umich.edu                daddr, reg, reg);
7172669Sktlim@umich.edu
7183772Sgblack@eecs.umich.edu    pkt->makeAtomicResponse();
7194326Sgblack@eecs.umich.edu    return pioDelay;
7202669Sktlim@umich.edu}
7214878Sstever@eecs.umich.edu
7224878Sstever@eecs.umich.eduTick
7236102Sgblack@eecs.umich.eduNSGigE::write(PacketPtr pkt)
7246974Stjones1@inf.ed.ac.uk{
7256974Stjones1@inf.ed.ac.uk    assert(ioEnable);
7262292SN/A
7272678Sktlim@umich.edu    Addr daddr = pkt->getAddr() & 0xfff;
7282678Sktlim@umich.edu    DPRINTF(EthernetPIO, "write da=%#x pa=%#x size=%d\n",
7292678Sktlim@umich.edu            daddr, pkt->getAddr(), pkt->getSize());
7302678Sktlim@umich.edu
7316974Stjones1@inf.ed.ac.uk    if (daddr > LAST && daddr <=  RESERVED) {
7326974Stjones1@inf.ed.ac.uk        panic("Accessing reserved register");
7336974Stjones1@inf.ed.ac.uk    } else if (daddr > RESERVED && daddr <= 0x3FC) {
7346974Stjones1@inf.ed.ac.uk        return writeConfig(pkt);
7356974Stjones1@inf.ed.ac.uk    } else if (daddr > 0x3FC)
7366974Stjones1@inf.ed.ac.uk        panic("Something is messed up!\n");
7376974Stjones1@inf.ed.ac.uk
7386974Stjones1@inf.ed.ac.uk    if (pkt->getSize() == sizeof(uint32_t)) {
7396974Stjones1@inf.ed.ac.uk        uint32_t reg = pkt->get<uint32_t>();
7406974Stjones1@inf.ed.ac.uk        uint16_t rfaddr;
7416974Stjones1@inf.ed.ac.uk
7426974Stjones1@inf.ed.ac.uk        DPRINTF(EthernetPIO, "write data=%d data=%#x\n", reg, reg);
7436974Stjones1@inf.ed.ac.uk
7446974Stjones1@inf.ed.ac.uk        switch (daddr) {
7456974Stjones1@inf.ed.ac.uk          case CR:
7466974Stjones1@inf.ed.ac.uk            regs.command = reg;
7476974Stjones1@inf.ed.ac.uk            if (reg & CR_TXD) {
7486974Stjones1@inf.ed.ac.uk                txEnable = false;
7496974Stjones1@inf.ed.ac.uk            } else if (reg & CR_TXE) {
7506974Stjones1@inf.ed.ac.uk                txEnable = true;
7516974Stjones1@inf.ed.ac.uk
7526974Stjones1@inf.ed.ac.uk                // the kernel is enabling the transmit machine
7536974Stjones1@inf.ed.ac.uk                if (txState == txIdle)
7546974Stjones1@inf.ed.ac.uk                    txKick();
7556974Stjones1@inf.ed.ac.uk            }
7566974Stjones1@inf.ed.ac.uk
7576974Stjones1@inf.ed.ac.uk            if (reg & CR_RXD) {
7586974Stjones1@inf.ed.ac.uk                rxEnable = false;
7592678Sktlim@umich.edu            } else if (reg & CR_RXE) {
7607720Sgblack@eecs.umich.edu                rxEnable = true;
7612292SN/A
7627720Sgblack@eecs.umich.edu                if (rxState == rxIdle)
7633797Sgblack@eecs.umich.edu                    rxKick();
7643221Sktlim@umich.edu            }
7652292SN/A
7662693Sktlim@umich.edu            if (reg & CR_TXR)
7674350Sgblack@eecs.umich.edu                txReset();
7686974Stjones1@inf.ed.ac.uk
7693326Sktlim@umich.edu            if (reg & CR_RXR)
7703326Sktlim@umich.edu                rxReset();
7713326Sktlim@umich.edu
7723326Sktlim@umich.edu            if (reg & CR_SWI)
7733326Sktlim@umich.edu                devIntrPost(ISR_SWI);
7743326Sktlim@umich.edu
7753326Sktlim@umich.edu            if (reg & CR_RST) {
7763326Sktlim@umich.edu                txReset();
7773326Sktlim@umich.edu                rxReset();
7783326Sktlim@umich.edu
7793326Sktlim@umich.edu                regsReset();
7803326Sktlim@umich.edu            }
7813326Sktlim@umich.edu            break;
7825606Snate@binkert.org
7833326Sktlim@umich.edu          case CFGR:
7843326Sktlim@umich.edu            if (reg & CFGR_LNKSTS ||
7853326Sktlim@umich.edu                reg & CFGR_SPDSTS ||
7862693Sktlim@umich.edu                reg & CFGR_DUPSTS ||
7872693Sktlim@umich.edu                reg & CFGR_RESERVED ||
7882693Sktlim@umich.edu                reg & CFGR_T64ADDR ||
7892693Sktlim@umich.edu                reg & CFGR_PCI64_DET)
7902693Sktlim@umich.edu
7912693Sktlim@umich.edu            // First clear all writable bits
7926974Stjones1@inf.ed.ac.uk            regs.config &= CFGR_LNKSTS | CFGR_SPDSTS | CFGR_DUPSTS |
7934032Sktlim@umich.edu                                   CFGR_RESERVED | CFGR_T64ADDR |
7943221Sktlim@umich.edu                                   CFGR_PCI64_DET;
7953221Sktlim@umich.edu            // Now set the appropriate writable bits
7966974Stjones1@inf.ed.ac.uk            regs.config |= reg & ~(CFGR_LNKSTS | CFGR_SPDSTS | CFGR_DUPSTS |
7976974Stjones1@inf.ed.ac.uk                                   CFGR_RESERVED | CFGR_T64ADDR |
7986974Stjones1@inf.ed.ac.uk                                   CFGR_PCI64_DET);
7996974Stjones1@inf.ed.ac.uk
8006974Stjones1@inf.ed.ac.uk// all these #if 0's are because i don't THINK the kernel needs to
8016974Stjones1@inf.ed.ac.uk// have these implemented. if there is a problem relating to one of
8022669Sktlim@umich.edu// these, you may need to add functionality in.
8036974Stjones1@inf.ed.ac.uk            if (reg & CFGR_TBI_EN) ;
8046974Stjones1@inf.ed.ac.uk            if (reg & CFGR_MODE_1000) ;
8056974Stjones1@inf.ed.ac.uk
8066974Stjones1@inf.ed.ac.uk            if (reg & CFGR_AUTO_1000)
8076974Stjones1@inf.ed.ac.uk                panic("CFGR_AUTO_1000 not implemented!\n");
8086974Stjones1@inf.ed.ac.uk
8096974Stjones1@inf.ed.ac.uk            if (reg & CFGR_PINT_DUPSTS ||
8106974Stjones1@inf.ed.ac.uk                reg & CFGR_PINT_LNKSTS ||
8116974Stjones1@inf.ed.ac.uk                reg & CFGR_PINT_SPDSTS)
8126974Stjones1@inf.ed.ac.uk                ;
8136974Stjones1@inf.ed.ac.uk
8146974Stjones1@inf.ed.ac.uk            if (reg & CFGR_TMRTEST) ;
8156974Stjones1@inf.ed.ac.uk            if (reg & CFGR_MRM_DIS) ;
8166974Stjones1@inf.ed.ac.uk            if (reg & CFGR_MWI_DIS) ;
8176974Stjones1@inf.ed.ac.uk
8186974Stjones1@inf.ed.ac.uk            if (reg & CFGR_T64ADDR) ;
8196974Stjones1@inf.ed.ac.uk            // panic("CFGR_T64ADDR is read only register!\n");
8206974Stjones1@inf.ed.ac.uk
8216974Stjones1@inf.ed.ac.uk            if (reg & CFGR_PCI64_DET)
8226974Stjones1@inf.ed.ac.uk                panic("CFGR_PCI64_DET is read only register!\n");
8236974Stjones1@inf.ed.ac.uk
8246974Stjones1@inf.ed.ac.uk            if (reg & CFGR_DATA64_EN) ;
8256974Stjones1@inf.ed.ac.uk            if (reg & CFGR_M64ADDR) ;
8266974Stjones1@inf.ed.ac.uk            if (reg & CFGR_PHY_RST) ;
8276974Stjones1@inf.ed.ac.uk            if (reg & CFGR_PHY_DIS) ;
8286974Stjones1@inf.ed.ac.uk
8296974Stjones1@inf.ed.ac.uk            if (reg & CFGR_EXTSTS_EN)
8302292SN/A                extstsEnable = true;
8312292SN/A            else
8322292SN/A                extstsEnable = false;
8332292SN/A
8342292SN/A            if (reg & CFGR_REQALG) ;
8352292SN/A            if (reg & CFGR_SB) ;
8362292SN/A            if (reg & CFGR_POW) ;
8372292SN/A            if (reg & CFGR_EXD) ;
8382292SN/A            if (reg & CFGR_PESEL) ;
8392292SN/A            if (reg & CFGR_BROM_DIS) ;
8402292SN/A            if (reg & CFGR_EXT_125) ;
8412292SN/A            if (reg & CFGR_BEM) ;
8422292SN/A            break;
8432292SN/A
8442292SN/A          case MEAR:
8452292SN/A            // Clear writable bits
8462292SN/A            regs.mear &= MEAR_EEDO;
8472292SN/A            // Set appropriate writable bits
8482292SN/A            regs.mear |= reg & ~MEAR_EEDO;
8492292SN/A
8502292SN/A            // FreeBSD uses the EEPROM to read PMATCH (for the MAC address)
8512292SN/A            // even though it could get it through RFDR
8522292SN/A            if (reg & MEAR_EESEL) {
8532292SN/A                // Rising edge of clock
8542292SN/A                if (reg & MEAR_EECLK && !eepromClk)
8552292SN/A                    eepromKick();
8562292SN/A            }
8572292SN/A            else {
8582329SN/A                eepromState = eepromStart;
8592292SN/A                regs.mear &= ~MEAR_EEDI;
8602292SN/A            }
8612292SN/A
8622292SN/A            eepromClk = reg & MEAR_EECLK;
8632292SN/A
8647720Sgblack@eecs.umich.edu            // since phy is completely faked, MEAR_MD* don't matter
8652292SN/A            if (reg & MEAR_MDIO) ;
8667720Sgblack@eecs.umich.edu            if (reg & MEAR_MDDIR) ;
8672292SN/A            if (reg & MEAR_MDC) ;
8682292SN/A            break;
8692292SN/A
8702292SN/A          case PTSCR:
8712292SN/A            regs.ptscr = reg & ~(PTSCR_RBIST_RDONLY);
8722292SN/A            // these control BISTs for various parts of chip - we
8732292SN/A            // don't care or do just fake that the BIST is done
8742292SN/A            if (reg & PTSCR_RBIST_EN)
8752329SN/A                regs.ptscr |= PTSCR_RBIST_DONE;
8762731Sktlim@umich.edu            if (reg & PTSCR_EEBIST_EN)
8772292SN/A                regs.ptscr &= ~PTSCR_EEBIST_EN;
8782292SN/A            if (reg & PTSCR_EELOAD_EN)
8792292SN/A                regs.ptscr &= ~PTSCR_EELOAD_EN;
8802292SN/A            break;
8812292SN/A
8822292SN/A          case ISR: /* writing to the ISR has no effect */
8832292SN/A            panic("ISR is a read only register!\n");
8842727Sktlim@umich.edu
8852292SN/A          case IMR:
8862292SN/A            regs.imr = reg;
8872292SN/A            devIntrChangeMask();
8882292SN/A            break;
8892292SN/A
8902292SN/A          case IER:
8912292SN/A            regs.ier = reg;
8922292SN/A            break;
8932292SN/A
8942292SN/A          case IHR:
8954032Sktlim@umich.edu            regs.ihr = reg;
8964032Sktlim@umich.edu            /* not going to implement real interrupt holdoff */
8974032Sktlim@umich.edu            break;
8984032Sktlim@umich.edu
8992292SN/A          case TXDP:
9002292SN/A            regs.txdp = (reg & 0xFFFFFFFC);
9012292SN/A            assert(txState == txIdle);
9022292SN/A            CTDD = false;
9032292SN/A            break;
9042329SN/A
9052292SN/A          case TXDP_HI:
9062292SN/A            regs.txdp_hi = reg;
9072292SN/A            break;
9082292SN/A
9097720Sgblack@eecs.umich.edu          case TX_CFG:
9102292SN/A            regs.txcfg = reg;
9117720Sgblack@eecs.umich.edu#if 0
9122292SN/A            if (reg & TX_CFG_CSI) ;
9132292SN/A            if (reg & TX_CFG_HBI) ;
9142329SN/A            if (reg & TX_CFG_MLB) ;
9152329SN/A            if (reg & TX_CFG_ATP) ;
9162292SN/A            if (reg & TX_CFG_ECRETRY) {
9172292SN/A                /*
9182292SN/A                 * this could easily be implemented, but considering
9192292SN/A                 * the network is just a fake pipe, wouldn't make
9202292SN/A                 * sense to do this
9212292SN/A                 */
9222292SN/A            }
9232329SN/A
9242731Sktlim@umich.edu            if (reg & TX_CFG_BRST_DIS) ;
9252292SN/A#endif
9262292SN/A
9272292SN/A#if 0
9284032Sktlim@umich.edu            /* we handle our own DMA, ignore the kernel's exhortations */
9294032Sktlim@umich.edu            if (reg & TX_CFG_MXDMA) ;
9304032Sktlim@umich.edu#endif
9314032Sktlim@umich.edu
9326974Stjones1@inf.ed.ac.uk            // also, we currently don't care about fill/drain
9336974Stjones1@inf.ed.ac.uk            // thresholds though this may change in the future with
9346974Stjones1@inf.ed.ac.uk            // more realistic networks or a driver which changes it
9356974Stjones1@inf.ed.ac.uk            // according to feedback
9366974Stjones1@inf.ed.ac.uk
9376974Stjones1@inf.ed.ac.uk            break;
9386974Stjones1@inf.ed.ac.uk
9394032Sktlim@umich.edu          case GPIOR:
9402292SN/A            // Only write writable bits
9412292SN/A            regs.gpior &= GPIOR_UNUSED | GPIOR_GP5_IN | GPIOR_GP4_IN
9422292SN/A                        | GPIOR_GP3_IN | GPIOR_GP2_IN | GPIOR_GP1_IN;
9432292SN/A            regs.gpior |= reg & ~(GPIOR_UNUSED | GPIOR_GP5_IN | GPIOR_GP4_IN
9442292SN/A                                | GPIOR_GP3_IN | GPIOR_GP2_IN | GPIOR_GP1_IN);
9452292SN/A            /* these just control general purpose i/o pins, don't matter */
9462292SN/A            break;
9472727Sktlim@umich.edu
9482292SN/A          case RXDP:
9492292SN/A            regs.rxdp = reg;
9502292SN/A            CRDD = false;
9512292SN/A            break;
9522292SN/A
9533349Sbinkertn@umich.edu          case RXDP_HI:
9542693Sktlim@umich.edu            regs.rxdp_hi = reg;
9552693Sktlim@umich.edu            break;
9562693Sktlim@umich.edu
9572693Sktlim@umich.edu          case RX_CFG:
9582693Sktlim@umich.edu            regs.rxcfg = reg;
9592693Sktlim@umich.edu#if 0
9602693Sktlim@umich.edu            if (reg & RX_CFG_AEP) ;
9612693Sktlim@umich.edu            if (reg & RX_CFG_ARP) ;
9622693Sktlim@umich.edu            if (reg & RX_CFG_STRIPCRC) ;
9632693Sktlim@umich.edu            if (reg & RX_CFG_RX_RD) ;
9642693Sktlim@umich.edu            if (reg & RX_CFG_ALP) ;
9652693Sktlim@umich.edu            if (reg & RX_CFG_AIRL) ;
9662693Sktlim@umich.edu
9672693Sktlim@umich.edu            /* we handle our own DMA, ignore what kernel says about it */
9682693Sktlim@umich.edu            if (reg & RX_CFG_MXDMA) ;
9692693Sktlim@umich.edu
9702733Sktlim@umich.edu            //also, we currently don't care about fill/drain thresholds
9712693Sktlim@umich.edu            //though this may change in the future with more realistic
9722732Sktlim@umich.edu            //networks or a driver which changes it according to feedback
9732693Sktlim@umich.edu            if (reg & (RX_CFG_DRTH | RX_CFG_DRTH0)) ;
9742733Sktlim@umich.edu#endif
9752693Sktlim@umich.edu            break;
9762693Sktlim@umich.edu
9772693Sktlim@umich.edu          case PQCR:
9782693Sktlim@umich.edu            /* there is no priority queueing used in the linux 2.6 driver */
9792693Sktlim@umich.edu            regs.pqcr = reg;
9802693Sktlim@umich.edu            break;
9812693Sktlim@umich.edu
9822678Sktlim@umich.edu          case WCSR:
9832678Sktlim@umich.edu            /* not going to implement wake on LAN */
9842678Sktlim@umich.edu            regs.wcsr = reg;
9852678Sktlim@umich.edu            break;
9862678Sktlim@umich.edu
9872678Sktlim@umich.edu          case PCR:
9882927Sktlim@umich.edu            /* not going to implement pause control */
9892678Sktlim@umich.edu            regs.pcr = reg;
9902727Sktlim@umich.edu            break;
9912678Sktlim@umich.edu
9922678Sktlim@umich.edu          case RFCR:
9932678Sktlim@umich.edu            regs.rfcr = reg;
9942678Sktlim@umich.edu
9952678Sktlim@umich.edu            rxFilterEnable = (reg & RFCR_RFEN) ? true : false;
9962678Sktlim@umich.edu            acceptBroadcast = (reg & RFCR_AAB) ? true : false;
9972678Sktlim@umich.edu            acceptMulticast = (reg & RFCR_AAM) ? true : false;
9982678Sktlim@umich.edu            acceptUnicast = (reg & RFCR_AAU) ? true : false;
9992678Sktlim@umich.edu            acceptPerfect = (reg & RFCR_APM) ? true : false;
10002678Sktlim@umich.edu            acceptArp = (reg & RFCR_AARP) ? true : false;
10012678Sktlim@umich.edu            multicastHashEnable = (reg & RFCR_MHEN) ? true : false;
10022678Sktlim@umich.edu
10032678Sktlim@umich.edu#if 0
10042678Sktlim@umich.edu            if (reg & RFCR_APAT)
10057598Sminkyu.jeong@arm.com                panic("RFCR_APAT not implemented!\n");
10067598Sminkyu.jeong@arm.com#endif
10077598Sminkyu.jeong@arm.com            if (reg & RFCR_UHEN)
10082678Sktlim@umich.edu                panic("Unicast hash filtering not used by drivers!\n");
10092678Sktlim@umich.edu
10102678Sktlim@umich.edu            if (reg & RFCR_ULM)
10112678Sktlim@umich.edu                panic("RFCR_ULM not implemented!\n");
10122292SN/A
10132292SN/A            break;
10142292SN/A
10152292SN/A          case RFDR:
10162292SN/A            rfaddr = (uint16_t)(regs.rfcr & RFCR_RFADDR);
10172292SN/A            switch (rfaddr) {
10182292SN/A              case 0x000:
10192292SN/A                rom.perfectMatch[0] = (uint8_t)reg;
10203126Sktlim@umich.edu                rom.perfectMatch[1] = (uint8_t)(reg >> 8);
10212292SN/A                break;
10222292SN/A              case 0x002:
10232292SN/A                rom.perfectMatch[2] = (uint8_t)reg;
10242292SN/A                rom.perfectMatch[3] = (uint8_t)(reg >> 8);
10252292SN/A                break;
10262292SN/A              case 0x004:
10272292SN/A                rom.perfectMatch[4] = (uint8_t)reg;
10282292SN/A                rom.perfectMatch[5] = (uint8_t)(reg >> 8);
10292292SN/A                break;
10302292SN/A              default:
10312292SN/A
10322292SN/A                if (rfaddr >= FHASH_ADDR &&
10332292SN/A                    rfaddr < FHASH_ADDR + FHASH_SIZE) {
10342329SN/A
10352329SN/A                    // Only word-aligned writes supported
10362329SN/A                    if (rfaddr % 2)
10372292SN/A                        panic("unaligned write to filter hash table!");
10382292SN/A
10392292SN/A                    rom.filterHash[rfaddr - FHASH_ADDR] = (uint8_t)reg;
10402292SN/A                    rom.filterHash[rfaddr - FHASH_ADDR + 1]
10412292SN/A                        = (uint8_t)(reg >> 8);
10422292SN/A                    break;
10432292SN/A                }
10442292SN/A                panic("writing RFDR for something other than pattern matching\
10452292SN/A                    or hashing! %#x\n", rfaddr);
10462292SN/A            }
10472316SN/A
10482316SN/A          case BRAR:
10492329SN/A            regs.brar = reg;
10502329SN/A            break;
10512329SN/A
10522329SN/A          case BRDR:
10532733Sktlim@umich.edu            panic("the driver never uses BRDR, something is wrong!\n");
10542316SN/A
10552732Sktlim@umich.edu          case SRR:
10562316SN/A            panic("SRR is read only register!\n");
10572733Sktlim@umich.edu
10582292SN/A          case MIBC:
10592292SN/A            panic("the driver never uses MIBC, something is wrong!\n");
10602292SN/A
10616974Stjones1@inf.ed.ac.uk          case VRCR:
10626974Stjones1@inf.ed.ac.uk            regs.vrcr = reg;
10636974Stjones1@inf.ed.ac.uk            break;
10646974Stjones1@inf.ed.ac.uk
10656974Stjones1@inf.ed.ac.uk          case VTCR:
10666974Stjones1@inf.ed.ac.uk            regs.vtcr = reg;
10676974Stjones1@inf.ed.ac.uk            break;
10686974Stjones1@inf.ed.ac.uk
10696974Stjones1@inf.ed.ac.uk          case VDR:
10706974Stjones1@inf.ed.ac.uk            panic("the driver never uses VDR, something is wrong!\n");
10716974Stjones1@inf.ed.ac.uk
10726974Stjones1@inf.ed.ac.uk          case CCSR:
10736974Stjones1@inf.ed.ac.uk            /* not going to implement clockrun stuff */
10746974Stjones1@inf.ed.ac.uk            regs.ccsr = reg;
10756974Stjones1@inf.ed.ac.uk            break;
10766974Stjones1@inf.ed.ac.uk
10772693Sktlim@umich.edu          case TBICR:
10782693Sktlim@umich.edu            regs.tbicr = reg;
10792693Sktlim@umich.edu            if (reg & TBICR_MR_LOOPBACK)
10802698Sktlim@umich.edu                panic("TBICR_MR_LOOPBACK never used, something wrong!\n");
10814985Sktlim@umich.edu
10822698Sktlim@umich.edu            if (reg & TBICR_MR_AN_ENABLE) {
10832693Sktlim@umich.edu                regs.tanlpar = regs.tanar;
10842698Sktlim@umich.edu                regs.tbisr |= (TBISR_MR_AN_COMPLETE | TBISR_MR_LINK_STATUS);
10856974Stjones1@inf.ed.ac.uk            }
10866974Stjones1@inf.ed.ac.uk
10876974Stjones1@inf.ed.ac.uk#if 0
10886974Stjones1@inf.ed.ac.uk            if (reg & TBICR_MR_RESTART_AN) ;
10896974Stjones1@inf.ed.ac.uk#endif
10906974Stjones1@inf.ed.ac.uk
10916974Stjones1@inf.ed.ac.uk            break;
10922699Sktlim@umich.edu
10932693Sktlim@umich.edu          case TBISR:
10946221Snate@binkert.org            panic("TBISR is read only register!\n");
10956974Stjones1@inf.ed.ac.uk
10966974Stjones1@inf.ed.ac.uk          case TANAR:
10976974Stjones1@inf.ed.ac.uk            // Only write the writable bits
10986974Stjones1@inf.ed.ac.uk            regs.tanar &= TANAR_RF1 | TANAR_RF2 | TANAR_UNUSED;
10996974Stjones1@inf.ed.ac.uk            regs.tanar |= reg & ~(TANAR_RF1 | TANAR_RF2 | TANAR_UNUSED);
11006974Stjones1@inf.ed.ac.uk
11016974Stjones1@inf.ed.ac.uk            // Pause capability unimplemented
11026974Stjones1@inf.ed.ac.uk#if 0
11032693Sktlim@umich.edu            if (reg & TANAR_PS2) ;
11042693Sktlim@umich.edu            if (reg & TANAR_PS1) ;
11052727Sktlim@umich.edu#endif
11062907Sktlim@umich.edu
11072693Sktlim@umich.edu            break;
11082693Sktlim@umich.edu
11092693Sktlim@umich.edu          case TANLPAR:
11102693Sktlim@umich.edu            panic("this should only be written to by the fake phy!\n");
11112693Sktlim@umich.edu
11122693Sktlim@umich.edu          case TANER:
11132693Sktlim@umich.edu            panic("TANER is read only register!\n");
11142693Sktlim@umich.edu
11152693Sktlim@umich.edu          case TESR:
11162693Sktlim@umich.edu            regs.tesr = reg;
11172292SN/A            break;
11182292SN/A
11192292SN/A          default:
11202292SN/A            panic("invalid register access daddr=%#x", daddr);
11212292SN/A        }
11222292SN/A    } else {
11232292SN/A        panic("Invalid Request Size");
11242292SN/A    }
11252292SN/A    pkt->makeAtomicResponse();
11262292SN/A    return pioDelay;
11272292SN/A}
11282292SN/A
11292292SN/Avoid
11302292SN/ANSGigE::devIntrPost(uint32_t interrupts)
11312292SN/A{
11322292SN/A    if (interrupts & ISR_RESERVE)
11332292SN/A        panic("Cannot set a reserved interrupt");
11342292SN/A
11352292SN/A    if (interrupts & ISR_NOIMPL)
11362292SN/A        warn("interrupt not implemented %#x\n", interrupts);
11372292SN/A
11382292SN/A    interrupts &= ISR_IMPL;
11392292SN/A    regs.isr |= interrupts;
11402292SN/A
11412292SN/A    if (interrupts & regs.imr) {
11422292SN/A        if (interrupts & ISR_SWI) {
11432292SN/A            totalSwi++;
11442292SN/A        }
11452292SN/A        if (interrupts & ISR_RXIDLE) {
11462292SN/A            totalRxIdle++;
11472329SN/A        }
11482329SN/A        if (interrupts & ISR_RXOK) {
11492329SN/A            totalRxOk++;
11502329SN/A        }
11512329SN/A        if (interrupts & ISR_RXDESC) {
11522329SN/A            totalRxDesc++;
11532329SN/A        }
11542329SN/A        if (interrupts & ISR_TXOK) {
11552329SN/A            totalTxOk++;
11562329SN/A        }
11572329SN/A        if (interrupts & ISR_TXIDLE) {
11582329SN/A            totalTxIdle++;
11597720Sgblack@eecs.umich.edu        }
11602329SN/A        if (interrupts & ISR_TXDESC) {
11612329SN/A            totalTxDesc++;
11622329SN/A        }
11632329SN/A        if (interrupts & ISR_RXORN) {
11642329SN/A            totalRxOrn++;
11652329SN/A        }
11662329SN/A    }
11672329SN/A
11682329SN/A    DPRINTF(EthernetIntr,
11692329SN/A            "interrupt written to ISR: intr=%#x isr=%#x imr=%#x\n",
11707720Sgblack@eecs.umich.edu            interrupts, regs.isr, regs.imr);
11712329SN/A
11722329SN/A    if ((regs.isr & regs.imr)) {
11732329SN/A        Tick when = curTick;
11742329SN/A        if ((regs.isr & regs.imr & ISR_NODELAY) == 0)
11752329SN/A            when += intrDelay;
11762329SN/A        cpuIntrPost(when);
1177    }
1178}
1179
1180/* writing this interrupt counting stats inside this means that this function
1181   is now limited to being used to clear all interrupts upon the kernel
1182   reading isr and servicing.  just telling you in case you were thinking
1183   of expanding use.
1184*/
1185void
1186NSGigE::devIntrClear(uint32_t interrupts)
1187{
1188    if (interrupts & ISR_RESERVE)
1189        panic("Cannot clear a reserved interrupt");
1190
1191    if (regs.isr & regs.imr & ISR_SWI) {
1192        postedSwi++;
1193    }
1194    if (regs.isr & regs.imr & ISR_RXIDLE) {
1195        postedRxIdle++;
1196    }
1197    if (regs.isr & regs.imr & ISR_RXOK) {
1198        postedRxOk++;
1199    }
1200    if (regs.isr & regs.imr & ISR_RXDESC) {
1201            postedRxDesc++;
1202    }
1203    if (regs.isr & regs.imr & ISR_TXOK) {
1204        postedTxOk++;
1205    }
1206    if (regs.isr & regs.imr & ISR_TXIDLE) {
1207        postedTxIdle++;
1208    }
1209    if (regs.isr & regs.imr & ISR_TXDESC) {
1210        postedTxDesc++;
1211    }
1212    if (regs.isr & regs.imr & ISR_RXORN) {
1213        postedRxOrn++;
1214    }
1215
1216    if (regs.isr & regs.imr & ISR_IMPL)
1217        postedInterrupts++;
1218
1219    interrupts &= ~ISR_NOIMPL;
1220    regs.isr &= ~interrupts;
1221
1222    DPRINTF(EthernetIntr,
1223            "interrupt cleared from ISR: intr=%x isr=%x imr=%x\n",
1224            interrupts, regs.isr, regs.imr);
1225
1226    if (!(regs.isr & regs.imr))
1227        cpuIntrClear();
1228}
1229
1230void
1231NSGigE::devIntrChangeMask()
1232{
1233    DPRINTF(EthernetIntr, "interrupt mask changed: isr=%x imr=%x masked=%x\n",
1234            regs.isr, regs.imr, regs.isr & regs.imr);
1235
1236    if (regs.isr & regs.imr)
1237        cpuIntrPost(curTick);
1238    else
1239        cpuIntrClear();
1240}
1241
1242void
1243NSGigE::cpuIntrPost(Tick when)
1244{
1245    // If the interrupt you want to post is later than an interrupt
1246    // already scheduled, just let it post in the coming one and don't
1247    // schedule another.
1248    // HOWEVER, must be sure that the scheduled intrTick is in the
1249    // future (this was formerly the source of a bug)
1250    /**
1251     * @todo this warning should be removed and the intrTick code should
1252     * be fixed.
1253     */
1254    assert(when >= curTick);
1255    assert(intrTick >= curTick || intrTick == 0);
1256    if (when > intrTick && intrTick != 0) {
1257        DPRINTF(EthernetIntr, "don't need to schedule event...intrTick=%d\n",
1258                intrTick);
1259        return;
1260    }
1261
1262    intrTick = when;
1263    if (intrTick < curTick) {
1264        debug_break();
1265        intrTick = curTick;
1266    }
1267
1268    DPRINTF(EthernetIntr, "going to schedule an interrupt for intrTick=%d\n",
1269            intrTick);
1270
1271    if (intrEvent)
1272        intrEvent->squash();
1273    intrEvent = new IntrEvent(this, intrTick, true);
1274}
1275
1276void
1277NSGigE::cpuInterrupt()
1278{
1279    assert(intrTick == curTick);
1280
1281    // Whether or not there's a pending interrupt, we don't care about
1282    // it anymore
1283    intrEvent = 0;
1284    intrTick = 0;
1285
1286    // Don't send an interrupt if there's already one
1287    if (cpuPendingIntr) {
1288        DPRINTF(EthernetIntr,
1289                "would send an interrupt now, but there's already pending\n");
1290    } else {
1291        // Send interrupt
1292        cpuPendingIntr = true;
1293
1294        DPRINTF(EthernetIntr, "posting interrupt\n");
1295        intrPost();
1296    }
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    txEvent.reschedule(curTick + cycles(1), true);
2313}
2314
2315bool
2316NSGigE::rxFilter(const EthPacketPtr &packet)
2317{
2318    EthPtr eth = packet;
2319    bool drop = true;
2320    string type;
2321
2322    const EthAddr &dst = eth->dst();
2323    if (dst.unicast()) {
2324        // If we're accepting all unicast addresses
2325        if (acceptUnicast)
2326            drop = false;
2327
2328        // If we make a perfect match
2329        if (acceptPerfect && dst == rom.perfectMatch)
2330            drop = false;
2331
2332        if (acceptArp && eth->type() == ETH_TYPE_ARP)
2333            drop = false;
2334
2335    } else if (dst.broadcast()) {
2336        // if we're accepting broadcasts
2337        if (acceptBroadcast)
2338            drop = false;
2339
2340    } else if (dst.multicast()) {
2341        // if we're accepting all multicasts
2342        if (acceptMulticast)
2343            drop = false;
2344
2345        // Multicast hashing faked - all packets accepted
2346        if (multicastHashEnable)
2347            drop = false;
2348    }
2349
2350    if (drop) {
2351        DPRINTF(Ethernet, "rxFilter drop\n");
2352        DDUMP(EthernetData, packet->data, packet->length);
2353    }
2354
2355    return drop;
2356}
2357
2358bool
2359NSGigE::recvPacket(EthPacketPtr packet)
2360{
2361    rxBytes += packet->length;
2362    rxPackets++;
2363
2364    DPRINTF(Ethernet, "Receiving packet from wire, rxFifoAvail=%d\n",
2365            rxFifo.avail());
2366
2367    if (!rxEnable) {
2368        DPRINTF(Ethernet, "receive disabled...packet dropped\n");
2369        return true;
2370    }
2371
2372    if (!rxFilterEnable) {
2373        DPRINTF(Ethernet,
2374            "receive packet filtering disabled . . . packet dropped\n");
2375        return true;
2376    }
2377
2378    if (rxFilter(packet)) {
2379        DPRINTF(Ethernet, "packet filtered...dropped\n");
2380        return true;
2381    }
2382
2383    if (rxFifo.avail() < packet->length) {
2384#if TRACING_ON
2385        IpPtr ip(packet);
2386        TcpPtr tcp(ip);
2387        if (ip) {
2388            DPRINTF(Ethernet,
2389                    "packet won't fit in receive buffer...pkt ID %d dropped\n",
2390                    ip->id());
2391            if (tcp) {
2392                DPRINTF(Ethernet, "Seq=%d\n", tcp->seq());
2393            }
2394        }
2395#endif
2396        droppedPackets++;
2397        devIntrPost(ISR_RXORN);
2398        return false;
2399    }
2400
2401    rxFifo.push(packet);
2402
2403    rxKick();
2404    return true;
2405}
2406
2407
2408void
2409NSGigE::resume()
2410{
2411    SimObject::resume();
2412
2413    // During drain we could have left the state machines in a waiting state and
2414    // they wouldn't get out until some other event occured to kick them.
2415    // This way they'll get out immediately
2416    txKick();
2417    rxKick();
2418}
2419
2420
2421//=====================================================================
2422//
2423//
2424void
2425NSGigE::serialize(ostream &os)
2426{
2427    // Serialize the PciDev base class
2428    PciDev::serialize(os);
2429
2430    /*
2431     * Finalize any DMA events now.
2432     */
2433    // @todo will mem system save pending dma?
2434
2435    /*
2436     * Serialize the device registers
2437     */
2438    SERIALIZE_SCALAR(regs.command);
2439    SERIALIZE_SCALAR(regs.config);
2440    SERIALIZE_SCALAR(regs.mear);
2441    SERIALIZE_SCALAR(regs.ptscr);
2442    SERIALIZE_SCALAR(regs.isr);
2443    SERIALIZE_SCALAR(regs.imr);
2444    SERIALIZE_SCALAR(regs.ier);
2445    SERIALIZE_SCALAR(regs.ihr);
2446    SERIALIZE_SCALAR(regs.txdp);
2447    SERIALIZE_SCALAR(regs.txdp_hi);
2448    SERIALIZE_SCALAR(regs.txcfg);
2449    SERIALIZE_SCALAR(regs.gpior);
2450    SERIALIZE_SCALAR(regs.rxdp);
2451    SERIALIZE_SCALAR(regs.rxdp_hi);
2452    SERIALIZE_SCALAR(regs.rxcfg);
2453    SERIALIZE_SCALAR(regs.pqcr);
2454    SERIALIZE_SCALAR(regs.wcsr);
2455    SERIALIZE_SCALAR(regs.pcr);
2456    SERIALIZE_SCALAR(regs.rfcr);
2457    SERIALIZE_SCALAR(regs.rfdr);
2458    SERIALIZE_SCALAR(regs.brar);
2459    SERIALIZE_SCALAR(regs.brdr);
2460    SERIALIZE_SCALAR(regs.srr);
2461    SERIALIZE_SCALAR(regs.mibc);
2462    SERIALIZE_SCALAR(regs.vrcr);
2463    SERIALIZE_SCALAR(regs.vtcr);
2464    SERIALIZE_SCALAR(regs.vdr);
2465    SERIALIZE_SCALAR(regs.ccsr);
2466    SERIALIZE_SCALAR(regs.tbicr);
2467    SERIALIZE_SCALAR(regs.tbisr);
2468    SERIALIZE_SCALAR(regs.tanar);
2469    SERIALIZE_SCALAR(regs.tanlpar);
2470    SERIALIZE_SCALAR(regs.taner);
2471    SERIALIZE_SCALAR(regs.tesr);
2472
2473    SERIALIZE_ARRAY(rom.perfectMatch, ETH_ADDR_LEN);
2474    SERIALIZE_ARRAY(rom.filterHash, FHASH_SIZE);
2475
2476    SERIALIZE_SCALAR(ioEnable);
2477
2478    /*
2479     * Serialize the data Fifos
2480     */
2481    rxFifo.serialize("rxFifo", os);
2482    txFifo.serialize("txFifo", os);
2483
2484    /*
2485     * Serialize the various helper variables
2486     */
2487    bool txPacketExists = txPacket;
2488    SERIALIZE_SCALAR(txPacketExists);
2489    if (txPacketExists) {
2490        txPacket->length = txPacketBufPtr - txPacket->data;
2491        txPacket->serialize("txPacket", os);
2492        uint32_t txPktBufPtr = (uint32_t) (txPacketBufPtr - txPacket->data);
2493        SERIALIZE_SCALAR(txPktBufPtr);
2494    }
2495
2496    bool rxPacketExists = rxPacket;
2497    SERIALIZE_SCALAR(rxPacketExists);
2498    if (rxPacketExists) {
2499        rxPacket->serialize("rxPacket", os);
2500        uint32_t rxPktBufPtr = (uint32_t) (rxPacketBufPtr - rxPacket->data);
2501        SERIALIZE_SCALAR(rxPktBufPtr);
2502    }
2503
2504    SERIALIZE_SCALAR(txXferLen);
2505    SERIALIZE_SCALAR(rxXferLen);
2506
2507    /*
2508     * Serialize Cached Descriptors
2509     */
2510    SERIALIZE_SCALAR(rxDesc64.link);
2511    SERIALIZE_SCALAR(rxDesc64.bufptr);
2512    SERIALIZE_SCALAR(rxDesc64.cmdsts);
2513    SERIALIZE_SCALAR(rxDesc64.extsts);
2514    SERIALIZE_SCALAR(txDesc64.link);
2515    SERIALIZE_SCALAR(txDesc64.bufptr);
2516    SERIALIZE_SCALAR(txDesc64.cmdsts);
2517    SERIALIZE_SCALAR(txDesc64.extsts);
2518    SERIALIZE_SCALAR(rxDesc32.link);
2519    SERIALIZE_SCALAR(rxDesc32.bufptr);
2520    SERIALIZE_SCALAR(rxDesc32.cmdsts);
2521    SERIALIZE_SCALAR(rxDesc32.extsts);
2522    SERIALIZE_SCALAR(txDesc32.link);
2523    SERIALIZE_SCALAR(txDesc32.bufptr);
2524    SERIALIZE_SCALAR(txDesc32.cmdsts);
2525    SERIALIZE_SCALAR(txDesc32.extsts);
2526    SERIALIZE_SCALAR(extstsEnable);
2527
2528    /*
2529     * Serialize tx state machine
2530     */
2531    int txState = this->txState;
2532    SERIALIZE_SCALAR(txState);
2533    SERIALIZE_SCALAR(txEnable);
2534    SERIALIZE_SCALAR(CTDD);
2535    SERIALIZE_SCALAR(txFragPtr);
2536    SERIALIZE_SCALAR(txDescCnt);
2537    int txDmaState = this->txDmaState;
2538    SERIALIZE_SCALAR(txDmaState);
2539    SERIALIZE_SCALAR(txKickTick);
2540
2541    /*
2542     * Serialize rx state machine
2543     */
2544    int rxState = this->rxState;
2545    SERIALIZE_SCALAR(rxState);
2546    SERIALIZE_SCALAR(rxEnable);
2547    SERIALIZE_SCALAR(CRDD);
2548    SERIALIZE_SCALAR(rxPktBytes);
2549    SERIALIZE_SCALAR(rxFragPtr);
2550    SERIALIZE_SCALAR(rxDescCnt);
2551    int rxDmaState = this->rxDmaState;
2552    SERIALIZE_SCALAR(rxDmaState);
2553    SERIALIZE_SCALAR(rxKickTick);
2554
2555    /*
2556     * Serialize EEPROM state machine
2557     */
2558    int eepromState = this->eepromState;
2559    SERIALIZE_SCALAR(eepromState);
2560    SERIALIZE_SCALAR(eepromClk);
2561    SERIALIZE_SCALAR(eepromBitsToRx);
2562    SERIALIZE_SCALAR(eepromOpcode);
2563    SERIALIZE_SCALAR(eepromAddress);
2564    SERIALIZE_SCALAR(eepromData);
2565
2566    /*
2567     * If there's a pending transmit, store the time so we can
2568     * reschedule it later
2569     */
2570    Tick transmitTick = txEvent.scheduled() ? txEvent.when() - curTick : 0;
2571    SERIALIZE_SCALAR(transmitTick);
2572
2573    /*
2574     * receive address filter settings
2575     */
2576    SERIALIZE_SCALAR(rxFilterEnable);
2577    SERIALIZE_SCALAR(acceptBroadcast);
2578    SERIALIZE_SCALAR(acceptMulticast);
2579    SERIALIZE_SCALAR(acceptUnicast);
2580    SERIALIZE_SCALAR(acceptPerfect);
2581    SERIALIZE_SCALAR(acceptArp);
2582    SERIALIZE_SCALAR(multicastHashEnable);
2583
2584    /*
2585     * Keep track of pending interrupt status.
2586     */
2587    SERIALIZE_SCALAR(intrTick);
2588    SERIALIZE_SCALAR(cpuPendingIntr);
2589    Tick intrEventTick = 0;
2590    if (intrEvent)
2591        intrEventTick = intrEvent->when();
2592    SERIALIZE_SCALAR(intrEventTick);
2593
2594}
2595
2596void
2597NSGigE::unserialize(Checkpoint *cp, const std::string &section)
2598{
2599    // Unserialize the PciDev base class
2600    PciDev::unserialize(cp, section);
2601
2602    UNSERIALIZE_SCALAR(regs.command);
2603    UNSERIALIZE_SCALAR(regs.config);
2604    UNSERIALIZE_SCALAR(regs.mear);
2605    UNSERIALIZE_SCALAR(regs.ptscr);
2606    UNSERIALIZE_SCALAR(regs.isr);
2607    UNSERIALIZE_SCALAR(regs.imr);
2608    UNSERIALIZE_SCALAR(regs.ier);
2609    UNSERIALIZE_SCALAR(regs.ihr);
2610    UNSERIALIZE_SCALAR(regs.txdp);
2611    UNSERIALIZE_SCALAR(regs.txdp_hi);
2612    UNSERIALIZE_SCALAR(regs.txcfg);
2613    UNSERIALIZE_SCALAR(regs.gpior);
2614    UNSERIALIZE_SCALAR(regs.rxdp);
2615    UNSERIALIZE_SCALAR(regs.rxdp_hi);
2616    UNSERIALIZE_SCALAR(regs.rxcfg);
2617    UNSERIALIZE_SCALAR(regs.pqcr);
2618    UNSERIALIZE_SCALAR(regs.wcsr);
2619    UNSERIALIZE_SCALAR(regs.pcr);
2620    UNSERIALIZE_SCALAR(regs.rfcr);
2621    UNSERIALIZE_SCALAR(regs.rfdr);
2622    UNSERIALIZE_SCALAR(regs.brar);
2623    UNSERIALIZE_SCALAR(regs.brdr);
2624    UNSERIALIZE_SCALAR(regs.srr);
2625    UNSERIALIZE_SCALAR(regs.mibc);
2626    UNSERIALIZE_SCALAR(regs.vrcr);
2627    UNSERIALIZE_SCALAR(regs.vtcr);
2628    UNSERIALIZE_SCALAR(regs.vdr);
2629    UNSERIALIZE_SCALAR(regs.ccsr);
2630    UNSERIALIZE_SCALAR(regs.tbicr);
2631    UNSERIALIZE_SCALAR(regs.tbisr);
2632    UNSERIALIZE_SCALAR(regs.tanar);
2633    UNSERIALIZE_SCALAR(regs.tanlpar);
2634    UNSERIALIZE_SCALAR(regs.taner);
2635    UNSERIALIZE_SCALAR(regs.tesr);
2636
2637    UNSERIALIZE_ARRAY(rom.perfectMatch, ETH_ADDR_LEN);
2638    UNSERIALIZE_ARRAY(rom.filterHash, FHASH_SIZE);
2639
2640    UNSERIALIZE_SCALAR(ioEnable);
2641
2642    /*
2643     * unserialize the data fifos
2644     */
2645    rxFifo.unserialize("rxFifo", cp, section);
2646    txFifo.unserialize("txFifo", cp, section);
2647
2648    /*
2649     * unserialize the various helper variables
2650     */
2651    bool txPacketExists;
2652    UNSERIALIZE_SCALAR(txPacketExists);
2653    if (txPacketExists) {
2654        txPacket = new EthPacketData(16384);
2655        txPacket->unserialize("txPacket", cp, section);
2656        uint32_t txPktBufPtr;
2657        UNSERIALIZE_SCALAR(txPktBufPtr);
2658        txPacketBufPtr = (uint8_t *) txPacket->data + txPktBufPtr;
2659    } else
2660        txPacket = 0;
2661
2662    bool rxPacketExists;
2663    UNSERIALIZE_SCALAR(rxPacketExists);
2664    rxPacket = 0;
2665    if (rxPacketExists) {
2666        rxPacket = new EthPacketData(16384);
2667        rxPacket->unserialize("rxPacket", cp, section);
2668        uint32_t rxPktBufPtr;
2669        UNSERIALIZE_SCALAR(rxPktBufPtr);
2670        rxPacketBufPtr = (uint8_t *) rxPacket->data + rxPktBufPtr;
2671    } else
2672        rxPacket = 0;
2673
2674    UNSERIALIZE_SCALAR(txXferLen);
2675    UNSERIALIZE_SCALAR(rxXferLen);
2676
2677    /*
2678     * Unserialize Cached Descriptors
2679     */
2680    UNSERIALIZE_SCALAR(rxDesc64.link);
2681    UNSERIALIZE_SCALAR(rxDesc64.bufptr);
2682    UNSERIALIZE_SCALAR(rxDesc64.cmdsts);
2683    UNSERIALIZE_SCALAR(rxDesc64.extsts);
2684    UNSERIALIZE_SCALAR(txDesc64.link);
2685    UNSERIALIZE_SCALAR(txDesc64.bufptr);
2686    UNSERIALIZE_SCALAR(txDesc64.cmdsts);
2687    UNSERIALIZE_SCALAR(txDesc64.extsts);
2688    UNSERIALIZE_SCALAR(rxDesc32.link);
2689    UNSERIALIZE_SCALAR(rxDesc32.bufptr);
2690    UNSERIALIZE_SCALAR(rxDesc32.cmdsts);
2691    UNSERIALIZE_SCALAR(rxDesc32.extsts);
2692    UNSERIALIZE_SCALAR(txDesc32.link);
2693    UNSERIALIZE_SCALAR(txDesc32.bufptr);
2694    UNSERIALIZE_SCALAR(txDesc32.cmdsts);
2695    UNSERIALIZE_SCALAR(txDesc32.extsts);
2696    UNSERIALIZE_SCALAR(extstsEnable);
2697
2698    /*
2699     * unserialize tx state machine
2700     */
2701    int txState;
2702    UNSERIALIZE_SCALAR(txState);
2703    this->txState = (TxState) txState;
2704    UNSERIALIZE_SCALAR(txEnable);
2705    UNSERIALIZE_SCALAR(CTDD);
2706    UNSERIALIZE_SCALAR(txFragPtr);
2707    UNSERIALIZE_SCALAR(txDescCnt);
2708    int txDmaState;
2709    UNSERIALIZE_SCALAR(txDmaState);
2710    this->txDmaState = (DmaState) txDmaState;
2711    UNSERIALIZE_SCALAR(txKickTick);
2712    if (txKickTick)
2713        txKickEvent.schedule(txKickTick);
2714
2715    /*
2716     * unserialize rx state machine
2717     */
2718    int rxState;
2719    UNSERIALIZE_SCALAR(rxState);
2720    this->rxState = (RxState) rxState;
2721    UNSERIALIZE_SCALAR(rxEnable);
2722    UNSERIALIZE_SCALAR(CRDD);
2723    UNSERIALIZE_SCALAR(rxPktBytes);
2724    UNSERIALIZE_SCALAR(rxFragPtr);
2725    UNSERIALIZE_SCALAR(rxDescCnt);
2726    int rxDmaState;
2727    UNSERIALIZE_SCALAR(rxDmaState);
2728    this->rxDmaState = (DmaState) rxDmaState;
2729    UNSERIALIZE_SCALAR(rxKickTick);
2730    if (rxKickTick)
2731        rxKickEvent.schedule(rxKickTick);
2732
2733    /*
2734     * Unserialize EEPROM state machine
2735     */
2736    int eepromState;
2737    UNSERIALIZE_SCALAR(eepromState);
2738    this->eepromState = (EEPROMState) eepromState;
2739    UNSERIALIZE_SCALAR(eepromClk);
2740    UNSERIALIZE_SCALAR(eepromBitsToRx);
2741    UNSERIALIZE_SCALAR(eepromOpcode);
2742    UNSERIALIZE_SCALAR(eepromAddress);
2743    UNSERIALIZE_SCALAR(eepromData);
2744
2745    /*
2746     * If there's a pending transmit, reschedule it now
2747     */
2748    Tick transmitTick;
2749    UNSERIALIZE_SCALAR(transmitTick);
2750    if (transmitTick)
2751        txEvent.schedule(curTick + transmitTick);
2752
2753    /*
2754     * unserialize receive address filter settings
2755     */
2756    UNSERIALIZE_SCALAR(rxFilterEnable);
2757    UNSERIALIZE_SCALAR(acceptBroadcast);
2758    UNSERIALIZE_SCALAR(acceptMulticast);
2759    UNSERIALIZE_SCALAR(acceptUnicast);
2760    UNSERIALIZE_SCALAR(acceptPerfect);
2761    UNSERIALIZE_SCALAR(acceptArp);
2762    UNSERIALIZE_SCALAR(multicastHashEnable);
2763
2764    /*
2765     * Keep track of pending interrupt status.
2766     */
2767    UNSERIALIZE_SCALAR(intrTick);
2768    UNSERIALIZE_SCALAR(cpuPendingIntr);
2769    Tick intrEventTick;
2770    UNSERIALIZE_SCALAR(intrEventTick);
2771    if (intrEventTick) {
2772        intrEvent = new IntrEvent(this, intrEventTick, true);
2773    }
2774}
2775
2776BEGIN_DECLARE_SIM_OBJECT_PARAMS(NSGigEInt)
2777
2778    SimObjectParam<EtherInt *> peer;
2779    SimObjectParam<NSGigE *> device;
2780
2781END_DECLARE_SIM_OBJECT_PARAMS(NSGigEInt)
2782
2783BEGIN_INIT_SIM_OBJECT_PARAMS(NSGigEInt)
2784
2785    INIT_PARAM_DFLT(peer, "peer interface", NULL),
2786    INIT_PARAM(device, "Ethernet device of this interface")
2787
2788END_INIT_SIM_OBJECT_PARAMS(NSGigEInt)
2789
2790CREATE_SIM_OBJECT(NSGigEInt)
2791{
2792    NSGigEInt *dev_int = new NSGigEInt(getInstanceName(), device);
2793
2794    EtherInt *p = (EtherInt *)peer;
2795    if (p) {
2796        dev_int->setPeer(p);
2797        p->setPeer(dev_int);
2798    }
2799
2800    return dev_int;
2801}
2802
2803REGISTER_SIM_OBJECT("NSGigEInt", NSGigEInt)
2804
2805
2806BEGIN_DECLARE_SIM_OBJECT_PARAMS(NSGigE)
2807
2808    SimObjectParam<System *> system;
2809    SimObjectParam<Platform *> platform;
2810    Param<Tick> min_backoff_delay;
2811    Param<Tick> max_backoff_delay;
2812    SimObjectParam<PciConfigData *> configdata;
2813    Param<uint32_t> pci_bus;
2814    Param<uint32_t> pci_dev;
2815    Param<uint32_t> pci_func;
2816    Param<Tick> pio_latency;
2817    Param<Tick> config_latency;
2818
2819    Param<Tick> clock;
2820    Param<bool> dma_desc_free;
2821    Param<bool> dma_data_free;
2822    Param<Tick> dma_read_delay;
2823    Param<Tick> dma_write_delay;
2824    Param<Tick> dma_read_factor;
2825    Param<Tick> dma_write_factor;
2826    Param<bool> dma_no_allocate;
2827    Param<Tick> intr_delay;
2828
2829    Param<Tick> rx_delay;
2830    Param<Tick> tx_delay;
2831    Param<uint32_t> rx_fifo_size;
2832    Param<uint32_t> tx_fifo_size;
2833
2834    Param<bool> rx_filter;
2835    Param<string> hardware_address;
2836    Param<bool> rx_thread;
2837    Param<bool> tx_thread;
2838    Param<bool> rss;
2839
2840END_DECLARE_SIM_OBJECT_PARAMS(NSGigE)
2841
2842BEGIN_INIT_SIM_OBJECT_PARAMS(NSGigE)
2843
2844    INIT_PARAM(system, "System pointer"),
2845    INIT_PARAM(platform, "Platform pointer"),
2846    INIT_PARAM(min_backoff_delay, "Minimum delay after receving a nack packed"),
2847    INIT_PARAM(max_backoff_delay, "Maximum delay after receving a nack packed"),
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->min_backoff_delay = min_backoff_delay;
2887    params->max_backoff_delay = max_backoff_delay;
2888    params->configData = configdata;
2889    params->busNum = pci_bus;
2890    params->deviceNum = pci_dev;
2891    params->functionNum = pci_func;
2892    params->pio_delay = pio_latency;
2893    params->config_delay = config_latency;
2894
2895    params->clock = clock;
2896    params->dma_desc_free = dma_desc_free;
2897    params->dma_data_free = dma_data_free;
2898    params->dma_read_delay = dma_read_delay;
2899    params->dma_write_delay = dma_write_delay;
2900    params->dma_read_factor = dma_read_factor;
2901    params->dma_write_factor = dma_write_factor;
2902    params->dma_no_allocate = dma_no_allocate;
2903    params->pio_delay = pio_latency;
2904    params->intr_delay = intr_delay;
2905
2906    params->rx_delay = rx_delay;
2907    params->tx_delay = tx_delay;
2908    params->rx_fifo_size = rx_fifo_size;
2909    params->tx_fifo_size = tx_fifo_size;
2910
2911    params->rx_filter = rx_filter;
2912    params->eaddr = hardware_address;
2913    params->rx_thread = rx_thread;
2914    params->tx_thread = tx_thread;
2915    params->rss = rss;
2916
2917    return new NSGigE(params);
2918}
2919
2920REGISTER_SIM_OBJECT("NSGigE", NSGigE)
2921