ns_gige.cc revision 4875
12292SN/A/* 27597Sminkyu.jeong@arm.com * Copyright (c) 2004-2005 The Regents of The University of Michigan 37597Sminkyu.jeong@arm.com * All rights reserved. 47597Sminkyu.jeong@arm.com * 57597Sminkyu.jeong@arm.com * Redistribution and use in source and binary forms, with or without 67597Sminkyu.jeong@arm.com * modification, are permitted provided that the following conditions are 77597Sminkyu.jeong@arm.com * met: redistributions of source code must retain the above copyright 87597Sminkyu.jeong@arm.com * notice, this list of conditions and the following disclaimer; 97597Sminkyu.jeong@arm.com * redistributions in binary form must reproduce the above copyright 107597Sminkyu.jeong@arm.com * notice, this list of conditions and the following disclaimer in the 117597Sminkyu.jeong@arm.com * documentation and/or other materials provided with the distribution; 127597Sminkyu.jeong@arm.com * neither the name of the copyright holders nor the names of its 137597Sminkyu.jeong@arm.com * contributors may be used to endorse or promote products derived from 142292SN/A * this software without specific prior written permission. 152292SN/A * 162292SN/A * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 172292SN/A * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 182292SN/A * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR 192292SN/A * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT 202292SN/A * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 212292SN/A * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT 222292SN/A * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 232292SN/A * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 242292SN/A * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 252292SN/A * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 262292SN/A * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 272292SN/A * 282292SN/A * Authors: Nathan Binkert 292292SN/A * Lisa Hsu 302292SN/A */ 312292SN/A 322292SN/A/** @file 332292SN/A * Device module for modelling the National Semiconductor 342292SN/A * DP83820 ethernet controller. Does not support priority queueing 352292SN/A */ 362292SN/A#include <deque> 372292SN/A#include <string> 382292SN/A 392689Sktlim@umich.edu#include "base/inet.hh" 402689Sktlim@umich.edu#include "cpu/thread_context.hh" 412689Sktlim@umich.edu#include "dev/etherlink.hh" 422292SN/A#include "dev/ns_gige.hh" 432292SN/A#include "dev/pciconfigall.hh" 443326Sktlim@umich.edu#include "mem/packet.hh" 456658Snate@binkert.org#include "mem/packet_access.hh" 462733Sktlim@umich.edu#include "sim/builder.hh" 472907Sktlim@umich.edu#include "sim/debug.hh" 482292SN/A#include "sim/host.hh" 492292SN/A#include "sim/stats.hh" 502722Sktlim@umich.edu#include "sim/system.hh" 512669Sktlim@umich.edu 522292SN/Aconst char *NsRxStateStrings[] = 532790Sktlim@umich.edu{ 542790Sktlim@umich.edu "rxIdle", 552790Sktlim@umich.edu "rxDescRefr", 562790Sktlim@umich.edu "rxDescRead", 572669Sktlim@umich.edu "rxFifoBlock", 582678Sktlim@umich.edu "rxFragWrite", 592678Sktlim@umich.edu "rxDescWrite", 605606Snate@binkert.org "rxAdvance" 612292SN/A}; 622678Sktlim@umich.edu 632292SN/Aconst char *NsTxStateStrings[] = 642292SN/A{ 652669Sktlim@umich.edu "txIdle", 662292SN/A "txDescRefr", 672678Sktlim@umich.edu "txDescRead", 682292SN/A "txFifoBlock", 692678Sktlim@umich.edu "txFragRead", 702678Sktlim@umich.edu "txDescWrite", 712678Sktlim@umich.edu "txAdvance" 724319Sktlim@umich.edu}; 734319Sktlim@umich.edu 744319Sktlim@umich.educonst char *NsDmaState[] = 754319Sktlim@umich.edu{ 764319Sktlim@umich.edu "dmaIdle", 772678Sktlim@umich.edu "dmaReading", 782678Sktlim@umich.edu "dmaWriting", 792292SN/A "dmaReadWaiting", 802678Sktlim@umich.edu "dmaWriteWaiting" 812678Sktlim@umich.edu}; 825336Shines@cs.fsu.edu 832678Sktlim@umich.eduusing namespace std; 844873Sstever@eecs.umich.eduusing namespace Net; 852678Sktlim@umich.eduusing namespace TheISA; 862292SN/A 872678Sktlim@umich.edu/////////////////////////////////////////////////////////////////////// 882678Sktlim@umich.edu// 892678Sktlim@umich.edu// NSGigE PCI Device 902678Sktlim@umich.edu// 912678Sktlim@umich.eduNSGigE::NSGigE(Params *p) 922678Sktlim@umich.edu : PciDev(p), ioEnable(false), 932678Sktlim@umich.edu txFifo(p->tx_fifo_size), rxFifo(p->rx_fifo_size), 942698Sktlim@umich.edu txPacket(0), rxPacket(0), txPacketBufPtr(NULL), rxPacketBufPtr(NULL), 952344SN/A txXferLen(0), rxXferLen(0), rxDmaFree(false), txDmaFree(false), 962678Sktlim@umich.edu clock(p->clock), 972678Sktlim@umich.edu txState(txIdle), txEnable(false), CTDD(false), txHalt(false), 984986Ssaidi@eecs.umich.edu txFragPtr(0), txDescCnt(0), txDmaState(dmaIdle), rxState(rxIdle), 994986Ssaidi@eecs.umich.edu rxEnable(false), CRDD(false), rxPktBytes(0), rxHalt(false), 1006974Stjones1@inf.ed.ac.uk rxFragPtr(0), rxDescCnt(0), rxDmaState(dmaIdle), extstsEnable(false), 1016974Stjones1@inf.ed.ac.uk eepromState(eepromStart), eepromClk(false), eepromBitsToRx(0), 1026974Stjones1@inf.ed.ac.uk eepromOpcode(0), eepromAddress(0), eepromData(0), 1036974Stjones1@inf.ed.ac.uk dmaReadDelay(p->dma_read_delay), dmaWriteDelay(p->dma_write_delay), 1046974Stjones1@inf.ed.ac.uk dmaReadFactor(p->dma_read_factor), dmaWriteFactor(p->dma_write_factor), 1056974Stjones1@inf.ed.ac.uk rxDmaData(NULL), rxDmaAddr(0), rxDmaLen(0), 1066974Stjones1@inf.ed.ac.uk txDmaData(NULL), txDmaAddr(0), txDmaLen(0), 1072678Sktlim@umich.edu rxDmaReadEvent(this), rxDmaWriteEvent(this), 1082820Sktlim@umich.edu txDmaReadEvent(this), txDmaWriteEvent(this), 1092678Sktlim@umich.edu dmaDescFree(p->dma_desc_free), dmaDataFree(p->dma_data_free), 1102678Sktlim@umich.edu txDelay(p->tx_delay), rxDelay(p->rx_delay), 1116974Stjones1@inf.ed.ac.uk rxKickTick(0), rxKickEvent(this), txKickTick(0), txKickEvent(this), 1126974Stjones1@inf.ed.ac.uk txEvent(this), rxFilterEnable(p->rx_filter), 1136974Stjones1@inf.ed.ac.uk acceptBroadcast(false), acceptMulticast(false), acceptUnicast(false), 1146974Stjones1@inf.ed.ac.uk acceptPerfect(false), acceptArp(false), multicastHashEnable(false), 1156974Stjones1@inf.ed.ac.uk intrDelay(p->intr_delay), intrTick(0), cpuPendingIntr(false), 1166974Stjones1@inf.ed.ac.uk intrEvent(0), interface(0) 1172678Sktlim@umich.edu{ 1182678Sktlim@umich.edu 1192678Sktlim@umich.edu 1202678Sktlim@umich.edu regsReset(); 1212678Sktlim@umich.edu memcpy(&rom.perfectMatch, p->eaddr.bytes(), ETH_ADDR_LEN); 1222344SN/A 1232307SN/A memset(&rxDesc32, 0, sizeof(rxDesc32)); 1246974Stjones1@inf.ed.ac.uk memset(&txDesc32, 0, sizeof(txDesc32)); 1256974Stjones1@inf.ed.ac.uk memset(&rxDesc64, 0, sizeof(rxDesc64)); 1266974Stjones1@inf.ed.ac.uk memset(&txDesc64, 0, sizeof(txDesc64)); 1276974Stjones1@inf.ed.ac.uk} 1282678Sktlim@umich.edu 1294032Sktlim@umich.eduNSGigE::~NSGigE() 1302678Sktlim@umich.edu{} 1312292SN/A 1322292SN/Avoid 1332292SN/ANSGigE::regStats() 1342292SN/A{ 1352678Sktlim@umich.edu txBytes 1362678Sktlim@umich.edu .name(name() + ".txBytes") 1376974Stjones1@inf.ed.ac.uk .desc("Bytes Transmitted") 1382292SN/A .prereq(txBytes) 1392292SN/A ; 1402292SN/A 1412292SN/A rxBytes 1422292SN/A .name(name() + ".rxBytes") 1435529Snate@binkert.org .desc("Bytes Received") 1445529Snate@binkert.org .prereq(rxBytes) 1455529Snate@binkert.org ; 1462292SN/A 1474329Sktlim@umich.edu txPackets 1484329Sktlim@umich.edu .name(name() + ".txPackets") 1494329Sktlim@umich.edu .desc("Number of Packets Transmitted") 1504329Sktlim@umich.edu .prereq(txBytes) 1512292SN/A ; 1522307SN/A 1532307SN/A rxPackets 1542907Sktlim@umich.edu .name(name() + ".rxPackets") 1552907Sktlim@umich.edu .desc("Number of Packets Received") 1562292SN/A .prereq(rxBytes) 1572292SN/A ; 1582329SN/A 1592329SN/A txIpChecksums 1602329SN/A .name(name() + ".txIpChecksums") 1612292SN/A .desc("Number of tx IP Checksums done by device") 1622292SN/A .precision(0) 1632292SN/A .prereq(txBytes) 1642292SN/A ; 1652292SN/A 1662292SN/A rxIpChecksums 1672292SN/A .name(name() + ".rxIpChecksums") 1682292SN/A .desc("Number of rx IP Checksums done by device") 1692292SN/A .precision(0) 1702292SN/A .prereq(rxBytes) 1712292SN/A ; 1723492Sktlim@umich.edu 1732329SN/A txTcpChecksums 1742292SN/A .name(name() + ".txTcpChecksums") 1752292SN/A .desc("Number of tx TCP Checksums done by device") 1762292SN/A .precision(0) 1772292SN/A .prereq(txBytes) 1782292SN/A ; 1792292SN/A 1802292SN/A rxTcpChecksums 1812292SN/A .name(name() + ".rxTcpChecksums") 1822292SN/A .desc("Number of rx TCP Checksums done by device") 1832292SN/A .precision(0) 1842292SN/A .prereq(rxBytes) 1852292SN/A ; 1862292SN/A 1872292SN/A txUdpChecksums 1882292SN/A .name(name() + ".txUdpChecksums") 1892292SN/A .desc("Number of tx UDP Checksums done by device") 1902292SN/A .precision(0) 1912727Sktlim@umich.edu .prereq(txBytes) 1922727Sktlim@umich.edu ; 1932727Sktlim@umich.edu 1942727Sktlim@umich.edu rxUdpChecksums 1952727Sktlim@umich.edu .name(name() + ".rxUdpChecksums") 1962727Sktlim@umich.edu .desc("Number of rx UDP Checksums done by device") 1972727Sktlim@umich.edu .precision(0) 1982727Sktlim@umich.edu .prereq(rxBytes) 1992727Sktlim@umich.edu ; 2002727Sktlim@umich.edu 2012727Sktlim@umich.edu descDmaReads 2022727Sktlim@umich.edu .name(name() + ".descDMAReads") 2032727Sktlim@umich.edu .desc("Number of descriptors the device read w/ DMA") 2042727Sktlim@umich.edu .precision(0) 2052727Sktlim@umich.edu ; 2062727Sktlim@umich.edu 2072727Sktlim@umich.edu descDmaWrites 2082727Sktlim@umich.edu .name(name() + ".descDMAWrites") 2092361SN/A .desc("Number of descriptors the device wrote w/ DMA") 2102361SN/A .precision(0) 2112361SN/A ; 2122361SN/A 2132727Sktlim@umich.edu descDmaRdBytes 2142727Sktlim@umich.edu .name(name() + ".descDmaReadBytes") 2152727Sktlim@umich.edu .desc("number of descriptor bytes read w/ DMA") 2162727Sktlim@umich.edu .precision(0) 2172727Sktlim@umich.edu ; 2182727Sktlim@umich.edu 2192727Sktlim@umich.edu descDmaWrBytes 2202727Sktlim@umich.edu .name(name() + ".descDmaWriteBytes") 2212727Sktlim@umich.edu .desc("number of descriptor bytes write w/ DMA") 2222727Sktlim@umich.edu .precision(0) 2232727Sktlim@umich.edu ; 2242727Sktlim@umich.edu 2252727Sktlim@umich.edu txBandwidth 2262727Sktlim@umich.edu .name(name() + ".txBandwidth") 2272727Sktlim@umich.edu .desc("Transmit Bandwidth (bits/s)") 2282727Sktlim@umich.edu .precision(0) 2292727Sktlim@umich.edu .prereq(txBytes) 2302727Sktlim@umich.edu ; 2312727Sktlim@umich.edu 2322727Sktlim@umich.edu rxBandwidth 2332727Sktlim@umich.edu .name(name() + ".rxBandwidth") 2342727Sktlim@umich.edu .desc("Receive Bandwidth (bits/s)") 2352727Sktlim@umich.edu .precision(0) 2364329Sktlim@umich.edu .prereq(rxBytes) 2374329Sktlim@umich.edu ; 2384329Sktlim@umich.edu 2394329Sktlim@umich.edu totBandwidth 2404329Sktlim@umich.edu .name(name() + ".totBandwidth") 2414329Sktlim@umich.edu .desc("Total Bandwidth (bits/s)") 2424329Sktlim@umich.edu .precision(0) 2434329Sktlim@umich.edu .prereq(totBytes) 2444329Sktlim@umich.edu ; 2454329Sktlim@umich.edu 2464329Sktlim@umich.edu totPackets 2474329Sktlim@umich.edu .name(name() + ".totPackets") 2484329Sktlim@umich.edu .desc("Total Packets") 2492292SN/A .precision(0) 2502292SN/A .prereq(totBytes) 2512292SN/A ; 2522292SN/A 2532292SN/A totBytes 2542292SN/A .name(name() + ".totBytes") 2552292SN/A .desc("Total Bytes") 2562292SN/A .precision(0) 2572292SN/A .prereq(totBytes) 2582292SN/A ; 2592292SN/A 2602292SN/A totPacketRate 2612292SN/A .name(name() + ".totPPS") 2622292SN/A .desc("Total Tranmission Rate (packets/s)") 2632307SN/A .precision(0) 2642307SN/A .prereq(totBytes) 2652307SN/A ; 2662367SN/A 2672367SN/A txPacketRate 2682307SN/A .name(name() + ".txPPS") 2692367SN/A .desc("Packet Tranmission Rate (packets/s)") 2702307SN/A .precision(0) 2712329SN/A .prereq(txBytes) 2722307SN/A ; 2732307SN/A 2742307SN/A rxPacketRate 2752307SN/A .name(name() + ".rxPPS") 2762307SN/A .desc("Packet Reception Rate (packets/s)") 2772307SN/A .precision(0) 2782307SN/A .prereq(rxBytes) 2792307SN/A ; 2802307SN/A 2812307SN/A postedSwi 2822307SN/A .name(name() + ".postedSwi") 2832307SN/A .desc("number of software interrupts posted to CPU") 2842307SN/A .precision(0) 2852307SN/A ; 2862307SN/A 2872329SN/A totalSwi 2882307SN/A .name(name() + ".totalSwi") 2892307SN/A .desc("total number of Swi written to ISR") 2902307SN/A .precision(0) 2912307SN/A ; 2922307SN/A 2932307SN/A coalescedSwi 2942307SN/A .name(name() + ".coalescedSwi") 2952307SN/A .desc("average number of Swi's coalesced into each post") 2962307SN/A .precision(0) 2972307SN/A ; 2982292SN/A 2992292SN/A postedRxIdle 3002329SN/A .name(name() + ".postedRxIdle") 3012329SN/A .desc("number of rxIdle interrupts posted to CPU") 3022292SN/A .precision(0) 3032329SN/A ; 3042329SN/A 3052292SN/A totalRxIdle 3062292SN/A .name(name() + ".totalRxIdle") 3072292SN/A .desc("total number of RxIdle written to ISR") 3082292SN/A .precision(0) 3092292SN/A ; 3102329SN/A 3112292SN/A coalescedRxIdle 3122292SN/A .name(name() + ".coalescedRxIdle") 3132292SN/A .desc("average number of RxIdle's coalesced into each post") 3142292SN/A .precision(0) 3152292SN/A ; 3162292SN/A 3172292SN/A postedRxOk 3182292SN/A .name(name() + ".postedRxOk") 3192329SN/A .desc("number of RxOk interrupts posted to CPU") 3202329SN/A .precision(0) 3212329SN/A ; 3222292SN/A 3232292SN/A totalRxOk 3242292SN/A .name(name() + ".totalRxOk") 3252292SN/A .desc("total number of RxOk written to ISR") 3262292SN/A .precision(0) 3272329SN/A ; 3282292SN/A 3292292SN/A coalescedRxOk 3302292SN/A .name(name() + ".coalescedRxOk") 3312292SN/A .desc("average number of RxOk's coalesced into each post") 3322292SN/A .precision(0) 3332292SN/A ; 3342292SN/A 3352292SN/A postedRxDesc 3362292SN/A .name(name() + ".postedRxDesc") 3372292SN/A .desc("number of RxDesc interrupts posted to CPU") 3382292SN/A .precision(0) 3392292SN/A ; 3402292SN/A 3412292SN/A totalRxDesc 3422292SN/A .name(name() + ".totalRxDesc") 3432292SN/A .desc("total number of RxDesc written to ISR") 3442292SN/A .precision(0) 3452292SN/A ; 3462292SN/A 3472292SN/A coalescedRxDesc 3482292SN/A .name(name() + ".coalescedRxDesc") 3492292SN/A .desc("average number of RxDesc's coalesced into each post") 3502292SN/A .precision(0) 3512292SN/A ; 3522329SN/A 3532329SN/A postedTxOk 3542292SN/A .name(name() + ".postedTxOk") 3557720Sgblack@eecs.umich.edu .desc("number of TxOk interrupts posted to CPU") 3567720Sgblack@eecs.umich.edu .precision(0) 3572292SN/A ; 3582292SN/A 3592292SN/A totalTxOk 3602292SN/A .name(name() + ".totalTxOk") 3612292SN/A .desc("total number of TxOk written to ISR") 3622292SN/A .precision(0) 3632292SN/A ; 3642292SN/A 3652292SN/A coalescedTxOk 3662292SN/A .name(name() + ".coalescedTxOk") 3672292SN/A .desc("average number of TxOk's coalesced into each post") 3682292SN/A .precision(0) 3692292SN/A ; 3702292SN/A 3712292SN/A postedTxIdle 3722292SN/A .name(name() + ".postedTxIdle") 3732292SN/A .desc("number of TxIdle interrupts posted to CPU") 3742292SN/A .precision(0) 3752292SN/A ; 3762292SN/A 3772292SN/A totalTxIdle 3782292SN/A .name(name() + ".totalTxIdle") 3792292SN/A .desc("total number of TxIdle written to ISR") 3802292SN/A .precision(0) 3817720Sgblack@eecs.umich.edu ; 3827720Sgblack@eecs.umich.edu 3832292SN/A coalescedTxIdle 3842292SN/A .name(name() + ".coalescedTxIdle") 3852292SN/A .desc("average number of TxIdle's coalesced into each post") 3862292SN/A .precision(0) 3872292SN/A ; 3882292SN/A 3892292SN/A postedTxDesc 3902292SN/A .name(name() + ".postedTxDesc") 3912292SN/A .desc("number of TxDesc interrupts posted to CPU") 3922292SN/A .precision(0) 3932292SN/A ; 3942292SN/A 3952292SN/A totalTxDesc 3962292SN/A .name(name() + ".totalTxDesc") 3972292SN/A .desc("total number of TxDesc written to ISR") 3982292SN/A .precision(0) 3992292SN/A ; 4002292SN/A 4012292SN/A coalescedTxDesc 4022292SN/A .name(name() + ".coalescedTxDesc") 4032292SN/A .desc("average number of TxDesc's coalesced into each post") 4042292SN/A .precision(0) 4052292SN/A ; 4062292SN/A 4072292SN/A postedRxOrn 4082292SN/A .name(name() + ".postedRxOrn") 4092292SN/A .desc("number of RxOrn posted to CPU") 4102292SN/A .precision(0) 4112292SN/A ; 4122292SN/A 4132292SN/A totalRxOrn 4142292SN/A .name(name() + ".totalRxOrn") 4152292SN/A .desc("total number of RxOrn written to ISR") 4162292SN/A .precision(0) 4172292SN/A ; 4182292SN/A 4192292SN/A coalescedRxOrn 4202292SN/A .name(name() + ".coalescedRxOrn") 4212292SN/A .desc("average number of RxOrn's coalesced into each post") 4222292SN/A .precision(0) 4232292SN/A ; 4242292SN/A 4252292SN/A coalescedTotal 4262292SN/A .name(name() + ".coalescedTotal") 4272292SN/A .desc("average number of interrupts coalesced into each post") 4282292SN/A .precision(0) 4292292SN/A ; 4302292SN/A 4312292SN/A postedInterrupts 4322292SN/A .name(name() + ".postedInterrupts") 4332292SN/A .desc("number of posts to CPU") 4342292SN/A .precision(0) 4352292SN/A ; 4362292SN/A 4372292SN/A droppedPackets 4382292SN/A .name(name() + ".droppedPackets") 4392292SN/A .desc("number of packets dropped") 4402292SN/A .precision(0) 4412292SN/A ; 4422292SN/A 4434032Sktlim@umich.edu coalescedSwi = totalSwi / postedInterrupts; 4442292SN/A coalescedRxIdle = totalRxIdle / postedInterrupts; 4452292SN/A coalescedRxOk = totalRxOk / postedInterrupts; 4462292SN/A coalescedRxDesc = totalRxDesc / postedInterrupts; 4477720Sgblack@eecs.umich.edu coalescedTxOk = totalTxOk / postedInterrupts; 4487720Sgblack@eecs.umich.edu coalescedTxIdle = totalTxIdle / postedInterrupts; 4492292SN/A coalescedTxDesc = totalTxDesc / postedInterrupts; 4504032Sktlim@umich.edu coalescedRxOrn = totalRxOrn / postedInterrupts; 4514032Sktlim@umich.edu 4522669Sktlim@umich.edu coalescedTotal = (totalSwi + totalRxIdle + totalRxOk + totalRxDesc + 4532292SN/A totalTxOk + totalTxIdle + totalTxDesc + 4547597Sminkyu.jeong@arm.com totalRxOrn) / postedInterrupts; 4557597Sminkyu.jeong@arm.com 4567597Sminkyu.jeong@arm.com txBandwidth = txBytes * Stats::constant(8) / simSeconds; 4572329SN/A rxBandwidth = rxBytes * Stats::constant(8) / simSeconds; 4582329SN/A totBandwidth = txBandwidth + rxBandwidth; 4592367SN/A totBytes = txBytes + rxBytes; 4602367SN/A totPackets = txPackets + rxPackets; 4617600Sminkyu.jeong@arm.com 4627600Sminkyu.jeong@arm.com txPacketRate = txPackets / simSeconds; 4637600Sminkyu.jeong@arm.com rxPacketRate = rxPackets / simSeconds; 4644032Sktlim@umich.edu} 4653731Sktlim@umich.edu 4662367SN/A 4672367SN/A/** 4682292SN/A * This is to write to the PCI general configuration registers 4692292SN/A */ 4704032Sktlim@umich.eduTick 4714032Sktlim@umich.eduNSGigE::writeConfig(PacketPtr pkt) 4724032Sktlim@umich.edu{ 4734032Sktlim@umich.edu int offset = pkt->getAddr() & PCI_CONFIG_SIZE; 4744032Sktlim@umich.edu if (offset < PCI_DEVICE_SPECIFIC) 4754032Sktlim@umich.edu PciDev::writeConfig(pkt); 4764032Sktlim@umich.edu else 4774032Sktlim@umich.edu panic("Device specific PCI config space not implemented!\n"); 4784032Sktlim@umich.edu 4794032Sktlim@umich.edu switch (offset) { 4804032Sktlim@umich.edu // seems to work fine without all these PCI settings, but i 4814032Sktlim@umich.edu // put in the IO to double check, an assertion will fail if we 4827616Sminkyu.jeong@arm.com // need to properly implement it 4837616Sminkyu.jeong@arm.com case PCI_COMMAND: 4847616Sminkyu.jeong@arm.com if (config.data[offset] & PCI_CMD_IOSE) 4857616Sminkyu.jeong@arm.com ioEnable = true; 4864032Sktlim@umich.edu else 4877616Sminkyu.jeong@arm.com ioEnable = false; 4887616Sminkyu.jeong@arm.com break; 4897616Sminkyu.jeong@arm.com } 4904032Sktlim@umich.edu 4914032Sktlim@umich.edu return configDelay; 4924032Sktlim@umich.edu} 4934032Sktlim@umich.edu 4944032Sktlim@umich.edu/** 4954032Sktlim@umich.edu * This reads the device registers, which are detailed in the NS83820 4964032Sktlim@umich.edu * spec sheet 4974032Sktlim@umich.edu */ 4984032Sktlim@umich.eduTick 4994032Sktlim@umich.eduNSGigE::read(PacketPtr pkt) 5004032Sktlim@umich.edu{ 5014032Sktlim@umich.edu assert(ioEnable); 5024032Sktlim@umich.edu 5034032Sktlim@umich.edu pkt->allocate(); 5044032Sktlim@umich.edu 5054032Sktlim@umich.edu //The mask is to give you only the offset into the device register file 5064032Sktlim@umich.edu Addr daddr = pkt->getAddr() & 0xfff; 5072292SN/A DPRINTF(EthernetPIO, "read da=%#x pa=%#x size=%d\n", 5082292SN/A daddr, pkt->getAddr(), pkt->getSize()); 5092292SN/A 5102292SN/A 5112292SN/A // there are some reserved registers, you can see ns_gige_reg.h and 5122292SN/A // the spec sheet for details 5132292SN/A if (daddr > LAST && daddr <= RESERVED) { 5142292SN/A panic("Accessing reserved register"); 5152292SN/A } else if (daddr > RESERVED && daddr <= 0x3FC) { 5162292SN/A return readConfig(pkt); 5172292SN/A } else if (daddr >= MIB_START && daddr <= MIB_END) { 5182292SN/A // don't implement all the MIB's. hopefully the kernel 5192292SN/A // doesn't actually DEPEND upon their values 5202292SN/A // MIB are just hardware stats keepers 5212292SN/A pkt->set<uint32_t>(0); 5227720Sgblack@eecs.umich.edu pkt->makeAtomicResponse(); 5237720Sgblack@eecs.umich.edu return pioDelay; 5242292SN/A } else if (daddr > 0x3FC) 5254032Sktlim@umich.edu panic("Something is messed up!\n"); 5264032Sktlim@umich.edu 5272292SN/A assert(pkt->getSize() == sizeof(uint32_t)); 5282292SN/A uint32_t ® = *pkt->getPtr<uint32_t>(); 5292292SN/A uint16_t rfaddr; 5302292SN/A 5312292SN/A switch (daddr) { 5322292SN/A case CR: 5332329SN/A reg = regs.command; 5347720Sgblack@eecs.umich.edu //these are supposed to be cleared on a read 5357720Sgblack@eecs.umich.edu reg &= ~(CR_RXD | CR_TXD | CR_TXR | CR_RXR); 5362292SN/A break; 5372292SN/A 5382292SN/A case CFGR: 5392292SN/A reg = regs.config; 5402292SN/A break; 5412292SN/A 5422336SN/A case MEAR: 5432336SN/A reg = regs.mear; 5442336SN/A break; 5452329SN/A 5462292SN/A case PTSCR: 5472329SN/A reg = regs.ptscr; 5482292SN/A break; 5492292SN/A 5504032Sktlim@umich.edu case ISR: 5514032Sktlim@umich.edu reg = regs.isr; 5524032Sktlim@umich.edu devIntrClear(ISR_ALL); 5534032Sktlim@umich.edu break; 5544032Sktlim@umich.edu 5552292SN/A case IMR: 5564032Sktlim@umich.edu reg = regs.imr; 5574032Sktlim@umich.edu break; 5584032Sktlim@umich.edu 5592329SN/A case IER: 5604032Sktlim@umich.edu reg = regs.ier; 5617616Sminkyu.jeong@arm.com break; 5627616Sminkyu.jeong@arm.com 5637616Sminkyu.jeong@arm.com case IHR: 5647616Sminkyu.jeong@arm.com reg = regs.ihr; 5654032Sktlim@umich.edu break; 5667616Sminkyu.jeong@arm.com 5677616Sminkyu.jeong@arm.com case TXDP: 5687616Sminkyu.jeong@arm.com reg = regs.txdp; 5694032Sktlim@umich.edu break; 5704032Sktlim@umich.edu 5714032Sktlim@umich.edu case TXDP_HI: 5724032Sktlim@umich.edu reg = regs.txdp_hi; 5734032Sktlim@umich.edu break; 5744032Sktlim@umich.edu 5754032Sktlim@umich.edu case TX_CFG: 5764032Sktlim@umich.edu reg = regs.txcfg; 5772292SN/A break; 5782292SN/A 5794032Sktlim@umich.edu case GPIOR: 5804032Sktlim@umich.edu reg = regs.gpior; 5814032Sktlim@umich.edu break; 5822292SN/A 5832292SN/A case RXDP: 5844032Sktlim@umich.edu reg = regs.rxdp; 5852292SN/A break; 5862292SN/A 5872292SN/A case RXDP_HI: 5882292SN/A reg = regs.rxdp_hi; 5892292SN/A break; 5902292SN/A 5912292SN/A case RX_CFG: 5922292SN/A reg = regs.rxcfg; 5932292SN/A break; 5942292SN/A 5952292SN/A case PQCR: 5967720Sgblack@eecs.umich.edu reg = regs.pqcr; 5977720Sgblack@eecs.umich.edu break; 5982292SN/A 5992292SN/A case WCSR: 6002292SN/A reg = regs.wcsr; 6012292SN/A break; 6022292SN/A 6032292SN/A case PCR: 6042292SN/A reg = regs.pcr; 6052292SN/A break; 6062292SN/A 6072292SN/A // see the spec sheet for how RFCR and RFDR work 6082292SN/A // basically, you write to RFCR to tell the machine 6092292SN/A // what you want to do next, then you act upon RFDR, 6102292SN/A // and the device will be prepared b/c of what you 6112292SN/A // wrote to RFCR 6122292SN/A case RFCR: 6132292SN/A reg = regs.rfcr; 6142292SN/A break; 6152292SN/A 6162292SN/A case RFDR: 6172292SN/A rfaddr = (uint16_t)(regs.rfcr & RFCR_RFADDR); 6182292SN/A switch (rfaddr) { 6192292SN/A // Read from perfect match ROM octets 6202292SN/A case 0x000: 6212292SN/A reg = rom.perfectMatch[1]; 6222292SN/A reg = reg << 8; 6232292SN/A reg += rom.perfectMatch[0]; 6242292SN/A break; 6252292SN/A case 0x002: 6262292SN/A reg = rom.perfectMatch[3] << 8; 6272329SN/A reg += rom.perfectMatch[2]; 6282329SN/A break; 6292292SN/A case 0x004: 6302292SN/A reg = rom.perfectMatch[5] << 8; 6312292SN/A reg += rom.perfectMatch[4]; 6322292SN/A break; 6332292SN/A default: 6347720Sgblack@eecs.umich.edu // Read filter hash table 6357720Sgblack@eecs.umich.edu if (rfaddr >= FHASH_ADDR && 6362292SN/A rfaddr < FHASH_ADDR + FHASH_SIZE) { 6372292SN/A 6382292SN/A // Only word-aligned reads supported 6392292SN/A if (rfaddr % 2) 6402292SN/A panic("unaligned read from filter hash table!"); 6412292SN/A 6422292SN/A reg = rom.filterHash[rfaddr - FHASH_ADDR + 1] << 8; 6432292SN/A reg += rom.filterHash[rfaddr - FHASH_ADDR]; 6442292SN/A break; 6452292SN/A } 6462292SN/A 6472292SN/A panic("reading RFDR for something other than pattern" 6482292SN/A " matching or hashing! %#x\n", rfaddr); 6496974Stjones1@inf.ed.ac.uk } 6506974Stjones1@inf.ed.ac.uk break; 6516974Stjones1@inf.ed.ac.uk 6526974Stjones1@inf.ed.ac.uk case SRR: 6536974Stjones1@inf.ed.ac.uk reg = regs.srr; 6546974Stjones1@inf.ed.ac.uk break; 6556974Stjones1@inf.ed.ac.uk 6566974Stjones1@inf.ed.ac.uk case MIBC: 6576974Stjones1@inf.ed.ac.uk reg = regs.mibc; 6586974Stjones1@inf.ed.ac.uk reg &= ~(MIBC_MIBS | MIBC_ACLR); 6596974Stjones1@inf.ed.ac.uk break; 6606974Stjones1@inf.ed.ac.uk 6616974Stjones1@inf.ed.ac.uk case VRCR: 6626974Stjones1@inf.ed.ac.uk reg = regs.vrcr; 6636974Stjones1@inf.ed.ac.uk break; 6646974Stjones1@inf.ed.ac.uk 6652292SN/A case VTCR: 6662292SN/A reg = regs.vtcr; 6676974Stjones1@inf.ed.ac.uk break; 6686974Stjones1@inf.ed.ac.uk 6696974Stjones1@inf.ed.ac.uk case VDR: 6706974Stjones1@inf.ed.ac.uk reg = regs.vdr; 6716974Stjones1@inf.ed.ac.uk break; 6726974Stjones1@inf.ed.ac.uk 6732292SN/A case CCSR: 6742292SN/A reg = regs.ccsr; 6752292SN/A break; 6762292SN/A 6772292SN/A case TBICR: 6782292SN/A reg = regs.tbicr; 6792907Sktlim@umich.edu break; 6802678Sktlim@umich.edu 6812678Sktlim@umich.edu case TBISR: 6822678Sktlim@umich.edu reg = regs.tbisr; 6832678Sktlim@umich.edu break; 6842678Sktlim@umich.edu 6852329SN/A case TANAR: 6862329SN/A reg = regs.tanar; 6872292SN/A break; 6882292SN/A 6892292SN/A case TANLPAR: 6902292SN/A reg = regs.tanlpar; 6912292SN/A break; 6922292SN/A 6932292SN/A case TANER: 6942678Sktlim@umich.edu reg = regs.taner; 6952292SN/A break; 6962292SN/A 6972292SN/A case TESR: 6982292SN/A reg = regs.tesr; 6992292SN/A break; 7002292SN/A 7012292SN/A case M5REG: 7022292SN/A reg = 0; 7032292SN/A if (params()->rx_thread) 7042292SN/A reg |= M5REG_RX_THREAD; 7052292SN/A if (params()->tx_thread) 7066974Stjones1@inf.ed.ac.uk reg |= M5REG_TX_THREAD; 7076974Stjones1@inf.ed.ac.uk if (params()->rss) 7086974Stjones1@inf.ed.ac.uk reg |= M5REG_RSS; 7096974Stjones1@inf.ed.ac.uk break; 7106974Stjones1@inf.ed.ac.uk 7112669Sktlim@umich.edu default: 7122669Sktlim@umich.edu panic("reading unimplemented register: addr=%#x", daddr); 7132669Sktlim@umich.edu } 7142292SN/A 7152292SN/A DPRINTF(EthernetPIO, "read from %#x: data=%d data=%#x\n", 7162669Sktlim@umich.edu daddr, reg, reg); 7172669Sktlim@umich.edu 7183772Sgblack@eecs.umich.edu pkt->makeAtomicResponse(); 7194326Sgblack@eecs.umich.edu return pioDelay; 7202669Sktlim@umich.edu} 7214878Sstever@eecs.umich.edu 7224878Sstever@eecs.umich.eduTick 7236102Sgblack@eecs.umich.eduNSGigE::write(PacketPtr pkt) 7246974Stjones1@inf.ed.ac.uk{ 7256974Stjones1@inf.ed.ac.uk assert(ioEnable); 7262292SN/A 7272678Sktlim@umich.edu Addr daddr = pkt->getAddr() & 0xfff; 7282678Sktlim@umich.edu DPRINTF(EthernetPIO, "write da=%#x pa=%#x size=%d\n", 7292678Sktlim@umich.edu daddr, pkt->getAddr(), pkt->getSize()); 7302678Sktlim@umich.edu 7316974Stjones1@inf.ed.ac.uk if (daddr > LAST && daddr <= RESERVED) { 7326974Stjones1@inf.ed.ac.uk panic("Accessing reserved register"); 7336974Stjones1@inf.ed.ac.uk } else if (daddr > RESERVED && daddr <= 0x3FC) { 7346974Stjones1@inf.ed.ac.uk return writeConfig(pkt); 7356974Stjones1@inf.ed.ac.uk } else if (daddr > 0x3FC) 7366974Stjones1@inf.ed.ac.uk panic("Something is messed up!\n"); 7376974Stjones1@inf.ed.ac.uk 7386974Stjones1@inf.ed.ac.uk if (pkt->getSize() == sizeof(uint32_t)) { 7396974Stjones1@inf.ed.ac.uk uint32_t reg = pkt->get<uint32_t>(); 7406974Stjones1@inf.ed.ac.uk uint16_t rfaddr; 7416974Stjones1@inf.ed.ac.uk 7426974Stjones1@inf.ed.ac.uk DPRINTF(EthernetPIO, "write data=%d data=%#x\n", reg, reg); 7436974Stjones1@inf.ed.ac.uk 7446974Stjones1@inf.ed.ac.uk switch (daddr) { 7456974Stjones1@inf.ed.ac.uk case CR: 7466974Stjones1@inf.ed.ac.uk regs.command = reg; 7476974Stjones1@inf.ed.ac.uk if (reg & CR_TXD) { 7486974Stjones1@inf.ed.ac.uk txEnable = false; 7496974Stjones1@inf.ed.ac.uk } else if (reg & CR_TXE) { 7506974Stjones1@inf.ed.ac.uk txEnable = true; 7516974Stjones1@inf.ed.ac.uk 7526974Stjones1@inf.ed.ac.uk // the kernel is enabling the transmit machine 7536974Stjones1@inf.ed.ac.uk if (txState == txIdle) 7546974Stjones1@inf.ed.ac.uk txKick(); 7556974Stjones1@inf.ed.ac.uk } 7566974Stjones1@inf.ed.ac.uk 7576974Stjones1@inf.ed.ac.uk if (reg & CR_RXD) { 7586974Stjones1@inf.ed.ac.uk rxEnable = false; 7592678Sktlim@umich.edu } else if (reg & CR_RXE) { 7607720Sgblack@eecs.umich.edu rxEnable = true; 7612292SN/A 7627720Sgblack@eecs.umich.edu if (rxState == rxIdle) 7633797Sgblack@eecs.umich.edu rxKick(); 7643221Sktlim@umich.edu } 7652292SN/A 7662693Sktlim@umich.edu if (reg & CR_TXR) 7674350Sgblack@eecs.umich.edu txReset(); 7686974Stjones1@inf.ed.ac.uk 7693326Sktlim@umich.edu if (reg & CR_RXR) 7703326Sktlim@umich.edu rxReset(); 7713326Sktlim@umich.edu 7723326Sktlim@umich.edu if (reg & CR_SWI) 7733326Sktlim@umich.edu devIntrPost(ISR_SWI); 7743326Sktlim@umich.edu 7753326Sktlim@umich.edu if (reg & CR_RST) { 7763326Sktlim@umich.edu txReset(); 7773326Sktlim@umich.edu rxReset(); 7783326Sktlim@umich.edu 7793326Sktlim@umich.edu regsReset(); 7803326Sktlim@umich.edu } 7813326Sktlim@umich.edu break; 7825606Snate@binkert.org 7833326Sktlim@umich.edu case CFGR: 7843326Sktlim@umich.edu if (reg & CFGR_LNKSTS || 7853326Sktlim@umich.edu reg & CFGR_SPDSTS || 7862693Sktlim@umich.edu reg & CFGR_DUPSTS || 7872693Sktlim@umich.edu reg & CFGR_RESERVED || 7882693Sktlim@umich.edu reg & CFGR_T64ADDR || 7892693Sktlim@umich.edu reg & CFGR_PCI64_DET) 7902693Sktlim@umich.edu 7912693Sktlim@umich.edu // First clear all writable bits 7926974Stjones1@inf.ed.ac.uk regs.config &= CFGR_LNKSTS | CFGR_SPDSTS | CFGR_DUPSTS | 7934032Sktlim@umich.edu CFGR_RESERVED | CFGR_T64ADDR | 7943221Sktlim@umich.edu CFGR_PCI64_DET; 7953221Sktlim@umich.edu // Now set the appropriate writable bits 7966974Stjones1@inf.ed.ac.uk regs.config |= reg & ~(CFGR_LNKSTS | CFGR_SPDSTS | CFGR_DUPSTS | 7976974Stjones1@inf.ed.ac.uk CFGR_RESERVED | CFGR_T64ADDR | 7986974Stjones1@inf.ed.ac.uk CFGR_PCI64_DET); 7996974Stjones1@inf.ed.ac.uk 8006974Stjones1@inf.ed.ac.uk// all these #if 0's are because i don't THINK the kernel needs to 8016974Stjones1@inf.ed.ac.uk// have these implemented. if there is a problem relating to one of 8022669Sktlim@umich.edu// these, you may need to add functionality in. 8036974Stjones1@inf.ed.ac.uk if (reg & CFGR_TBI_EN) ; 8046974Stjones1@inf.ed.ac.uk if (reg & CFGR_MODE_1000) ; 8056974Stjones1@inf.ed.ac.uk 8066974Stjones1@inf.ed.ac.uk if (reg & CFGR_AUTO_1000) 8076974Stjones1@inf.ed.ac.uk panic("CFGR_AUTO_1000 not implemented!\n"); 8086974Stjones1@inf.ed.ac.uk 8096974Stjones1@inf.ed.ac.uk if (reg & CFGR_PINT_DUPSTS || 8106974Stjones1@inf.ed.ac.uk reg & CFGR_PINT_LNKSTS || 8116974Stjones1@inf.ed.ac.uk reg & CFGR_PINT_SPDSTS) 8126974Stjones1@inf.ed.ac.uk ; 8136974Stjones1@inf.ed.ac.uk 8146974Stjones1@inf.ed.ac.uk if (reg & CFGR_TMRTEST) ; 8156974Stjones1@inf.ed.ac.uk if (reg & CFGR_MRM_DIS) ; 8166974Stjones1@inf.ed.ac.uk if (reg & CFGR_MWI_DIS) ; 8176974Stjones1@inf.ed.ac.uk 8186974Stjones1@inf.ed.ac.uk if (reg & CFGR_T64ADDR) ; 8196974Stjones1@inf.ed.ac.uk // panic("CFGR_T64ADDR is read only register!\n"); 8206974Stjones1@inf.ed.ac.uk 8216974Stjones1@inf.ed.ac.uk if (reg & CFGR_PCI64_DET) 8226974Stjones1@inf.ed.ac.uk panic("CFGR_PCI64_DET is read only register!\n"); 8236974Stjones1@inf.ed.ac.uk 8246974Stjones1@inf.ed.ac.uk if (reg & CFGR_DATA64_EN) ; 8256974Stjones1@inf.ed.ac.uk if (reg & CFGR_M64ADDR) ; 8266974Stjones1@inf.ed.ac.uk if (reg & CFGR_PHY_RST) ; 8276974Stjones1@inf.ed.ac.uk if (reg & CFGR_PHY_DIS) ; 8286974Stjones1@inf.ed.ac.uk 8296974Stjones1@inf.ed.ac.uk if (reg & CFGR_EXTSTS_EN) 8302292SN/A extstsEnable = true; 8312292SN/A else 8322292SN/A extstsEnable = false; 8332292SN/A 8342292SN/A if (reg & CFGR_REQALG) ; 8352292SN/A if (reg & CFGR_SB) ; 8362292SN/A if (reg & CFGR_POW) ; 8372292SN/A if (reg & CFGR_EXD) ; 8382292SN/A if (reg & CFGR_PESEL) ; 8392292SN/A if (reg & CFGR_BROM_DIS) ; 8402292SN/A if (reg & CFGR_EXT_125) ; 8412292SN/A if (reg & CFGR_BEM) ; 8422292SN/A break; 8432292SN/A 8442292SN/A case MEAR: 8452292SN/A // Clear writable bits 8462292SN/A regs.mear &= MEAR_EEDO; 8472292SN/A // Set appropriate writable bits 8482292SN/A regs.mear |= reg & ~MEAR_EEDO; 8492292SN/A 8502292SN/A // FreeBSD uses the EEPROM to read PMATCH (for the MAC address) 8512292SN/A // even though it could get it through RFDR 8522292SN/A if (reg & MEAR_EESEL) { 8532292SN/A // Rising edge of clock 8542292SN/A if (reg & MEAR_EECLK && !eepromClk) 8552292SN/A eepromKick(); 8562292SN/A } 8572292SN/A else { 8582329SN/A eepromState = eepromStart; 8592292SN/A regs.mear &= ~MEAR_EEDI; 8602292SN/A } 8612292SN/A 8622292SN/A eepromClk = reg & MEAR_EECLK; 8632292SN/A 8647720Sgblack@eecs.umich.edu // since phy is completely faked, MEAR_MD* don't matter 8652292SN/A if (reg & MEAR_MDIO) ; 8667720Sgblack@eecs.umich.edu if (reg & MEAR_MDDIR) ; 8672292SN/A if (reg & MEAR_MDC) ; 8682292SN/A break; 8692292SN/A 8702292SN/A case PTSCR: 8712292SN/A regs.ptscr = reg & ~(PTSCR_RBIST_RDONLY); 8722292SN/A // these control BISTs for various parts of chip - we 8732292SN/A // don't care or do just fake that the BIST is done 8742292SN/A if (reg & PTSCR_RBIST_EN) 8752329SN/A regs.ptscr |= PTSCR_RBIST_DONE; 8762731Sktlim@umich.edu if (reg & PTSCR_EEBIST_EN) 8772292SN/A regs.ptscr &= ~PTSCR_EEBIST_EN; 8782292SN/A if (reg & PTSCR_EELOAD_EN) 8792292SN/A regs.ptscr &= ~PTSCR_EELOAD_EN; 8802292SN/A break; 8812292SN/A 8822292SN/A case ISR: /* writing to the ISR has no effect */ 8832292SN/A panic("ISR is a read only register!\n"); 8842727Sktlim@umich.edu 8852292SN/A case IMR: 8862292SN/A regs.imr = reg; 8872292SN/A devIntrChangeMask(); 8882292SN/A break; 8892292SN/A 8902292SN/A case IER: 8912292SN/A regs.ier = reg; 8922292SN/A break; 8932292SN/A 8942292SN/A case IHR: 8954032Sktlim@umich.edu regs.ihr = reg; 8964032Sktlim@umich.edu /* not going to implement real interrupt holdoff */ 8974032Sktlim@umich.edu break; 8984032Sktlim@umich.edu 8992292SN/A case TXDP: 9002292SN/A regs.txdp = (reg & 0xFFFFFFFC); 9012292SN/A assert(txState == txIdle); 9022292SN/A CTDD = false; 9032292SN/A break; 9042329SN/A 9052292SN/A case TXDP_HI: 9062292SN/A regs.txdp_hi = reg; 9072292SN/A break; 9082292SN/A 9097720Sgblack@eecs.umich.edu case TX_CFG: 9102292SN/A regs.txcfg = reg; 9117720Sgblack@eecs.umich.edu#if 0 9122292SN/A if (reg & TX_CFG_CSI) ; 9132292SN/A if (reg & TX_CFG_HBI) ; 9142329SN/A if (reg & TX_CFG_MLB) ; 9152329SN/A if (reg & TX_CFG_ATP) ; 9162292SN/A if (reg & TX_CFG_ECRETRY) { 9172292SN/A /* 9182292SN/A * this could easily be implemented, but considering 9192292SN/A * the network is just a fake pipe, wouldn't make 9202292SN/A * sense to do this 9212292SN/A */ 9222292SN/A } 9232329SN/A 9242731Sktlim@umich.edu if (reg & TX_CFG_BRST_DIS) ; 9252292SN/A#endif 9262292SN/A 9272292SN/A#if 0 9284032Sktlim@umich.edu /* we handle our own DMA, ignore the kernel's exhortations */ 9294032Sktlim@umich.edu if (reg & TX_CFG_MXDMA) ; 9304032Sktlim@umich.edu#endif 9314032Sktlim@umich.edu 9326974Stjones1@inf.ed.ac.uk // also, we currently don't care about fill/drain 9336974Stjones1@inf.ed.ac.uk // thresholds though this may change in the future with 9346974Stjones1@inf.ed.ac.uk // more realistic networks or a driver which changes it 9356974Stjones1@inf.ed.ac.uk // according to feedback 9366974Stjones1@inf.ed.ac.uk 9376974Stjones1@inf.ed.ac.uk break; 9386974Stjones1@inf.ed.ac.uk 9394032Sktlim@umich.edu case GPIOR: 9402292SN/A // Only write writable bits 9412292SN/A regs.gpior &= GPIOR_UNUSED | GPIOR_GP5_IN | GPIOR_GP4_IN 9422292SN/A | GPIOR_GP3_IN | GPIOR_GP2_IN | GPIOR_GP1_IN; 9432292SN/A regs.gpior |= reg & ~(GPIOR_UNUSED | GPIOR_GP5_IN | GPIOR_GP4_IN 9442292SN/A | GPIOR_GP3_IN | GPIOR_GP2_IN | GPIOR_GP1_IN); 9452292SN/A /* these just control general purpose i/o pins, don't matter */ 9462292SN/A break; 9472727Sktlim@umich.edu 9482292SN/A case RXDP: 9492292SN/A regs.rxdp = reg; 9502292SN/A CRDD = false; 9512292SN/A break; 9522292SN/A 9533349Sbinkertn@umich.edu case RXDP_HI: 9542693Sktlim@umich.edu regs.rxdp_hi = reg; 9552693Sktlim@umich.edu break; 9562693Sktlim@umich.edu 9572693Sktlim@umich.edu case RX_CFG: 9582693Sktlim@umich.edu regs.rxcfg = reg; 9592693Sktlim@umich.edu#if 0 9602693Sktlim@umich.edu if (reg & RX_CFG_AEP) ; 9612693Sktlim@umich.edu if (reg & RX_CFG_ARP) ; 9622693Sktlim@umich.edu if (reg & RX_CFG_STRIPCRC) ; 9632693Sktlim@umich.edu if (reg & RX_CFG_RX_RD) ; 9642693Sktlim@umich.edu if (reg & RX_CFG_ALP) ; 9652693Sktlim@umich.edu if (reg & RX_CFG_AIRL) ; 9662693Sktlim@umich.edu 9672693Sktlim@umich.edu /* we handle our own DMA, ignore what kernel says about it */ 9682693Sktlim@umich.edu if (reg & RX_CFG_MXDMA) ; 9692693Sktlim@umich.edu 9702733Sktlim@umich.edu //also, we currently don't care about fill/drain thresholds 9712693Sktlim@umich.edu //though this may change in the future with more realistic 9722732Sktlim@umich.edu //networks or a driver which changes it according to feedback 9732693Sktlim@umich.edu if (reg & (RX_CFG_DRTH | RX_CFG_DRTH0)) ; 9742733Sktlim@umich.edu#endif 9752693Sktlim@umich.edu break; 9762693Sktlim@umich.edu 9772693Sktlim@umich.edu case PQCR: 9782693Sktlim@umich.edu /* there is no priority queueing used in the linux 2.6 driver */ 9792693Sktlim@umich.edu regs.pqcr = reg; 9802693Sktlim@umich.edu break; 9812693Sktlim@umich.edu 9822678Sktlim@umich.edu case WCSR: 9832678Sktlim@umich.edu /* not going to implement wake on LAN */ 9842678Sktlim@umich.edu regs.wcsr = reg; 9852678Sktlim@umich.edu break; 9862678Sktlim@umich.edu 9872678Sktlim@umich.edu case PCR: 9882927Sktlim@umich.edu /* not going to implement pause control */ 9892678Sktlim@umich.edu regs.pcr = reg; 9902727Sktlim@umich.edu break; 9912678Sktlim@umich.edu 9922678Sktlim@umich.edu case RFCR: 9932678Sktlim@umich.edu regs.rfcr = reg; 9942678Sktlim@umich.edu 9952678Sktlim@umich.edu rxFilterEnable = (reg & RFCR_RFEN) ? true : false; 9962678Sktlim@umich.edu acceptBroadcast = (reg & RFCR_AAB) ? true : false; 9972678Sktlim@umich.edu acceptMulticast = (reg & RFCR_AAM) ? true : false; 9982678Sktlim@umich.edu acceptUnicast = (reg & RFCR_AAU) ? true : false; 9992678Sktlim@umich.edu acceptPerfect = (reg & RFCR_APM) ? true : false; 10002678Sktlim@umich.edu acceptArp = (reg & RFCR_AARP) ? true : false; 10012678Sktlim@umich.edu multicastHashEnable = (reg & RFCR_MHEN) ? true : false; 10022678Sktlim@umich.edu 10032678Sktlim@umich.edu#if 0 10042678Sktlim@umich.edu if (reg & RFCR_APAT) 10057598Sminkyu.jeong@arm.com panic("RFCR_APAT not implemented!\n"); 10067598Sminkyu.jeong@arm.com#endif 10077598Sminkyu.jeong@arm.com if (reg & RFCR_UHEN) 10082678Sktlim@umich.edu panic("Unicast hash filtering not used by drivers!\n"); 10092678Sktlim@umich.edu 10102678Sktlim@umich.edu if (reg & RFCR_ULM) 10112678Sktlim@umich.edu panic("RFCR_ULM not implemented!\n"); 10122292SN/A 10132292SN/A break; 10142292SN/A 10152292SN/A case RFDR: 10162292SN/A rfaddr = (uint16_t)(regs.rfcr & RFCR_RFADDR); 10172292SN/A switch (rfaddr) { 10182292SN/A case 0x000: 10192292SN/A rom.perfectMatch[0] = (uint8_t)reg; 10203126Sktlim@umich.edu rom.perfectMatch[1] = (uint8_t)(reg >> 8); 10212292SN/A break; 10222292SN/A case 0x002: 10232292SN/A rom.perfectMatch[2] = (uint8_t)reg; 10242292SN/A rom.perfectMatch[3] = (uint8_t)(reg >> 8); 10252292SN/A break; 10262292SN/A case 0x004: 10272292SN/A rom.perfectMatch[4] = (uint8_t)reg; 10282292SN/A rom.perfectMatch[5] = (uint8_t)(reg >> 8); 10292292SN/A break; 10302292SN/A default: 10312292SN/A 10322292SN/A if (rfaddr >= FHASH_ADDR && 10332292SN/A rfaddr < FHASH_ADDR + FHASH_SIZE) { 10342329SN/A 10352329SN/A // Only word-aligned writes supported 10362329SN/A if (rfaddr % 2) 10372292SN/A panic("unaligned write to filter hash table!"); 10382292SN/A 10392292SN/A rom.filterHash[rfaddr - FHASH_ADDR] = (uint8_t)reg; 10402292SN/A rom.filterHash[rfaddr - FHASH_ADDR + 1] 10412292SN/A = (uint8_t)(reg >> 8); 10422292SN/A break; 10432292SN/A } 10442292SN/A panic("writing RFDR for something other than pattern matching\ 10452292SN/A or hashing! %#x\n", rfaddr); 10462292SN/A } 10472316SN/A 10482316SN/A case BRAR: 10492329SN/A regs.brar = reg; 10502329SN/A break; 10512329SN/A 10522329SN/A case BRDR: 10532733Sktlim@umich.edu panic("the driver never uses BRDR, something is wrong!\n"); 10542316SN/A 10552732Sktlim@umich.edu case SRR: 10562316SN/A panic("SRR is read only register!\n"); 10572733Sktlim@umich.edu 10582292SN/A case MIBC: 10592292SN/A panic("the driver never uses MIBC, something is wrong!\n"); 10602292SN/A 10616974Stjones1@inf.ed.ac.uk case VRCR: 10626974Stjones1@inf.ed.ac.uk regs.vrcr = reg; 10636974Stjones1@inf.ed.ac.uk break; 10646974Stjones1@inf.ed.ac.uk 10656974Stjones1@inf.ed.ac.uk case VTCR: 10666974Stjones1@inf.ed.ac.uk regs.vtcr = reg; 10676974Stjones1@inf.ed.ac.uk break; 10686974Stjones1@inf.ed.ac.uk 10696974Stjones1@inf.ed.ac.uk case VDR: 10706974Stjones1@inf.ed.ac.uk panic("the driver never uses VDR, something is wrong!\n"); 10716974Stjones1@inf.ed.ac.uk 10726974Stjones1@inf.ed.ac.uk case CCSR: 10736974Stjones1@inf.ed.ac.uk /* not going to implement clockrun stuff */ 10746974Stjones1@inf.ed.ac.uk regs.ccsr = reg; 10756974Stjones1@inf.ed.ac.uk break; 10766974Stjones1@inf.ed.ac.uk 10772693Sktlim@umich.edu case TBICR: 10782693Sktlim@umich.edu regs.tbicr = reg; 10792693Sktlim@umich.edu if (reg & TBICR_MR_LOOPBACK) 10802698Sktlim@umich.edu panic("TBICR_MR_LOOPBACK never used, something wrong!\n"); 10814985Sktlim@umich.edu 10822698Sktlim@umich.edu if (reg & TBICR_MR_AN_ENABLE) { 10832693Sktlim@umich.edu regs.tanlpar = regs.tanar; 10842698Sktlim@umich.edu regs.tbisr |= (TBISR_MR_AN_COMPLETE | TBISR_MR_LINK_STATUS); 10856974Stjones1@inf.ed.ac.uk } 10866974Stjones1@inf.ed.ac.uk 10876974Stjones1@inf.ed.ac.uk#if 0 10886974Stjones1@inf.ed.ac.uk if (reg & TBICR_MR_RESTART_AN) ; 10896974Stjones1@inf.ed.ac.uk#endif 10906974Stjones1@inf.ed.ac.uk 10916974Stjones1@inf.ed.ac.uk break; 10922699Sktlim@umich.edu 10932693Sktlim@umich.edu case TBISR: 10946221Snate@binkert.org panic("TBISR is read only register!\n"); 10956974Stjones1@inf.ed.ac.uk 10966974Stjones1@inf.ed.ac.uk case TANAR: 10976974Stjones1@inf.ed.ac.uk // Only write the writable bits 10986974Stjones1@inf.ed.ac.uk regs.tanar &= TANAR_RF1 | TANAR_RF2 | TANAR_UNUSED; 10996974Stjones1@inf.ed.ac.uk regs.tanar |= reg & ~(TANAR_RF1 | TANAR_RF2 | TANAR_UNUSED); 11006974Stjones1@inf.ed.ac.uk 11016974Stjones1@inf.ed.ac.uk // Pause capability unimplemented 11026974Stjones1@inf.ed.ac.uk#if 0 11032693Sktlim@umich.edu if (reg & TANAR_PS2) ; 11042693Sktlim@umich.edu if (reg & TANAR_PS1) ; 11052727Sktlim@umich.edu#endif 11062907Sktlim@umich.edu 11072693Sktlim@umich.edu break; 11082693Sktlim@umich.edu 11092693Sktlim@umich.edu case TANLPAR: 11102693Sktlim@umich.edu panic("this should only be written to by the fake phy!\n"); 11112693Sktlim@umich.edu 11122693Sktlim@umich.edu case TANER: 11132693Sktlim@umich.edu panic("TANER is read only register!\n"); 11142693Sktlim@umich.edu 11152693Sktlim@umich.edu case TESR: 11162693Sktlim@umich.edu regs.tesr = reg; 11172292SN/A break; 11182292SN/A 11192292SN/A default: 11202292SN/A panic("invalid register access daddr=%#x", daddr); 11212292SN/A } 11222292SN/A } else { 11232292SN/A panic("Invalid Request Size"); 11242292SN/A } 11252292SN/A pkt->makeAtomicResponse(); 11262292SN/A return pioDelay; 11272292SN/A} 11282292SN/A 11292292SN/Avoid 11302292SN/ANSGigE::devIntrPost(uint32_t interrupts) 11312292SN/A{ 11322292SN/A if (interrupts & ISR_RESERVE) 11332292SN/A panic("Cannot set a reserved interrupt"); 11342292SN/A 11352292SN/A if (interrupts & ISR_NOIMPL) 11362292SN/A warn("interrupt not implemented %#x\n", interrupts); 11372292SN/A 11382292SN/A interrupts &= ISR_IMPL; 11392292SN/A regs.isr |= interrupts; 11402292SN/A 11412292SN/A if (interrupts & regs.imr) { 11422292SN/A if (interrupts & ISR_SWI) { 11432292SN/A totalSwi++; 11442292SN/A } 11452292SN/A if (interrupts & ISR_RXIDLE) { 11462292SN/A totalRxIdle++; 11472329SN/A } 11482329SN/A if (interrupts & ISR_RXOK) { 11492329SN/A totalRxOk++; 11502329SN/A } 11512329SN/A if (interrupts & ISR_RXDESC) { 11522329SN/A totalRxDesc++; 11532329SN/A } 11542329SN/A if (interrupts & ISR_TXOK) { 11552329SN/A totalTxOk++; 11562329SN/A } 11572329SN/A if (interrupts & ISR_TXIDLE) { 11582329SN/A totalTxIdle++; 11597720Sgblack@eecs.umich.edu } 11602329SN/A if (interrupts & ISR_TXDESC) { 11612329SN/A totalTxDesc++; 11622329SN/A } 11632329SN/A if (interrupts & ISR_RXORN) { 11642329SN/A totalRxOrn++; 11652329SN/A } 11662329SN/A } 11672329SN/A 11682329SN/A DPRINTF(EthernetIntr, 11692329SN/A "interrupt written to ISR: intr=%#x isr=%#x imr=%#x\n", 11707720Sgblack@eecs.umich.edu interrupts, regs.isr, regs.imr); 11712329SN/A 11722329SN/A if ((regs.isr & regs.imr)) { 11732329SN/A Tick when = curTick; 11742329SN/A if ((regs.isr & regs.imr & ISR_NODELAY) == 0) 11752329SN/A when += intrDelay; 11762329SN/A cpuIntrPost(when); 1177 } 1178} 1179 1180/* writing this interrupt counting stats inside this means that this function 1181 is now limited to being used to clear all interrupts upon the kernel 1182 reading isr and servicing. just telling you in case you were thinking 1183 of expanding use. 1184*/ 1185void 1186NSGigE::devIntrClear(uint32_t interrupts) 1187{ 1188 if (interrupts & ISR_RESERVE) 1189 panic("Cannot clear a reserved interrupt"); 1190 1191 if (regs.isr & regs.imr & ISR_SWI) { 1192 postedSwi++; 1193 } 1194 if (regs.isr & regs.imr & ISR_RXIDLE) { 1195 postedRxIdle++; 1196 } 1197 if (regs.isr & regs.imr & ISR_RXOK) { 1198 postedRxOk++; 1199 } 1200 if (regs.isr & regs.imr & ISR_RXDESC) { 1201 postedRxDesc++; 1202 } 1203 if (regs.isr & regs.imr & ISR_TXOK) { 1204 postedTxOk++; 1205 } 1206 if (regs.isr & regs.imr & ISR_TXIDLE) { 1207 postedTxIdle++; 1208 } 1209 if (regs.isr & regs.imr & ISR_TXDESC) { 1210 postedTxDesc++; 1211 } 1212 if (regs.isr & regs.imr & ISR_RXORN) { 1213 postedRxOrn++; 1214 } 1215 1216 if (regs.isr & regs.imr & ISR_IMPL) 1217 postedInterrupts++; 1218 1219 interrupts &= ~ISR_NOIMPL; 1220 regs.isr &= ~interrupts; 1221 1222 DPRINTF(EthernetIntr, 1223 "interrupt cleared from ISR: intr=%x isr=%x imr=%x\n", 1224 interrupts, regs.isr, regs.imr); 1225 1226 if (!(regs.isr & regs.imr)) 1227 cpuIntrClear(); 1228} 1229 1230void 1231NSGigE::devIntrChangeMask() 1232{ 1233 DPRINTF(EthernetIntr, "interrupt mask changed: isr=%x imr=%x masked=%x\n", 1234 regs.isr, regs.imr, regs.isr & regs.imr); 1235 1236 if (regs.isr & regs.imr) 1237 cpuIntrPost(curTick); 1238 else 1239 cpuIntrClear(); 1240} 1241 1242void 1243NSGigE::cpuIntrPost(Tick when) 1244{ 1245 // If the interrupt you want to post is later than an interrupt 1246 // already scheduled, just let it post in the coming one and don't 1247 // schedule another. 1248 // HOWEVER, must be sure that the scheduled intrTick is in the 1249 // future (this was formerly the source of a bug) 1250 /** 1251 * @todo this warning should be removed and the intrTick code should 1252 * be fixed. 1253 */ 1254 assert(when >= curTick); 1255 assert(intrTick >= curTick || intrTick == 0); 1256 if (when > intrTick && intrTick != 0) { 1257 DPRINTF(EthernetIntr, "don't need to schedule event...intrTick=%d\n", 1258 intrTick); 1259 return; 1260 } 1261 1262 intrTick = when; 1263 if (intrTick < curTick) { 1264 debug_break(); 1265 intrTick = curTick; 1266 } 1267 1268 DPRINTF(EthernetIntr, "going to schedule an interrupt for intrTick=%d\n", 1269 intrTick); 1270 1271 if (intrEvent) 1272 intrEvent->squash(); 1273 intrEvent = new IntrEvent(this, intrTick, true); 1274} 1275 1276void 1277NSGigE::cpuInterrupt() 1278{ 1279 assert(intrTick == curTick); 1280 1281 // Whether or not there's a pending interrupt, we don't care about 1282 // it anymore 1283 intrEvent = 0; 1284 intrTick = 0; 1285 1286 // Don't send an interrupt if there's already one 1287 if (cpuPendingIntr) { 1288 DPRINTF(EthernetIntr, 1289 "would send an interrupt now, but there's already pending\n"); 1290 } else { 1291 // Send interrupt 1292 cpuPendingIntr = true; 1293 1294 DPRINTF(EthernetIntr, "posting interrupt\n"); 1295 intrPost(); 1296 } 1297} 1298 1299void 1300NSGigE::cpuIntrClear() 1301{ 1302 if (!cpuPendingIntr) 1303 return; 1304 1305 if (intrEvent) { 1306 intrEvent->squash(); 1307 intrEvent = 0; 1308 } 1309 1310 intrTick = 0; 1311 1312 cpuPendingIntr = false; 1313 1314 DPRINTF(EthernetIntr, "clearing interrupt\n"); 1315 intrClear(); 1316} 1317 1318bool 1319NSGigE::cpuIntrPending() const 1320{ return cpuPendingIntr; } 1321 1322void 1323NSGigE::txReset() 1324{ 1325 1326 DPRINTF(Ethernet, "transmit reset\n"); 1327 1328 CTDD = false; 1329 txEnable = false;; 1330 txFragPtr = 0; 1331 assert(txDescCnt == 0); 1332 txFifo.clear(); 1333 txState = txIdle; 1334 assert(txDmaState == dmaIdle); 1335} 1336 1337void 1338NSGigE::rxReset() 1339{ 1340 DPRINTF(Ethernet, "receive reset\n"); 1341 1342 CRDD = false; 1343 assert(rxPktBytes == 0); 1344 rxEnable = false; 1345 rxFragPtr = 0; 1346 assert(rxDescCnt == 0); 1347 assert(rxDmaState == dmaIdle); 1348 rxFifo.clear(); 1349 rxState = rxIdle; 1350} 1351 1352void 1353NSGigE::regsReset() 1354{ 1355 memset(®s, 0, sizeof(regs)); 1356 regs.config = (CFGR_LNKSTS | CFGR_TBI_EN | CFGR_MODE_1000); 1357 regs.mear = 0x12; 1358 regs.txcfg = 0x120; // set drain threshold to 1024 bytes and 1359 // fill threshold to 32 bytes 1360 regs.rxcfg = 0x4; // set drain threshold to 16 bytes 1361 regs.srr = 0x0103; // set the silicon revision to rev B or 0x103 1362 regs.mibc = MIBC_FRZ; 1363 regs.vdr = 0x81; // set the vlan tag type to 802.1q 1364 regs.tesr = 0xc000; // TBI capable of both full and half duplex 1365 regs.brar = 0xffffffff; 1366 1367 extstsEnable = false; 1368 acceptBroadcast = false; 1369 acceptMulticast = false; 1370 acceptUnicast = false; 1371 acceptPerfect = false; 1372 acceptArp = false; 1373} 1374 1375bool 1376NSGigE::doRxDmaRead() 1377{ 1378 assert(rxDmaState == dmaIdle || rxDmaState == dmaReadWaiting); 1379 rxDmaState = dmaReading; 1380 1381 if (dmaPending() || getState() != Running) 1382 rxDmaState = dmaReadWaiting; 1383 else 1384 dmaRead(rxDmaAddr, rxDmaLen, &rxDmaReadEvent, (uint8_t*)rxDmaData); 1385 1386 return true; 1387} 1388 1389void 1390NSGigE::rxDmaReadDone() 1391{ 1392 assert(rxDmaState == dmaReading); 1393 rxDmaState = dmaIdle; 1394 1395 DPRINTF(EthernetDMA, "rx dma read paddr=%#x len=%d\n", 1396 rxDmaAddr, rxDmaLen); 1397 DDUMP(EthernetDMA, rxDmaData, rxDmaLen); 1398 1399 // If the transmit state machine has a pending DMA, let it go first 1400 if (txDmaState == dmaReadWaiting || txDmaState == dmaWriteWaiting) 1401 txKick(); 1402 1403 rxKick(); 1404} 1405 1406bool 1407NSGigE::doRxDmaWrite() 1408{ 1409 assert(rxDmaState == dmaIdle || rxDmaState == dmaWriteWaiting); 1410 rxDmaState = dmaWriting; 1411 1412 if (dmaPending() || getState() != Running) 1413 rxDmaState = dmaWriteWaiting; 1414 else 1415 dmaWrite(rxDmaAddr, rxDmaLen, &rxDmaWriteEvent, (uint8_t*)rxDmaData); 1416 return true; 1417} 1418 1419void 1420NSGigE::rxDmaWriteDone() 1421{ 1422 assert(rxDmaState == dmaWriting); 1423 rxDmaState = dmaIdle; 1424 1425 DPRINTF(EthernetDMA, "rx dma write paddr=%#x len=%d\n", 1426 rxDmaAddr, rxDmaLen); 1427 DDUMP(EthernetDMA, rxDmaData, rxDmaLen); 1428 1429 // If the transmit state machine has a pending DMA, let it go first 1430 if (txDmaState == dmaReadWaiting || txDmaState == dmaWriteWaiting) 1431 txKick(); 1432 1433 rxKick(); 1434} 1435 1436void 1437NSGigE::rxKick() 1438{ 1439 bool is64bit = (bool)(regs.config & CFGR_M64ADDR); 1440 1441 DPRINTF(EthernetSM, 1442 "receive kick rxState=%s (rxBuf.size=%d) %d-bit\n", 1443 NsRxStateStrings[rxState], rxFifo.size(), is64bit ? 64 : 32); 1444 1445 Addr link, bufptr; 1446 uint32_t &cmdsts = is64bit ? rxDesc64.cmdsts : rxDesc32.cmdsts; 1447 uint32_t &extsts = is64bit ? rxDesc64.extsts : rxDesc32.extsts; 1448 1449 next: 1450 if (clock) { 1451 if (rxKickTick > curTick) { 1452 DPRINTF(EthernetSM, "receive kick exiting, can't run till %d\n", 1453 rxKickTick); 1454 1455 goto exit; 1456 } 1457 1458 // Go to the next state machine clock tick. 1459 rxKickTick = curTick + cycles(1); 1460 } 1461 1462 switch(rxDmaState) { 1463 case dmaReadWaiting: 1464 if (doRxDmaRead()) 1465 goto exit; 1466 break; 1467 case dmaWriteWaiting: 1468 if (doRxDmaWrite()) 1469 goto exit; 1470 break; 1471 default: 1472 break; 1473 } 1474 1475 link = is64bit ? (Addr)rxDesc64.link : (Addr)rxDesc32.link; 1476 bufptr = is64bit ? (Addr)rxDesc64.bufptr : (Addr)rxDesc32.bufptr; 1477 1478 // see state machine from spec for details 1479 // the way this works is, if you finish work on one state and can 1480 // go directly to another, you do that through jumping to the 1481 // label "next". however, if you have intermediate work, like DMA 1482 // so that you can't go to the next state yet, you go to exit and 1483 // exit the loop. however, when the DMA is done it will trigger 1484 // an event and come back to this loop. 1485 switch (rxState) { 1486 case rxIdle: 1487 if (!rxEnable) { 1488 DPRINTF(EthernetSM, "Receive Disabled! Nothing to do.\n"); 1489 goto exit; 1490 } 1491 1492 if (CRDD) { 1493 rxState = rxDescRefr; 1494 1495 rxDmaAddr = regs.rxdp & 0x3fffffff; 1496 rxDmaData = 1497 is64bit ? (void *)&rxDesc64.link : (void *)&rxDesc32.link; 1498 rxDmaLen = is64bit ? sizeof(rxDesc64.link) : sizeof(rxDesc32.link); 1499 rxDmaFree = dmaDescFree; 1500 1501 descDmaReads++; 1502 descDmaRdBytes += rxDmaLen; 1503 1504 if (doRxDmaRead()) 1505 goto exit; 1506 } else { 1507 rxState = rxDescRead; 1508 1509 rxDmaAddr = regs.rxdp & 0x3fffffff; 1510 rxDmaData = is64bit ? (void *)&rxDesc64 : (void *)&rxDesc32; 1511 rxDmaLen = is64bit ? sizeof(rxDesc64) : sizeof(rxDesc32); 1512 rxDmaFree = dmaDescFree; 1513 1514 descDmaReads++; 1515 descDmaRdBytes += rxDmaLen; 1516 1517 if (doRxDmaRead()) 1518 goto exit; 1519 } 1520 break; 1521 1522 case rxDescRefr: 1523 if (rxDmaState != dmaIdle) 1524 goto exit; 1525 1526 rxState = rxAdvance; 1527 break; 1528 1529 case rxDescRead: 1530 if (rxDmaState != dmaIdle) 1531 goto exit; 1532 1533 DPRINTF(EthernetDesc, "rxDesc: addr=%08x read descriptor\n", 1534 regs.rxdp & 0x3fffffff); 1535 DPRINTF(EthernetDesc, 1536 "rxDesc: link=%#x bufptr=%#x cmdsts=%08x extsts=%08x\n", 1537 link, bufptr, cmdsts, extsts); 1538 1539 if (cmdsts & CMDSTS_OWN) { 1540 devIntrPost(ISR_RXIDLE); 1541 rxState = rxIdle; 1542 goto exit; 1543 } else { 1544 rxState = rxFifoBlock; 1545 rxFragPtr = bufptr; 1546 rxDescCnt = cmdsts & CMDSTS_LEN_MASK; 1547 } 1548 break; 1549 1550 case rxFifoBlock: 1551 if (!rxPacket) { 1552 /** 1553 * @todo in reality, we should be able to start processing 1554 * the packet as it arrives, and not have to wait for the 1555 * full packet ot be in the receive fifo. 1556 */ 1557 if (rxFifo.empty()) 1558 goto exit; 1559 1560 DPRINTF(EthernetSM, "****processing receive of new packet****\n"); 1561 1562 // If we don't have a packet, grab a new one from the fifo. 1563 rxPacket = rxFifo.front(); 1564 rxPktBytes = rxPacket->length; 1565 rxPacketBufPtr = rxPacket->data; 1566 1567#if TRACING_ON 1568 if (DTRACE(Ethernet)) { 1569 IpPtr ip(rxPacket); 1570 if (ip) { 1571 DPRINTF(Ethernet, "ID is %d\n", ip->id()); 1572 TcpPtr tcp(ip); 1573 if (tcp) { 1574 DPRINTF(Ethernet, 1575 "Src Port=%d, Dest Port=%d, Seq=%d, Ack=%d\n", 1576 tcp->sport(), tcp->dport(), tcp->seq(), 1577 tcp->ack()); 1578 } 1579 } 1580 } 1581#endif 1582 1583 // sanity check - i think the driver behaves like this 1584 assert(rxDescCnt >= rxPktBytes); 1585 rxFifo.pop(); 1586 } 1587 1588 1589 // dont' need the && rxDescCnt > 0 if driver sanity check 1590 // above holds 1591 if (rxPktBytes > 0) { 1592 rxState = rxFragWrite; 1593 // don't need min<>(rxPktBytes,rxDescCnt) if above sanity 1594 // check holds 1595 rxXferLen = rxPktBytes; 1596 1597 rxDmaAddr = rxFragPtr & 0x3fffffff; 1598 rxDmaData = rxPacketBufPtr; 1599 rxDmaLen = rxXferLen; 1600 rxDmaFree = dmaDataFree; 1601 1602 if (doRxDmaWrite()) 1603 goto exit; 1604 1605 } else { 1606 rxState = rxDescWrite; 1607 1608 //if (rxPktBytes == 0) { /* packet is done */ 1609 assert(rxPktBytes == 0); 1610 DPRINTF(EthernetSM, "done with receiving packet\n"); 1611 1612 cmdsts |= CMDSTS_OWN; 1613 cmdsts &= ~CMDSTS_MORE; 1614 cmdsts |= CMDSTS_OK; 1615 cmdsts &= 0xffff0000; 1616 cmdsts += rxPacket->length; //i.e. set CMDSTS_SIZE 1617 1618#if 0 1619 /* 1620 * all the driver uses these are for its own stats keeping 1621 * which we don't care about, aren't necessary for 1622 * functionality and doing this would just slow us down. 1623 * if they end up using this in a later version for 1624 * functional purposes, just undef 1625 */ 1626 if (rxFilterEnable) { 1627 cmdsts &= ~CMDSTS_DEST_MASK; 1628 const EthAddr &dst = rxFifoFront()->dst(); 1629 if (dst->unicast()) 1630 cmdsts |= CMDSTS_DEST_SELF; 1631 if (dst->multicast()) 1632 cmdsts |= CMDSTS_DEST_MULTI; 1633 if (dst->broadcast()) 1634 cmdsts |= CMDSTS_DEST_MASK; 1635 } 1636#endif 1637 1638 IpPtr ip(rxPacket); 1639 if (extstsEnable && ip) { 1640 extsts |= EXTSTS_IPPKT; 1641 rxIpChecksums++; 1642 if (cksum(ip) != 0) { 1643 DPRINTF(EthernetCksum, "Rx IP Checksum Error\n"); 1644 extsts |= EXTSTS_IPERR; 1645 } 1646 TcpPtr tcp(ip); 1647 UdpPtr udp(ip); 1648 if (tcp) { 1649 extsts |= EXTSTS_TCPPKT; 1650 rxTcpChecksums++; 1651 if (cksum(tcp) != 0) { 1652 DPRINTF(EthernetCksum, "Rx TCP Checksum Error\n"); 1653 extsts |= EXTSTS_TCPERR; 1654 1655 } 1656 } else if (udp) { 1657 extsts |= EXTSTS_UDPPKT; 1658 rxUdpChecksums++; 1659 if (cksum(udp) != 0) { 1660 DPRINTF(EthernetCksum, "Rx UDP Checksum Error\n"); 1661 extsts |= EXTSTS_UDPERR; 1662 } 1663 } 1664 } 1665 rxPacket = 0; 1666 1667 /* 1668 * the driver seems to always receive into desc buffers 1669 * of size 1514, so you never have a pkt that is split 1670 * into multiple descriptors on the receive side, so 1671 * i don't implement that case, hence the assert above. 1672 */ 1673 1674 DPRINTF(EthernetDesc, 1675 "rxDesc: addr=%08x writeback cmdsts extsts\n", 1676 regs.rxdp & 0x3fffffff); 1677 DPRINTF(EthernetDesc, 1678 "rxDesc: link=%#x bufptr=%#x cmdsts=%08x extsts=%08x\n", 1679 link, bufptr, cmdsts, extsts); 1680 1681 rxDmaAddr = regs.rxdp & 0x3fffffff; 1682 rxDmaData = &cmdsts; 1683 if (is64bit) { 1684 rxDmaAddr += offsetof(ns_desc64, cmdsts); 1685 rxDmaLen = sizeof(rxDesc64.cmdsts) + sizeof(rxDesc64.extsts); 1686 } else { 1687 rxDmaAddr += offsetof(ns_desc32, cmdsts); 1688 rxDmaLen = sizeof(rxDesc32.cmdsts) + sizeof(rxDesc32.extsts); 1689 } 1690 rxDmaFree = dmaDescFree; 1691 1692 descDmaWrites++; 1693 descDmaWrBytes += rxDmaLen; 1694 1695 if (doRxDmaWrite()) 1696 goto exit; 1697 } 1698 break; 1699 1700 case rxFragWrite: 1701 if (rxDmaState != dmaIdle) 1702 goto exit; 1703 1704 rxPacketBufPtr += rxXferLen; 1705 rxFragPtr += rxXferLen; 1706 rxPktBytes -= rxXferLen; 1707 1708 rxState = rxFifoBlock; 1709 break; 1710 1711 case rxDescWrite: 1712 if (rxDmaState != dmaIdle) 1713 goto exit; 1714 1715 assert(cmdsts & CMDSTS_OWN); 1716 1717 assert(rxPacket == 0); 1718 devIntrPost(ISR_RXOK); 1719 1720 if (cmdsts & CMDSTS_INTR) 1721 devIntrPost(ISR_RXDESC); 1722 1723 if (!rxEnable) { 1724 DPRINTF(EthernetSM, "Halting the RX state machine\n"); 1725 rxState = rxIdle; 1726 goto exit; 1727 } else 1728 rxState = rxAdvance; 1729 break; 1730 1731 case rxAdvance: 1732 if (link == 0) { 1733 devIntrPost(ISR_RXIDLE); 1734 rxState = rxIdle; 1735 CRDD = true; 1736 goto exit; 1737 } else { 1738 if (rxDmaState != dmaIdle) 1739 goto exit; 1740 rxState = rxDescRead; 1741 regs.rxdp = link; 1742 CRDD = false; 1743 1744 rxDmaAddr = regs.rxdp & 0x3fffffff; 1745 rxDmaData = is64bit ? (void *)&rxDesc64 : (void *)&rxDesc32; 1746 rxDmaLen = is64bit ? sizeof(rxDesc64) : sizeof(rxDesc32); 1747 rxDmaFree = dmaDescFree; 1748 1749 if (doRxDmaRead()) 1750 goto exit; 1751 } 1752 break; 1753 1754 default: 1755 panic("Invalid rxState!"); 1756 } 1757 1758 DPRINTF(EthernetSM, "entering next rxState=%s\n", 1759 NsRxStateStrings[rxState]); 1760 goto next; 1761 1762 exit: 1763 /** 1764 * @todo do we want to schedule a future kick? 1765 */ 1766 DPRINTF(EthernetSM, "rx state machine exited rxState=%s\n", 1767 NsRxStateStrings[rxState]); 1768 1769 if (clock && !rxKickEvent.scheduled()) 1770 rxKickEvent.schedule(rxKickTick); 1771} 1772 1773void 1774NSGigE::transmit() 1775{ 1776 if (txFifo.empty()) { 1777 DPRINTF(Ethernet, "nothing to transmit\n"); 1778 return; 1779 } 1780 1781 DPRINTF(Ethernet, "Attempt Pkt Transmit: txFifo length=%d\n", 1782 txFifo.size()); 1783 if (interface->sendPacket(txFifo.front())) { 1784#if TRACING_ON 1785 if (DTRACE(Ethernet)) { 1786 IpPtr ip(txFifo.front()); 1787 if (ip) { 1788 DPRINTF(Ethernet, "ID is %d\n", ip->id()); 1789 TcpPtr tcp(ip); 1790 if (tcp) { 1791 DPRINTF(Ethernet, 1792 "Src Port=%d, Dest Port=%d, Seq=%d, Ack=%d\n", 1793 tcp->sport(), tcp->dport(), tcp->seq(), 1794 tcp->ack()); 1795 } 1796 } 1797 } 1798#endif 1799 1800 DDUMP(EthernetData, txFifo.front()->data, txFifo.front()->length); 1801 txBytes += txFifo.front()->length; 1802 txPackets++; 1803 1804 DPRINTF(Ethernet, "Successful Xmit! now txFifoAvail is %d\n", 1805 txFifo.avail()); 1806 txFifo.pop(); 1807 1808 /* 1809 * normally do a writeback of the descriptor here, and ONLY 1810 * after that is done, send this interrupt. but since our 1811 * stuff never actually fails, just do this interrupt here, 1812 * otherwise the code has to stray from this nice format. 1813 * besides, it's functionally the same. 1814 */ 1815 devIntrPost(ISR_TXOK); 1816 } 1817 1818 if (!txFifo.empty() && !txEvent.scheduled()) { 1819 DPRINTF(Ethernet, "reschedule transmit\n"); 1820 txEvent.schedule(curTick + retryTime); 1821 } 1822} 1823 1824bool 1825NSGigE::doTxDmaRead() 1826{ 1827 assert(txDmaState == dmaIdle || txDmaState == dmaReadWaiting); 1828 txDmaState = dmaReading; 1829 1830 if (dmaPending() || getState() != Running) 1831 txDmaState = dmaReadWaiting; 1832 else 1833 dmaRead(txDmaAddr, txDmaLen, &txDmaReadEvent, (uint8_t*)txDmaData); 1834 1835 return true; 1836} 1837 1838void 1839NSGigE::txDmaReadDone() 1840{ 1841 assert(txDmaState == dmaReading); 1842 txDmaState = dmaIdle; 1843 1844 DPRINTF(EthernetDMA, "tx dma read paddr=%#x len=%d\n", 1845 txDmaAddr, txDmaLen); 1846 DDUMP(EthernetDMA, txDmaData, txDmaLen); 1847 1848 // If the receive state machine has a pending DMA, let it go first 1849 if (rxDmaState == dmaReadWaiting || rxDmaState == dmaWriteWaiting) 1850 rxKick(); 1851 1852 txKick(); 1853} 1854 1855bool 1856NSGigE::doTxDmaWrite() 1857{ 1858 assert(txDmaState == dmaIdle || txDmaState == dmaWriteWaiting); 1859 txDmaState = dmaWriting; 1860 1861 if (dmaPending() || getState() != Running) 1862 txDmaState = dmaWriteWaiting; 1863 else 1864 dmaWrite(txDmaAddr, txDmaLen, &txDmaWriteEvent, (uint8_t*)txDmaData); 1865 return true; 1866} 1867 1868void 1869NSGigE::txDmaWriteDone() 1870{ 1871 assert(txDmaState == dmaWriting); 1872 txDmaState = dmaIdle; 1873 1874 DPRINTF(EthernetDMA, "tx dma write paddr=%#x len=%d\n", 1875 txDmaAddr, txDmaLen); 1876 DDUMP(EthernetDMA, txDmaData, txDmaLen); 1877 1878 // If the receive state machine has a pending DMA, let it go first 1879 if (rxDmaState == dmaReadWaiting || rxDmaState == dmaWriteWaiting) 1880 rxKick(); 1881 1882 txKick(); 1883} 1884 1885void 1886NSGigE::txKick() 1887{ 1888 bool is64bit = (bool)(regs.config & CFGR_M64ADDR); 1889 1890 DPRINTF(EthernetSM, "transmit kick txState=%s %d-bit\n", 1891 NsTxStateStrings[txState], is64bit ? 64 : 32); 1892 1893 Addr link, bufptr; 1894 uint32_t &cmdsts = is64bit ? txDesc64.cmdsts : txDesc32.cmdsts; 1895 uint32_t &extsts = is64bit ? txDesc64.extsts : txDesc32.extsts; 1896 1897 next: 1898 if (clock) { 1899 if (txKickTick > curTick) { 1900 DPRINTF(EthernetSM, "transmit kick exiting, can't run till %d\n", 1901 txKickTick); 1902 goto exit; 1903 } 1904 1905 // Go to the next state machine clock tick. 1906 txKickTick = curTick + cycles(1); 1907 } 1908 1909 switch(txDmaState) { 1910 case dmaReadWaiting: 1911 if (doTxDmaRead()) 1912 goto exit; 1913 break; 1914 case dmaWriteWaiting: 1915 if (doTxDmaWrite()) 1916 goto exit; 1917 break; 1918 default: 1919 break; 1920 } 1921 1922 link = is64bit ? (Addr)txDesc64.link : (Addr)txDesc32.link; 1923 bufptr = is64bit ? (Addr)txDesc64.bufptr : (Addr)txDesc32.bufptr; 1924 switch (txState) { 1925 case txIdle: 1926 if (!txEnable) { 1927 DPRINTF(EthernetSM, "Transmit disabled. Nothing to do.\n"); 1928 goto exit; 1929 } 1930 1931 if (CTDD) { 1932 txState = txDescRefr; 1933 1934 txDmaAddr = regs.txdp & 0x3fffffff; 1935 txDmaData = 1936 is64bit ? (void *)&txDesc64.link : (void *)&txDesc32.link; 1937 txDmaLen = is64bit ? sizeof(txDesc64.link) : sizeof(txDesc32.link); 1938 txDmaFree = dmaDescFree; 1939 1940 descDmaReads++; 1941 descDmaRdBytes += txDmaLen; 1942 1943 if (doTxDmaRead()) 1944 goto exit; 1945 1946 } else { 1947 txState = txDescRead; 1948 1949 txDmaAddr = regs.txdp & 0x3fffffff; 1950 txDmaData = is64bit ? (void *)&txDesc64 : (void *)&txDesc32; 1951 txDmaLen = is64bit ? sizeof(txDesc64) : sizeof(txDesc32); 1952 txDmaFree = dmaDescFree; 1953 1954 descDmaReads++; 1955 descDmaRdBytes += txDmaLen; 1956 1957 if (doTxDmaRead()) 1958 goto exit; 1959 } 1960 break; 1961 1962 case txDescRefr: 1963 if (txDmaState != dmaIdle) 1964 goto exit; 1965 1966 txState = txAdvance; 1967 break; 1968 1969 case txDescRead: 1970 if (txDmaState != dmaIdle) 1971 goto exit; 1972 1973 DPRINTF(EthernetDesc, "txDesc: addr=%08x read descriptor\n", 1974 regs.txdp & 0x3fffffff); 1975 DPRINTF(EthernetDesc, 1976 "txDesc: link=%#x bufptr=%#x cmdsts=%#08x extsts=%#08x\n", 1977 link, bufptr, cmdsts, extsts); 1978 1979 if (cmdsts & CMDSTS_OWN) { 1980 txState = txFifoBlock; 1981 txFragPtr = bufptr; 1982 txDescCnt = cmdsts & CMDSTS_LEN_MASK; 1983 } else { 1984 devIntrPost(ISR_TXIDLE); 1985 txState = txIdle; 1986 goto exit; 1987 } 1988 break; 1989 1990 case txFifoBlock: 1991 if (!txPacket) { 1992 DPRINTF(EthernetSM, "****starting the tx of a new packet****\n"); 1993 txPacket = new EthPacketData(16384); 1994 txPacketBufPtr = txPacket->data; 1995 } 1996 1997 if (txDescCnt == 0) { 1998 DPRINTF(EthernetSM, "the txDescCnt == 0, done with descriptor\n"); 1999 if (cmdsts & CMDSTS_MORE) { 2000 DPRINTF(EthernetSM, "there are more descriptors to come\n"); 2001 txState = txDescWrite; 2002 2003 cmdsts &= ~CMDSTS_OWN; 2004 2005 txDmaAddr = regs.txdp & 0x3fffffff; 2006 txDmaData = &cmdsts; 2007 if (is64bit) { 2008 txDmaAddr += offsetof(ns_desc64, cmdsts); 2009 txDmaLen = sizeof(txDesc64.cmdsts); 2010 } else { 2011 txDmaAddr += offsetof(ns_desc32, cmdsts); 2012 txDmaLen = sizeof(txDesc32.cmdsts); 2013 } 2014 txDmaFree = dmaDescFree; 2015 2016 if (doTxDmaWrite()) 2017 goto exit; 2018 2019 } else { /* this packet is totally done */ 2020 DPRINTF(EthernetSM, "This packet is done, let's wrap it up\n"); 2021 /* deal with the the packet that just finished */ 2022 if ((regs.vtcr & VTCR_PPCHK) && extstsEnable) { 2023 IpPtr ip(txPacket); 2024 if (extsts & EXTSTS_UDPPKT) { 2025 UdpPtr udp(ip); 2026 udp->sum(0); 2027 udp->sum(cksum(udp)); 2028 txUdpChecksums++; 2029 } else if (extsts & EXTSTS_TCPPKT) { 2030 TcpPtr tcp(ip); 2031 tcp->sum(0); 2032 tcp->sum(cksum(tcp)); 2033 txTcpChecksums++; 2034 } 2035 if (extsts & EXTSTS_IPPKT) { 2036 ip->sum(0); 2037 ip->sum(cksum(ip)); 2038 txIpChecksums++; 2039 } 2040 } 2041 2042 txPacket->length = txPacketBufPtr - txPacket->data; 2043 // this is just because the receive can't handle a 2044 // packet bigger want to make sure 2045 if (txPacket->length > 1514) 2046 panic("transmit packet too large, %s > 1514\n", 2047 txPacket->length); 2048 2049#ifndef NDEBUG 2050 bool success = 2051#endif 2052 txFifo.push(txPacket); 2053 assert(success); 2054 2055 /* 2056 * this following section is not tqo spec, but 2057 * functionally shouldn't be any different. normally, 2058 * the chip will wait til the transmit has occurred 2059 * before writing back the descriptor because it has 2060 * to wait to see that it was successfully transmitted 2061 * to decide whether to set CMDSTS_OK or not. 2062 * however, in the simulator since it is always 2063 * successfully transmitted, and writing it exactly to 2064 * spec would complicate the code, we just do it here 2065 */ 2066 2067 cmdsts &= ~CMDSTS_OWN; 2068 cmdsts |= CMDSTS_OK; 2069 2070 DPRINTF(EthernetDesc, 2071 "txDesc writeback: cmdsts=%08x extsts=%08x\n", 2072 cmdsts, extsts); 2073 2074 txDmaFree = dmaDescFree; 2075 txDmaAddr = regs.txdp & 0x3fffffff; 2076 txDmaData = &cmdsts; 2077 if (is64bit) { 2078 txDmaAddr += offsetof(ns_desc64, cmdsts); 2079 txDmaLen = 2080 sizeof(txDesc64.cmdsts) + sizeof(txDesc64.extsts); 2081 } else { 2082 txDmaAddr += offsetof(ns_desc32, cmdsts); 2083 txDmaLen = 2084 sizeof(txDesc32.cmdsts) + sizeof(txDesc32.extsts); 2085 } 2086 2087 descDmaWrites++; 2088 descDmaWrBytes += txDmaLen; 2089 2090 transmit(); 2091 txPacket = 0; 2092 2093 if (!txEnable) { 2094 DPRINTF(EthernetSM, "halting TX state machine\n"); 2095 txState = txIdle; 2096 goto exit; 2097 } else 2098 txState = txAdvance; 2099 2100 if (doTxDmaWrite()) 2101 goto exit; 2102 } 2103 } else { 2104 DPRINTF(EthernetSM, "this descriptor isn't done yet\n"); 2105 if (!txFifo.full()) { 2106 txState = txFragRead; 2107 2108 /* 2109 * The number of bytes transferred is either whatever 2110 * is left in the descriptor (txDescCnt), or if there 2111 * is not enough room in the fifo, just whatever room 2112 * is left in the fifo 2113 */ 2114 txXferLen = min<uint32_t>(txDescCnt, txFifo.avail()); 2115 2116 txDmaAddr = txFragPtr & 0x3fffffff; 2117 txDmaData = txPacketBufPtr; 2118 txDmaLen = txXferLen; 2119 txDmaFree = dmaDataFree; 2120 2121 if (doTxDmaRead()) 2122 goto exit; 2123 } else { 2124 txState = txFifoBlock; 2125 transmit(); 2126 2127 goto exit; 2128 } 2129 2130 } 2131 break; 2132 2133 case txFragRead: 2134 if (txDmaState != dmaIdle) 2135 goto exit; 2136 2137 txPacketBufPtr += txXferLen; 2138 txFragPtr += txXferLen; 2139 txDescCnt -= txXferLen; 2140 txFifo.reserve(txXferLen); 2141 2142 txState = txFifoBlock; 2143 break; 2144 2145 case txDescWrite: 2146 if (txDmaState != dmaIdle) 2147 goto exit; 2148 2149 if (cmdsts & CMDSTS_INTR) 2150 devIntrPost(ISR_TXDESC); 2151 2152 if (!txEnable) { 2153 DPRINTF(EthernetSM, "halting TX state machine\n"); 2154 txState = txIdle; 2155 goto exit; 2156 } else 2157 txState = txAdvance; 2158 break; 2159 2160 case txAdvance: 2161 if (link == 0) { 2162 devIntrPost(ISR_TXIDLE); 2163 txState = txIdle; 2164 goto exit; 2165 } else { 2166 if (txDmaState != dmaIdle) 2167 goto exit; 2168 txState = txDescRead; 2169 regs.txdp = link; 2170 CTDD = false; 2171 2172 txDmaAddr = link & 0x3fffffff; 2173 txDmaData = is64bit ? (void *)&txDesc64 : (void *)&txDesc32; 2174 txDmaLen = is64bit ? sizeof(txDesc64) : sizeof(txDesc32); 2175 txDmaFree = dmaDescFree; 2176 2177 if (doTxDmaRead()) 2178 goto exit; 2179 } 2180 break; 2181 2182 default: 2183 panic("invalid state"); 2184 } 2185 2186 DPRINTF(EthernetSM, "entering next txState=%s\n", 2187 NsTxStateStrings[txState]); 2188 goto next; 2189 2190 exit: 2191 /** 2192 * @todo do we want to schedule a future kick? 2193 */ 2194 DPRINTF(EthernetSM, "tx state machine exited txState=%s\n", 2195 NsTxStateStrings[txState]); 2196 2197 if (clock && !txKickEvent.scheduled()) 2198 txKickEvent.schedule(txKickTick); 2199} 2200 2201/** 2202 * Advance the EEPROM state machine 2203 * Called on rising edge of EEPROM clock bit in MEAR 2204 */ 2205void 2206NSGigE::eepromKick() 2207{ 2208 switch (eepromState) { 2209 2210 case eepromStart: 2211 2212 // Wait for start bit 2213 if (regs.mear & MEAR_EEDI) { 2214 // Set up to get 2 opcode bits 2215 eepromState = eepromGetOpcode; 2216 eepromBitsToRx = 2; 2217 eepromOpcode = 0; 2218 } 2219 break; 2220 2221 case eepromGetOpcode: 2222 eepromOpcode <<= 1; 2223 eepromOpcode += (regs.mear & MEAR_EEDI) ? 1 : 0; 2224 --eepromBitsToRx; 2225 2226 // Done getting opcode 2227 if (eepromBitsToRx == 0) { 2228 if (eepromOpcode != EEPROM_READ) 2229 panic("only EEPROM reads are implemented!"); 2230 2231 // Set up to get address 2232 eepromState = eepromGetAddress; 2233 eepromBitsToRx = 6; 2234 eepromAddress = 0; 2235 } 2236 break; 2237 2238 case eepromGetAddress: 2239 eepromAddress <<= 1; 2240 eepromAddress += (regs.mear & MEAR_EEDI) ? 1 : 0; 2241 --eepromBitsToRx; 2242 2243 // Done getting address 2244 if (eepromBitsToRx == 0) { 2245 2246 if (eepromAddress >= EEPROM_SIZE) 2247 panic("EEPROM read access out of range!"); 2248 2249 switch (eepromAddress) { 2250 2251 case EEPROM_PMATCH2_ADDR: 2252 eepromData = rom.perfectMatch[5]; 2253 eepromData <<= 8; 2254 eepromData += rom.perfectMatch[4]; 2255 break; 2256 2257 case EEPROM_PMATCH1_ADDR: 2258 eepromData = rom.perfectMatch[3]; 2259 eepromData <<= 8; 2260 eepromData += rom.perfectMatch[2]; 2261 break; 2262 2263 case EEPROM_PMATCH0_ADDR: 2264 eepromData = rom.perfectMatch[1]; 2265 eepromData <<= 8; 2266 eepromData += rom.perfectMatch[0]; 2267 break; 2268 2269 default: 2270 panic("FreeBSD driver only uses EEPROM to read PMATCH!"); 2271 } 2272 // Set up to read data 2273 eepromState = eepromRead; 2274 eepromBitsToRx = 16; 2275 2276 // Clear data in bit 2277 regs.mear &= ~MEAR_EEDI; 2278 } 2279 break; 2280 2281 case eepromRead: 2282 // Clear Data Out bit 2283 regs.mear &= ~MEAR_EEDO; 2284 // Set bit to value of current EEPROM bit 2285 regs.mear |= (eepromData & 0x8000) ? MEAR_EEDO : 0x0; 2286 2287 eepromData <<= 1; 2288 --eepromBitsToRx; 2289 2290 // All done 2291 if (eepromBitsToRx == 0) { 2292 eepromState = eepromStart; 2293 } 2294 break; 2295 2296 default: 2297 panic("invalid EEPROM state"); 2298 } 2299 2300} 2301 2302void 2303NSGigE::transferDone() 2304{ 2305 if (txFifo.empty()) { 2306 DPRINTF(Ethernet, "transfer complete: txFifo empty...nothing to do\n"); 2307 return; 2308 } 2309 2310 DPRINTF(Ethernet, "transfer complete: data in txFifo...schedule xmit\n"); 2311 2312 txEvent.reschedule(curTick + cycles(1), true); 2313} 2314 2315bool 2316NSGigE::rxFilter(const EthPacketPtr &packet) 2317{ 2318 EthPtr eth = packet; 2319 bool drop = true; 2320 string type; 2321 2322 const EthAddr &dst = eth->dst(); 2323 if (dst.unicast()) { 2324 // If we're accepting all unicast addresses 2325 if (acceptUnicast) 2326 drop = false; 2327 2328 // If we make a perfect match 2329 if (acceptPerfect && dst == rom.perfectMatch) 2330 drop = false; 2331 2332 if (acceptArp && eth->type() == ETH_TYPE_ARP) 2333 drop = false; 2334 2335 } else if (dst.broadcast()) { 2336 // if we're accepting broadcasts 2337 if (acceptBroadcast) 2338 drop = false; 2339 2340 } else if (dst.multicast()) { 2341 // if we're accepting all multicasts 2342 if (acceptMulticast) 2343 drop = false; 2344 2345 // Multicast hashing faked - all packets accepted 2346 if (multicastHashEnable) 2347 drop = false; 2348 } 2349 2350 if (drop) { 2351 DPRINTF(Ethernet, "rxFilter drop\n"); 2352 DDUMP(EthernetData, packet->data, packet->length); 2353 } 2354 2355 return drop; 2356} 2357 2358bool 2359NSGigE::recvPacket(EthPacketPtr packet) 2360{ 2361 rxBytes += packet->length; 2362 rxPackets++; 2363 2364 DPRINTF(Ethernet, "Receiving packet from wire, rxFifoAvail=%d\n", 2365 rxFifo.avail()); 2366 2367 if (!rxEnable) { 2368 DPRINTF(Ethernet, "receive disabled...packet dropped\n"); 2369 return true; 2370 } 2371 2372 if (!rxFilterEnable) { 2373 DPRINTF(Ethernet, 2374 "receive packet filtering disabled . . . packet dropped\n"); 2375 return true; 2376 } 2377 2378 if (rxFilter(packet)) { 2379 DPRINTF(Ethernet, "packet filtered...dropped\n"); 2380 return true; 2381 } 2382 2383 if (rxFifo.avail() < packet->length) { 2384#if TRACING_ON 2385 IpPtr ip(packet); 2386 TcpPtr tcp(ip); 2387 if (ip) { 2388 DPRINTF(Ethernet, 2389 "packet won't fit in receive buffer...pkt ID %d dropped\n", 2390 ip->id()); 2391 if (tcp) { 2392 DPRINTF(Ethernet, "Seq=%d\n", tcp->seq()); 2393 } 2394 } 2395#endif 2396 droppedPackets++; 2397 devIntrPost(ISR_RXORN); 2398 return false; 2399 } 2400 2401 rxFifo.push(packet); 2402 2403 rxKick(); 2404 return true; 2405} 2406 2407 2408void 2409NSGigE::resume() 2410{ 2411 SimObject::resume(); 2412 2413 // During drain we could have left the state machines in a waiting state and 2414 // they wouldn't get out until some other event occured to kick them. 2415 // This way they'll get out immediately 2416 txKick(); 2417 rxKick(); 2418} 2419 2420 2421//===================================================================== 2422// 2423// 2424void 2425NSGigE::serialize(ostream &os) 2426{ 2427 // Serialize the PciDev base class 2428 PciDev::serialize(os); 2429 2430 /* 2431 * Finalize any DMA events now. 2432 */ 2433 // @todo will mem system save pending dma? 2434 2435 /* 2436 * Serialize the device registers 2437 */ 2438 SERIALIZE_SCALAR(regs.command); 2439 SERIALIZE_SCALAR(regs.config); 2440 SERIALIZE_SCALAR(regs.mear); 2441 SERIALIZE_SCALAR(regs.ptscr); 2442 SERIALIZE_SCALAR(regs.isr); 2443 SERIALIZE_SCALAR(regs.imr); 2444 SERIALIZE_SCALAR(regs.ier); 2445 SERIALIZE_SCALAR(regs.ihr); 2446 SERIALIZE_SCALAR(regs.txdp); 2447 SERIALIZE_SCALAR(regs.txdp_hi); 2448 SERIALIZE_SCALAR(regs.txcfg); 2449 SERIALIZE_SCALAR(regs.gpior); 2450 SERIALIZE_SCALAR(regs.rxdp); 2451 SERIALIZE_SCALAR(regs.rxdp_hi); 2452 SERIALIZE_SCALAR(regs.rxcfg); 2453 SERIALIZE_SCALAR(regs.pqcr); 2454 SERIALIZE_SCALAR(regs.wcsr); 2455 SERIALIZE_SCALAR(regs.pcr); 2456 SERIALIZE_SCALAR(regs.rfcr); 2457 SERIALIZE_SCALAR(regs.rfdr); 2458 SERIALIZE_SCALAR(regs.brar); 2459 SERIALIZE_SCALAR(regs.brdr); 2460 SERIALIZE_SCALAR(regs.srr); 2461 SERIALIZE_SCALAR(regs.mibc); 2462 SERIALIZE_SCALAR(regs.vrcr); 2463 SERIALIZE_SCALAR(regs.vtcr); 2464 SERIALIZE_SCALAR(regs.vdr); 2465 SERIALIZE_SCALAR(regs.ccsr); 2466 SERIALIZE_SCALAR(regs.tbicr); 2467 SERIALIZE_SCALAR(regs.tbisr); 2468 SERIALIZE_SCALAR(regs.tanar); 2469 SERIALIZE_SCALAR(regs.tanlpar); 2470 SERIALIZE_SCALAR(regs.taner); 2471 SERIALIZE_SCALAR(regs.tesr); 2472 2473 SERIALIZE_ARRAY(rom.perfectMatch, ETH_ADDR_LEN); 2474 SERIALIZE_ARRAY(rom.filterHash, FHASH_SIZE); 2475 2476 SERIALIZE_SCALAR(ioEnable); 2477 2478 /* 2479 * Serialize the data Fifos 2480 */ 2481 rxFifo.serialize("rxFifo", os); 2482 txFifo.serialize("txFifo", os); 2483 2484 /* 2485 * Serialize the various helper variables 2486 */ 2487 bool txPacketExists = txPacket; 2488 SERIALIZE_SCALAR(txPacketExists); 2489 if (txPacketExists) { 2490 txPacket->length = txPacketBufPtr - txPacket->data; 2491 txPacket->serialize("txPacket", os); 2492 uint32_t txPktBufPtr = (uint32_t) (txPacketBufPtr - txPacket->data); 2493 SERIALIZE_SCALAR(txPktBufPtr); 2494 } 2495 2496 bool rxPacketExists = rxPacket; 2497 SERIALIZE_SCALAR(rxPacketExists); 2498 if (rxPacketExists) { 2499 rxPacket->serialize("rxPacket", os); 2500 uint32_t rxPktBufPtr = (uint32_t) (rxPacketBufPtr - rxPacket->data); 2501 SERIALIZE_SCALAR(rxPktBufPtr); 2502 } 2503 2504 SERIALIZE_SCALAR(txXferLen); 2505 SERIALIZE_SCALAR(rxXferLen); 2506 2507 /* 2508 * Serialize Cached Descriptors 2509 */ 2510 SERIALIZE_SCALAR(rxDesc64.link); 2511 SERIALIZE_SCALAR(rxDesc64.bufptr); 2512 SERIALIZE_SCALAR(rxDesc64.cmdsts); 2513 SERIALIZE_SCALAR(rxDesc64.extsts); 2514 SERIALIZE_SCALAR(txDesc64.link); 2515 SERIALIZE_SCALAR(txDesc64.bufptr); 2516 SERIALIZE_SCALAR(txDesc64.cmdsts); 2517 SERIALIZE_SCALAR(txDesc64.extsts); 2518 SERIALIZE_SCALAR(rxDesc32.link); 2519 SERIALIZE_SCALAR(rxDesc32.bufptr); 2520 SERIALIZE_SCALAR(rxDesc32.cmdsts); 2521 SERIALIZE_SCALAR(rxDesc32.extsts); 2522 SERIALIZE_SCALAR(txDesc32.link); 2523 SERIALIZE_SCALAR(txDesc32.bufptr); 2524 SERIALIZE_SCALAR(txDesc32.cmdsts); 2525 SERIALIZE_SCALAR(txDesc32.extsts); 2526 SERIALIZE_SCALAR(extstsEnable); 2527 2528 /* 2529 * Serialize tx state machine 2530 */ 2531 int txState = this->txState; 2532 SERIALIZE_SCALAR(txState); 2533 SERIALIZE_SCALAR(txEnable); 2534 SERIALIZE_SCALAR(CTDD); 2535 SERIALIZE_SCALAR(txFragPtr); 2536 SERIALIZE_SCALAR(txDescCnt); 2537 int txDmaState = this->txDmaState; 2538 SERIALIZE_SCALAR(txDmaState); 2539 SERIALIZE_SCALAR(txKickTick); 2540 2541 /* 2542 * Serialize rx state machine 2543 */ 2544 int rxState = this->rxState; 2545 SERIALIZE_SCALAR(rxState); 2546 SERIALIZE_SCALAR(rxEnable); 2547 SERIALIZE_SCALAR(CRDD); 2548 SERIALIZE_SCALAR(rxPktBytes); 2549 SERIALIZE_SCALAR(rxFragPtr); 2550 SERIALIZE_SCALAR(rxDescCnt); 2551 int rxDmaState = this->rxDmaState; 2552 SERIALIZE_SCALAR(rxDmaState); 2553 SERIALIZE_SCALAR(rxKickTick); 2554 2555 /* 2556 * Serialize EEPROM state machine 2557 */ 2558 int eepromState = this->eepromState; 2559 SERIALIZE_SCALAR(eepromState); 2560 SERIALIZE_SCALAR(eepromClk); 2561 SERIALIZE_SCALAR(eepromBitsToRx); 2562 SERIALIZE_SCALAR(eepromOpcode); 2563 SERIALIZE_SCALAR(eepromAddress); 2564 SERIALIZE_SCALAR(eepromData); 2565 2566 /* 2567 * If there's a pending transmit, store the time so we can 2568 * reschedule it later 2569 */ 2570 Tick transmitTick = txEvent.scheduled() ? txEvent.when() - curTick : 0; 2571 SERIALIZE_SCALAR(transmitTick); 2572 2573 /* 2574 * receive address filter settings 2575 */ 2576 SERIALIZE_SCALAR(rxFilterEnable); 2577 SERIALIZE_SCALAR(acceptBroadcast); 2578 SERIALIZE_SCALAR(acceptMulticast); 2579 SERIALIZE_SCALAR(acceptUnicast); 2580 SERIALIZE_SCALAR(acceptPerfect); 2581 SERIALIZE_SCALAR(acceptArp); 2582 SERIALIZE_SCALAR(multicastHashEnable); 2583 2584 /* 2585 * Keep track of pending interrupt status. 2586 */ 2587 SERIALIZE_SCALAR(intrTick); 2588 SERIALIZE_SCALAR(cpuPendingIntr); 2589 Tick intrEventTick = 0; 2590 if (intrEvent) 2591 intrEventTick = intrEvent->when(); 2592 SERIALIZE_SCALAR(intrEventTick); 2593 2594} 2595 2596void 2597NSGigE::unserialize(Checkpoint *cp, const std::string §ion) 2598{ 2599 // Unserialize the PciDev base class 2600 PciDev::unserialize(cp, section); 2601 2602 UNSERIALIZE_SCALAR(regs.command); 2603 UNSERIALIZE_SCALAR(regs.config); 2604 UNSERIALIZE_SCALAR(regs.mear); 2605 UNSERIALIZE_SCALAR(regs.ptscr); 2606 UNSERIALIZE_SCALAR(regs.isr); 2607 UNSERIALIZE_SCALAR(regs.imr); 2608 UNSERIALIZE_SCALAR(regs.ier); 2609 UNSERIALIZE_SCALAR(regs.ihr); 2610 UNSERIALIZE_SCALAR(regs.txdp); 2611 UNSERIALIZE_SCALAR(regs.txdp_hi); 2612 UNSERIALIZE_SCALAR(regs.txcfg); 2613 UNSERIALIZE_SCALAR(regs.gpior); 2614 UNSERIALIZE_SCALAR(regs.rxdp); 2615 UNSERIALIZE_SCALAR(regs.rxdp_hi); 2616 UNSERIALIZE_SCALAR(regs.rxcfg); 2617 UNSERIALIZE_SCALAR(regs.pqcr); 2618 UNSERIALIZE_SCALAR(regs.wcsr); 2619 UNSERIALIZE_SCALAR(regs.pcr); 2620 UNSERIALIZE_SCALAR(regs.rfcr); 2621 UNSERIALIZE_SCALAR(regs.rfdr); 2622 UNSERIALIZE_SCALAR(regs.brar); 2623 UNSERIALIZE_SCALAR(regs.brdr); 2624 UNSERIALIZE_SCALAR(regs.srr); 2625 UNSERIALIZE_SCALAR(regs.mibc); 2626 UNSERIALIZE_SCALAR(regs.vrcr); 2627 UNSERIALIZE_SCALAR(regs.vtcr); 2628 UNSERIALIZE_SCALAR(regs.vdr); 2629 UNSERIALIZE_SCALAR(regs.ccsr); 2630 UNSERIALIZE_SCALAR(regs.tbicr); 2631 UNSERIALIZE_SCALAR(regs.tbisr); 2632 UNSERIALIZE_SCALAR(regs.tanar); 2633 UNSERIALIZE_SCALAR(regs.tanlpar); 2634 UNSERIALIZE_SCALAR(regs.taner); 2635 UNSERIALIZE_SCALAR(regs.tesr); 2636 2637 UNSERIALIZE_ARRAY(rom.perfectMatch, ETH_ADDR_LEN); 2638 UNSERIALIZE_ARRAY(rom.filterHash, FHASH_SIZE); 2639 2640 UNSERIALIZE_SCALAR(ioEnable); 2641 2642 /* 2643 * unserialize the data fifos 2644 */ 2645 rxFifo.unserialize("rxFifo", cp, section); 2646 txFifo.unserialize("txFifo", cp, section); 2647 2648 /* 2649 * unserialize the various helper variables 2650 */ 2651 bool txPacketExists; 2652 UNSERIALIZE_SCALAR(txPacketExists); 2653 if (txPacketExists) { 2654 txPacket = new EthPacketData(16384); 2655 txPacket->unserialize("txPacket", cp, section); 2656 uint32_t txPktBufPtr; 2657 UNSERIALIZE_SCALAR(txPktBufPtr); 2658 txPacketBufPtr = (uint8_t *) txPacket->data + txPktBufPtr; 2659 } else 2660 txPacket = 0; 2661 2662 bool rxPacketExists; 2663 UNSERIALIZE_SCALAR(rxPacketExists); 2664 rxPacket = 0; 2665 if (rxPacketExists) { 2666 rxPacket = new EthPacketData(16384); 2667 rxPacket->unserialize("rxPacket", cp, section); 2668 uint32_t rxPktBufPtr; 2669 UNSERIALIZE_SCALAR(rxPktBufPtr); 2670 rxPacketBufPtr = (uint8_t *) rxPacket->data + rxPktBufPtr; 2671 } else 2672 rxPacket = 0; 2673 2674 UNSERIALIZE_SCALAR(txXferLen); 2675 UNSERIALIZE_SCALAR(rxXferLen); 2676 2677 /* 2678 * Unserialize Cached Descriptors 2679 */ 2680 UNSERIALIZE_SCALAR(rxDesc64.link); 2681 UNSERIALIZE_SCALAR(rxDesc64.bufptr); 2682 UNSERIALIZE_SCALAR(rxDesc64.cmdsts); 2683 UNSERIALIZE_SCALAR(rxDesc64.extsts); 2684 UNSERIALIZE_SCALAR(txDesc64.link); 2685 UNSERIALIZE_SCALAR(txDesc64.bufptr); 2686 UNSERIALIZE_SCALAR(txDesc64.cmdsts); 2687 UNSERIALIZE_SCALAR(txDesc64.extsts); 2688 UNSERIALIZE_SCALAR(rxDesc32.link); 2689 UNSERIALIZE_SCALAR(rxDesc32.bufptr); 2690 UNSERIALIZE_SCALAR(rxDesc32.cmdsts); 2691 UNSERIALIZE_SCALAR(rxDesc32.extsts); 2692 UNSERIALIZE_SCALAR(txDesc32.link); 2693 UNSERIALIZE_SCALAR(txDesc32.bufptr); 2694 UNSERIALIZE_SCALAR(txDesc32.cmdsts); 2695 UNSERIALIZE_SCALAR(txDesc32.extsts); 2696 UNSERIALIZE_SCALAR(extstsEnable); 2697 2698 /* 2699 * unserialize tx state machine 2700 */ 2701 int txState; 2702 UNSERIALIZE_SCALAR(txState); 2703 this->txState = (TxState) txState; 2704 UNSERIALIZE_SCALAR(txEnable); 2705 UNSERIALIZE_SCALAR(CTDD); 2706 UNSERIALIZE_SCALAR(txFragPtr); 2707 UNSERIALIZE_SCALAR(txDescCnt); 2708 int txDmaState; 2709 UNSERIALIZE_SCALAR(txDmaState); 2710 this->txDmaState = (DmaState) txDmaState; 2711 UNSERIALIZE_SCALAR(txKickTick); 2712 if (txKickTick) 2713 txKickEvent.schedule(txKickTick); 2714 2715 /* 2716 * unserialize rx state machine 2717 */ 2718 int rxState; 2719 UNSERIALIZE_SCALAR(rxState); 2720 this->rxState = (RxState) rxState; 2721 UNSERIALIZE_SCALAR(rxEnable); 2722 UNSERIALIZE_SCALAR(CRDD); 2723 UNSERIALIZE_SCALAR(rxPktBytes); 2724 UNSERIALIZE_SCALAR(rxFragPtr); 2725 UNSERIALIZE_SCALAR(rxDescCnt); 2726 int rxDmaState; 2727 UNSERIALIZE_SCALAR(rxDmaState); 2728 this->rxDmaState = (DmaState) rxDmaState; 2729 UNSERIALIZE_SCALAR(rxKickTick); 2730 if (rxKickTick) 2731 rxKickEvent.schedule(rxKickTick); 2732 2733 /* 2734 * Unserialize EEPROM state machine 2735 */ 2736 int eepromState; 2737 UNSERIALIZE_SCALAR(eepromState); 2738 this->eepromState = (EEPROMState) eepromState; 2739 UNSERIALIZE_SCALAR(eepromClk); 2740 UNSERIALIZE_SCALAR(eepromBitsToRx); 2741 UNSERIALIZE_SCALAR(eepromOpcode); 2742 UNSERIALIZE_SCALAR(eepromAddress); 2743 UNSERIALIZE_SCALAR(eepromData); 2744 2745 /* 2746 * If there's a pending transmit, reschedule it now 2747 */ 2748 Tick transmitTick; 2749 UNSERIALIZE_SCALAR(transmitTick); 2750 if (transmitTick) 2751 txEvent.schedule(curTick + transmitTick); 2752 2753 /* 2754 * unserialize receive address filter settings 2755 */ 2756 UNSERIALIZE_SCALAR(rxFilterEnable); 2757 UNSERIALIZE_SCALAR(acceptBroadcast); 2758 UNSERIALIZE_SCALAR(acceptMulticast); 2759 UNSERIALIZE_SCALAR(acceptUnicast); 2760 UNSERIALIZE_SCALAR(acceptPerfect); 2761 UNSERIALIZE_SCALAR(acceptArp); 2762 UNSERIALIZE_SCALAR(multicastHashEnable); 2763 2764 /* 2765 * Keep track of pending interrupt status. 2766 */ 2767 UNSERIALIZE_SCALAR(intrTick); 2768 UNSERIALIZE_SCALAR(cpuPendingIntr); 2769 Tick intrEventTick; 2770 UNSERIALIZE_SCALAR(intrEventTick); 2771 if (intrEventTick) { 2772 intrEvent = new IntrEvent(this, intrEventTick, true); 2773 } 2774} 2775 2776BEGIN_DECLARE_SIM_OBJECT_PARAMS(NSGigEInt) 2777 2778 SimObjectParam<EtherInt *> peer; 2779 SimObjectParam<NSGigE *> device; 2780 2781END_DECLARE_SIM_OBJECT_PARAMS(NSGigEInt) 2782 2783BEGIN_INIT_SIM_OBJECT_PARAMS(NSGigEInt) 2784 2785 INIT_PARAM_DFLT(peer, "peer interface", NULL), 2786 INIT_PARAM(device, "Ethernet device of this interface") 2787 2788END_INIT_SIM_OBJECT_PARAMS(NSGigEInt) 2789 2790CREATE_SIM_OBJECT(NSGigEInt) 2791{ 2792 NSGigEInt *dev_int = new NSGigEInt(getInstanceName(), device); 2793 2794 EtherInt *p = (EtherInt *)peer; 2795 if (p) { 2796 dev_int->setPeer(p); 2797 p->setPeer(dev_int); 2798 } 2799 2800 return dev_int; 2801} 2802 2803REGISTER_SIM_OBJECT("NSGigEInt", NSGigEInt) 2804 2805 2806BEGIN_DECLARE_SIM_OBJECT_PARAMS(NSGigE) 2807 2808 SimObjectParam<System *> system; 2809 SimObjectParam<Platform *> platform; 2810 Param<Tick> min_backoff_delay; 2811 Param<Tick> max_backoff_delay; 2812 SimObjectParam<PciConfigData *> configdata; 2813 Param<uint32_t> pci_bus; 2814 Param<uint32_t> pci_dev; 2815 Param<uint32_t> pci_func; 2816 Param<Tick> pio_latency; 2817 Param<Tick> config_latency; 2818 2819 Param<Tick> clock; 2820 Param<bool> dma_desc_free; 2821 Param<bool> dma_data_free; 2822 Param<Tick> dma_read_delay; 2823 Param<Tick> dma_write_delay; 2824 Param<Tick> dma_read_factor; 2825 Param<Tick> dma_write_factor; 2826 Param<bool> dma_no_allocate; 2827 Param<Tick> intr_delay; 2828 2829 Param<Tick> rx_delay; 2830 Param<Tick> tx_delay; 2831 Param<uint32_t> rx_fifo_size; 2832 Param<uint32_t> tx_fifo_size; 2833 2834 Param<bool> rx_filter; 2835 Param<string> hardware_address; 2836 Param<bool> rx_thread; 2837 Param<bool> tx_thread; 2838 Param<bool> rss; 2839 2840END_DECLARE_SIM_OBJECT_PARAMS(NSGigE) 2841 2842BEGIN_INIT_SIM_OBJECT_PARAMS(NSGigE) 2843 2844 INIT_PARAM(system, "System pointer"), 2845 INIT_PARAM(platform, "Platform pointer"), 2846 INIT_PARAM(min_backoff_delay, "Minimum delay after receving a nack packed"), 2847 INIT_PARAM(max_backoff_delay, "Maximum delay after receving a nack packed"), 2848 INIT_PARAM(configdata, "PCI Config data"), 2849 INIT_PARAM(pci_bus, "PCI bus ID"), 2850 INIT_PARAM(pci_dev, "PCI device number"), 2851 INIT_PARAM(pci_func, "PCI function code"), 2852 INIT_PARAM_DFLT(pio_latency, "Programmed IO latency in bus cycles", 1), 2853 INIT_PARAM(config_latency, "Number of cycles for a config read or write"), 2854 INIT_PARAM(clock, "State machine cycle time"), 2855 2856 INIT_PARAM(dma_desc_free, "DMA of Descriptors is free"), 2857 INIT_PARAM(dma_data_free, "DMA of Data is free"), 2858 INIT_PARAM(dma_read_delay, "fixed delay for dma reads"), 2859 INIT_PARAM(dma_write_delay, "fixed delay for dma writes"), 2860 INIT_PARAM(dma_read_factor, "multiplier for dma reads"), 2861 INIT_PARAM(dma_write_factor, "multiplier for dma writes"), 2862 INIT_PARAM(dma_no_allocate, "Should DMA reads allocate cache lines"), 2863 INIT_PARAM(intr_delay, "Interrupt Delay in microseconds"), 2864 2865 INIT_PARAM(rx_delay, "Receive Delay"), 2866 INIT_PARAM(tx_delay, "Transmit Delay"), 2867 INIT_PARAM(rx_fifo_size, "max size in bytes of rxFifo"), 2868 INIT_PARAM(tx_fifo_size, "max size in bytes of txFifo"), 2869 2870 INIT_PARAM(rx_filter, "Enable Receive Filter"), 2871 INIT_PARAM(hardware_address, "Ethernet Hardware Address"), 2872 INIT_PARAM(rx_thread, ""), 2873 INIT_PARAM(tx_thread, ""), 2874 INIT_PARAM(rss, "") 2875 2876END_INIT_SIM_OBJECT_PARAMS(NSGigE) 2877 2878 2879CREATE_SIM_OBJECT(NSGigE) 2880{ 2881 NSGigE::Params *params = new NSGigE::Params; 2882 2883 params->name = getInstanceName(); 2884 params->platform = platform; 2885 params->system = system; 2886 params->min_backoff_delay = min_backoff_delay; 2887 params->max_backoff_delay = max_backoff_delay; 2888 params->configData = configdata; 2889 params->busNum = pci_bus; 2890 params->deviceNum = pci_dev; 2891 params->functionNum = pci_func; 2892 params->pio_delay = pio_latency; 2893 params->config_delay = config_latency; 2894 2895 params->clock = clock; 2896 params->dma_desc_free = dma_desc_free; 2897 params->dma_data_free = dma_data_free; 2898 params->dma_read_delay = dma_read_delay; 2899 params->dma_write_delay = dma_write_delay; 2900 params->dma_read_factor = dma_read_factor; 2901 params->dma_write_factor = dma_write_factor; 2902 params->dma_no_allocate = dma_no_allocate; 2903 params->pio_delay = pio_latency; 2904 params->intr_delay = intr_delay; 2905 2906 params->rx_delay = rx_delay; 2907 params->tx_delay = tx_delay; 2908 params->rx_fifo_size = rx_fifo_size; 2909 params->tx_fifo_size = tx_fifo_size; 2910 2911 params->rx_filter = rx_filter; 2912 params->eaddr = hardware_address; 2913 params->rx_thread = rx_thread; 2914 params->tx_thread = tx_thread; 2915 params->rss = rss; 2916 2917 return new NSGigE(params); 2918} 2919 2920REGISTER_SIM_OBJECT("NSGigE", NSGigE) 2921