ns_gige.cc revision 1762
19814Sandreas.hansson@arm.com/*
22292SN/A * Copyright (c) 2004-2005 The Regents of The University of Michigan
310333Smitch.hayenga@arm.com * All rights reserved.
410239Sbinhpham@cs.rutgers.edu *
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
147597Sminkyu.jeong@arm.com * this software without specific prior written permission.
157597Sminkyu.jeong@arm.com *
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
292292SN/A/** @file
302292SN/A * Device module for modelling the National Semiconductor
312292SN/A * DP83820 ethernet controller.  Does not support priority queueing
322292SN/A */
332292SN/A#include <cstdio>
342292SN/A#include <deque>
352292SN/A#include <string>
362292SN/A
372292SN/A#include "base/inet.hh"
382292SN/A#include "cpu/exec_context.hh"
392292SN/A#include "dev/etherlink.hh"
402292SN/A#include "dev/ns_gige.hh"
412689Sktlim@umich.edu#include "dev/pciconfigall.hh"
422689Sktlim@umich.edu#include "mem/bus/bus.hh"
432689Sktlim@umich.edu#include "mem/bus/dma_interface.hh"
442292SN/A#include "mem/bus/pio_interface.hh"
452292SN/A#include "mem/bus/pio_interface_impl.hh"
469944Smatt.horsnell@ARM.com#include "mem/functional/memory_control.hh"
479944Smatt.horsnell@ARM.com#include "mem/functional/physical.hh"
489944Smatt.horsnell@ARM.com#include "sim/builder.hh"
498591Sgblack@eecs.umich.edu#include "sim/debug.hh"
503326Sktlim@umich.edu#include "sim/host.hh"
518229Snate@binkert.org#include "sim/stats.hh"
526658Snate@binkert.org#include "targetarch/vtophys.hh"
538887Sgeoffrey.blake@arm.com
542907Sktlim@umich.educonst char *NsRxStateStrings[] =
552292SN/A{
568232Snate@binkert.org    "rxIdle",
578232Snate@binkert.org    "rxDescRefr",
588232Snate@binkert.org    "rxDescRead",
599527SMatt.Horsnell@arm.com    "rxFifoBlock",
602722Sktlim@umich.edu    "rxFragWrite",
612669Sktlim@umich.edu    "rxDescWrite",
622292SN/A    "rxAdvance"
632669Sktlim@umich.edu};
642678Sktlim@umich.edu
652678Sktlim@umich.educonst char *NsTxStateStrings[] =
668581Ssteve.reinhardt@amd.com{
678581Ssteve.reinhardt@amd.com    "txIdle",
682292SN/A    "txDescRefr",
692292SN/A    "txDescRead",
702292SN/A    "txFifoBlock",
712669Sktlim@umich.edu    "txFragRead",
722292SN/A    "txDescWrite",
732678Sktlim@umich.edu    "txAdvance"
742292SN/A};
759444SAndreas.Sandberg@ARM.com
769444SAndreas.Sandberg@ARM.comconst char *NsDmaState[] =
779444SAndreas.Sandberg@ARM.com{
784319Sktlim@umich.edu    "dmaIdle",
794319Sktlim@umich.edu    "dmaReading",
804319Sktlim@umich.edu    "dmaWriting",
814319Sktlim@umich.edu    "dmaReadWaiting",
824319Sktlim@umich.edu    "dmaWriteWaiting"
832678Sktlim@umich.edu};
842678Sktlim@umich.edu
852292SN/Ausing namespace std;
862678Sktlim@umich.eduusing namespace Net;
872678Sktlim@umich.edu
885336Shines@cs.fsu.edu///////////////////////////////////////////////////////////////////////
892678Sktlim@umich.edu//
904873Sstever@eecs.umich.edu// NSGigE PCI Device
912678Sktlim@umich.edu//
922292SN/ANSGigE::NSGigE(Params *p)
932678Sktlim@umich.edu    : PciDev(p), ioEnable(false),
942678Sktlim@umich.edu      txFifo(p->tx_fifo_size), rxFifo(p->rx_fifo_size),
952678Sktlim@umich.edu      txPacket(0), rxPacket(0), txPacketBufPtr(NULL), rxPacketBufPtr(NULL),
962678Sktlim@umich.edu      txXferLen(0), rxXferLen(0), clock(p->clock),
972678Sktlim@umich.edu      txState(txIdle), txEnable(false), CTDD(false),
982678Sktlim@umich.edu      txFragPtr(0), txDescCnt(0), txDmaState(dmaIdle), rxState(rxIdle),
997852SMatt.Horsnell@arm.com      rxEnable(false), CRDD(false), rxPktBytes(0),
1007852SMatt.Horsnell@arm.com      rxFragPtr(0), rxDescCnt(0), rxDmaState(dmaIdle), extstsEnable(false),
1012344SN/A      rxDmaReadEvent(this), rxDmaWriteEvent(this),
10210333Smitch.hayenga@arm.com      txDmaReadEvent(this), txDmaWriteEvent(this),
10310333Smitch.hayenga@arm.com      dmaDescFree(p->dma_desc_free), dmaDataFree(p->dma_data_free),
10410333Smitch.hayenga@arm.com      txDelay(p->tx_delay), rxDelay(p->rx_delay),
10510333Smitch.hayenga@arm.com      rxKickTick(0), txKickTick(0),
10610333Smitch.hayenga@arm.com      txEvent(this), rxFilterEnable(p->rx_filter), acceptBroadcast(false),
10710333Smitch.hayenga@arm.com      acceptMulticast(false), acceptUnicast(false),
10810333Smitch.hayenga@arm.com      acceptPerfect(false), acceptArp(false),
10910333Smitch.hayenga@arm.com      physmem(p->pmem), intrTick(0), cpuPendingIntr(false),
1102678Sktlim@umich.edu      intrEvent(0), interface(0)
1116974Stjones1@inf.ed.ac.uk{
1126974Stjones1@inf.ed.ac.uk    if (p->header_bus) {
1136974Stjones1@inf.ed.ac.uk        pioInterface = newPioInterface(name(), p->hier,
1146974Stjones1@inf.ed.ac.uk                                       p->header_bus, this,
1156974Stjones1@inf.ed.ac.uk                                       &NSGigE::cacheAccess);
1169444SAndreas.Sandberg@ARM.com
11710327Smitch.hayenga@arm.com        pioLatency = p->pio_latency * p->header_bus->clockRate;
1182678Sktlim@umich.edu
1196974Stjones1@inf.ed.ac.uk        if (p->payload_bus)
1206974Stjones1@inf.ed.ac.uk            dmaInterface = new DMAInterface<Bus>(name() + ".dma",
1216974Stjones1@inf.ed.ac.uk                                                 p->header_bus,
1226974Stjones1@inf.ed.ac.uk                                                 p->payload_bus, 1,
1236974Stjones1@inf.ed.ac.uk                                                 p->dma_no_allocate);
1246974Stjones1@inf.ed.ac.uk        else
1252678Sktlim@umich.edu            dmaInterface = new DMAInterface<Bus>(name() + ".dma",
1262678Sktlim@umich.edu                                                 p->header_bus,
1272678Sktlim@umich.edu                                                 p->header_bus, 1,
1282678Sktlim@umich.edu                                                 p->dma_no_allocate);
1292678Sktlim@umich.edu    } else if (p->payload_bus) {
1302344SN/A        pioInterface = newPioInterface(name(), p->hier,
1312307SN/A                                       p->payload_bus, this,
1326974Stjones1@inf.ed.ac.uk                                       &NSGigE::cacheAccess);
1336974Stjones1@inf.ed.ac.uk
1346974Stjones1@inf.ed.ac.uk        pioLatency = p->pio_latency * p->payload_bus->clockRate;
1356974Stjones1@inf.ed.ac.uk
13610020Smatt.horsnell@ARM.com        dmaInterface = new DMAInterface<Bus>(name() + ".dma",
13710020Smatt.horsnell@ARM.com                                             p->payload_bus,
13810023Smatt.horsnell@ARM.com                                             p->payload_bus, 1,
13910023Smatt.horsnell@ARM.com                                             p->dma_no_allocate);
1402678Sktlim@umich.edu    }
1412292SN/A
1422292SN/A
1432292SN/A    intrDelay = p->intr_delay;
1442292SN/A    dmaReadDelay = p->dma_read_delay;
1458545Ssaidi@eecs.umich.edu    dmaWriteDelay = p->dma_write_delay;
14611243Spau.cabre@metempsy.com    dmaReadFactor = p->dma_read_factor;
14711243Spau.cabre@metempsy.com    dmaWriteFactor = p->dma_write_factor;
1482292SN/A
1492292SN/A    regsReset();
1502292SN/A    memcpy(&rom.perfectMatch, p->eaddr.bytes(), ETH_ADDR_LEN);
1512292SN/A}
1522292SN/A
1535529Snate@binkert.orgNSGigE::~NSGigE()
1545529Snate@binkert.org{}
1555529Snate@binkert.org
1562292SN/Avoid
1574329Sktlim@umich.eduNSGigE::regStats()
1584329Sktlim@umich.edu{
1594329Sktlim@umich.edu    txBytes
1602907Sktlim@umich.edu        .name(name() + ".txBytes")
1612907Sktlim@umich.edu        .desc("Bytes Transmitted")
1622292SN/A        .prereq(txBytes)
1632292SN/A        ;
16410175SMitch.Hayenga@ARM.com
16510175SMitch.Hayenga@ARM.com    rxBytes
1662329SN/A        .name(name() + ".rxBytes")
1672329SN/A        .desc("Bytes Received")
1682329SN/A        .prereq(rxBytes)
1692292SN/A        ;
1709936SFaissal.Sleiman@arm.com
1719936SFaissal.Sleiman@arm.com    txPackets
1729936SFaissal.Sleiman@arm.com        .name(name() + ".txPackets")
1739936SFaissal.Sleiman@arm.com        .desc("Number of Packets Transmitted")
1742292SN/A        .prereq(txBytes)
1752292SN/A        ;
1762292SN/A
1778199SAli.Saidi@ARM.com    rxPackets
1788199SAli.Saidi@ARM.com        .name(name() + ".rxPackets")
1799444SAndreas.Sandberg@ARM.com        .desc("Number of Packets Received")
1809444SAndreas.Sandberg@ARM.com        .prereq(rxBytes)
1819444SAndreas.Sandberg@ARM.com        ;
1829444SAndreas.Sandberg@ARM.com
1839444SAndreas.Sandberg@ARM.com    txIpChecksums
1849444SAndreas.Sandberg@ARM.com        .name(name() + ".txIpChecksums")
1859444SAndreas.Sandberg@ARM.com        .desc("Number of tx IP Checksums done by device")
1869444SAndreas.Sandberg@ARM.com        .precision(0)
1879444SAndreas.Sandberg@ARM.com        .prereq(txBytes)
1889444SAndreas.Sandberg@ARM.com        ;
1899444SAndreas.Sandberg@ARM.com
1909444SAndreas.Sandberg@ARM.com    rxIpChecksums
1918199SAli.Saidi@ARM.com        .name(name() + ".rxIpChecksums")
1922292SN/A        .desc("Number of rx IP Checksums done by device")
1932292SN/A        .precision(0)
1942292SN/A        .prereq(rxBytes)
1952292SN/A        ;
1962292SN/A
1972292SN/A    txTcpChecksums
1983492Sktlim@umich.edu        .name(name() + ".txTcpChecksums")
1992329SN/A        .desc("Number of tx TCP Checksums done by device")
2002292SN/A        .precision(0)
2019444SAndreas.Sandberg@ARM.com        .prereq(txBytes)
2029444SAndreas.Sandberg@ARM.com        ;
2039814Sandreas.hansson@arm.com
2042292SN/A    rxTcpChecksums
2052292SN/A        .name(name() + ".rxTcpChecksums")
2062292SN/A        .desc("Number of rx TCP Checksums done by device")
2072292SN/A        .precision(0)
2082292SN/A        .prereq(rxBytes)
2092292SN/A        ;
2102292SN/A
2112292SN/A    txUdpChecksums
2122292SN/A        .name(name() + ".txUdpChecksums")
21310386Sandreas.hansson@arm.com        .desc("Number of tx UDP Checksums done by device")
2142292SN/A        .precision(0)
2152292SN/A        .prereq(txBytes)
2162292SN/A        ;
2172292SN/A
2182292SN/A    rxUdpChecksums
2192727Sktlim@umich.edu        .name(name() + ".rxUdpChecksums")
2202727Sktlim@umich.edu        .desc("Number of rx UDP Checksums done by device")
2212727Sktlim@umich.edu        .precision(0)
2222727Sktlim@umich.edu        .prereq(rxBytes)
2232727Sktlim@umich.edu        ;
2242727Sktlim@umich.edu
2252727Sktlim@umich.edu    descDmaReads
2262727Sktlim@umich.edu        .name(name() + ".descDMAReads")
2272727Sktlim@umich.edu        .desc("Number of descriptors the device read w/ DMA")
2282727Sktlim@umich.edu        .precision(0)
2292727Sktlim@umich.edu        ;
2302727Sktlim@umich.edu
2312727Sktlim@umich.edu    descDmaWrites
2322727Sktlim@umich.edu        .name(name() + ".descDMAWrites")
2332727Sktlim@umich.edu        .desc("Number of descriptors the device wrote w/ DMA")
2342727Sktlim@umich.edu        .precision(0)
2352727Sktlim@umich.edu        ;
2362727Sktlim@umich.edu
2372361SN/A    descDmaRdBytes
2382361SN/A        .name(name() + ".descDmaReadBytes")
2392361SN/A        .desc("number of descriptor bytes read w/ DMA")
2402361SN/A        .precision(0)
2412727Sktlim@umich.edu        ;
2422727Sktlim@umich.edu
2432727Sktlim@umich.edu   descDmaWrBytes
2442727Sktlim@umich.edu        .name(name() + ".descDmaWriteBytes")
2452727Sktlim@umich.edu        .desc("number of descriptor bytes write w/ DMA")
2462727Sktlim@umich.edu        .precision(0)
2472727Sktlim@umich.edu        ;
2482727Sktlim@umich.edu
2492727Sktlim@umich.edu    txBandwidth
2502727Sktlim@umich.edu        .name(name() + ".txBandwidth")
2512727Sktlim@umich.edu        .desc("Transmit Bandwidth (bits/s)")
2522727Sktlim@umich.edu        .precision(0)
2532727Sktlim@umich.edu        .prereq(txBytes)
2542727Sktlim@umich.edu        ;
2552727Sktlim@umich.edu
2562727Sktlim@umich.edu    rxBandwidth
2572727Sktlim@umich.edu        .name(name() + ".rxBandwidth")
2582727Sktlim@umich.edu        .desc("Receive Bandwidth (bits/s)")
2592727Sktlim@umich.edu        .precision(0)
2602727Sktlim@umich.edu        .prereq(rxBytes)
2612727Sktlim@umich.edu        ;
2622727Sktlim@umich.edu
2632727Sktlim@umich.edu    totBandwidth
2648922Swilliam.wang@arm.com        .name(name() + ".totBandwidth")
2654329Sktlim@umich.edu        .desc("Total Bandwidth (bits/s)")
2664329Sktlim@umich.edu        .precision(0)
2674329Sktlim@umich.edu        .prereq(totBytes)
2684329Sktlim@umich.edu        ;
2694329Sktlim@umich.edu
2704329Sktlim@umich.edu    totPackets
2712292SN/A        .name(name() + ".totPackets")
2722292SN/A        .desc("Total Packets")
2732292SN/A        .precision(0)
2742292SN/A        .prereq(totBytes)
2752292SN/A        ;
2762292SN/A
2772292SN/A    totBytes
2782292SN/A        .name(name() + ".totBytes")
2792292SN/A        .desc("Total Bytes")
2802292SN/A        .precision(0)
2812292SN/A        .prereq(totBytes)
2822292SN/A        ;
2832292SN/A
2842292SN/A    totPacketRate
2859444SAndreas.Sandberg@ARM.com        .name(name() + ".totPPS")
2862307SN/A        .desc("Total Tranmission Rate (packets/s)")
2879444SAndreas.Sandberg@ARM.com        .precision(0)
2882367SN/A        .prereq(totBytes)
2892307SN/A        ;
2902329SN/A
2919444SAndreas.Sandberg@ARM.com    txPacketRate
2922307SN/A        .name(name() + ".txPPS")
2932307SN/A        .desc("Packet Tranmission Rate (packets/s)")
2942307SN/A        .precision(0)
2952307SN/A        .prereq(txBytes)
2962307SN/A        ;
2972307SN/A
2989444SAndreas.Sandberg@ARM.com    rxPacketRate
2992307SN/A        .name(name() + ".rxPPS")
3002307SN/A        .desc("Packet Reception Rate (packets/s)")
3012307SN/A        .precision(0)
3022307SN/A        .prereq(rxBytes)
3032292SN/A        ;
3042292SN/A
3052329SN/A    postedSwi
3062329SN/A        .name(name() + ".postedSwi")
3072292SN/A        .desc("number of software interrupts posted to CPU")
3082329SN/A        .precision(0)
3092329SN/A        ;
3102292SN/A
3112292SN/A    totalSwi
3122292SN/A        .name(name() + ".totalSwi")
3132292SN/A        .desc("number of total Swi written to ISR")
3142292SN/A        .precision(0)
3152329SN/A        ;
3162292SN/A
3172292SN/A    coalescedSwi
3189936SFaissal.Sleiman@arm.com        .name(name() + ".coalescedSwi")
3192292SN/A        .desc("average number of Swi's coalesced into each post")
3202292SN/A        .precision(0)
3212292SN/A        ;
3222292SN/A
3232292SN/A    postedRxIdle
3242292SN/A        .name(name() + ".postedRxIdle")
3252329SN/A        .desc("number of rxIdle interrupts posted to CPU")
3262329SN/A        .precision(0)
3272329SN/A        ;
3282292SN/A
3292292SN/A    totalRxIdle
3302292SN/A        .name(name() + ".totalRxIdle")
3312292SN/A        .desc("number of total RxIdle written to ISR")
3322292SN/A        .precision(0)
3332329SN/A        ;
3342292SN/A
3359936SFaissal.Sleiman@arm.com    coalescedRxIdle
3369936SFaissal.Sleiman@arm.com        .name(name() + ".coalescedRxIdle")
3372292SN/A        .desc("average number of RxIdle's coalesced into each post")
3382292SN/A        .precision(0)
3392292SN/A        ;
3402292SN/A
3412292SN/A    postedRxOk
3422292SN/A        .name(name() + ".postedRxOk")
3432292SN/A        .desc("number of RxOk interrupts posted to CPU")
3442292SN/A        .precision(0)
3452292SN/A        ;
3462292SN/A
3472292SN/A    totalRxOk
3482292SN/A        .name(name() + ".totalRxOk")
3492292SN/A        .desc("number of total RxOk written to ISR")
3502292SN/A        .precision(0)
3512292SN/A        ;
3522292SN/A
3532292SN/A    coalescedRxOk
3542292SN/A        .name(name() + ".coalescedRxOk")
3552292SN/A        .desc("average number of RxOk's coalesced into each post")
3562292SN/A        .precision(0)
3572292SN/A        ;
3582292SN/A
3592292SN/A    postedRxDesc
3602329SN/A        .name(name() + ".postedRxDesc")
3612329SN/A        .desc("number of RxDesc interrupts posted to CPU")
3622292SN/A        .precision(0)
3637720Sgblack@eecs.umich.edu        ;
3647720Sgblack@eecs.umich.edu
3652292SN/A    totalRxDesc
3662292SN/A        .name(name() + ".totalRxDesc")
3672292SN/A        .desc("number of total RxDesc written to ISR")
3682292SN/A        .precision(0)
3692292SN/A        ;
3702292SN/A
3712292SN/A    coalescedRxDesc
3722292SN/A        .name(name() + ".coalescedRxDesc")
3732292SN/A        .desc("average number of RxDesc's coalesced into each post")
3742292SN/A        .precision(0)
3752292SN/A        ;
3762292SN/A
3772292SN/A    postedTxOk
3782292SN/A        .name(name() + ".postedTxOk")
3792292SN/A        .desc("number of TxOk interrupts posted to CPU")
3802292SN/A        .precision(0)
3812292SN/A        ;
3822292SN/A
3832292SN/A    totalTxOk
3842292SN/A        .name(name() + ".totalTxOk")
3852292SN/A        .desc("number of total TxOk written to ISR")
3862292SN/A        .precision(0)
3872292SN/A        ;
3882292SN/A
3897720Sgblack@eecs.umich.edu    coalescedTxOk
3907720Sgblack@eecs.umich.edu        .name(name() + ".coalescedTxOk")
3912292SN/A        .desc("average number of TxOk's coalesced into each post")
3922292SN/A        .precision(0)
3932292SN/A        ;
3942292SN/A
3952292SN/A    postedTxIdle
3962292SN/A        .name(name() + ".postedTxIdle")
3972292SN/A        .desc("number of TxIdle interrupts posted to CPU")
3982292SN/A        .precision(0)
3992292SN/A        ;
4002292SN/A
4012292SN/A    totalTxIdle
4022292SN/A        .name(name() + ".totalTxIdle")
4032292SN/A        .desc("number of total TxIdle written to ISR")
4042292SN/A        .precision(0)
4052292SN/A        ;
4062292SN/A
4072292SN/A    coalescedTxIdle
4082292SN/A        .name(name() + ".coalescedTxIdle")
4092292SN/A        .desc("average number of TxIdle's coalesced into each post")
4102292SN/A        .precision(0)
4112292SN/A        ;
4122292SN/A
4132292SN/A    postedTxDesc
4142292SN/A        .name(name() + ".postedTxDesc")
41510239Sbinhpham@cs.rutgers.edu        .desc("number of TxDesc interrupts posted to CPU")
4162292SN/A        .precision(0)
41710239Sbinhpham@cs.rutgers.edu        ;
41810239Sbinhpham@cs.rutgers.edu
41910239Sbinhpham@cs.rutgers.edu    totalTxDesc
42010239Sbinhpham@cs.rutgers.edu        .name(name() + ".totalTxDesc")
42110239Sbinhpham@cs.rutgers.edu        .desc("number of total TxDesc written to ISR")
4222292SN/A        .precision(0)
42310239Sbinhpham@cs.rutgers.edu        ;
42410239Sbinhpham@cs.rutgers.edu
42510239Sbinhpham@cs.rutgers.edu    coalescedTxDesc
42610239Sbinhpham@cs.rutgers.edu        .name(name() + ".coalescedTxDesc")
42710239Sbinhpham@cs.rutgers.edu        .desc("average number of TxDesc's coalesced into each post")
42810239Sbinhpham@cs.rutgers.edu        .precision(0)
42910239Sbinhpham@cs.rutgers.edu        ;
43010239Sbinhpham@cs.rutgers.edu
43110239Sbinhpham@cs.rutgers.edu    postedRxOrn
43210239Sbinhpham@cs.rutgers.edu        .name(name() + ".postedRxOrn")
4332292SN/A        .desc("number of RxOrn posted to CPU")
4342292SN/A        .precision(0)
4358545Ssaidi@eecs.umich.edu        ;
4368545Ssaidi@eecs.umich.edu
4378545Ssaidi@eecs.umich.edu    totalRxOrn
43811357Sstephan.diestelhorst@arm.com        .name(name() + ".totalRxOrn")
43911357Sstephan.diestelhorst@arm.com        .desc("number of total RxOrn written to ISR")
44011357Sstephan.diestelhorst@arm.com        .precision(0)
4418545Ssaidi@eecs.umich.edu        ;
44210030SAli.Saidi@ARM.com
4438545Ssaidi@eecs.umich.edu    coalescedRxOrn
44411356Skrinat01@arm.com        .name(name() + ".coalescedRxOrn")
44511356Skrinat01@arm.com        .desc("average number of RxOrn's coalesced into each post")
44610030SAli.Saidi@ARM.com        .precision(0)
4479383SAli.Saidi@ARM.com        ;
4489383SAli.Saidi@ARM.com
4499383SAli.Saidi@ARM.com    coalescedTotal
4509383SAli.Saidi@ARM.com        .name(name() + ".coalescedTotal")
4519383SAli.Saidi@ARM.com        .desc("average number of interrupts coalesced into each post")
4529383SAli.Saidi@ARM.com        .precision(0)
4539383SAli.Saidi@ARM.com        ;
45410030SAli.Saidi@ARM.com
45510030SAli.Saidi@ARM.com    postedInterrupts
45610030SAli.Saidi@ARM.com        .name(name() + ".postedInterrupts")
45710030SAli.Saidi@ARM.com        .desc("number of posts to CPU")
45811097Songal@cs.wisc.edu        .precision(0)
45911097Songal@cs.wisc.edu        ;
46011097Songal@cs.wisc.edu
46110030SAli.Saidi@ARM.com    droppedPackets
46211097Songal@cs.wisc.edu        .name(name() + ".droppedPackets")
46311097Songal@cs.wisc.edu        .desc("number of packets dropped")
46411097Songal@cs.wisc.edu        .precision(0)
46510030SAli.Saidi@ARM.com        ;
46610030SAli.Saidi@ARM.com
46710030SAli.Saidi@ARM.com    coalescedSwi = totalSwi / postedInterrupts;
4688545Ssaidi@eecs.umich.edu    coalescedRxIdle = totalRxIdle / postedInterrupts;
4698545Ssaidi@eecs.umich.edu    coalescedRxOk = totalRxOk / postedInterrupts;
4708545Ssaidi@eecs.umich.edu    coalescedRxDesc = totalRxDesc / postedInterrupts;
47110030SAli.Saidi@ARM.com    coalescedTxOk = totalTxOk / postedInterrupts;
4728545Ssaidi@eecs.umich.edu    coalescedTxIdle = totalTxIdle / postedInterrupts;
4738545Ssaidi@eecs.umich.edu    coalescedTxDesc = totalTxDesc / postedInterrupts;
47410149Smarco.elver@ed.ac.uk    coalescedRxOrn = totalRxOrn / postedInterrupts;
47510149Smarco.elver@ed.ac.uk
4768545Ssaidi@eecs.umich.edu    coalescedTotal = (totalSwi + totalRxIdle + totalRxOk + totalRxDesc + totalTxOk
4778545Ssaidi@eecs.umich.edu                      + totalTxIdle + totalTxDesc + totalRxOrn) / postedInterrupts;
4788545Ssaidi@eecs.umich.edu
47910824SAndreas.Sandberg@ARM.com    txBandwidth = txBytes * Stats::constant(8) / simSeconds;
4808545Ssaidi@eecs.umich.edu    rxBandwidth = rxBytes * Stats::constant(8) / simSeconds;
4818545Ssaidi@eecs.umich.edu    totBandwidth = txBandwidth + rxBandwidth;
4828545Ssaidi@eecs.umich.edu    totBytes = txBytes + rxBytes;
4838545Ssaidi@eecs.umich.edu    totPackets = txPackets + rxPackets;
48411097Songal@cs.wisc.edu
48511097Songal@cs.wisc.edu    txPacketRate = txPackets / simSeconds;
48611097Songal@cs.wisc.edu    rxPacketRate = rxPackets / simSeconds;
4878545Ssaidi@eecs.umich.edu}
48811097Songal@cs.wisc.edu
4898545Ssaidi@eecs.umich.edu/**
49011097Songal@cs.wisc.edu * This is to read the PCI general configuration registers
49111097Songal@cs.wisc.edu */
49210149Smarco.elver@ed.ac.ukvoid
49310149Smarco.elver@ed.ac.ukNSGigE::ReadConfig(int offset, int size, uint8_t *data)
49410149Smarco.elver@ed.ac.uk{
49510149Smarco.elver@ed.ac.uk    if (offset < PCI_DEVICE_SPECIFIC)
49610149Smarco.elver@ed.ac.uk        PciDev::ReadConfig(offset, size, data);
49710149Smarco.elver@ed.ac.uk    else
49810149Smarco.elver@ed.ac.uk        panic("Device specific PCI config space not implemented!\n");
4998545Ssaidi@eecs.umich.edu}
50010030SAli.Saidi@ARM.com
5018545Ssaidi@eecs.umich.edu/**
5028545Ssaidi@eecs.umich.edu * This is to write to the PCI general configuration registers
50310474Sandreas.hansson@arm.com */
5048545Ssaidi@eecs.umich.eduvoid
50510030SAli.Saidi@ARM.comNSGigE::WriteConfig(int offset, int size, uint32_t data)
50610030SAli.Saidi@ARM.com{
50710030SAli.Saidi@ARM.com    if (offset < PCI_DEVICE_SPECIFIC)
50810030SAli.Saidi@ARM.com        PciDev::WriteConfig(offset, size, data);
50910030SAli.Saidi@ARM.com    else
51010030SAli.Saidi@ARM.com        panic("Device specific PCI config space not implemented!\n");
51110030SAli.Saidi@ARM.com
51210030SAli.Saidi@ARM.com    // Need to catch writes to BARs to update the PIO interface
51310030SAli.Saidi@ARM.com    switch (offset) {
5148545Ssaidi@eecs.umich.edu        // seems to work fine without all these PCI settings, but i
5158545Ssaidi@eecs.umich.edu        // put in the IO to double check, an assertion will fail if we
5168545Ssaidi@eecs.umich.edu        // need to properly implement it
5179046SAli.Saidi@ARM.com      case PCI_COMMAND:
5188545Ssaidi@eecs.umich.edu        if (config.data[offset] & PCI_CMD_IOSE)
5198545Ssaidi@eecs.umich.edu            ioEnable = true;
5208545Ssaidi@eecs.umich.edu        else
5218545Ssaidi@eecs.umich.edu            ioEnable = false;
5228545Ssaidi@eecs.umich.edu
5238545Ssaidi@eecs.umich.edu#if 0
5248545Ssaidi@eecs.umich.edu        if (config.data[offset] & PCI_CMD_BME) {
5258545Ssaidi@eecs.umich.edu            bmEnabled = true;
5262292SN/A        }
5278199SAli.Saidi@ARM.com        else {
5288199SAli.Saidi@ARM.com            bmEnabled = false;
5298199SAli.Saidi@ARM.com        }
5308199SAli.Saidi@ARM.com
5318199SAli.Saidi@ARM.com        if (config.data[offset] & PCI_CMD_MSE) {
5328199SAli.Saidi@ARM.com            memEnable = true;
5338199SAli.Saidi@ARM.com        }
5348199SAli.Saidi@ARM.com        else {
5358199SAli.Saidi@ARM.com            memEnable = false;
5368199SAli.Saidi@ARM.com        }
5378199SAli.Saidi@ARM.com#endif
5388199SAli.Saidi@ARM.com        break;
53910824SAndreas.Sandberg@ARM.com
5408199SAli.Saidi@ARM.com      case PCI0_BASE_ADDR0:
5418199SAli.Saidi@ARM.com        if (BARAddrs[0] != 0) {
5428199SAli.Saidi@ARM.com            if (pioInterface)
5438199SAli.Saidi@ARM.com                pioInterface->addAddrRange(RangeSize(BARAddrs[0], BARSize[0]));
5448199SAli.Saidi@ARM.com
5458199SAli.Saidi@ARM.com            BARAddrs[0] &= EV5::PAddrUncachedMask;
5468199SAli.Saidi@ARM.com        }
5478199SAli.Saidi@ARM.com        break;
5488272SAli.Saidi@ARM.com      case PCI0_BASE_ADDR1:
5498545Ssaidi@eecs.umich.edu        if (BARAddrs[1] != 0) {
5508545Ssaidi@eecs.umich.edu            if (pioInterface)
5518545Ssaidi@eecs.umich.edu                pioInterface->addAddrRange(RangeSize(BARAddrs[1], BARSize[1]));
5528545Ssaidi@eecs.umich.edu
5539046SAli.Saidi@ARM.com            BARAddrs[1] &= EV5::PAddrUncachedMask;
5548545Ssaidi@eecs.umich.edu        }
5558545Ssaidi@eecs.umich.edu        break;
5568545Ssaidi@eecs.umich.edu    }
5578592Sgblack@eecs.umich.edu}
5588592Sgblack@eecs.umich.edu
5598545Ssaidi@eecs.umich.edu/**
5608199SAli.Saidi@ARM.com * This reads the device registers, which are detailed in the NS83820
5618545Ssaidi@eecs.umich.edu * spec sheet
5628199SAli.Saidi@ARM.com */
56310474Sandreas.hansson@arm.comFault
56410474Sandreas.hansson@arm.comNSGigE::read(MemReqPtr &req, uint8_t *data)
56510474Sandreas.hansson@arm.com{
56610474Sandreas.hansson@arm.com    assert(ioEnable);
5678545Ssaidi@eecs.umich.edu
5688545Ssaidi@eecs.umich.edu    //The mask is to give you only the offset into the device register file
5698199SAli.Saidi@ARM.com    Addr daddr = req->paddr & 0xfff;
5708545Ssaidi@eecs.umich.edu    DPRINTF(EthernetPIO, "read  da=%#x pa=%#x va=%#x size=%d\n",
5718545Ssaidi@eecs.umich.edu            daddr, req->paddr, req->vaddr, req->size);
5729046SAli.Saidi@ARM.com
57310575SMarco.Elver@ARM.com
5748545Ssaidi@eecs.umich.edu    // there are some reserved registers, you can see ns_gige_reg.h and
5758545Ssaidi@eecs.umich.edu    // the spec sheet for details
5768545Ssaidi@eecs.umich.edu    if (daddr > LAST && daddr <=  RESERVED) {
5778545Ssaidi@eecs.umich.edu        panic("Accessing reserved register");
5788545Ssaidi@eecs.umich.edu    } else if (daddr > RESERVED && daddr <= 0x3FC) {
5798545Ssaidi@eecs.umich.edu        ReadConfig(daddr & 0xff, req->size, data);
5808545Ssaidi@eecs.umich.edu        return No_Fault;
5818545Ssaidi@eecs.umich.edu    } else if (daddr >= MIB_START && daddr <= MIB_END) {
5828545Ssaidi@eecs.umich.edu        // don't implement all the MIB's.  hopefully the kernel
5838592Sgblack@eecs.umich.edu        // doesn't actually DEPEND upon their values
5848592Sgblack@eecs.umich.edu        // MIB are just hardware stats keepers
5858592Sgblack@eecs.umich.edu        uint32_t &reg = *(uint32_t *) data;
5868545Ssaidi@eecs.umich.edu        reg = 0;
5878545Ssaidi@eecs.umich.edu        return No_Fault;
5888545Ssaidi@eecs.umich.edu    } else if (daddr > 0x3FC)
5898545Ssaidi@eecs.umich.edu        panic("Something is messed up!\n");
59010474Sandreas.hansson@arm.com
59110474Sandreas.hansson@arm.com    switch (req->size) {
59210474Sandreas.hansson@arm.com      case sizeof(uint32_t):
59310474Sandreas.hansson@arm.com        {
5948545Ssaidi@eecs.umich.edu            uint32_t &reg = *(uint32_t *)data;
5958199SAli.Saidi@ARM.com
5968199SAli.Saidi@ARM.com            switch (daddr) {
5978199SAli.Saidi@ARM.com              case CR:
5988199SAli.Saidi@ARM.com                reg = regs.command;
5998199SAli.Saidi@ARM.com                //these are supposed to be cleared on a read
6008199SAli.Saidi@ARM.com                reg &= ~(CR_RXD | CR_TXD | CR_TXR | CR_RXR);
6018199SAli.Saidi@ARM.com                break;
6028199SAli.Saidi@ARM.com
6038199SAli.Saidi@ARM.com              case CFGR:
6048199SAli.Saidi@ARM.com                reg = regs.config;
6058199SAli.Saidi@ARM.com                break;
6068199SAli.Saidi@ARM.com
6072292SN/A              case MEAR:
6082292SN/A                reg = regs.mear;
6094032Sktlim@umich.edu                break;
6102292SN/A
6112292SN/A              case PTSCR:
6122292SN/A                reg = regs.ptscr;
6137720Sgblack@eecs.umich.edu                break;
6147944SGiacomo.Gabrielli@arm.com
6152292SN/A              case ISR:
6164032Sktlim@umich.edu                reg = regs.isr;
6174032Sktlim@umich.edu                devIntrClear(ISR_ALL);
6182669Sktlim@umich.edu                break;
6192292SN/A
6207944SGiacomo.Gabrielli@arm.com              case IMR:
6217944SGiacomo.Gabrielli@arm.com                reg = regs.imr;
6227944SGiacomo.Gabrielli@arm.com                break;
6237944SGiacomo.Gabrielli@arm.com
6247597Sminkyu.jeong@arm.com              case IER:
6257597Sminkyu.jeong@arm.com                reg = regs.ier;
62610231Ssteve.reinhardt@amd.com                break;
6272329SN/A
62810824SAndreas.Sandberg@ARM.com              case IHR:
62910824SAndreas.Sandberg@ARM.com                reg = regs.ihr;
63010824SAndreas.Sandberg@ARM.com                break;
63110231Ssteve.reinhardt@amd.com
6327848SAli.Saidi@ARM.com              case TXDP:
6337600Sminkyu.jeong@arm.com                reg = regs.txdp;
6347600Sminkyu.jeong@arm.com                break;
6357600Sminkyu.jeong@arm.com
63610824SAndreas.Sandberg@ARM.com              case TXDP_HI:
6373731Sktlim@umich.edu                reg = regs.txdp_hi;
6382367SN/A                break;
6392367SN/A
6402292SN/A              case TX_CFG:
6412292SN/A                reg = regs.txcfg;
64210333Smitch.hayenga@arm.com                break;
6439046SAli.Saidi@ARM.com
6444032Sktlim@umich.edu              case GPIOR:
6454032Sktlim@umich.edu                reg = regs.gpior;
6464032Sktlim@umich.edu                break;
6478199SAli.Saidi@ARM.com
6488199SAli.Saidi@ARM.com              case RXDP:
6492292SN/A                reg = regs.rxdp;
6502292SN/A                break;
6512292SN/A
6522292SN/A              case RXDP_HI:
6532292SN/A                reg = regs.rxdp_hi;
6542292SN/A                break;
6552292SN/A
6562292SN/A              case RX_CFG:
6572292SN/A                reg = regs.rxcfg;
6582292SN/A                break;
6592292SN/A
6602292SN/A              case PQCR:
6612292SN/A                reg = regs.pqcr;
6622292SN/A                break;
6632292SN/A
6647720Sgblack@eecs.umich.edu              case WCSR:
6657720Sgblack@eecs.umich.edu                reg = regs.wcsr;
6662292SN/A                break;
6674032Sktlim@umich.edu
6684032Sktlim@umich.edu              case PCR:
6692292SN/A                reg = regs.pcr;
6702292SN/A                break;
6712292SN/A
6722292SN/A                // see the spec sheet for how RFCR and RFDR work
6732292SN/A                // basically, you write to RFCR to tell the machine
6742292SN/A                // what you want to do next, then you act upon RFDR,
6757944SGiacomo.Gabrielli@arm.com                // and the device will be prepared b/c of what you
6767944SGiacomo.Gabrielli@arm.com                // wrote to RFCR
6777944SGiacomo.Gabrielli@arm.com              case RFCR:
6787944SGiacomo.Gabrielli@arm.com                reg = regs.rfcr;
67910231Ssteve.reinhardt@amd.com                break;
6807848SAli.Saidi@ARM.com
6817848SAli.Saidi@ARM.com              case RFDR:
6822329SN/A                switch (regs.rfcr & RFCR_RFADDR) {
6837782Sminkyu.jeong@arm.com                  case 0x000:
6847720Sgblack@eecs.umich.edu                    reg = rom.perfectMatch[1];
6852292SN/A                    reg = reg << 8;
6862292SN/A                    reg += rom.perfectMatch[0];
68710231Ssteve.reinhardt@amd.com                    break;
6887782Sminkyu.jeong@arm.com                  case 0x002:
6897782Sminkyu.jeong@arm.com                    reg = rom.perfectMatch[3] << 8;
6907782Sminkyu.jeong@arm.com                    reg += rom.perfectMatch[2];
6912292SN/A                    break;
6922292SN/A                  case 0x004:
6932292SN/A                    reg = rom.perfectMatch[5] << 8;
6942292SN/A                    reg += rom.perfectMatch[4];
6952336SN/A                    break;
6962336SN/A                  default:
6972336SN/A                    panic("reading RFDR for something other than PMATCH!\n");
6982329SN/A                    // didn't implement other RFDR functionality b/c
6992292SN/A                    // driver didn't use it
7002329SN/A                }
7012292SN/A                break;
7022292SN/A
7038199SAli.Saidi@ARM.com              case SRR:
7042292SN/A                reg = regs.srr;
7052292SN/A                break;
7062292SN/A
7072292SN/A              case MIBC:
7082292SN/A                reg = regs.mibc;
7092292SN/A                reg &= ~(MIBC_MIBS | MIBC_ACLR);
7102292SN/A                break;
7112292SN/A
7122292SN/A              case VRCR:
7137720Sgblack@eecs.umich.edu                reg = regs.vrcr;
7147720Sgblack@eecs.umich.edu                break;
7152292SN/A
7162292SN/A              case VTCR:
7172292SN/A                reg = regs.vtcr;
7182292SN/A                break;
7192292SN/A
7202292SN/A              case VDR:
7212292SN/A                reg = regs.vdr;
7222292SN/A                break;
7232292SN/A
7242292SN/A              case CCSR:
7252292SN/A                reg = regs.ccsr;
7262292SN/A                break;
7272292SN/A
7282292SN/A              case TBICR:
7292292SN/A                reg = regs.tbicr;
7302292SN/A                break;
7312292SN/A
7322292SN/A              case TBISR:
7332292SN/A                reg = regs.tbisr;
7342292SN/A                break;
7352292SN/A
7362292SN/A              case TANAR:
7372292SN/A                reg = regs.tanar;
7382292SN/A                break;
7392292SN/A
7402292SN/A              case TANLPAR:
7412292SN/A                reg = regs.tanlpar;
7422292SN/A                break;
7432292SN/A
7442329SN/A              case TANER:
7452329SN/A                reg = regs.taner;
7462292SN/A                break;
7472292SN/A
7482292SN/A              case TESR:
7492292SN/A                reg = regs.tesr;
7502292SN/A                break;
7517720Sgblack@eecs.umich.edu
7527720Sgblack@eecs.umich.edu              case M5REG:
7532292SN/A                reg = params()->m5reg;
7542292SN/A                break;
7552292SN/A
7562292SN/A              default:
7572292SN/A                panic("reading unimplemented register: addr=%#x", daddr);
7582292SN/A            }
7592292SN/A
7602292SN/A            DPRINTF(EthernetPIO, "read from %#x: data=%d data=%#x\n",
7612292SN/A                    daddr, reg, reg);
7622292SN/A        }
7632292SN/A        break;
7642292SN/A
7652292SN/A      default:
7666974Stjones1@inf.ed.ac.uk        panic("accessing register with invalid size: addr=%#x, size=%d",
7676974Stjones1@inf.ed.ac.uk              daddr, req->size);
7686974Stjones1@inf.ed.ac.uk    }
7696974Stjones1@inf.ed.ac.uk
7706974Stjones1@inf.ed.ac.uk    return No_Fault;
7716974Stjones1@inf.ed.ac.uk}
7726974Stjones1@inf.ed.ac.uk
7736974Stjones1@inf.ed.ac.ukFault
7746974Stjones1@inf.ed.ac.ukNSGigE::write(MemReqPtr &req, const uint8_t *data)
7756974Stjones1@inf.ed.ac.uk{
7766974Stjones1@inf.ed.ac.uk    assert(ioEnable);
7776974Stjones1@inf.ed.ac.uk
7786974Stjones1@inf.ed.ac.uk    Addr daddr = req->paddr & 0xfff;
7796974Stjones1@inf.ed.ac.uk    DPRINTF(EthernetPIO, "write da=%#x pa=%#x va=%#x size=%d\n",
7806974Stjones1@inf.ed.ac.uk            daddr, req->paddr, req->vaddr, req->size);
7816974Stjones1@inf.ed.ac.uk
7822292SN/A    if (daddr > LAST && daddr <=  RESERVED) {
7832292SN/A        panic("Accessing reserved register");
7846974Stjones1@inf.ed.ac.uk    } else if (daddr > RESERVED && daddr <= 0x3FC) {
7856974Stjones1@inf.ed.ac.uk        WriteConfig(daddr & 0xff, req->size, *(uint32_t *)data);
7866974Stjones1@inf.ed.ac.uk        return No_Fault;
7876974Stjones1@inf.ed.ac.uk    } else if (daddr > 0x3FC)
7886974Stjones1@inf.ed.ac.uk        panic("Something is messed up!\n");
7896974Stjones1@inf.ed.ac.uk
7902292SN/A    if (req->size == sizeof(uint32_t)) {
7912292SN/A        uint32_t reg = *(uint32_t *)data;
7922292SN/A        DPRINTF(EthernetPIO, "write data=%d data=%#x\n", reg, reg);
7932292SN/A
7948727Snilay@cs.wisc.edu        switch (daddr) {
7952292SN/A          case CR:
7962292SN/A            regs.command = reg;
79710333Smitch.hayenga@arm.com            if (reg & CR_TXD) {
7982678Sktlim@umich.edu                txEnable = false;
7992678Sktlim@umich.edu            } else if (reg & CR_TXE) {
8002678Sktlim@umich.edu                txEnable = true;
8012678Sktlim@umich.edu
8022678Sktlim@umich.edu                // the kernel is enabling the transmit machine
8032329SN/A                if (txState == txIdle)
8042329SN/A                    txKick();
8052292SN/A            }
8062292SN/A
8072292SN/A            if (reg & CR_RXD) {
8082292SN/A                rxEnable = false;
8092292SN/A            } else if (reg & CR_RXE) {
8102292SN/A                rxEnable = true;
8112292SN/A
8122678Sktlim@umich.edu                if (rxState == rxIdle)
8132292SN/A                    rxKick();
8142292SN/A            }
8152292SN/A
8162292SN/A            if (reg & CR_TXR)
8172292SN/A                txReset();
8182292SN/A
8192292SN/A            if (reg & CR_RXR)
8202292SN/A                rxReset();
8212292SN/A
8222292SN/A            if (reg & CR_SWI)
8232292SN/A                devIntrPost(ISR_SWI);
8246974Stjones1@inf.ed.ac.uk
8256974Stjones1@inf.ed.ac.uk            if (reg & CR_RST) {
8266974Stjones1@inf.ed.ac.uk                txReset();
8276974Stjones1@inf.ed.ac.uk                rxReset();
8286974Stjones1@inf.ed.ac.uk
8292669Sktlim@umich.edu                regsReset();
8302669Sktlim@umich.edu            }
8312669Sktlim@umich.edu            break;
8328481Sgblack@eecs.umich.edu
8338481Sgblack@eecs.umich.edu          case CFGR:
8348481Sgblack@eecs.umich.edu            if (reg & CFGR_LNKSTS ||
8352292SN/A                reg & CFGR_SPDSTS ||
8362292SN/A                reg & CFGR_DUPSTS ||
8372669Sktlim@umich.edu                reg & CFGR_RESERVED ||
83810031SAli.Saidi@ARM.com                reg & CFGR_T64ADDR ||
8393772Sgblack@eecs.umich.edu                reg & CFGR_PCI64_DET)
84010031SAli.Saidi@ARM.com                panic("writing to read-only or reserved CFGR bits!\n");
84110031SAli.Saidi@ARM.com
84210031SAli.Saidi@ARM.com            regs.config |= reg & ~(CFGR_LNKSTS | CFGR_SPDSTS | CFGR_DUPSTS |
84310031SAli.Saidi@ARM.com                                   CFGR_RESERVED | CFGR_T64ADDR | CFGR_PCI64_DET);
8442669Sktlim@umich.edu
8456974Stjones1@inf.ed.ac.uk// all these #if 0's are because i don't THINK the kernel needs to
8466974Stjones1@inf.ed.ac.uk// have these implemented. if there is a problem relating to one of
8472292SN/A// these, you may need to add functionality in.
8482678Sktlim@umich.edu#if 0
8492678Sktlim@umich.edu            if (reg & CFGR_TBI_EN) ;
8502678Sktlim@umich.edu            if (reg & CFGR_MODE_1000) ;
8512678Sktlim@umich.edu#endif
8526974Stjones1@inf.ed.ac.uk
8536974Stjones1@inf.ed.ac.uk            if (reg & CFGR_AUTO_1000)
8546974Stjones1@inf.ed.ac.uk                panic("CFGR_AUTO_1000 not implemented!\n");
8556974Stjones1@inf.ed.ac.uk
85610342SCurtis.Dunham@arm.com#if 0
8576974Stjones1@inf.ed.ac.uk            if (reg & CFGR_PINT_DUPSTS ||
8586974Stjones1@inf.ed.ac.uk                reg & CFGR_PINT_LNKSTS ||
8596974Stjones1@inf.ed.ac.uk                reg & CFGR_PINT_SPDSTS)
8606974Stjones1@inf.ed.ac.uk                ;
86110342SCurtis.Dunham@arm.com
86210342SCurtis.Dunham@arm.com            if (reg & CFGR_TMRTEST) ;
8636974Stjones1@inf.ed.ac.uk            if (reg & CFGR_MRM_DIS) ;
8646974Stjones1@inf.ed.ac.uk            if (reg & CFGR_MWI_DIS) ;
8656974Stjones1@inf.ed.ac.uk
8666974Stjones1@inf.ed.ac.uk            if (reg & CFGR_T64ADDR)
8676974Stjones1@inf.ed.ac.uk                panic("CFGR_T64ADDR is read only register!\n");
8686974Stjones1@inf.ed.ac.uk
8696974Stjones1@inf.ed.ac.uk            if (reg & CFGR_PCI64_DET)
8706974Stjones1@inf.ed.ac.uk                panic("CFGR_PCI64_DET is read only register!\n");
8716974Stjones1@inf.ed.ac.uk
8726974Stjones1@inf.ed.ac.uk            if (reg & CFGR_DATA64_EN) ;
8736974Stjones1@inf.ed.ac.uk            if (reg & CFGR_M64ADDR) ;
8746974Stjones1@inf.ed.ac.uk            if (reg & CFGR_PHY_RST) ;
8756974Stjones1@inf.ed.ac.uk            if (reg & CFGR_PHY_DIS) ;
8766974Stjones1@inf.ed.ac.uk#endif
8772678Sktlim@umich.edu
8787720Sgblack@eecs.umich.edu            if (reg & CFGR_EXTSTS_EN)
8792292SN/A                extstsEnable = true;
8807720Sgblack@eecs.umich.edu            else
8813797Sgblack@eecs.umich.edu                extstsEnable = false;
8823221Sktlim@umich.edu
8832292SN/A#if 0
8842693Sktlim@umich.edu              if (reg & CFGR_REQALG) ;
8854350Sgblack@eecs.umich.edu              if (reg & CFGR_SB) ;
8866974Stjones1@inf.ed.ac.uk              if (reg & CFGR_POW) ;
8873326Sktlim@umich.edu              if (reg & CFGR_EXD) ;
8883326Sktlim@umich.edu              if (reg & CFGR_PESEL) ;
8893326Sktlim@umich.edu              if (reg & CFGR_BROM_DIS) ;
8909046SAli.Saidi@ARM.com              if (reg & CFGR_EXT_125) ;
89110030SAli.Saidi@ARM.com              if (reg & CFGR_BEM) ;
8929046SAli.Saidi@ARM.com#endif
8933326Sktlim@umich.edu            break;
8943326Sktlim@umich.edu
8953326Sktlim@umich.edu          case MEAR:
8963326Sktlim@umich.edu            regs.mear = reg;
8973326Sktlim@umich.edu            // since phy is completely faked, MEAR_MD* don't matter
8983326Sktlim@umich.edu            // and since the driver never uses MEAR_EE*, they don't
8993326Sktlim@umich.edu            // matter
9007823Ssteve.reinhardt@amd.com#if 0
9018887Sgeoffrey.blake@arm.com            if (reg & MEAR_EEDI) ;
9028887Sgeoffrey.blake@arm.com            if (reg & MEAR_EEDO) ; // this one is read only
9038887Sgeoffrey.blake@arm.com            if (reg & MEAR_EECLK) ;
9048887Sgeoffrey.blake@arm.com            if (reg & MEAR_EESEL) ;
9058887Sgeoffrey.blake@arm.com            if (reg & MEAR_MDIO) ;
9068887Sgeoffrey.blake@arm.com            if (reg & MEAR_MDDIR) ;
9073326Sktlim@umich.edu            if (reg & MEAR_MDC) ;
9083326Sktlim@umich.edu#endif
9093326Sktlim@umich.edu            break;
9102693Sktlim@umich.edu
9112693Sktlim@umich.edu          case PTSCR:
9122693Sktlim@umich.edu            regs.ptscr = reg & ~(PTSCR_RBIST_RDONLY);
9132693Sktlim@umich.edu            // these control BISTs for various parts of chip - we
9142693Sktlim@umich.edu            // don't care or do just fake that the BIST is done
9152693Sktlim@umich.edu            if (reg & PTSCR_RBIST_EN)
9168481Sgblack@eecs.umich.edu                regs.ptscr |= PTSCR_RBIST_DONE;
9178481Sgblack@eecs.umich.edu            if (reg & PTSCR_EEBIST_EN)
9188481Sgblack@eecs.umich.edu                regs.ptscr &= ~PTSCR_EEBIST_EN;
9198481Sgblack@eecs.umich.edu            if (reg & PTSCR_EELOAD_EN)
9208481Sgblack@eecs.umich.edu                regs.ptscr &= ~PTSCR_EELOAD_EN;
9218481Sgblack@eecs.umich.edu            break;
9228481Sgblack@eecs.umich.edu
9238481Sgblack@eecs.umich.edu          case ISR: /* writing to the ISR has no effect */
9248481Sgblack@eecs.umich.edu            panic("ISR is a read only register!\n");
9258481Sgblack@eecs.umich.edu
9268481Sgblack@eecs.umich.edu          case IMR:
9278481Sgblack@eecs.umich.edu            regs.imr = reg;
9288481Sgblack@eecs.umich.edu            devIntrChangeMask();
9298481Sgblack@eecs.umich.edu            break;
9308481Sgblack@eecs.umich.edu
9318481Sgblack@eecs.umich.edu          case IER:
9328481Sgblack@eecs.umich.edu            regs.ier = reg;
9338481Sgblack@eecs.umich.edu            break;
9348481Sgblack@eecs.umich.edu
9358481Sgblack@eecs.umich.edu          case IHR:
9368481Sgblack@eecs.umich.edu            regs.ihr = reg;
9374032Sktlim@umich.edu            /* not going to implement real interrupt holdoff */
9383221Sktlim@umich.edu            break;
9393221Sktlim@umich.edu
9406974Stjones1@inf.ed.ac.uk          case TXDP:
9416974Stjones1@inf.ed.ac.uk            regs.txdp = (reg & 0xFFFFFFFC);
9428481Sgblack@eecs.umich.edu            assert(txState == txIdle);
9436974Stjones1@inf.ed.ac.uk            CTDD = false;
9446974Stjones1@inf.ed.ac.uk            break;
9456974Stjones1@inf.ed.ac.uk
9462669Sktlim@umich.edu          case TXDP_HI:
9476974Stjones1@inf.ed.ac.uk            regs.txdp_hi = reg;
9486974Stjones1@inf.ed.ac.uk            break;
9498481Sgblack@eecs.umich.edu
9506974Stjones1@inf.ed.ac.uk          case TX_CFG:
9516974Stjones1@inf.ed.ac.uk            regs.txcfg = reg;
9526974Stjones1@inf.ed.ac.uk#if 0
9536974Stjones1@inf.ed.ac.uk            if (reg & TX_CFG_CSI) ;
9546974Stjones1@inf.ed.ac.uk            if (reg & TX_CFG_HBI) ;
9556974Stjones1@inf.ed.ac.uk            if (reg & TX_CFG_MLB) ;
9566974Stjones1@inf.ed.ac.uk            if (reg & TX_CFG_ATP) ;
9576974Stjones1@inf.ed.ac.uk            if (reg & TX_CFG_ECRETRY) {
9586974Stjones1@inf.ed.ac.uk                /*
9596974Stjones1@inf.ed.ac.uk                 * this could easily be implemented, but considering
9606974Stjones1@inf.ed.ac.uk                 * the network is just a fake pipe, wouldn't make
9616974Stjones1@inf.ed.ac.uk                 * sense to do this
9626974Stjones1@inf.ed.ac.uk                 */
9636974Stjones1@inf.ed.ac.uk            }
9646974Stjones1@inf.ed.ac.uk
9656974Stjones1@inf.ed.ac.uk            if (reg & TX_CFG_BRST_DIS) ;
9666974Stjones1@inf.ed.ac.uk#endif
9676974Stjones1@inf.ed.ac.uk
9686974Stjones1@inf.ed.ac.uk#if 0
9696974Stjones1@inf.ed.ac.uk            /* we handle our own DMA, ignore the kernel's exhortations */
9706974Stjones1@inf.ed.ac.uk            if (reg & TX_CFG_MXDMA) ;
9716974Stjones1@inf.ed.ac.uk#endif
9726974Stjones1@inf.ed.ac.uk
9736974Stjones1@inf.ed.ac.uk            // also, we currently don't care about fill/drain
9742292SN/A            // thresholds though this may change in the future with
9752292SN/A            // more realistic networks or a driver which changes it
9762292SN/A            // according to feedback
9772292SN/A
9782292SN/A            break;
9792292SN/A
9802292SN/A          case GPIOR:
9812292SN/A            regs.gpior = reg;
9822292SN/A            /* these just control general purpose i/o pins, don't matter */
9832292SN/A            break;
9842292SN/A
9852292SN/A          case RXDP:
9862292SN/A            regs.rxdp = reg;
9872292SN/A            CRDD = false;
9882292SN/A            break;
9892292SN/A
9902292SN/A          case RXDP_HI:
9912292SN/A            regs.rxdp_hi = reg;
9922292SN/A            break;
9932292SN/A
9942292SN/A          case RX_CFG:
9952292SN/A            regs.rxcfg = reg;
9962292SN/A#if 0
9972292SN/A            if (reg & RX_CFG_AEP) ;
9982292SN/A            if (reg & RX_CFG_ARP) ;
9992292SN/A            if (reg & RX_CFG_STRIPCRC) ;
10002292SN/A            if (reg & RX_CFG_RX_RD) ;
10012292SN/A            if (reg & RX_CFG_ALP) ;
10022329SN/A            if (reg & RX_CFG_AIRL) ;
10032292SN/A
10042292SN/A            /* we handle our own DMA, ignore what kernel says about it */
10052292SN/A            if (reg & RX_CFG_MXDMA) ;
10062292SN/A
10072292SN/A            //also, we currently don't care about fill/drain thresholds
10087720Sgblack@eecs.umich.edu            //though this may change in the future with more realistic
10092292SN/A            //networks or a driver which changes it according to feedback
10107720Sgblack@eecs.umich.edu            if (reg & (RX_CFG_DRTH | RX_CFG_DRTH0)) ;
10112292SN/A#endif
10122292SN/A            break;
10132292SN/A
10142292SN/A          case PQCR:
10152292SN/A            /* there is no priority queueing used in the linux 2.6 driver */
10162292SN/A            regs.pqcr = reg;
10172292SN/A            break;
10182292SN/A
10192329SN/A          case WCSR:
10202731Sktlim@umich.edu            /* not going to implement wake on LAN */
10212292SN/A            regs.wcsr = reg;
10222292SN/A            break;
10232292SN/A
10242292SN/A          case PCR:
10252292SN/A            /* not going to implement pause control */
10262292SN/A            regs.pcr = reg;
10272292SN/A            break;
10282727Sktlim@umich.edu
10292292SN/A          case RFCR:
10302292SN/A            regs.rfcr = reg;
10314032Sktlim@umich.edu
10324032Sktlim@umich.edu            rxFilterEnable = (reg & RFCR_RFEN) ? true : false;
10334032Sktlim@umich.edu            acceptBroadcast = (reg & RFCR_AAB) ? true : false;
10344032Sktlim@umich.edu            acceptMulticast = (reg & RFCR_AAM) ? true : false;
10352292SN/A            acceptUnicast = (reg & RFCR_AAU) ? true : false;
10362292SN/A            acceptPerfect = (reg & RFCR_APM) ? true : false;
10372292SN/A            acceptArp = (reg & RFCR_AARP) ? true : false;
10382292SN/A
10392292SN/A#if 0
10402329SN/A            if (reg & RFCR_APAT)
10412292SN/A                panic("RFCR_APAT not implemented!\n");
10422292SN/A#endif
10432292SN/A
10442292SN/A            if (reg & RFCR_MHEN || reg & RFCR_UHEN)
10457720Sgblack@eecs.umich.edu                panic("hash filtering not implemented!\n");
10462292SN/A
10477720Sgblack@eecs.umich.edu            if (reg & RFCR_ULM)
10482292SN/A                panic("RFCR_ULM not implemented!\n");
10492292SN/A
10502329SN/A            break;
10512329SN/A
10522292SN/A          case RFDR:
10532292SN/A            panic("the driver never writes to RFDR, something is wrong!\n");
10542292SN/A
10552292SN/A          case BRAR:
10562292SN/A            panic("the driver never uses BRAR, something is wrong!\n");
10572292SN/A
10582292SN/A          case BRDR:
10592329SN/A            panic("the driver never uses BRDR, something is wrong!\n");
10602731Sktlim@umich.edu
10612292SN/A          case SRR:
10622292SN/A            panic("SRR is read only register!\n");
10632292SN/A
10644032Sktlim@umich.edu          case MIBC:
10654032Sktlim@umich.edu            panic("the driver never uses MIBC, something is wrong!\n");
10664032Sktlim@umich.edu
10674032Sktlim@umich.edu          case VRCR:
10686974Stjones1@inf.ed.ac.uk            regs.vrcr = reg;
10696974Stjones1@inf.ed.ac.uk            break;
10706974Stjones1@inf.ed.ac.uk
10716974Stjones1@inf.ed.ac.uk          case VTCR:
10726974Stjones1@inf.ed.ac.uk            regs.vtcr = reg;
10736974Stjones1@inf.ed.ac.uk            break;
10746974Stjones1@inf.ed.ac.uk
10754032Sktlim@umich.edu          case VDR:
10762292SN/A            panic("the driver never uses VDR, something is wrong!\n");
10772292SN/A            break;
10782292SN/A
10792292SN/A          case CCSR:
10802292SN/A            /* not going to implement clockrun stuff */
10812292SN/A            regs.ccsr = reg;
10822292SN/A            break;
10832727Sktlim@umich.edu
10842292SN/A          case TBICR:
10852292SN/A            regs.tbicr = reg;
10862292SN/A            if (reg & TBICR_MR_LOOPBACK)
10872292SN/A                panic("TBICR_MR_LOOPBACK never used, something wrong!\n");
10882292SN/A
10893349Sbinkertn@umich.edu            if (reg & TBICR_MR_AN_ENABLE) {
10902693Sktlim@umich.edu                regs.tanlpar = regs.tanar;
10912693Sktlim@umich.edu                regs.tbisr |= (TBISR_MR_AN_COMPLETE | TBISR_MR_LINK_STATUS);
10922693Sktlim@umich.edu            }
10932693Sktlim@umich.edu
10942693Sktlim@umich.edu#if 0
10952693Sktlim@umich.edu            if (reg & TBICR_MR_RESTART_AN) ;
10962693Sktlim@umich.edu#endif
10972693Sktlim@umich.edu
10982693Sktlim@umich.edu            break;
10992693Sktlim@umich.edu
11002693Sktlim@umich.edu          case TBISR:
11012693Sktlim@umich.edu            panic("TBISR is read only register!\n");
11022693Sktlim@umich.edu
11032693Sktlim@umich.edu          case TANAR:
11042693Sktlim@umich.edu            regs.tanar = reg;
11052693Sktlim@umich.edu            if (reg & TANAR_PS2)
11068887Sgeoffrey.blake@arm.com                panic("this isn't used in driver, something wrong!\n");
11072693Sktlim@umich.edu
11082732Sktlim@umich.edu            if (reg & TANAR_PS1)
11092693Sktlim@umich.edu                panic("this isn't used in driver, something wrong!\n");
11102693Sktlim@umich.edu            break;
11112693Sktlim@umich.edu
11128727Snilay@cs.wisc.edu          case TANLPAR:
11138727Snilay@cs.wisc.edu            panic("this should only be written to by the fake phy!\n");
11148727Snilay@cs.wisc.edu
11158727Snilay@cs.wisc.edu          case TANER:
11162693Sktlim@umich.edu            panic("TANER is read only register!\n");
11172693Sktlim@umich.edu
11182693Sktlim@umich.edu          case TESR:
11192693Sktlim@umich.edu            regs.tesr = reg;
11202693Sktlim@umich.edu            break;
11212678Sktlim@umich.edu
11222678Sktlim@umich.edu          default:
11232678Sktlim@umich.edu            panic("invalid register access daddr=%#x", daddr);
11242678Sktlim@umich.edu        }
11252678Sktlim@umich.edu    } else {
11262678Sktlim@umich.edu        panic("Invalid Request Size");
11272678Sktlim@umich.edu    }
11282727Sktlim@umich.edu
11292678Sktlim@umich.edu    return No_Fault;
11302678Sktlim@umich.edu}
11312678Sktlim@umich.edu
11322678Sktlim@umich.eduvoid
11332678Sktlim@umich.eduNSGigE::devIntrPost(uint32_t interrupts)
11342678Sktlim@umich.edu{
113510575SMarco.Elver@ARM.com    if (interrupts & ISR_RESERVE)
113610575SMarco.Elver@ARM.com        panic("Cannot set a reserved interrupt");
113710575SMarco.Elver@ARM.com
113810575SMarco.Elver@ARM.com    if (interrupts & ISR_NOIMPL)
113910575SMarco.Elver@ARM.com        warn("interrupt not implemented %#x\n", interrupts);
114010575SMarco.Elver@ARM.com
114110575SMarco.Elver@ARM.com    interrupts &= ~ISR_NOIMPL;
114210575SMarco.Elver@ARM.com    regs.isr |= interrupts;
114310575SMarco.Elver@ARM.com
114410575SMarco.Elver@ARM.com    if (interrupts & regs.imr) {
114510575SMarco.Elver@ARM.com        if (interrupts & ISR_SWI) {
114610575SMarco.Elver@ARM.com            totalSwi++;
114710575SMarco.Elver@ARM.com        }
114810575SMarco.Elver@ARM.com        if (interrupts & ISR_RXIDLE) {
11492678Sktlim@umich.edu            totalRxIdle++;
11502678Sktlim@umich.edu        }
11512678Sktlim@umich.edu        if (interrupts & ISR_RXOK) {
11522678Sktlim@umich.edu            totalRxOk++;
11532678Sktlim@umich.edu        }
11542678Sktlim@umich.edu        if (interrupts & ISR_RXDESC) {
11557598Sminkyu.jeong@arm.com            totalRxDesc++;
11567598Sminkyu.jeong@arm.com        }
11577598Sminkyu.jeong@arm.com        if (interrupts & ISR_TXOK) {
11582678Sktlim@umich.edu            totalTxOk++;
11592678Sktlim@umich.edu        }
11602678Sktlim@umich.edu        if (interrupts & ISR_TXIDLE) {
11612678Sktlim@umich.edu            totalTxIdle++;
11622292SN/A        }
11632292SN/A        if (interrupts & ISR_TXDESC) {
11642292SN/A            totalTxDesc++;
11652292SN/A        }
11662292SN/A        if (interrupts & ISR_RXORN) {
11672292SN/A            totalRxOrn++;
11682292SN/A        }
11692292SN/A    }
11703126Sktlim@umich.edu
11712292SN/A    DPRINTF(EthernetIntr,
11722292SN/A            "interrupt written to ISR: intr=%#x isr=%#x imr=%#x\n",
11732292SN/A            interrupts, regs.isr, regs.imr);
11742292SN/A
11752292SN/A    if ((regs.isr & regs.imr)) {
11762292SN/A        Tick when = curTick;
11772292SN/A        if (!(regs.isr & regs.imr & ISR_NODELAY))
11782292SN/A            when += intrDelay;
11792292SN/A        cpuIntrPost(when);
11802292SN/A    }
11812292SN/A}
11822292SN/A
11832292SN/A/* writing this interrupt counting stats inside this means that this function
11842329SN/A   is now limited to being used to clear all interrupts upon the kernel
11852329SN/A   reading isr and servicing.  just telling you in case you were thinking
11862329SN/A   of expanding use.
11872292SN/A*/
11889527SMatt.Horsnell@arm.comvoid
11899527SMatt.Horsnell@arm.comNSGigE::devIntrClear(uint32_t interrupts)
11909527SMatt.Horsnell@arm.com{
11919527SMatt.Horsnell@arm.com    if (interrupts & ISR_RESERVE)
11929527SMatt.Horsnell@arm.com        panic("Cannot clear a reserved interrupt");
11939527SMatt.Horsnell@arm.com
11949527SMatt.Horsnell@arm.com    if (regs.isr & regs.imr & ISR_SWI) {
11952292SN/A        postedSwi++;
11962292SN/A    }
11972292SN/A    if (regs.isr & regs.imr & ISR_RXIDLE) {
11982292SN/A        postedRxIdle++;
11992292SN/A    }
12002292SN/A    if (regs.isr & regs.imr & ISR_RXOK) {
12012292SN/A        postedRxOk++;
12022292SN/A    }
12032292SN/A    if (regs.isr & regs.imr & ISR_RXDESC) {
12042316SN/A            postedRxDesc++;
12052316SN/A    }
12062329SN/A    if (regs.isr & regs.imr & ISR_TXOK) {
12078727Snilay@cs.wisc.edu        postedTxOk++;
12088727Snilay@cs.wisc.edu    }
12098727Snilay@cs.wisc.edu    if (regs.isr & regs.imr & ISR_TXIDLE) {
12108727Snilay@cs.wisc.edu        postedTxIdle++;
12112329SN/A    }
12122329SN/A    if (regs.isr & regs.imr & ISR_TXDESC) {
12132329SN/A        postedTxDesc++;
12142316SN/A    }
12152732Sktlim@umich.edu    if (regs.isr & regs.imr & ISR_RXORN) {
12162316SN/A        postedRxOrn++;
12172292SN/A    }
12182292SN/A
12192292SN/A    if (regs.isr & regs.imr & (ISR_SWI | ISR_RXIDLE | ISR_RXOK | ISR_RXDESC |
12206974Stjones1@inf.ed.ac.uk                               ISR_TXOK | ISR_TXIDLE | ISR_TXDESC | ISR_RXORN) )
12216974Stjones1@inf.ed.ac.uk        postedInterrupts++;
12226974Stjones1@inf.ed.ac.uk
12238975Sandreas.hansson@arm.com    interrupts &= ~ISR_NOIMPL;
12246974Stjones1@inf.ed.ac.uk    regs.isr &= ~interrupts;
12256974Stjones1@inf.ed.ac.uk
12266974Stjones1@inf.ed.ac.uk    DPRINTF(EthernetIntr,
12276974Stjones1@inf.ed.ac.uk            "interrupt cleared from ISR: intr=%x isr=%x imr=%x\n",
12286974Stjones1@inf.ed.ac.uk            interrupts, regs.isr, regs.imr);
12296974Stjones1@inf.ed.ac.uk
12306974Stjones1@inf.ed.ac.uk    if (!(regs.isr & regs.imr))
12316974Stjones1@inf.ed.ac.uk        cpuIntrClear();
12326974Stjones1@inf.ed.ac.uk}
12336974Stjones1@inf.ed.ac.uk
12346974Stjones1@inf.ed.ac.ukvoid
12352693Sktlim@umich.eduNSGigE::devIntrChangeMask()
12362693Sktlim@umich.edu{
12372693Sktlim@umich.edu    DPRINTF(EthernetIntr, "interrupt mask changed: isr=%x imr=%x masked=%x\n",
12382698Sktlim@umich.edu            regs.isr, regs.imr, regs.isr & regs.imr);
12394985Sktlim@umich.edu
12402698Sktlim@umich.edu    if (regs.isr & regs.imr)
12412693Sktlim@umich.edu        cpuIntrPost(curTick);
12428587Snilay@cs.wisc.edu    else
12438587Snilay@cs.wisc.edu        cpuIntrClear();
12448587Snilay@cs.wisc.edu}
12458975Sandreas.hansson@arm.com
12466974Stjones1@inf.ed.ac.ukvoid
12478133SAli.Saidi@ARM.comNSGigE::cpuIntrPost(Tick when)
12488133SAli.Saidi@ARM.com{
12498133SAli.Saidi@ARM.com    // If the interrupt you want to post is later than an interrupt
12506974Stjones1@inf.ed.ac.uk    // already scheduled, just let it post in the coming one and don't
12516974Stjones1@inf.ed.ac.uk    // schedule another.
12522699Sktlim@umich.edu    // HOWEVER, must be sure that the scheduled intrTick is in the
12532693Sktlim@umich.edu    // future (this was formerly the source of a bug)
12546974Stjones1@inf.ed.ac.uk    /**
12556974Stjones1@inf.ed.ac.uk     * @todo this warning should be removed and the intrTick code should
12566974Stjones1@inf.ed.ac.uk     * be fixed.
12576974Stjones1@inf.ed.ac.uk     */
12586974Stjones1@inf.ed.ac.uk    assert(when >= curTick);
12596974Stjones1@inf.ed.ac.uk    assert(intrTick >= curTick || intrTick == 0);
12606974Stjones1@inf.ed.ac.uk    if (when > intrTick && intrTick != 0) {
12616974Stjones1@inf.ed.ac.uk        DPRINTF(EthernetIntr, "don't need to schedule event...intrTick=%d\n",
12622693Sktlim@umich.edu                intrTick);
12632693Sktlim@umich.edu        return;
12642727Sktlim@umich.edu    }
12652693Sktlim@umich.edu
12662693Sktlim@umich.edu    intrTick = when;
12672693Sktlim@umich.edu    if (intrTick < curTick) {
12682693Sktlim@umich.edu        debug_break();
12692693Sktlim@umich.edu        intrTick = curTick;
12702292SN/A    }
12719440SAndreas.Sandberg@ARM.com
12722292SN/A    DPRINTF(EthernetIntr, "going to schedule an interrupt for intrTick=%d\n",
12732292SN/A            intrTick);
12742292SN/A
12752292SN/A    if (intrEvent)
12762292SN/A        intrEvent->squash();
12772292SN/A    intrEvent = new IntrEvent(this, true);
12782292SN/A    intrEvent->schedule(intrTick);
12799440SAndreas.Sandberg@ARM.com}
12802292SN/A
12812292SN/Avoid
12822292SN/ANSGigE::cpuInterrupt()
12832292SN/A{
12842292SN/A    assert(intrTick == curTick);
12852292SN/A
12862292SN/A    // Whether or not there's a pending interrupt, we don't care about
12879440SAndreas.Sandberg@ARM.com    // it anymore
12882292SN/A    intrEvent = 0;
12892292SN/A    intrTick = 0;
12902292SN/A
12912292SN/A    // Don't send an interrupt if there's already one
12922292SN/A    if (cpuPendingIntr) {
12932292SN/A        DPRINTF(EthernetIntr,
12942292SN/A                "would send an interrupt now, but there's already pending\n");
12959440SAndreas.Sandberg@ARM.com    } else {
12962292SN/A        // Send interrupt
12972292SN/A        cpuPendingIntr = true;
12982292SN/A
12992292SN/A        DPRINTF(EthernetIntr, "posting interrupt\n");
13002329SN/A        intrPost();
13012329SN/A    }
13022329SN/A}
13039440SAndreas.Sandberg@ARM.com
13042329SN/Avoid
13052329SN/ANSGigE::cpuIntrClear()
13062329SN/A{
13072329SN/A    if (!cpuPendingIntr)
13082329SN/A        return;
13092329SN/A
13102329SN/A    if (intrEvent) {
13112329SN/A        intrEvent->squash();
13129440SAndreas.Sandberg@ARM.com        intrEvent = 0;
13139440SAndreas.Sandberg@ARM.com    }
13142329SN/A
13152329SN/A    intrTick = 0;
13162329SN/A
13179440SAndreas.Sandberg@ARM.com    cpuPendingIntr = false;
13182329SN/A
13192329SN/A    DPRINTF(EthernetIntr, "clearing interrupt\n");
13202329SN/A    intrClear();
13212329SN/A}
13222329SN/A
13232329SN/Abool
13242329SN/ANSGigE::cpuIntrPending() const
13259440SAndreas.Sandberg@ARM.com{ return cpuPendingIntr; }
13269440SAndreas.Sandberg@ARM.com
13272329SN/Avoid
13282329SN/ANSGigE::txReset()
13292329SN/A{
13302329SN/A
13312329SN/A    DPRINTF(Ethernet, "transmit reset\n");
13322329SN/A
13339944Smatt.horsnell@ARM.com    CTDD = false;
13349944Smatt.horsnell@ARM.com    txEnable = false;;
1335    txFragPtr = 0;
1336    assert(txDescCnt == 0);
1337    txFifo.clear();
1338    txState = txIdle;
1339    assert(txDmaState == dmaIdle);
1340}
1341
1342void
1343NSGigE::rxReset()
1344{
1345    DPRINTF(Ethernet, "receive reset\n");
1346
1347    CRDD = false;
1348    assert(rxPktBytes == 0);
1349    rxEnable = false;
1350    rxFragPtr = 0;
1351    assert(rxDescCnt == 0);
1352    assert(rxDmaState == dmaIdle);
1353    rxFifo.clear();
1354    rxState = rxIdle;
1355}
1356
1357void
1358NSGigE::regsReset()
1359{
1360    memset(&regs, 0, sizeof(regs));
1361    regs.config = CFGR_LNKSTS;
1362    regs.mear = 0x22;
1363    regs.txcfg = 0x120; // set drain threshold to 1024 bytes and
1364                        // fill threshold to 32 bytes
1365    regs.rxcfg = 0x4;   // set drain threshold to 16 bytes
1366    regs.srr = 0x0103;  // set the silicon revision to rev B or 0x103
1367    regs.mibc = MIBC_FRZ;
1368    regs.vdr = 0x81;    // set the vlan tag type to 802.1q
1369    regs.tesr = 0xc000; // TBI capable of both full and half duplex
1370
1371    extstsEnable = false;
1372    acceptBroadcast = false;
1373    acceptMulticast = false;
1374    acceptUnicast = false;
1375    acceptPerfect = false;
1376    acceptArp = false;
1377}
1378
1379void
1380NSGigE::rxDmaReadCopy()
1381{
1382    assert(rxDmaState == dmaReading);
1383
1384    physmem->dma_read((uint8_t *)rxDmaData, rxDmaAddr, rxDmaLen);
1385    rxDmaState = dmaIdle;
1386
1387    DPRINTF(EthernetDMA, "rx dma read  paddr=%#x len=%d\n",
1388            rxDmaAddr, rxDmaLen);
1389    DDUMP(EthernetDMA, rxDmaData, rxDmaLen);
1390}
1391
1392bool
1393NSGigE::doRxDmaRead()
1394{
1395    assert(rxDmaState == dmaIdle || rxDmaState == dmaReadWaiting);
1396    rxDmaState = dmaReading;
1397
1398    if (dmaInterface && !rxDmaFree) {
1399        if (dmaInterface->busy())
1400            rxDmaState = dmaReadWaiting;
1401        else
1402            dmaInterface->doDMA(Read, rxDmaAddr, rxDmaLen, curTick,
1403                                &rxDmaReadEvent, true);
1404        return true;
1405    }
1406
1407    if (dmaReadDelay == 0 && dmaReadFactor == 0) {
1408        rxDmaReadCopy();
1409        return false;
1410    }
1411
1412    Tick factor = ((rxDmaLen + ULL(63)) >> ULL(6)) * dmaReadFactor;
1413    Tick start = curTick + dmaReadDelay + factor;
1414    rxDmaReadEvent.schedule(start);
1415    return true;
1416}
1417
1418void
1419NSGigE::rxDmaReadDone()
1420{
1421    assert(rxDmaState == dmaReading);
1422    rxDmaReadCopy();
1423
1424    // If the transmit state machine has a pending DMA, let it go first
1425    if (txDmaState == dmaReadWaiting || txDmaState == dmaWriteWaiting)
1426        txKick();
1427
1428    rxKick();
1429}
1430
1431void
1432NSGigE::rxDmaWriteCopy()
1433{
1434    assert(rxDmaState == dmaWriting);
1435
1436    physmem->dma_write(rxDmaAddr, (uint8_t *)rxDmaData, rxDmaLen);
1437    rxDmaState = dmaIdle;
1438
1439    DPRINTF(EthernetDMA, "rx dma write paddr=%#x len=%d\n",
1440            rxDmaAddr, rxDmaLen);
1441    DDUMP(EthernetDMA, rxDmaData, rxDmaLen);
1442}
1443
1444bool
1445NSGigE::doRxDmaWrite()
1446{
1447    assert(rxDmaState == dmaIdle || rxDmaState == dmaWriteWaiting);
1448    rxDmaState = dmaWriting;
1449
1450    if (dmaInterface && !rxDmaFree) {
1451        if (dmaInterface->busy())
1452            rxDmaState = dmaWriteWaiting;
1453        else
1454            dmaInterface->doDMA(WriteInvalidate, rxDmaAddr, rxDmaLen, curTick,
1455                                &rxDmaWriteEvent, true);
1456        return true;
1457    }
1458
1459    if (dmaWriteDelay == 0 && dmaWriteFactor == 0) {
1460        rxDmaWriteCopy();
1461        return false;
1462    }
1463
1464    Tick factor = ((rxDmaLen + ULL(63)) >> ULL(6)) * dmaWriteFactor;
1465    Tick start = curTick + dmaWriteDelay + factor;
1466    rxDmaWriteEvent.schedule(start);
1467    return true;
1468}
1469
1470void
1471NSGigE::rxDmaWriteDone()
1472{
1473    assert(rxDmaState == dmaWriting);
1474    rxDmaWriteCopy();
1475
1476    // If the transmit state machine has a pending DMA, let it go first
1477    if (txDmaState == dmaReadWaiting || txDmaState == dmaWriteWaiting)
1478        txKick();
1479
1480    rxKick();
1481}
1482
1483void
1484NSGigE::rxKick()
1485{
1486    DPRINTF(EthernetSM, "receive kick rxState=%s (rxBuf.size=%d)\n",
1487            NsRxStateStrings[rxState], rxFifo.size());
1488
1489    if (rxKickTick > curTick) {
1490        DPRINTF(EthernetSM, "receive kick exiting, can't run till %d\n",
1491                rxKickTick);
1492        return;
1493    }
1494
1495  next:
1496    switch(rxDmaState) {
1497      case dmaReadWaiting:
1498        if (doRxDmaRead())
1499            goto exit;
1500        break;
1501      case dmaWriteWaiting:
1502        if (doRxDmaWrite())
1503            goto exit;
1504        break;
1505      default:
1506        break;
1507    }
1508
1509    // see state machine from spec for details
1510    // the way this works is, if you finish work on one state and can
1511    // go directly to another, you do that through jumping to the
1512    // label "next".  however, if you have intermediate work, like DMA
1513    // so that you can't go to the next state yet, you go to exit and
1514    // exit the loop.  however, when the DMA is done it will trigger
1515    // an event and come back to this loop.
1516    switch (rxState) {
1517      case rxIdle:
1518        if (!rxEnable) {
1519            DPRINTF(EthernetSM, "Receive Disabled! Nothing to do.\n");
1520            goto exit;
1521        }
1522
1523        if (CRDD) {
1524            rxState = rxDescRefr;
1525
1526            rxDmaAddr = regs.rxdp & 0x3fffffff;
1527            rxDmaData = &rxDescCache + offsetof(ns_desc, link);
1528            rxDmaLen = sizeof(rxDescCache.link);
1529            rxDmaFree = dmaDescFree;
1530
1531            descDmaReads++;
1532            descDmaRdBytes += rxDmaLen;
1533
1534            if (doRxDmaRead())
1535                goto exit;
1536        } else {
1537            rxState = rxDescRead;
1538
1539            rxDmaAddr = regs.rxdp & 0x3fffffff;
1540            rxDmaData = &rxDescCache;
1541            rxDmaLen = sizeof(ns_desc);
1542            rxDmaFree = dmaDescFree;
1543
1544            descDmaReads++;
1545            descDmaRdBytes += rxDmaLen;
1546
1547            if (doRxDmaRead())
1548                goto exit;
1549        }
1550        break;
1551
1552      case rxDescRefr:
1553        if (rxDmaState != dmaIdle)
1554            goto exit;
1555
1556        rxState = rxAdvance;
1557        break;
1558
1559     case rxDescRead:
1560        if (rxDmaState != dmaIdle)
1561            goto exit;
1562
1563        DPRINTF(EthernetDesc,
1564                "rxDescCache: addr=%08x read descriptor\n",
1565                regs.rxdp & 0x3fffffff);
1566        DPRINTF(EthernetDesc,
1567                "rxDescCache: link=%08x bufptr=%08x cmdsts=%08x extsts=%08x\n",
1568                rxDescCache.link, rxDescCache.bufptr, rxDescCache.cmdsts,
1569                rxDescCache.extsts);
1570
1571        if (rxDescCache.cmdsts & CMDSTS_OWN) {
1572            devIntrPost(ISR_RXIDLE);
1573            rxState = rxIdle;
1574            goto exit;
1575        } else {
1576            rxState = rxFifoBlock;
1577            rxFragPtr = rxDescCache.bufptr;
1578            rxDescCnt = rxDescCache.cmdsts & CMDSTS_LEN_MASK;
1579        }
1580        break;
1581
1582      case rxFifoBlock:
1583        if (!rxPacket) {
1584            /**
1585             * @todo in reality, we should be able to start processing
1586             * the packet as it arrives, and not have to wait for the
1587             * full packet ot be in the receive fifo.
1588             */
1589            if (rxFifo.empty())
1590                goto exit;
1591
1592            DPRINTF(EthernetSM, "****processing receive of new packet****\n");
1593
1594            // If we don't have a packet, grab a new one from the fifo.
1595            rxPacket = rxFifo.front();
1596            rxPktBytes = rxPacket->length;
1597            rxPacketBufPtr = rxPacket->data;
1598
1599#if TRACING_ON
1600            if (DTRACE(Ethernet)) {
1601                IpPtr ip(rxPacket);
1602                if (ip) {
1603                    DPRINTF(Ethernet, "ID is %d\n", ip->id());
1604                    TcpPtr tcp(ip);
1605                    if (tcp) {
1606                        DPRINTF(Ethernet,
1607                                "Src Port=%d, Dest Port=%d, Seq=%d, Ack=%d\n",
1608                                tcp->sport(), tcp->dport(), tcp->seq(),
1609                                tcp->ack());
1610                    }
1611                }
1612            }
1613#endif
1614
1615            // sanity check - i think the driver behaves like this
1616            assert(rxDescCnt >= rxPktBytes);
1617            rxFifo.pop();
1618        }
1619
1620
1621        // dont' need the && rxDescCnt > 0 if driver sanity check
1622        // above holds
1623        if (rxPktBytes > 0) {
1624            rxState = rxFragWrite;
1625            // don't need min<>(rxPktBytes,rxDescCnt) if above sanity
1626            // check holds
1627            rxXferLen = rxPktBytes;
1628
1629            rxDmaAddr = rxFragPtr & 0x3fffffff;
1630            rxDmaData = rxPacketBufPtr;
1631            rxDmaLen = rxXferLen;
1632            rxDmaFree = dmaDataFree;
1633
1634            if (doRxDmaWrite())
1635                goto exit;
1636
1637        } else {
1638            rxState = rxDescWrite;
1639
1640            //if (rxPktBytes == 0) {  /* packet is done */
1641            assert(rxPktBytes == 0);
1642            DPRINTF(EthernetSM, "done with receiving packet\n");
1643
1644            rxDescCache.cmdsts |= CMDSTS_OWN;
1645            rxDescCache.cmdsts &= ~CMDSTS_MORE;
1646            rxDescCache.cmdsts |= CMDSTS_OK;
1647            rxDescCache.cmdsts &= 0xffff0000;
1648            rxDescCache.cmdsts += rxPacket->length;   //i.e. set CMDSTS_SIZE
1649
1650#if 0
1651            /*
1652             * all the driver uses these are for its own stats keeping
1653             * which we don't care about, aren't necessary for
1654             * functionality and doing this would just slow us down.
1655             * if they end up using this in a later version for
1656             * functional purposes, just undef
1657             */
1658            if (rxFilterEnable) {
1659                rxDescCache.cmdsts &= ~CMDSTS_DEST_MASK;
1660                const EthAddr &dst = rxFifoFront()->dst();
1661                if (dst->unicast())
1662                    rxDescCache.cmdsts |= CMDSTS_DEST_SELF;
1663                if (dst->multicast())
1664                    rxDescCache.cmdsts |= CMDSTS_DEST_MULTI;
1665                if (dst->broadcast())
1666                    rxDescCache.cmdsts |= CMDSTS_DEST_MASK;
1667            }
1668#endif
1669
1670            IpPtr ip(rxPacket);
1671            if (extstsEnable && ip) {
1672                rxDescCache.extsts |= EXTSTS_IPPKT;
1673                rxIpChecksums++;
1674                if (cksum(ip) != 0) {
1675                    DPRINTF(EthernetCksum, "Rx IP Checksum Error\n");
1676                    rxDescCache.extsts |= EXTSTS_IPERR;
1677                }
1678                TcpPtr tcp(ip);
1679                UdpPtr udp(ip);
1680                if (tcp) {
1681                    rxDescCache.extsts |= EXTSTS_TCPPKT;
1682                    rxTcpChecksums++;
1683                    if (cksum(tcp) != 0) {
1684                        DPRINTF(EthernetCksum, "Rx TCP Checksum Error\n");
1685                        rxDescCache.extsts |= EXTSTS_TCPERR;
1686
1687                    }
1688                } else if (udp) {
1689                    rxDescCache.extsts |= EXTSTS_UDPPKT;
1690                    rxUdpChecksums++;
1691                    if (cksum(udp) != 0) {
1692                        DPRINTF(EthernetCksum, "Rx UDP Checksum Error\n");
1693                        rxDescCache.extsts |= EXTSTS_UDPERR;
1694                    }
1695                }
1696            }
1697            rxPacket = 0;
1698
1699            /*
1700             * the driver seems to always receive into desc buffers
1701             * of size 1514, so you never have a pkt that is split
1702             * into multiple descriptors on the receive side, so
1703             * i don't implement that case, hence the assert above.
1704             */
1705
1706            DPRINTF(EthernetDesc,
1707                    "rxDescCache: addr=%08x writeback cmdsts extsts\n",
1708                    regs.rxdp & 0x3fffffff);
1709            DPRINTF(EthernetDesc,
1710                    "rxDescCache: link=%08x bufptr=%08x cmdsts=%08x extsts=%08x\n",
1711                    rxDescCache.link, rxDescCache.bufptr, rxDescCache.cmdsts,
1712                    rxDescCache.extsts);
1713
1714            rxDmaAddr = (regs.rxdp + offsetof(ns_desc, cmdsts)) & 0x3fffffff;
1715            rxDmaData = &(rxDescCache.cmdsts);
1716            rxDmaLen = sizeof(rxDescCache.cmdsts) + sizeof(rxDescCache.extsts);
1717            rxDmaFree = dmaDescFree;
1718
1719            descDmaWrites++;
1720            descDmaWrBytes += rxDmaLen;
1721
1722            if (doRxDmaWrite())
1723                goto exit;
1724        }
1725        break;
1726
1727      case rxFragWrite:
1728        if (rxDmaState != dmaIdle)
1729            goto exit;
1730
1731        rxPacketBufPtr += rxXferLen;
1732        rxFragPtr += rxXferLen;
1733        rxPktBytes -= rxXferLen;
1734
1735        rxState = rxFifoBlock;
1736        break;
1737
1738      case rxDescWrite:
1739        if (rxDmaState != dmaIdle)
1740            goto exit;
1741
1742        assert(rxDescCache.cmdsts & CMDSTS_OWN);
1743
1744        assert(rxPacket == 0);
1745        devIntrPost(ISR_RXOK);
1746
1747        if (rxDescCache.cmdsts & CMDSTS_INTR)
1748            devIntrPost(ISR_RXDESC);
1749
1750        if (!rxEnable) {
1751            DPRINTF(EthernetSM, "Halting the RX state machine\n");
1752            rxState = rxIdle;
1753            goto exit;
1754        } else
1755            rxState = rxAdvance;
1756        break;
1757
1758      case rxAdvance:
1759        if (rxDescCache.link == 0) {
1760            devIntrPost(ISR_RXIDLE);
1761            rxState = rxIdle;
1762            CRDD = true;
1763            goto exit;
1764        } else {
1765            rxState = rxDescRead;
1766            regs.rxdp = rxDescCache.link;
1767            CRDD = false;
1768
1769            rxDmaAddr = regs.rxdp & 0x3fffffff;
1770            rxDmaData = &rxDescCache;
1771            rxDmaLen = sizeof(ns_desc);
1772            rxDmaFree = dmaDescFree;
1773
1774            if (doRxDmaRead())
1775                goto exit;
1776        }
1777        break;
1778
1779      default:
1780        panic("Invalid rxState!");
1781    }
1782
1783    DPRINTF(EthernetSM, "entering next rxState=%s\n",
1784            NsRxStateStrings[rxState]);
1785
1786    goto next;
1787
1788  exit:
1789    /**
1790     * @todo do we want to schedule a future kick?
1791     */
1792    DPRINTF(EthernetSM, "rx state machine exited rxState=%s\n",
1793            NsRxStateStrings[rxState]);
1794}
1795
1796void
1797NSGigE::transmit()
1798{
1799    if (txFifo.empty()) {
1800        DPRINTF(Ethernet, "nothing to transmit\n");
1801        return;
1802    }
1803
1804    DPRINTF(Ethernet, "Attempt Pkt Transmit: txFifo length=%d\n",
1805            txFifo.size());
1806    if (interface->sendPacket(txFifo.front())) {
1807#if TRACING_ON
1808        if (DTRACE(Ethernet)) {
1809            IpPtr ip(txFifo.front());
1810            if (ip) {
1811                DPRINTF(Ethernet, "ID is %d\n", ip->id());
1812                TcpPtr tcp(ip);
1813                if (tcp) {
1814                    DPRINTF(Ethernet,
1815                            "Src Port=%d, Dest Port=%d, Seq=%d, Ack=%d\n",
1816                            tcp->sport(), tcp->dport(), tcp->seq(), tcp->ack());
1817                }
1818            }
1819        }
1820#endif
1821
1822        DDUMP(EthernetData, txFifo.front()->data, txFifo.front()->length);
1823        txBytes += txFifo.front()->length;
1824        txPackets++;
1825
1826        DPRINTF(Ethernet, "Successful Xmit! now txFifoAvail is %d\n",
1827                txFifo.avail());
1828        txFifo.pop();
1829
1830        /*
1831         * normally do a writeback of the descriptor here, and ONLY
1832         * after that is done, send this interrupt.  but since our
1833         * stuff never actually fails, just do this interrupt here,
1834         * otherwise the code has to stray from this nice format.
1835         * besides, it's functionally the same.
1836         */
1837        devIntrPost(ISR_TXOK);
1838    }
1839
1840   if (!txFifo.empty() && !txEvent.scheduled()) {
1841       DPRINTF(Ethernet, "reschedule transmit\n");
1842       txEvent.schedule(curTick + retryTime);
1843   }
1844}
1845
1846void
1847NSGigE::txDmaReadCopy()
1848{
1849    assert(txDmaState == dmaReading);
1850
1851    physmem->dma_read((uint8_t *)txDmaData, txDmaAddr, txDmaLen);
1852    txDmaState = dmaIdle;
1853
1854    DPRINTF(EthernetDMA, "tx dma read  paddr=%#x len=%d\n",
1855            txDmaAddr, txDmaLen);
1856    DDUMP(EthernetDMA, txDmaData, txDmaLen);
1857}
1858
1859bool
1860NSGigE::doTxDmaRead()
1861{
1862    assert(txDmaState == dmaIdle || txDmaState == dmaReadWaiting);
1863    txDmaState = dmaReading;
1864
1865    if (dmaInterface && !txDmaFree) {
1866        if (dmaInterface->busy())
1867            txDmaState = dmaReadWaiting;
1868        else
1869            dmaInterface->doDMA(Read, txDmaAddr, txDmaLen, curTick,
1870                                &txDmaReadEvent, true);
1871        return true;
1872    }
1873
1874    if (dmaReadDelay == 0 && dmaReadFactor == 0.0) {
1875        txDmaReadCopy();
1876        return false;
1877    }
1878
1879    Tick factor = ((txDmaLen + ULL(63)) >> ULL(6)) * dmaReadFactor;
1880    Tick start = curTick + dmaReadDelay + factor;
1881    txDmaReadEvent.schedule(start);
1882    return true;
1883}
1884
1885void
1886NSGigE::txDmaReadDone()
1887{
1888    assert(txDmaState == dmaReading);
1889    txDmaReadCopy();
1890
1891    // If the receive state machine  has a pending DMA, let it go first
1892    if (rxDmaState == dmaReadWaiting || rxDmaState == dmaWriteWaiting)
1893        rxKick();
1894
1895    txKick();
1896}
1897
1898void
1899NSGigE::txDmaWriteCopy()
1900{
1901    assert(txDmaState == dmaWriting);
1902
1903    physmem->dma_write(txDmaAddr, (uint8_t *)txDmaData, txDmaLen);
1904    txDmaState = dmaIdle;
1905
1906    DPRINTF(EthernetDMA, "tx dma write paddr=%#x len=%d\n",
1907            txDmaAddr, txDmaLen);
1908    DDUMP(EthernetDMA, txDmaData, txDmaLen);
1909}
1910
1911bool
1912NSGigE::doTxDmaWrite()
1913{
1914    assert(txDmaState == dmaIdle || txDmaState == dmaWriteWaiting);
1915    txDmaState = dmaWriting;
1916
1917    if (dmaInterface && !txDmaFree) {
1918        if (dmaInterface->busy())
1919            txDmaState = dmaWriteWaiting;
1920        else
1921            dmaInterface->doDMA(WriteInvalidate, txDmaAddr, txDmaLen, curTick,
1922                                &txDmaWriteEvent, true);
1923        return true;
1924    }
1925
1926    if (dmaWriteDelay == 0 && dmaWriteFactor == 0.0) {
1927        txDmaWriteCopy();
1928        return false;
1929    }
1930
1931    Tick factor = ((txDmaLen + ULL(63)) >> ULL(6)) * dmaWriteFactor;
1932    Tick start = curTick + dmaWriteDelay + factor;
1933    txDmaWriteEvent.schedule(start);
1934    return true;
1935}
1936
1937void
1938NSGigE::txDmaWriteDone()
1939{
1940    assert(txDmaState == dmaWriting);
1941    txDmaWriteCopy();
1942
1943    // If the receive state machine  has a pending DMA, let it go first
1944    if (rxDmaState == dmaReadWaiting || rxDmaState == dmaWriteWaiting)
1945        rxKick();
1946
1947    txKick();
1948}
1949
1950void
1951NSGigE::txKick()
1952{
1953    DPRINTF(EthernetSM, "transmit kick txState=%s\n",
1954            NsTxStateStrings[txState]);
1955
1956    if (txKickTick > curTick) {
1957        DPRINTF(EthernetSM, "transmit kick exiting, can't run till %d\n",
1958                txKickTick);
1959
1960        return;
1961    }
1962
1963  next:
1964    switch(txDmaState) {
1965      case dmaReadWaiting:
1966        if (doTxDmaRead())
1967            goto exit;
1968        break;
1969      case dmaWriteWaiting:
1970        if (doTxDmaWrite())
1971            goto exit;
1972        break;
1973      default:
1974        break;
1975    }
1976
1977    switch (txState) {
1978      case txIdle:
1979        if (!txEnable) {
1980            DPRINTF(EthernetSM, "Transmit disabled.  Nothing to do.\n");
1981            goto exit;
1982        }
1983
1984        if (CTDD) {
1985            txState = txDescRefr;
1986
1987            txDmaAddr = regs.txdp & 0x3fffffff;
1988            txDmaData = &txDescCache + offsetof(ns_desc, link);
1989            txDmaLen = sizeof(txDescCache.link);
1990            txDmaFree = dmaDescFree;
1991
1992            descDmaReads++;
1993            descDmaRdBytes += txDmaLen;
1994
1995            if (doTxDmaRead())
1996                goto exit;
1997
1998        } else {
1999            txState = txDescRead;
2000
2001            txDmaAddr = regs.txdp & 0x3fffffff;
2002            txDmaData = &txDescCache;
2003            txDmaLen = sizeof(ns_desc);
2004            txDmaFree = dmaDescFree;
2005
2006            descDmaReads++;
2007            descDmaRdBytes += txDmaLen;
2008
2009            if (doTxDmaRead())
2010                goto exit;
2011        }
2012        break;
2013
2014      case txDescRefr:
2015        if (txDmaState != dmaIdle)
2016            goto exit;
2017
2018        txState = txAdvance;
2019        break;
2020
2021      case txDescRead:
2022        if (txDmaState != dmaIdle)
2023            goto exit;
2024
2025        DPRINTF(EthernetDesc,
2026                "txDescCache: link=%08x bufptr=%08x cmdsts=%08x extsts=%08x\n",
2027                txDescCache.link, txDescCache.bufptr, txDescCache.cmdsts,
2028                txDescCache.extsts);
2029
2030        if (txDescCache.cmdsts & CMDSTS_OWN) {
2031            txState = txFifoBlock;
2032            txFragPtr = txDescCache.bufptr;
2033            txDescCnt = txDescCache.cmdsts & CMDSTS_LEN_MASK;
2034        } else {
2035            devIntrPost(ISR_TXIDLE);
2036            txState = txIdle;
2037            goto exit;
2038        }
2039        break;
2040
2041      case txFifoBlock:
2042        if (!txPacket) {
2043            DPRINTF(EthernetSM, "****starting the tx of a new packet****\n");
2044            txPacket = new PacketData(16384);
2045            txPacketBufPtr = txPacket->data;
2046        }
2047
2048        if (txDescCnt == 0) {
2049            DPRINTF(EthernetSM, "the txDescCnt == 0, done with descriptor\n");
2050            if (txDescCache.cmdsts & CMDSTS_MORE) {
2051                DPRINTF(EthernetSM, "there are more descriptors to come\n");
2052                txState = txDescWrite;
2053
2054                txDescCache.cmdsts &= ~CMDSTS_OWN;
2055
2056                txDmaAddr = regs.txdp + offsetof(ns_desc, cmdsts);
2057                txDmaAddr &= 0x3fffffff;
2058                txDmaData = &(txDescCache.cmdsts);
2059                txDmaLen = sizeof(txDescCache.cmdsts);
2060                txDmaFree = dmaDescFree;
2061
2062                if (doTxDmaWrite())
2063                    goto exit;
2064
2065            } else { /* this packet is totally done */
2066                DPRINTF(EthernetSM, "This packet is done, let's wrap it up\n");
2067                /* deal with the the packet that just finished */
2068                if ((regs.vtcr & VTCR_PPCHK) && extstsEnable) {
2069                    IpPtr ip(txPacket);
2070                    if (txDescCache.extsts & EXTSTS_UDPPKT) {
2071                        UdpPtr udp(ip);
2072                        udp->sum(0);
2073                        udp->sum(cksum(udp));
2074                        txUdpChecksums++;
2075                    } else if (txDescCache.extsts & EXTSTS_TCPPKT) {
2076                        TcpPtr tcp(ip);
2077                        tcp->sum(0);
2078                        tcp->sum(cksum(tcp));
2079                        txTcpChecksums++;
2080                    }
2081                    if (txDescCache.extsts & EXTSTS_IPPKT) {
2082                        ip->sum(0);
2083                        ip->sum(cksum(ip));
2084                        txIpChecksums++;
2085                    }
2086                }
2087
2088                txPacket->length = txPacketBufPtr - txPacket->data;
2089                // this is just because the receive can't handle a
2090                // packet bigger want to make sure
2091                assert(txPacket->length <= 1514);
2092#ifndef NDEBUG
2093                bool success =
2094#endif
2095                    txFifo.push(txPacket);
2096                assert(success);
2097
2098                /*
2099                 * this following section is not tqo spec, but
2100                 * functionally shouldn't be any different.  normally,
2101                 * the chip will wait til the transmit has occurred
2102                 * before writing back the descriptor because it has
2103                 * to wait to see that it was successfully transmitted
2104                 * to decide whether to set CMDSTS_OK or not.
2105                 * however, in the simulator since it is always
2106                 * successfully transmitted, and writing it exactly to
2107                 * spec would complicate the code, we just do it here
2108                 */
2109
2110                txDescCache.cmdsts &= ~CMDSTS_OWN;
2111                txDescCache.cmdsts |= CMDSTS_OK;
2112
2113                DPRINTF(EthernetDesc,
2114                        "txDesc writeback: cmdsts=%08x extsts=%08x\n",
2115                        txDescCache.cmdsts, txDescCache.extsts);
2116
2117                txDmaAddr = regs.txdp + offsetof(ns_desc, cmdsts);
2118                txDmaAddr &= 0x3fffffff;
2119                txDmaData = &(txDescCache.cmdsts);
2120                txDmaLen = sizeof(txDescCache.cmdsts) +
2121                    sizeof(txDescCache.extsts);
2122                txDmaFree = dmaDescFree;
2123
2124                descDmaWrites++;
2125                descDmaWrBytes += txDmaLen;
2126
2127                transmit();
2128                txPacket = 0;
2129
2130                if (!txEnable) {
2131                    DPRINTF(EthernetSM, "halting TX state machine\n");
2132                    txState = txIdle;
2133                    goto exit;
2134                } else
2135                    txState = txAdvance;
2136
2137                if (doTxDmaWrite())
2138                    goto exit;
2139            }
2140        } else {
2141            DPRINTF(EthernetSM, "this descriptor isn't done yet\n");
2142            if (!txFifo.full()) {
2143                txState = txFragRead;
2144
2145                /*
2146                 * The number of bytes transferred is either whatever
2147                 * is left in the descriptor (txDescCnt), or if there
2148                 * is not enough room in the fifo, just whatever room
2149                 * is left in the fifo
2150                 */
2151                txXferLen = min<uint32_t>(txDescCnt, txFifo.avail());
2152
2153                txDmaAddr = txFragPtr & 0x3fffffff;
2154                txDmaData = txPacketBufPtr;
2155                txDmaLen = txXferLen;
2156                txDmaFree = dmaDataFree;
2157
2158                if (doTxDmaRead())
2159                    goto exit;
2160            } else {
2161                txState = txFifoBlock;
2162                transmit();
2163
2164                goto exit;
2165            }
2166
2167        }
2168        break;
2169
2170      case txFragRead:
2171        if (txDmaState != dmaIdle)
2172            goto exit;
2173
2174        txPacketBufPtr += txXferLen;
2175        txFragPtr += txXferLen;
2176        txDescCnt -= txXferLen;
2177        txFifo.reserve(txXferLen);
2178
2179        txState = txFifoBlock;
2180        break;
2181
2182      case txDescWrite:
2183        if (txDmaState != dmaIdle)
2184            goto exit;
2185
2186        if (txDescCache.cmdsts & CMDSTS_INTR)
2187            devIntrPost(ISR_TXDESC);
2188
2189        txState = txAdvance;
2190        break;
2191
2192      case txAdvance:
2193        if (txDescCache.link == 0) {
2194            devIntrPost(ISR_TXIDLE);
2195            txState = txIdle;
2196            goto exit;
2197        } else {
2198            txState = txDescRead;
2199            regs.txdp = txDescCache.link;
2200            CTDD = false;
2201
2202            txDmaAddr = txDescCache.link & 0x3fffffff;
2203            txDmaData = &txDescCache;
2204            txDmaLen = sizeof(ns_desc);
2205            txDmaFree = dmaDescFree;
2206
2207            if (doTxDmaRead())
2208                goto exit;
2209        }
2210        break;
2211
2212      default:
2213        panic("invalid state");
2214    }
2215
2216    DPRINTF(EthernetSM, "entering next txState=%s\n",
2217            NsTxStateStrings[txState]);
2218
2219    goto next;
2220
2221  exit:
2222    /**
2223     * @todo do we want to schedule a future kick?
2224     */
2225    DPRINTF(EthernetSM, "tx state machine exited txState=%s\n",
2226            NsTxStateStrings[txState]);
2227}
2228
2229void
2230NSGigE::transferDone()
2231{
2232    if (txFifo.empty()) {
2233        DPRINTF(Ethernet, "transfer complete: txFifo empty...nothing to do\n");
2234        return;
2235    }
2236
2237    DPRINTF(Ethernet, "transfer complete: data in txFifo...schedule xmit\n");
2238
2239    if (txEvent.scheduled())
2240        txEvent.reschedule(curTick + cycles(1));
2241    else
2242        txEvent.schedule(curTick + cycles(1));
2243}
2244
2245bool
2246NSGigE::rxFilter(const PacketPtr &packet)
2247{
2248    EthPtr eth = packet;
2249    bool drop = true;
2250    string type;
2251
2252    const EthAddr &dst = eth->dst();
2253    if (dst.unicast()) {
2254        // If we're accepting all unicast addresses
2255        if (acceptUnicast)
2256            drop = false;
2257
2258        // If we make a perfect match
2259        if (acceptPerfect && dst == rom.perfectMatch)
2260            drop = false;
2261
2262        if (acceptArp && eth->type() == ETH_TYPE_ARP)
2263            drop = false;
2264
2265    } else if (dst.broadcast()) {
2266        // if we're accepting broadcasts
2267        if (acceptBroadcast)
2268            drop = false;
2269
2270    } else if (dst.multicast()) {
2271        // if we're accepting all multicasts
2272        if (acceptMulticast)
2273            drop = false;
2274
2275    }
2276
2277    if (drop) {
2278        DPRINTF(Ethernet, "rxFilter drop\n");
2279        DDUMP(EthernetData, packet->data, packet->length);
2280    }
2281
2282    return drop;
2283}
2284
2285bool
2286NSGigE::recvPacket(PacketPtr packet)
2287{
2288    rxBytes += packet->length;
2289    rxPackets++;
2290
2291    DPRINTF(Ethernet, "Receiving packet from wire, rxFifoAvail=%d\n",
2292            rxFifo.avail());
2293
2294    if (!rxEnable) {
2295        DPRINTF(Ethernet, "receive disabled...packet dropped\n");
2296        debug_break();
2297        interface->recvDone();
2298        return true;
2299    }
2300
2301    if (rxFilterEnable && rxFilter(packet)) {
2302        DPRINTF(Ethernet, "packet filtered...dropped\n");
2303        interface->recvDone();
2304        return true;
2305    }
2306
2307    if (rxFifo.avail() < packet->length) {
2308#if TRACING_ON
2309        IpPtr ip(packet);
2310        TcpPtr tcp(ip);
2311        if (ip) {
2312            DPRINTF(Ethernet,
2313                    "packet won't fit in receive buffer...pkt ID %d dropped\n",
2314                    ip->id());
2315            if (tcp) {
2316                DPRINTF(Ethernet, "Seq=%d\n", tcp->seq());
2317            }
2318        }
2319#endif
2320        droppedPackets++;
2321        devIntrPost(ISR_RXORN);
2322        return false;
2323    }
2324
2325    rxFifo.push(packet);
2326    interface->recvDone();
2327
2328    rxKick();
2329    return true;
2330}
2331
2332//=====================================================================
2333//
2334//
2335void
2336NSGigE::serialize(ostream &os)
2337{
2338    // Serialize the PciDev base class
2339    PciDev::serialize(os);
2340
2341    /*
2342     * Finalize any DMA events now.
2343     */
2344    if (rxDmaReadEvent.scheduled())
2345        rxDmaReadCopy();
2346    if (rxDmaWriteEvent.scheduled())
2347        rxDmaWriteCopy();
2348    if (txDmaReadEvent.scheduled())
2349        txDmaReadCopy();
2350    if (txDmaWriteEvent.scheduled())
2351        txDmaWriteCopy();
2352
2353    /*
2354     * Serialize the device registers
2355     */
2356    SERIALIZE_SCALAR(regs.command);
2357    SERIALIZE_SCALAR(regs.config);
2358    SERIALIZE_SCALAR(regs.mear);
2359    SERIALIZE_SCALAR(regs.ptscr);
2360    SERIALIZE_SCALAR(regs.isr);
2361    SERIALIZE_SCALAR(regs.imr);
2362    SERIALIZE_SCALAR(regs.ier);
2363    SERIALIZE_SCALAR(regs.ihr);
2364    SERIALIZE_SCALAR(regs.txdp);
2365    SERIALIZE_SCALAR(regs.txdp_hi);
2366    SERIALIZE_SCALAR(regs.txcfg);
2367    SERIALIZE_SCALAR(regs.gpior);
2368    SERIALIZE_SCALAR(regs.rxdp);
2369    SERIALIZE_SCALAR(regs.rxdp_hi);
2370    SERIALIZE_SCALAR(regs.rxcfg);
2371    SERIALIZE_SCALAR(regs.pqcr);
2372    SERIALIZE_SCALAR(regs.wcsr);
2373    SERIALIZE_SCALAR(regs.pcr);
2374    SERIALIZE_SCALAR(regs.rfcr);
2375    SERIALIZE_SCALAR(regs.rfdr);
2376    SERIALIZE_SCALAR(regs.srr);
2377    SERIALIZE_SCALAR(regs.mibc);
2378    SERIALIZE_SCALAR(regs.vrcr);
2379    SERIALIZE_SCALAR(regs.vtcr);
2380    SERIALIZE_SCALAR(regs.vdr);
2381    SERIALIZE_SCALAR(regs.ccsr);
2382    SERIALIZE_SCALAR(regs.tbicr);
2383    SERIALIZE_SCALAR(regs.tbisr);
2384    SERIALIZE_SCALAR(regs.tanar);
2385    SERIALIZE_SCALAR(regs.tanlpar);
2386    SERIALIZE_SCALAR(regs.taner);
2387    SERIALIZE_SCALAR(regs.tesr);
2388
2389    SERIALIZE_ARRAY(rom.perfectMatch, ETH_ADDR_LEN);
2390
2391    SERIALIZE_SCALAR(ioEnable);
2392
2393    /*
2394     * Serialize the data Fifos
2395     */
2396    rxFifo.serialize("rxFifo", os);
2397    txFifo.serialize("txFifo", os);
2398
2399    /*
2400     * Serialize the various helper variables
2401     */
2402    bool txPacketExists = txPacket;
2403    SERIALIZE_SCALAR(txPacketExists);
2404    if (txPacketExists) {
2405        txPacket->length = txPacketBufPtr - txPacket->data;
2406        txPacket->serialize("txPacket", os);
2407        uint32_t txPktBufPtr = (uint32_t) (txPacketBufPtr - txPacket->data);
2408        SERIALIZE_SCALAR(txPktBufPtr);
2409    }
2410
2411    bool rxPacketExists = rxPacket;
2412    SERIALIZE_SCALAR(rxPacketExists);
2413    if (rxPacketExists) {
2414        rxPacket->serialize("rxPacket", os);
2415        uint32_t rxPktBufPtr = (uint32_t) (rxPacketBufPtr - rxPacket->data);
2416        SERIALIZE_SCALAR(rxPktBufPtr);
2417    }
2418
2419    SERIALIZE_SCALAR(txXferLen);
2420    SERIALIZE_SCALAR(rxXferLen);
2421
2422    /*
2423     * Serialize DescCaches
2424     */
2425    SERIALIZE_SCALAR(txDescCache.link);
2426    SERIALIZE_SCALAR(txDescCache.bufptr);
2427    SERIALIZE_SCALAR(txDescCache.cmdsts);
2428    SERIALIZE_SCALAR(txDescCache.extsts);
2429    SERIALIZE_SCALAR(rxDescCache.link);
2430    SERIALIZE_SCALAR(rxDescCache.bufptr);
2431    SERIALIZE_SCALAR(rxDescCache.cmdsts);
2432    SERIALIZE_SCALAR(rxDescCache.extsts);
2433
2434    /*
2435     * Serialize tx state machine
2436     */
2437    int txState = this->txState;
2438    SERIALIZE_SCALAR(txState);
2439    SERIALIZE_SCALAR(txEnable);
2440    SERIALIZE_SCALAR(CTDD);
2441    SERIALIZE_SCALAR(txFragPtr);
2442    SERIALIZE_SCALAR(txDescCnt);
2443    int txDmaState = this->txDmaState;
2444    SERIALIZE_SCALAR(txDmaState);
2445
2446    /*
2447     * Serialize rx state machine
2448     */
2449    int rxState = this->rxState;
2450    SERIALIZE_SCALAR(rxState);
2451    SERIALIZE_SCALAR(rxEnable);
2452    SERIALIZE_SCALAR(CRDD);
2453    SERIALIZE_SCALAR(rxPktBytes);
2454    SERIALIZE_SCALAR(rxFragPtr);
2455    SERIALIZE_SCALAR(rxDescCnt);
2456    int rxDmaState = this->rxDmaState;
2457    SERIALIZE_SCALAR(rxDmaState);
2458
2459    SERIALIZE_SCALAR(extstsEnable);
2460
2461    /*
2462     * If there's a pending transmit, store the time so we can
2463     * reschedule it later
2464     */
2465    Tick transmitTick = txEvent.scheduled() ? txEvent.when() - curTick : 0;
2466    SERIALIZE_SCALAR(transmitTick);
2467
2468    /*
2469     * receive address filter settings
2470     */
2471    SERIALIZE_SCALAR(rxFilterEnable);
2472    SERIALIZE_SCALAR(acceptBroadcast);
2473    SERIALIZE_SCALAR(acceptMulticast);
2474    SERIALIZE_SCALAR(acceptUnicast);
2475    SERIALIZE_SCALAR(acceptPerfect);
2476    SERIALIZE_SCALAR(acceptArp);
2477
2478    /*
2479     * Keep track of pending interrupt status.
2480     */
2481    SERIALIZE_SCALAR(intrTick);
2482    SERIALIZE_SCALAR(cpuPendingIntr);
2483    Tick intrEventTick = 0;
2484    if (intrEvent)
2485        intrEventTick = intrEvent->when();
2486    SERIALIZE_SCALAR(intrEventTick);
2487
2488}
2489
2490void
2491NSGigE::unserialize(Checkpoint *cp, const std::string &section)
2492{
2493    // Unserialize the PciDev base class
2494    PciDev::unserialize(cp, section);
2495
2496    UNSERIALIZE_SCALAR(regs.command);
2497    UNSERIALIZE_SCALAR(regs.config);
2498    UNSERIALIZE_SCALAR(regs.mear);
2499    UNSERIALIZE_SCALAR(regs.ptscr);
2500    UNSERIALIZE_SCALAR(regs.isr);
2501    UNSERIALIZE_SCALAR(regs.imr);
2502    UNSERIALIZE_SCALAR(regs.ier);
2503    UNSERIALIZE_SCALAR(regs.ihr);
2504    UNSERIALIZE_SCALAR(regs.txdp);
2505    UNSERIALIZE_SCALAR(regs.txdp_hi);
2506    UNSERIALIZE_SCALAR(regs.txcfg);
2507    UNSERIALIZE_SCALAR(regs.gpior);
2508    UNSERIALIZE_SCALAR(regs.rxdp);
2509    UNSERIALIZE_SCALAR(regs.rxdp_hi);
2510    UNSERIALIZE_SCALAR(regs.rxcfg);
2511    UNSERIALIZE_SCALAR(regs.pqcr);
2512    UNSERIALIZE_SCALAR(regs.wcsr);
2513    UNSERIALIZE_SCALAR(regs.pcr);
2514    UNSERIALIZE_SCALAR(regs.rfcr);
2515    UNSERIALIZE_SCALAR(regs.rfdr);
2516    UNSERIALIZE_SCALAR(regs.srr);
2517    UNSERIALIZE_SCALAR(regs.mibc);
2518    UNSERIALIZE_SCALAR(regs.vrcr);
2519    UNSERIALIZE_SCALAR(regs.vtcr);
2520    UNSERIALIZE_SCALAR(regs.vdr);
2521    UNSERIALIZE_SCALAR(regs.ccsr);
2522    UNSERIALIZE_SCALAR(regs.tbicr);
2523    UNSERIALIZE_SCALAR(regs.tbisr);
2524    UNSERIALIZE_SCALAR(regs.tanar);
2525    UNSERIALIZE_SCALAR(regs.tanlpar);
2526    UNSERIALIZE_SCALAR(regs.taner);
2527    UNSERIALIZE_SCALAR(regs.tesr);
2528
2529    UNSERIALIZE_ARRAY(rom.perfectMatch, ETH_ADDR_LEN);
2530
2531    UNSERIALIZE_SCALAR(ioEnable);
2532
2533    /*
2534     * unserialize the data fifos
2535     */
2536    rxFifo.unserialize("rxFifo", cp, section);
2537    txFifo.unserialize("txFifo", cp, section);
2538
2539    /*
2540     * unserialize the various helper variables
2541     */
2542    bool txPacketExists;
2543    UNSERIALIZE_SCALAR(txPacketExists);
2544    if (txPacketExists) {
2545        txPacket = new PacketData(16384);
2546        txPacket->unserialize("txPacket", cp, section);
2547        uint32_t txPktBufPtr;
2548        UNSERIALIZE_SCALAR(txPktBufPtr);
2549        txPacketBufPtr = (uint8_t *) txPacket->data + txPktBufPtr;
2550    } else
2551        txPacket = 0;
2552
2553    bool rxPacketExists;
2554    UNSERIALIZE_SCALAR(rxPacketExists);
2555    rxPacket = 0;
2556    if (rxPacketExists) {
2557        rxPacket = new PacketData(16384);
2558        rxPacket->unserialize("rxPacket", cp, section);
2559        uint32_t rxPktBufPtr;
2560        UNSERIALIZE_SCALAR(rxPktBufPtr);
2561        rxPacketBufPtr = (uint8_t *) rxPacket->data + rxPktBufPtr;
2562    } else
2563        rxPacket = 0;
2564
2565    UNSERIALIZE_SCALAR(txXferLen);
2566    UNSERIALIZE_SCALAR(rxXferLen);
2567
2568    /*
2569     * Unserialize DescCaches
2570     */
2571    UNSERIALIZE_SCALAR(txDescCache.link);
2572    UNSERIALIZE_SCALAR(txDescCache.bufptr);
2573    UNSERIALIZE_SCALAR(txDescCache.cmdsts);
2574    UNSERIALIZE_SCALAR(txDescCache.extsts);
2575    UNSERIALIZE_SCALAR(rxDescCache.link);
2576    UNSERIALIZE_SCALAR(rxDescCache.bufptr);
2577    UNSERIALIZE_SCALAR(rxDescCache.cmdsts);
2578    UNSERIALIZE_SCALAR(rxDescCache.extsts);
2579
2580    /*
2581     * unserialize tx state machine
2582     */
2583    int txState;
2584    UNSERIALIZE_SCALAR(txState);
2585    this->txState = (TxState) txState;
2586    UNSERIALIZE_SCALAR(txEnable);
2587    UNSERIALIZE_SCALAR(CTDD);
2588    UNSERIALIZE_SCALAR(txFragPtr);
2589    UNSERIALIZE_SCALAR(txDescCnt);
2590    int txDmaState;
2591    UNSERIALIZE_SCALAR(txDmaState);
2592    this->txDmaState = (DmaState) txDmaState;
2593
2594    /*
2595     * unserialize rx state machine
2596     */
2597    int rxState;
2598    UNSERIALIZE_SCALAR(rxState);
2599    this->rxState = (RxState) rxState;
2600    UNSERIALIZE_SCALAR(rxEnable);
2601    UNSERIALIZE_SCALAR(CRDD);
2602    UNSERIALIZE_SCALAR(rxPktBytes);
2603    UNSERIALIZE_SCALAR(rxFragPtr);
2604    UNSERIALIZE_SCALAR(rxDescCnt);
2605    int rxDmaState;
2606    UNSERIALIZE_SCALAR(rxDmaState);
2607    this->rxDmaState = (DmaState) rxDmaState;
2608
2609    UNSERIALIZE_SCALAR(extstsEnable);
2610
2611     /*
2612     * If there's a pending transmit, reschedule it now
2613     */
2614    Tick transmitTick;
2615    UNSERIALIZE_SCALAR(transmitTick);
2616    if (transmitTick)
2617        txEvent.schedule(curTick + transmitTick);
2618
2619    /*
2620     * unserialize receive address filter settings
2621     */
2622    UNSERIALIZE_SCALAR(rxFilterEnable);
2623    UNSERIALIZE_SCALAR(acceptBroadcast);
2624    UNSERIALIZE_SCALAR(acceptMulticast);
2625    UNSERIALIZE_SCALAR(acceptUnicast);
2626    UNSERIALIZE_SCALAR(acceptPerfect);
2627    UNSERIALIZE_SCALAR(acceptArp);
2628
2629    /*
2630     * Keep track of pending interrupt status.
2631     */
2632    UNSERIALIZE_SCALAR(intrTick);
2633    UNSERIALIZE_SCALAR(cpuPendingIntr);
2634    Tick intrEventTick;
2635    UNSERIALIZE_SCALAR(intrEventTick);
2636    if (intrEventTick) {
2637        intrEvent = new IntrEvent(this, true);
2638        intrEvent->schedule(intrEventTick);
2639    }
2640
2641    /*
2642     * re-add addrRanges to bus bridges
2643     */
2644    if (pioInterface) {
2645        pioInterface->addAddrRange(RangeSize(BARAddrs[0], BARSize[0]));
2646        pioInterface->addAddrRange(RangeSize(BARAddrs[1], BARSize[1]));
2647    }
2648}
2649
2650Tick
2651NSGigE::cacheAccess(MemReqPtr &req)
2652{
2653    DPRINTF(EthernetPIO, "timing access to paddr=%#x (daddr=%#x)\n",
2654            req->paddr, req->paddr - addr);
2655    return curTick + pioLatency;
2656}
2657
2658BEGIN_DECLARE_SIM_OBJECT_PARAMS(NSGigEInt)
2659
2660    SimObjectParam<EtherInt *> peer;
2661    SimObjectParam<NSGigE *> device;
2662
2663END_DECLARE_SIM_OBJECT_PARAMS(NSGigEInt)
2664
2665BEGIN_INIT_SIM_OBJECT_PARAMS(NSGigEInt)
2666
2667    INIT_PARAM_DFLT(peer, "peer interface", NULL),
2668    INIT_PARAM(device, "Ethernet device of this interface")
2669
2670END_INIT_SIM_OBJECT_PARAMS(NSGigEInt)
2671
2672CREATE_SIM_OBJECT(NSGigEInt)
2673{
2674    NSGigEInt *dev_int = new NSGigEInt(getInstanceName(), device);
2675
2676    EtherInt *p = (EtherInt *)peer;
2677    if (p) {
2678        dev_int->setPeer(p);
2679        p->setPeer(dev_int);
2680    }
2681
2682    return dev_int;
2683}
2684
2685REGISTER_SIM_OBJECT("NSGigEInt", NSGigEInt)
2686
2687
2688BEGIN_DECLARE_SIM_OBJECT_PARAMS(NSGigE)
2689
2690    Param<Addr> addr;
2691    Param<Tick> clock;
2692    Param<Tick> tx_delay;
2693    Param<Tick> rx_delay;
2694    Param<Tick> intr_delay;
2695    SimObjectParam<MemoryController *> mmu;
2696    SimObjectParam<PhysicalMemory *> physmem;
2697    Param<bool> rx_filter;
2698    Param<string> hardware_address;
2699    SimObjectParam<Bus*> io_bus;
2700    SimObjectParam<Bus*> payload_bus;
2701    SimObjectParam<HierParams *> hier;
2702    Param<Tick> pio_latency;
2703    Param<bool> dma_desc_free;
2704    Param<bool> dma_data_free;
2705    Param<Tick> dma_read_delay;
2706    Param<Tick> dma_write_delay;
2707    Param<Tick> dma_read_factor;
2708    Param<Tick> dma_write_factor;
2709    SimObjectParam<PciConfigAll *> configspace;
2710    SimObjectParam<PciConfigData *> configdata;
2711    SimObjectParam<Platform *> platform;
2712    Param<uint32_t> pci_bus;
2713    Param<uint32_t> pci_dev;
2714    Param<uint32_t> pci_func;
2715    Param<uint32_t> tx_fifo_size;
2716    Param<uint32_t> rx_fifo_size;
2717    Param<uint32_t> m5reg;
2718    Param<bool> dma_no_allocate;
2719
2720END_DECLARE_SIM_OBJECT_PARAMS(NSGigE)
2721
2722BEGIN_INIT_SIM_OBJECT_PARAMS(NSGigE)
2723
2724    INIT_PARAM(addr, "Device Address"),
2725    INIT_PARAM(clock, "State machine processor frequency"),
2726    INIT_PARAM(tx_delay, "Transmit Delay"),
2727    INIT_PARAM(rx_delay, "Receive Delay"),
2728    INIT_PARAM(intr_delay, "Interrupt Delay in microseconds"),
2729    INIT_PARAM(mmu, "Memory Controller"),
2730    INIT_PARAM(physmem, "Physical Memory"),
2731    INIT_PARAM_DFLT(rx_filter, "Enable Receive Filter", true),
2732    INIT_PARAM_DFLT(hardware_address, "Ethernet Hardware Address",
2733                    "00:99:00:00:00:01"),
2734    INIT_PARAM_DFLT(io_bus, "The IO Bus to attach to for headers", NULL),
2735    INIT_PARAM_DFLT(payload_bus, "The IO Bus to attach to for payload", NULL),
2736    INIT_PARAM_DFLT(hier, "Hierarchy global variables", &defaultHierParams),
2737    INIT_PARAM_DFLT(pio_latency, "Programmed IO latency in bus cycles", 1),
2738    INIT_PARAM_DFLT(dma_desc_free, "DMA of Descriptors is free", false),
2739    INIT_PARAM_DFLT(dma_data_free, "DMA of Data is free", false),
2740    INIT_PARAM_DFLT(dma_read_delay, "fixed delay for dma reads", 0),
2741    INIT_PARAM_DFLT(dma_write_delay, "fixed delay for dma writes", 0),
2742    INIT_PARAM_DFLT(dma_read_factor, "multiplier for dma reads", 0),
2743    INIT_PARAM_DFLT(dma_write_factor, "multiplier for dma writes", 0),
2744    INIT_PARAM(configspace, "PCI Configspace"),
2745    INIT_PARAM(configdata, "PCI Config data"),
2746    INIT_PARAM(platform, "Platform"),
2747    INIT_PARAM(pci_bus, "PCI bus"),
2748    INIT_PARAM(pci_dev, "PCI device number"),
2749    INIT_PARAM(pci_func, "PCI function code"),
2750    INIT_PARAM_DFLT(tx_fifo_size, "max size in bytes of txFifo", 131072),
2751    INIT_PARAM_DFLT(rx_fifo_size, "max size in bytes of rxFifo", 131072),
2752    INIT_PARAM(m5reg, "m5 register"),
2753    INIT_PARAM_DFLT(dma_no_allocate, "Should DMA reads allocate cache lines", true)
2754
2755END_INIT_SIM_OBJECT_PARAMS(NSGigE)
2756
2757
2758CREATE_SIM_OBJECT(NSGigE)
2759{
2760    NSGigE::Params *params = new NSGigE::Params;
2761
2762    params->name = getInstanceName();
2763    params->mmu = mmu;
2764    params->configSpace = configspace;
2765    params->configData = configdata;
2766    params->plat = platform;
2767    params->busNum = pci_bus;
2768    params->deviceNum = pci_dev;
2769    params->functionNum = pci_func;
2770
2771    params->clock = clock;
2772    params->intr_delay = intr_delay;
2773    params->pmem = physmem;
2774    params->tx_delay = tx_delay;
2775    params->rx_delay = rx_delay;
2776    params->hier = hier;
2777    params->header_bus = io_bus;
2778    params->payload_bus = payload_bus;
2779    params->pio_latency = pio_latency;
2780    params->dma_desc_free = dma_desc_free;
2781    params->dma_data_free = dma_data_free;
2782    params->dma_read_delay = dma_read_delay;
2783    params->dma_write_delay = dma_write_delay;
2784    params->dma_read_factor = dma_read_factor;
2785    params->dma_write_factor = dma_write_factor;
2786    params->rx_filter = rx_filter;
2787    params->eaddr = hardware_address;
2788    params->tx_fifo_size = tx_fifo_size;
2789    params->rx_fifo_size = rx_fifo_size;
2790    params->m5reg = m5reg;
2791    params->dma_no_allocate = dma_no_allocate;
2792    return new NSGigE(params);
2793}
2794
2795REGISTER_SIM_OBJECT("NSGigE", NSGigE)
2796