ns_gige.cc revision 1909
14403Srdreslin@umich.edu/*
21693Sstever@eecs.umich.edu * Copyright (c) 2004-2005 The Regents of The University of Michigan
31693Sstever@eecs.umich.edu * All rights reserved.
41693Sstever@eecs.umich.edu *
51693Sstever@eecs.umich.edu * Redistribution and use in source and binary forms, with or without
61693Sstever@eecs.umich.edu * modification, are permitted provided that the following conditions are
71693Sstever@eecs.umich.edu * met: redistributions of source code must retain the above copyright
81693Sstever@eecs.umich.edu * notice, this list of conditions and the following disclaimer;
91693Sstever@eecs.umich.edu * redistributions in binary form must reproduce the above copyright
101693Sstever@eecs.umich.edu * notice, this list of conditions and the following disclaimer in the
111693Sstever@eecs.umich.edu * documentation and/or other materials provided with the distribution;
121693Sstever@eecs.umich.edu * neither the name of the copyright holders nor the names of its
131693Sstever@eecs.umich.edu * contributors may be used to endorse or promote products derived from
141693Sstever@eecs.umich.edu * this software without specific prior written permission.
151693Sstever@eecs.umich.edu *
161693Sstever@eecs.umich.edu * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
171693Sstever@eecs.umich.edu * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
181693Sstever@eecs.umich.edu * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
191693Sstever@eecs.umich.edu * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
201693Sstever@eecs.umich.edu * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
211693Sstever@eecs.umich.edu * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
221693Sstever@eecs.umich.edu * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
231693Sstever@eecs.umich.edu * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
241693Sstever@eecs.umich.edu * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
251693Sstever@eecs.umich.edu * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
261693Sstever@eecs.umich.edu * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
271693Sstever@eecs.umich.edu */
281693Sstever@eecs.umich.edu
293358Srdreslin@umich.edu/** @file
303358Srdreslin@umich.edu * Device module for modelling the National Semiconductor
311516SN/A * DP83820 ethernet controller.  Does not support priority queueing
3212564Sgabeblack@google.com */
3312564Sgabeblack@google.com#include <cstdio>
346654Snate@binkert.org#include <deque>
356654Snate@binkert.org#include <string>
366654Snate@binkert.org
376654Snate@binkert.org#include "base/inet.hh"
383358Srdreslin@umich.edu#include "cpu/exec_context.hh"
393358Srdreslin@umich.edu#include "dev/etherlink.hh"
406654Snate@binkert.org#include "dev/ns_gige.hh"
413358Srdreslin@umich.edu#include "dev/pciconfigall.hh"
423358Srdreslin@umich.edu#include "mem/bus/bus.hh"
433358Srdreslin@umich.edu#include "mem/bus/dma_interface.hh"
443358Srdreslin@umich.edu#include "mem/bus/pio_interface.hh"
453358Srdreslin@umich.edu#include "mem/bus/pio_interface_impl.hh"
463358Srdreslin@umich.edu#include "mem/functional/memory_control.hh"
473358Srdreslin@umich.edu#include "mem/functional/physical.hh"
483358Srdreslin@umich.edu#include "sim/builder.hh"
493358Srdreslin@umich.edu#include "sim/debug.hh"
503358Srdreslin@umich.edu#include "sim/host.hh"
513358Srdreslin@umich.edu#include "sim/stats.hh"
523358Srdreslin@umich.edu#include "targetarch/vtophys.hh"
533360Srdreslin@umich.edu
543358Srdreslin@umich.educonst char *NsRxStateStrings[] =
553360Srdreslin@umich.edu{
563360Srdreslin@umich.edu    "rxIdle",
573360Srdreslin@umich.edu    "rxDescRefr",
585255Ssaidi@eecs.umich.edu    "rxDescRead",
593360Srdreslin@umich.edu    "rxFifoBlock",
603360Srdreslin@umich.edu    "rxFragWrite",
613360Srdreslin@umich.edu    "rxDescWrite",
625255Ssaidi@eecs.umich.edu    "rxAdvance"
633358Srdreslin@umich.edu};
644403Srdreslin@umich.edu
653360Srdreslin@umich.educonst char *NsTxStateStrings[] =
663358Srdreslin@umich.edu{
673358Srdreslin@umich.edu    "txIdle",
683358Srdreslin@umich.edu    "txDescRefr",
693358Srdreslin@umich.edu    "txDescRead",
703358Srdreslin@umich.edu    "txFifoBlock",
713358Srdreslin@umich.edu    "txFragRead",
7212564Sgabeblack@google.com    "txDescWrite",
733358Srdreslin@umich.edu    "txAdvance"
743358Srdreslin@umich.edu};
753360Srdreslin@umich.edu
7612564Sgabeblack@google.comconst char *NsDmaState[] =
773360Srdreslin@umich.edu{
783360Srdreslin@umich.edu    "dmaIdle",
793358Srdreslin@umich.edu    "dmaReading",
803358Srdreslin@umich.edu    "dmaWriting",
813358Srdreslin@umich.edu    "dmaReadWaiting",
8211851Sbrandon.potter@amd.com    "dmaWriteWaiting"
834403Srdreslin@umich.edu};
844403Srdreslin@umich.edu
855256Ssaidi@eecs.umich.eduusing namespace std;
865255Ssaidi@eecs.umich.eduusing namespace Net;
873358Srdreslin@umich.edu
8811851Sbrandon.potter@amd.com///////////////////////////////////////////////////////////////////////
894403Srdreslin@umich.edu//
904403Srdreslin@umich.edu// NSGigE PCI Device
915255Ssaidi@eecs.umich.edu//
923358Srdreslin@umich.eduNSGigE::NSGigE(Params *p)
9311851Sbrandon.potter@amd.com    : PciDev(p), ioEnable(false),
944403Srdreslin@umich.edu      txFifo(p->tx_fifo_size), rxFifo(p->rx_fifo_size),
955255Ssaidi@eecs.umich.edu      txPacket(0), rxPacket(0), txPacketBufPtr(NULL), rxPacketBufPtr(NULL),
964403Srdreslin@umich.edu      txXferLen(0), rxXferLen(0), clock(p->clock),
973358Srdreslin@umich.edu      txState(txIdle), txEnable(false), CTDD(false),
9811851Sbrandon.potter@amd.com      txFragPtr(0), txDescCnt(0), txDmaState(dmaIdle), rxState(rxIdle),
994403Srdreslin@umich.edu      rxEnable(false), CRDD(false), rxPktBytes(0),
1005255Ssaidi@eecs.umich.edu      rxFragPtr(0), rxDescCnt(0), rxDmaState(dmaIdle), extstsEnable(false),
1014403Srdreslin@umich.edu      eepromState(eepromStart), rxDmaReadEvent(this), rxDmaWriteEvent(this),
1023358Srdreslin@umich.edu      txDmaReadEvent(this), txDmaWriteEvent(this),
10311851Sbrandon.potter@amd.com      dmaDescFree(p->dma_desc_free), dmaDataFree(p->dma_data_free),
1044403Srdreslin@umich.edu      txDelay(p->tx_delay), rxDelay(p->rx_delay),
1055255Ssaidi@eecs.umich.edu      rxKickTick(0), rxKickEvent(this), txKickTick(0), txKickEvent(this),
1064403Srdreslin@umich.edu      txEvent(this), rxFilterEnable(p->rx_filter), acceptBroadcast(false),
1073358Srdreslin@umich.edu      acceptMulticast(false), acceptUnicast(false),
10811851Sbrandon.potter@amd.com      acceptPerfect(false), acceptArp(false), multicastHashEnable(false),
1094403Srdreslin@umich.edu      physmem(p->pmem), intrTick(0), cpuPendingIntr(false),
1105255Ssaidi@eecs.umich.edu      intrEvent(0), interface(0)
1114403Srdreslin@umich.edu{
1124403Srdreslin@umich.edu    if (p->header_bus) {
1133358Srdreslin@umich.edu        pioInterface = newPioInterface(name() + ".pio", p->hier,
11411851Sbrandon.potter@amd.com                                       p->header_bus, this,
1154403Srdreslin@umich.edu                                       &NSGigE::cacheAccess);
1165255Ssaidi@eecs.umich.edu
1174403Srdreslin@umich.edu        pioLatency = p->pio_latency * p->header_bus->clockRate;
1184403Srdreslin@umich.edu
1194403Srdreslin@umich.edu        if (p->payload_bus)
1203360Srdreslin@umich.edu            dmaInterface = new DMAInterface<Bus>(name() + ".dma",
1214403Srdreslin@umich.edu                                                 p->header_bus,
1223358Srdreslin@umich.edu                                                 p->payload_bus, 1,
12311851Sbrandon.potter@amd.com                                                 p->dma_no_allocate);
1244403Srdreslin@umich.edu        else
1255255Ssaidi@eecs.umich.edu            dmaInterface = new DMAInterface<Bus>(name() + ".dma",
1264403Srdreslin@umich.edu                                                 p->header_bus,
1273358Srdreslin@umich.edu                                                 p->header_bus, 1,
12811851Sbrandon.potter@amd.com                                                 p->dma_no_allocate);
1294403Srdreslin@umich.edu    } else if (p->payload_bus) {
1305255Ssaidi@eecs.umich.edu        pioInterface = newPioInterface(name() + ".pio2", p->hier,
1314403Srdreslin@umich.edu                                       p->payload_bus, this,
1323358Srdreslin@umich.edu                                       &NSGigE::cacheAccess);
13311851Sbrandon.potter@amd.com
1344403Srdreslin@umich.edu        pioLatency = p->pio_latency * p->payload_bus->clockRate;
1355256Ssaidi@eecs.umich.edu
1365255Ssaidi@eecs.umich.edu        dmaInterface = new DMAInterface<Bus>(name() + ".dma",
1374403Srdreslin@umich.edu                                             p->payload_bus,
1383358Srdreslin@umich.edu                                             p->payload_bus, 1,
13911851Sbrandon.potter@amd.com                                             p->dma_no_allocate);
1404403Srdreslin@umich.edu    }
1415255Ssaidi@eecs.umich.edu
1424403Srdreslin@umich.edu
1434403Srdreslin@umich.edu    intrDelay = p->intr_delay;
1444403Srdreslin@umich.edu    dmaReadDelay = p->dma_read_delay;
1453360Srdreslin@umich.edu    dmaWriteDelay = p->dma_write_delay;
1464403Srdreslin@umich.edu    dmaReadFactor = p->dma_read_factor;
1473358Srdreslin@umich.edu    dmaWriteFactor = p->dma_write_factor;
14811851Sbrandon.potter@amd.com
1494403Srdreslin@umich.edu    regsReset();
1505255Ssaidi@eecs.umich.edu    memcpy(&rom.perfectMatch, p->eaddr.bytes(), ETH_ADDR_LEN);
1514403Srdreslin@umich.edu
1524403Srdreslin@umich.edu    memset(&rxDesc32, 0, sizeof(rxDesc32));
1534403Srdreslin@umich.edu    memset(&txDesc32, 0, sizeof(txDesc32));
1543360Srdreslin@umich.edu    memset(&rxDesc64, 0, sizeof(rxDesc64));
1554403Srdreslin@umich.edu    memset(&txDesc64, 0, sizeof(txDesc64));
1563358Srdreslin@umich.edu}
1573358Srdreslin@umich.edu
1583358Srdreslin@umich.eduNSGigE::~NSGigE()
1593358Srdreslin@umich.edu{}
1603358Srdreslin@umich.edu
16111053Sandreas.hansson@arm.comvoid
1623358Srdreslin@umich.eduNSGigE::regStats()
1633358Srdreslin@umich.edu{
1643358Srdreslin@umich.edu    txBytes
1653358Srdreslin@umich.edu        .name(name() + ".txBytes")
1663358Srdreslin@umich.edu        .desc("Bytes Transmitted")
1673358Srdreslin@umich.edu        .prereq(txBytes)
1683358Srdreslin@umich.edu        ;
1693358Srdreslin@umich.edu
17011053Sandreas.hansson@arm.com    rxBytes
1713358Srdreslin@umich.edu        .name(name() + ".rxBytes")
1723358Srdreslin@umich.edu        .desc("Bytes Received")
1733358Srdreslin@umich.edu        .prereq(rxBytes)
1743358Srdreslin@umich.edu        ;
1753358Srdreslin@umich.edu
1763358Srdreslin@umich.edu    txPackets
1773358Srdreslin@umich.edu        .name(name() + ".txPackets")
1783358Srdreslin@umich.edu        .desc("Number of Packets Transmitted")
1793358Srdreslin@umich.edu        .prereq(txBytes)
1803358Srdreslin@umich.edu        ;
1813358Srdreslin@umich.edu
1823358Srdreslin@umich.edu    rxPackets
1833358Srdreslin@umich.edu        .name(name() + ".rxPackets")
1843358Srdreslin@umich.edu        .desc("Number of Packets Received")
18513731Sandreas.sandberg@arm.com        .prereq(rxBytes)
1863358Srdreslin@umich.edu        ;
1873358Srdreslin@umich.edu
1883358Srdreslin@umich.edu    txIpChecksums
18913731Sandreas.sandberg@arm.com        .name(name() + ".txIpChecksums")
1901516SN/A        .desc("Number of tx IP Checksums done by device")
1913358Srdreslin@umich.edu        .precision(0)
1923358Srdreslin@umich.edu        .prereq(txBytes)
19313731Sandreas.sandberg@arm.com        ;
1941516SN/A
1953358Srdreslin@umich.edu    rxIpChecksums
1963358Srdreslin@umich.edu        .name(name() + ".rxIpChecksums")
1973358Srdreslin@umich.edu        .desc("Number of rx IP Checksums done by device")
1988931Sandreas.hansson@arm.com        .precision(0)
19910720Sandreas.hansson@arm.com        .prereq(rxBytes)
2009790Sakash.bagdia@arm.com        ;
2011516SN/A
20210720Sandreas.hansson@arm.com    txTcpChecksums
2033358Srdreslin@umich.edu        .name(name() + ".txTcpChecksums")
2043358Srdreslin@umich.edu        .desc("Number of tx TCP Checksums done by device")
2053358Srdreslin@umich.edu        .precision(0)
2063358Srdreslin@umich.edu        .prereq(txBytes)
2073358Srdreslin@umich.edu        ;
2083358Srdreslin@umich.edu
2098847Sandreas.hansson@arm.com    rxTcpChecksums
2108847Sandreas.hansson@arm.com        .name(name() + ".rxTcpChecksums")
2118847Sandreas.hansson@arm.com        .desc("Number of rx TCP Checksums done by device")
2128847Sandreas.hansson@arm.com        .precision(0)
2133358Srdreslin@umich.edu        .prereq(rxBytes)
2143358Srdreslin@umich.edu        ;
2153358Srdreslin@umich.edu
2163358Srdreslin@umich.edu    txUdpChecksums
2173358Srdreslin@umich.edu        .name(name() + ".txUdpChecksums")
2183358Srdreslin@umich.edu        .desc("Number of tx UDP Checksums done by device")
2193358Srdreslin@umich.edu        .precision(0)
2203358Srdreslin@umich.edu        .prereq(txBytes)
2217876Sgblack@eecs.umich.edu        ;
2223358Srdreslin@umich.edu
2233358Srdreslin@umich.edu    rxUdpChecksums
2243358Srdreslin@umich.edu        .name(name() + ".rxUdpChecksums")
2253358Srdreslin@umich.edu        .desc("Number of rx UDP Checksums done by device")
2263358Srdreslin@umich.edu        .precision(0)
2273358Srdreslin@umich.edu        .prereq(rxBytes)
2288801Sgblack@eecs.umich.edu        ;
2293358Srdreslin@umich.edu
2303358Srdreslin@umich.edu    descDmaReads
2313358Srdreslin@umich.edu        .name(name() + ".descDMAReads")
2323358Srdreslin@umich.edu        .desc("Number of descriptors the device read w/ DMA")
2333358Srdreslin@umich.edu        .precision(0)
2343358Srdreslin@umich.edu        ;
2353358Srdreslin@umich.edu
2363358Srdreslin@umich.edu    descDmaWrites
2373358Srdreslin@umich.edu        .name(name() + ".descDMAWrites")
2383358Srdreslin@umich.edu        .desc("Number of descriptors the device wrote w/ DMA")
2393358Srdreslin@umich.edu        .precision(0)
2403358Srdreslin@umich.edu        ;
2413358Srdreslin@umich.edu
2423358Srdreslin@umich.edu    descDmaRdBytes
2433358Srdreslin@umich.edu        .name(name() + ".descDmaReadBytes")
2443358Srdreslin@umich.edu        .desc("number of descriptor bytes read w/ DMA")
2453358Srdreslin@umich.edu        .precision(0)
2463358Srdreslin@umich.edu        ;
2473358Srdreslin@umich.edu
2483358Srdreslin@umich.edu   descDmaWrBytes
2493358Srdreslin@umich.edu        .name(name() + ".descDmaWriteBytes")
2503358Srdreslin@umich.edu        .desc("number of descriptor bytes write w/ DMA")
2513358Srdreslin@umich.edu        .precision(0)
2523358Srdreslin@umich.edu        ;
2533358Srdreslin@umich.edu
2543358Srdreslin@umich.edu    txBandwidth
2553358Srdreslin@umich.edu        .name(name() + ".txBandwidth")
2563358Srdreslin@umich.edu        .desc("Transmit Bandwidth (bits/s)")
2571516SN/A        .precision(0)
25812564Sgabeblack@google.com        .prereq(txBytes)
25912564Sgabeblack@google.com        ;
26012564Sgabeblack@google.com
26112564Sgabeblack@google.com    rxBandwidth
2625256Ssaidi@eecs.umich.edu        .name(name() + ".rxBandwidth")
2633358Srdreslin@umich.edu        .desc("Receive Bandwidth (bits/s)")
2643358Srdreslin@umich.edu        .precision(0)
2653358Srdreslin@umich.edu        .prereq(rxBytes)
2663358Srdreslin@umich.edu        ;
2673358Srdreslin@umich.edu
2683358Srdreslin@umich.edu    totBandwidth
2693358Srdreslin@umich.edu        .name(name() + ".totBandwidth")
2703358Srdreslin@umich.edu        .desc("Total Bandwidth (bits/s)")
2713358Srdreslin@umich.edu        .precision(0)
2723358Srdreslin@umich.edu        .prereq(totBytes)
2733358Srdreslin@umich.edu        ;
2743358Srdreslin@umich.edu
2753358Srdreslin@umich.edu    totPackets
2763358Srdreslin@umich.edu        .name(name() + ".totPackets")
2773358Srdreslin@umich.edu        .desc("Total Packets")
2783358Srdreslin@umich.edu        .precision(0)
2797525Ssteve.reinhardt@amd.com        .prereq(totBytes)
2803358Srdreslin@umich.edu        ;
2813358Srdreslin@umich.edu
2823358Srdreslin@umich.edu    totBytes
2833358Srdreslin@umich.edu        .name(name() + ".totBytes")
2843358Srdreslin@umich.edu        .desc("Total Bytes")
2853646Srdreslin@umich.edu        .precision(0)
2863358Srdreslin@umich.edu        .prereq(totBytes)
28712564Sgabeblack@google.com        ;
2883358Srdreslin@umich.edu
289    totPacketRate
290        .name(name() + ".totPPS")
291        .desc("Total Tranmission Rate (packets/s)")
292        .precision(0)
293        .prereq(totBytes)
294        ;
295
296    txPacketRate
297        .name(name() + ".txPPS")
298        .desc("Packet Tranmission Rate (packets/s)")
299        .precision(0)
300        .prereq(txBytes)
301        ;
302
303    rxPacketRate
304        .name(name() + ".rxPPS")
305        .desc("Packet Reception Rate (packets/s)")
306        .precision(0)
307        .prereq(rxBytes)
308        ;
309
310    postedSwi
311        .name(name() + ".postedSwi")
312        .desc("number of software interrupts posted to CPU")
313        .precision(0)
314        ;
315
316    totalSwi
317        .name(name() + ".totalSwi")
318        .desc("number of total Swi written to ISR")
319        .precision(0)
320        ;
321
322    coalescedSwi
323        .name(name() + ".coalescedSwi")
324        .desc("average number of Swi's coalesced into each post")
325        .precision(0)
326        ;
327
328    postedRxIdle
329        .name(name() + ".postedRxIdle")
330        .desc("number of rxIdle interrupts posted to CPU")
331        .precision(0)
332        ;
333
334    totalRxIdle
335        .name(name() + ".totalRxIdle")
336        .desc("number of total RxIdle written to ISR")
337        .precision(0)
338        ;
339
340    coalescedRxIdle
341        .name(name() + ".coalescedRxIdle")
342        .desc("average number of RxIdle's coalesced into each post")
343        .precision(0)
344        ;
345
346    postedRxOk
347        .name(name() + ".postedRxOk")
348        .desc("number of RxOk interrupts posted to CPU")
349        .precision(0)
350        ;
351
352    totalRxOk
353        .name(name() + ".totalRxOk")
354        .desc("number of total RxOk written to ISR")
355        .precision(0)
356        ;
357
358    coalescedRxOk
359        .name(name() + ".coalescedRxOk")
360        .desc("average number of RxOk's coalesced into each post")
361        .precision(0)
362        ;
363
364    postedRxDesc
365        .name(name() + ".postedRxDesc")
366        .desc("number of RxDesc interrupts posted to CPU")
367        .precision(0)
368        ;
369
370    totalRxDesc
371        .name(name() + ".totalRxDesc")
372        .desc("number of total RxDesc written to ISR")
373        .precision(0)
374        ;
375
376    coalescedRxDesc
377        .name(name() + ".coalescedRxDesc")
378        .desc("average number of RxDesc's coalesced into each post")
379        .precision(0)
380        ;
381
382    postedTxOk
383        .name(name() + ".postedTxOk")
384        .desc("number of TxOk interrupts posted to CPU")
385        .precision(0)
386        ;
387
388    totalTxOk
389        .name(name() + ".totalTxOk")
390        .desc("number of total TxOk written to ISR")
391        .precision(0)
392        ;
393
394    coalescedTxOk
395        .name(name() + ".coalescedTxOk")
396        .desc("average number of TxOk's coalesced into each post")
397        .precision(0)
398        ;
399
400    postedTxIdle
401        .name(name() + ".postedTxIdle")
402        .desc("number of TxIdle interrupts posted to CPU")
403        .precision(0)
404        ;
405
406    totalTxIdle
407        .name(name() + ".totalTxIdle")
408        .desc("number of total TxIdle written to ISR")
409        .precision(0)
410        ;
411
412    coalescedTxIdle
413        .name(name() + ".coalescedTxIdle")
414        .desc("average number of TxIdle's coalesced into each post")
415        .precision(0)
416        ;
417
418    postedTxDesc
419        .name(name() + ".postedTxDesc")
420        .desc("number of TxDesc interrupts posted to CPU")
421        .precision(0)
422        ;
423
424    totalTxDesc
425        .name(name() + ".totalTxDesc")
426        .desc("number of total TxDesc written to ISR")
427        .precision(0)
428        ;
429
430    coalescedTxDesc
431        .name(name() + ".coalescedTxDesc")
432        .desc("average number of TxDesc's coalesced into each post")
433        .precision(0)
434        ;
435
436    postedRxOrn
437        .name(name() + ".postedRxOrn")
438        .desc("number of RxOrn posted to CPU")
439        .precision(0)
440        ;
441
442    totalRxOrn
443        .name(name() + ".totalRxOrn")
444        .desc("number of total RxOrn written to ISR")
445        .precision(0)
446        ;
447
448    coalescedRxOrn
449        .name(name() + ".coalescedRxOrn")
450        .desc("average number of RxOrn's coalesced into each post")
451        .precision(0)
452        ;
453
454    coalescedTotal
455        .name(name() + ".coalescedTotal")
456        .desc("average number of interrupts coalesced into each post")
457        .precision(0)
458        ;
459
460    postedInterrupts
461        .name(name() + ".postedInterrupts")
462        .desc("number of posts to CPU")
463        .precision(0)
464        ;
465
466    droppedPackets
467        .name(name() + ".droppedPackets")
468        .desc("number of packets dropped")
469        .precision(0)
470        ;
471
472    coalescedSwi = totalSwi / postedInterrupts;
473    coalescedRxIdle = totalRxIdle / postedInterrupts;
474    coalescedRxOk = totalRxOk / postedInterrupts;
475    coalescedRxDesc = totalRxDesc / postedInterrupts;
476    coalescedTxOk = totalTxOk / postedInterrupts;
477    coalescedTxIdle = totalTxIdle / postedInterrupts;
478    coalescedTxDesc = totalTxDesc / postedInterrupts;
479    coalescedRxOrn = totalRxOrn / postedInterrupts;
480
481    coalescedTotal = (totalSwi + totalRxIdle + totalRxOk + totalRxDesc +
482                      totalTxOk + totalTxIdle + totalTxDesc +
483                      totalRxOrn) / postedInterrupts;
484
485    txBandwidth = txBytes * Stats::constant(8) / simSeconds;
486    rxBandwidth = rxBytes * Stats::constant(8) / simSeconds;
487    totBandwidth = txBandwidth + rxBandwidth;
488    totBytes = txBytes + rxBytes;
489    totPackets = txPackets + rxPackets;
490
491    txPacketRate = txPackets / simSeconds;
492    rxPacketRate = rxPackets / simSeconds;
493}
494
495/**
496 * This is to read the PCI general configuration registers
497 */
498void
499NSGigE::readConfig(int offset, int size, uint8_t *data)
500{
501    if (offset < PCI_DEVICE_SPECIFIC)
502        PciDev::readConfig(offset, size, data);
503    else
504        panic("Device specific PCI config space not implemented!\n");
505}
506
507/**
508 * This is to write to the PCI general configuration registers
509 */
510void
511NSGigE::writeConfig(int offset, int size, const uint8_t* data)
512{
513    if (offset < PCI_DEVICE_SPECIFIC)
514        PciDev::writeConfig(offset, size, data);
515    else
516        panic("Device specific PCI config space not implemented!\n");
517
518    // Need to catch writes to BARs to update the PIO interface
519    switch (offset) {
520        // seems to work fine without all these PCI settings, but i
521        // put in the IO to double check, an assertion will fail if we
522        // need to properly implement it
523      case PCI_COMMAND:
524        if (config.data[offset] & PCI_CMD_IOSE)
525            ioEnable = true;
526        else
527            ioEnable = false;
528
529#if 0
530        if (config.data[offset] & PCI_CMD_BME) {
531            bmEnabled = true;
532        }
533        else {
534            bmEnabled = false;
535        }
536
537        if (config.data[offset] & PCI_CMD_MSE) {
538            memEnable = true;
539        }
540        else {
541            memEnable = false;
542        }
543#endif
544        break;
545
546      case PCI0_BASE_ADDR0:
547        if (BARAddrs[0] != 0) {
548            if (pioInterface)
549                pioInterface->addAddrRange(RangeSize(BARAddrs[0], BARSize[0]));
550
551            BARAddrs[0] &= EV5::PAddrUncachedMask;
552        }
553        break;
554      case PCI0_BASE_ADDR1:
555        if (BARAddrs[1] != 0) {
556            if (pioInterface)
557                pioInterface->addAddrRange(RangeSize(BARAddrs[1], BARSize[1]));
558
559            BARAddrs[1] &= EV5::PAddrUncachedMask;
560        }
561        break;
562    }
563}
564
565/**
566 * This reads the device registers, which are detailed in the NS83820
567 * spec sheet
568 */
569Fault
570NSGigE::read(MemReqPtr &req, uint8_t *data)
571{
572    assert(ioEnable);
573
574    //The mask is to give you only the offset into the device register file
575    Addr daddr = req->paddr & 0xfff;
576    DPRINTF(EthernetPIO, "read  da=%#x pa=%#x va=%#x size=%d\n",
577            daddr, req->paddr, req->vaddr, req->size);
578
579
580    // there are some reserved registers, you can see ns_gige_reg.h and
581    // the spec sheet for details
582    if (daddr > LAST && daddr <=  RESERVED) {
583        panic("Accessing reserved register");
584    } else if (daddr > RESERVED && daddr <= 0x3FC) {
585        readConfig(daddr & 0xff, req->size, data);
586        return No_Fault;
587    } else if (daddr >= MIB_START && daddr <= MIB_END) {
588        // don't implement all the MIB's.  hopefully the kernel
589        // doesn't actually DEPEND upon their values
590        // MIB are just hardware stats keepers
591        uint32_t &reg = *(uint32_t *) data;
592        reg = 0;
593        return No_Fault;
594    } else if (daddr > 0x3FC)
595        panic("Something is messed up!\n");
596
597    switch (req->size) {
598      case sizeof(uint32_t):
599        {
600            uint32_t &reg = *(uint32_t *)data;
601            uint16_t rfaddr;
602
603            switch (daddr) {
604              case CR:
605                reg = regs.command;
606                //these are supposed to be cleared on a read
607                reg &= ~(CR_RXD | CR_TXD | CR_TXR | CR_RXR);
608                break;
609
610              case CFGR:
611                reg = regs.config;
612                break;
613
614              case MEAR:
615                reg = regs.mear;
616                break;
617
618              case PTSCR:
619                reg = regs.ptscr;
620                break;
621
622              case ISR:
623                reg = regs.isr;
624                devIntrClear(ISR_ALL);
625                break;
626
627              case IMR:
628                reg = regs.imr;
629                break;
630
631              case IER:
632                reg = regs.ier;
633                break;
634
635              case IHR:
636                reg = regs.ihr;
637                break;
638
639              case TXDP:
640                reg = regs.txdp;
641                break;
642
643              case TXDP_HI:
644                reg = regs.txdp_hi;
645                break;
646
647              case TX_CFG:
648                reg = regs.txcfg;
649                break;
650
651              case GPIOR:
652                reg = regs.gpior;
653                break;
654
655              case RXDP:
656                reg = regs.rxdp;
657                break;
658
659              case RXDP_HI:
660                reg = regs.rxdp_hi;
661                break;
662
663              case RX_CFG:
664                reg = regs.rxcfg;
665                break;
666
667              case PQCR:
668                reg = regs.pqcr;
669                break;
670
671              case WCSR:
672                reg = regs.wcsr;
673                break;
674
675              case PCR:
676                reg = regs.pcr;
677                break;
678
679                // see the spec sheet for how RFCR and RFDR work
680                // basically, you write to RFCR to tell the machine
681                // what you want to do next, then you act upon RFDR,
682                // and the device will be prepared b/c of what you
683                // wrote to RFCR
684              case RFCR:
685                reg = regs.rfcr;
686                break;
687
688              case RFDR:
689                rfaddr = (uint16_t)(regs.rfcr & RFCR_RFADDR);
690                switch (rfaddr) {
691                  // Read from perfect match ROM octets
692                  case 0x000:
693                    reg = rom.perfectMatch[1];
694                    reg = reg << 8;
695                    reg += rom.perfectMatch[0];
696                    break;
697                  case 0x002:
698                    reg = rom.perfectMatch[3] << 8;
699                    reg += rom.perfectMatch[2];
700                    break;
701                  case 0x004:
702                    reg = rom.perfectMatch[5] << 8;
703                    reg += rom.perfectMatch[4];
704                    break;
705                  default:
706                    // Read filter hash table
707                    if (rfaddr >= FHASH_ADDR &&
708                        rfaddr < FHASH_ADDR + FHASH_SIZE) {
709
710                        // Only word-aligned reads supported
711                        if (rfaddr % 2)
712                            panic("unaligned read from filter hash table!");
713
714                        reg = rom.filterHash[rfaddr - FHASH_ADDR + 1] << 8;
715                        reg += rom.filterHash[rfaddr - FHASH_ADDR];
716                        break;
717                    }
718
719                    panic("reading RFDR for something other than pattern"
720                          " matching or hashing! %#x\n", rfaddr);
721                }
722                break;
723
724              case SRR:
725                reg = regs.srr;
726                break;
727
728              case MIBC:
729                reg = regs.mibc;
730                reg &= ~(MIBC_MIBS | MIBC_ACLR);
731                break;
732
733              case VRCR:
734                reg = regs.vrcr;
735                break;
736
737              case VTCR:
738                reg = regs.vtcr;
739                break;
740
741              case VDR:
742                reg = regs.vdr;
743                break;
744
745              case CCSR:
746                reg = regs.ccsr;
747                break;
748
749              case TBICR:
750                reg = regs.tbicr;
751                break;
752
753              case TBISR:
754                reg = regs.tbisr;
755                break;
756
757              case TANAR:
758                reg = regs.tanar;
759                break;
760
761              case TANLPAR:
762                reg = regs.tanlpar;
763                break;
764
765              case TANER:
766                reg = regs.taner;
767                break;
768
769              case TESR:
770                reg = regs.tesr;
771                break;
772
773              case M5REG:
774                reg = params()->m5reg;
775                break;
776
777              default:
778                panic("reading unimplemented register: addr=%#x", daddr);
779            }
780
781            DPRINTF(EthernetPIO, "read from %#x: data=%d data=%#x\n",
782                    daddr, reg, reg);
783        }
784        break;
785
786      default:
787        panic("accessing register with invalid size: addr=%#x, size=%d",
788              daddr, req->size);
789    }
790
791    return No_Fault;
792}
793
794Fault
795NSGigE::write(MemReqPtr &req, const uint8_t *data)
796{
797    assert(ioEnable);
798
799    Addr daddr = req->paddr & 0xfff;
800    DPRINTF(EthernetPIO, "write da=%#x pa=%#x va=%#x size=%d\n",
801            daddr, req->paddr, req->vaddr, req->size);
802
803    if (daddr > LAST && daddr <=  RESERVED) {
804        panic("Accessing reserved register");
805    } else if (daddr > RESERVED && daddr <= 0x3FC) {
806        writeConfig(daddr & 0xff, req->size, data);
807        return No_Fault;
808    } else if (daddr > 0x3FC)
809        panic("Something is messed up!\n");
810
811    if (req->size == sizeof(uint32_t)) {
812        uint32_t reg = *(uint32_t *)data;
813        uint16_t rfaddr;
814
815        DPRINTF(EthernetPIO, "write data=%d data=%#x\n", reg, reg);
816
817        switch (daddr) {
818          case CR:
819            regs.command = reg;
820            if (reg & CR_TXD) {
821                txEnable = false;
822            } else if (reg & CR_TXE) {
823                txEnable = true;
824
825                // the kernel is enabling the transmit machine
826                if (txState == txIdle)
827                    txKick();
828            }
829
830            if (reg & CR_RXD) {
831                rxEnable = false;
832            } else if (reg & CR_RXE) {
833                rxEnable = true;
834
835                if (rxState == rxIdle)
836                    rxKick();
837            }
838
839            if (reg & CR_TXR)
840                txReset();
841
842            if (reg & CR_RXR)
843                rxReset();
844
845            if (reg & CR_SWI)
846                devIntrPost(ISR_SWI);
847
848            if (reg & CR_RST) {
849                txReset();
850                rxReset();
851
852                regsReset();
853            }
854            break;
855
856          case CFGR:
857            if (reg & CFGR_LNKSTS ||
858                reg & CFGR_SPDSTS ||
859                reg & CFGR_DUPSTS ||
860                reg & CFGR_RESERVED ||
861                reg & CFGR_T64ADDR ||
862                reg & CFGR_PCI64_DET)
863
864            // First clear all writable bits
865            regs.config &= CFGR_LNKSTS | CFGR_SPDSTS | CFGR_DUPSTS |
866                                   CFGR_RESERVED | CFGR_T64ADDR |
867                                   CFGR_PCI64_DET;
868            // Now set the appropriate writable bits
869            regs.config |= reg & ~(CFGR_LNKSTS | CFGR_SPDSTS | CFGR_DUPSTS |
870                                   CFGR_RESERVED | CFGR_T64ADDR |
871                                   CFGR_PCI64_DET);
872
873// all these #if 0's are because i don't THINK the kernel needs to
874// have these implemented. if there is a problem relating to one of
875// these, you may need to add functionality in.
876            if (reg & CFGR_TBI_EN) ;
877            if (reg & CFGR_MODE_1000) ;
878
879            if (reg & CFGR_AUTO_1000)
880                panic("CFGR_AUTO_1000 not implemented!\n");
881
882            if (reg & CFGR_PINT_DUPSTS ||
883                reg & CFGR_PINT_LNKSTS ||
884                reg & CFGR_PINT_SPDSTS)
885                ;
886
887            if (reg & CFGR_TMRTEST) ;
888            if (reg & CFGR_MRM_DIS) ;
889            if (reg & CFGR_MWI_DIS) ;
890
891            if (reg & CFGR_T64ADDR) ;
892            // panic("CFGR_T64ADDR is read only register!\n");
893
894            if (reg & CFGR_PCI64_DET)
895                panic("CFGR_PCI64_DET is read only register!\n");
896
897            if (reg & CFGR_DATA64_EN) ;
898            if (reg & CFGR_M64ADDR) ;
899            if (reg & CFGR_PHY_RST) ;
900            if (reg & CFGR_PHY_DIS) ;
901
902            if (reg & CFGR_EXTSTS_EN)
903                extstsEnable = true;
904            else
905                extstsEnable = false;
906
907            if (reg & CFGR_REQALG) ;
908            if (reg & CFGR_SB) ;
909            if (reg & CFGR_POW) ;
910            if (reg & CFGR_EXD) ;
911            if (reg & CFGR_PESEL) ;
912            if (reg & CFGR_BROM_DIS) ;
913            if (reg & CFGR_EXT_125) ;
914            if (reg & CFGR_BEM) ;
915            break;
916
917          case MEAR:
918            // Clear writable bits
919            regs.mear &= MEAR_EEDO;
920            // Set appropriate writable bits
921            regs.mear |= reg & ~MEAR_EEDO;
922
923            // FreeBSD uses the EEPROM to read PMATCH (for the MAC address)
924            // even though it could get it through RFDR
925            if (reg & MEAR_EESEL) {
926                // Rising edge of clock
927                if (reg & MEAR_EECLK && !eepromClk)
928                    eepromKick();
929            }
930            else {
931                eepromState = eepromStart;
932                regs.mear &= ~MEAR_EEDI;
933            }
934
935            eepromClk = reg & MEAR_EECLK;
936
937            // since phy is completely faked, MEAR_MD* don't matter
938            if (reg & MEAR_MDIO) ;
939            if (reg & MEAR_MDDIR) ;
940            if (reg & MEAR_MDC) ;
941            break;
942
943          case PTSCR:
944            regs.ptscr = reg & ~(PTSCR_RBIST_RDONLY);
945            // these control BISTs for various parts of chip - we
946            // don't care or do just fake that the BIST is done
947            if (reg & PTSCR_RBIST_EN)
948                regs.ptscr |= PTSCR_RBIST_DONE;
949            if (reg & PTSCR_EEBIST_EN)
950                regs.ptscr &= ~PTSCR_EEBIST_EN;
951            if (reg & PTSCR_EELOAD_EN)
952                regs.ptscr &= ~PTSCR_EELOAD_EN;
953            break;
954
955          case ISR: /* writing to the ISR has no effect */
956            panic("ISR is a read only register!\n");
957
958          case IMR:
959            regs.imr = reg;
960            devIntrChangeMask();
961            break;
962
963          case IER:
964            regs.ier = reg;
965            break;
966
967          case IHR:
968            regs.ihr = reg;
969            /* not going to implement real interrupt holdoff */
970            break;
971
972          case TXDP:
973            regs.txdp = (reg & 0xFFFFFFFC);
974            assert(txState == txIdle);
975            CTDD = false;
976            break;
977
978          case TXDP_HI:
979            regs.txdp_hi = reg;
980            break;
981
982          case TX_CFG:
983            regs.txcfg = reg;
984#if 0
985            if (reg & TX_CFG_CSI) ;
986            if (reg & TX_CFG_HBI) ;
987            if (reg & TX_CFG_MLB) ;
988            if (reg & TX_CFG_ATP) ;
989            if (reg & TX_CFG_ECRETRY) {
990                /*
991                 * this could easily be implemented, but considering
992                 * the network is just a fake pipe, wouldn't make
993                 * sense to do this
994                 */
995            }
996
997            if (reg & TX_CFG_BRST_DIS) ;
998#endif
999
1000#if 0
1001            /* we handle our own DMA, ignore the kernel's exhortations */
1002            if (reg & TX_CFG_MXDMA) ;
1003#endif
1004
1005            // also, we currently don't care about fill/drain
1006            // thresholds though this may change in the future with
1007            // more realistic networks or a driver which changes it
1008            // according to feedback
1009
1010            break;
1011
1012          case GPIOR:
1013            // Only write writable bits
1014            regs.gpior &= GPIOR_UNUSED | GPIOR_GP5_IN | GPIOR_GP4_IN
1015                        | GPIOR_GP3_IN | GPIOR_GP2_IN | GPIOR_GP1_IN;
1016            regs.gpior |= reg & ~(GPIOR_UNUSED | GPIOR_GP5_IN | GPIOR_GP4_IN
1017                                | GPIOR_GP3_IN | GPIOR_GP2_IN | GPIOR_GP1_IN);
1018            /* these just control general purpose i/o pins, don't matter */
1019            break;
1020
1021          case RXDP:
1022            regs.rxdp = reg;
1023            CRDD = false;
1024            break;
1025
1026          case RXDP_HI:
1027            regs.rxdp_hi = reg;
1028            break;
1029
1030          case RX_CFG:
1031            regs.rxcfg = reg;
1032#if 0
1033            if (reg & RX_CFG_AEP) ;
1034            if (reg & RX_CFG_ARP) ;
1035            if (reg & RX_CFG_STRIPCRC) ;
1036            if (reg & RX_CFG_RX_RD) ;
1037            if (reg & RX_CFG_ALP) ;
1038            if (reg & RX_CFG_AIRL) ;
1039
1040            /* we handle our own DMA, ignore what kernel says about it */
1041            if (reg & RX_CFG_MXDMA) ;
1042
1043            //also, we currently don't care about fill/drain thresholds
1044            //though this may change in the future with more realistic
1045            //networks or a driver which changes it according to feedback
1046            if (reg & (RX_CFG_DRTH | RX_CFG_DRTH0)) ;
1047#endif
1048            break;
1049
1050          case PQCR:
1051            /* there is no priority queueing used in the linux 2.6 driver */
1052            regs.pqcr = reg;
1053            break;
1054
1055          case WCSR:
1056            /* not going to implement wake on LAN */
1057            regs.wcsr = reg;
1058            break;
1059
1060          case PCR:
1061            /* not going to implement pause control */
1062            regs.pcr = reg;
1063            break;
1064
1065          case RFCR:
1066            regs.rfcr = reg;
1067
1068            rxFilterEnable = (reg & RFCR_RFEN) ? true : false;
1069            acceptBroadcast = (reg & RFCR_AAB) ? true : false;
1070            acceptMulticast = (reg & RFCR_AAM) ? true : false;
1071            acceptUnicast = (reg & RFCR_AAU) ? true : false;
1072            acceptPerfect = (reg & RFCR_APM) ? true : false;
1073            acceptArp = (reg & RFCR_AARP) ? true : false;
1074            multicastHashEnable = (reg & RFCR_MHEN) ? true : false;
1075
1076#if 0
1077            if (reg & RFCR_APAT)
1078                panic("RFCR_APAT not implemented!\n");
1079#endif
1080            if (reg & RFCR_UHEN)
1081                panic("Unicast hash filtering not used by drivers!\n");
1082
1083            if (reg & RFCR_ULM)
1084                panic("RFCR_ULM not implemented!\n");
1085
1086            break;
1087
1088          case RFDR:
1089            rfaddr = (uint16_t)(regs.rfcr & RFCR_RFADDR);
1090            switch (rfaddr) {
1091              case 0x000:
1092                rom.perfectMatch[0] = (uint8_t)reg;
1093                rom.perfectMatch[1] = (uint8_t)(reg >> 8);
1094                break;
1095              case 0x002:
1096                rom.perfectMatch[2] = (uint8_t)reg;
1097                rom.perfectMatch[3] = (uint8_t)(reg >> 8);
1098                break;
1099              case 0x004:
1100                rom.perfectMatch[4] = (uint8_t)reg;
1101                rom.perfectMatch[5] = (uint8_t)(reg >> 8);
1102                break;
1103              default:
1104
1105                if (rfaddr >= FHASH_ADDR &&
1106                    rfaddr < FHASH_ADDR + FHASH_SIZE) {
1107
1108                    // Only word-aligned writes supported
1109                    if (rfaddr % 2)
1110                        panic("unaligned write to filter hash table!");
1111
1112                    rom.filterHash[rfaddr - FHASH_ADDR] = (uint8_t)reg;
1113                    rom.filterHash[rfaddr - FHASH_ADDR + 1]
1114                        = (uint8_t)(reg >> 8);
1115                    break;
1116                }
1117                panic("writing RFDR for something other than pattern matching\
1118                    or hashing! %#x\n", rfaddr);
1119            }
1120
1121          case BRAR:
1122            regs.brar = reg;
1123            break;
1124
1125          case BRDR:
1126            panic("the driver never uses BRDR, something is wrong!\n");
1127
1128          case SRR:
1129            panic("SRR is read only register!\n");
1130
1131          case MIBC:
1132            panic("the driver never uses MIBC, something is wrong!\n");
1133
1134          case VRCR:
1135            regs.vrcr = reg;
1136            break;
1137
1138          case VTCR:
1139            regs.vtcr = reg;
1140            break;
1141
1142          case VDR:
1143            panic("the driver never uses VDR, something is wrong!\n");
1144
1145          case CCSR:
1146            /* not going to implement clockrun stuff */
1147            regs.ccsr = reg;
1148            break;
1149
1150          case TBICR:
1151            regs.tbicr = reg;
1152            if (reg & TBICR_MR_LOOPBACK)
1153                panic("TBICR_MR_LOOPBACK never used, something wrong!\n");
1154
1155            if (reg & TBICR_MR_AN_ENABLE) {
1156                regs.tanlpar = regs.tanar;
1157                regs.tbisr |= (TBISR_MR_AN_COMPLETE | TBISR_MR_LINK_STATUS);
1158            }
1159
1160#if 0
1161            if (reg & TBICR_MR_RESTART_AN) ;
1162#endif
1163
1164            break;
1165
1166          case TBISR:
1167            panic("TBISR is read only register!\n");
1168
1169          case TANAR:
1170            // Only write the writable bits
1171            regs.tanar &= TANAR_RF1 | TANAR_RF2 | TANAR_UNUSED;
1172            regs.tanar |= reg & ~(TANAR_RF1 | TANAR_RF2 | TANAR_UNUSED);
1173
1174            // Pause capability unimplemented
1175#if 0
1176            if (reg & TANAR_PS2) ;
1177            if (reg & TANAR_PS1) ;
1178#endif
1179
1180            break;
1181
1182          case TANLPAR:
1183            panic("this should only be written to by the fake phy!\n");
1184
1185          case TANER:
1186            panic("TANER is read only register!\n");
1187
1188          case TESR:
1189            regs.tesr = reg;
1190            break;
1191
1192          default:
1193            panic("invalid register access daddr=%#x", daddr);
1194        }
1195    } else {
1196        panic("Invalid Request Size");
1197    }
1198
1199    return No_Fault;
1200}
1201
1202void
1203NSGigE::devIntrPost(uint32_t interrupts)
1204{
1205    if (interrupts & ISR_RESERVE)
1206        panic("Cannot set a reserved interrupt");
1207
1208    if (interrupts & ISR_NOIMPL)
1209        warn("interrupt not implemented %#x\n", interrupts);
1210
1211    interrupts &= ISR_IMPL;
1212    regs.isr |= interrupts;
1213
1214    if (interrupts & regs.imr) {
1215        if (interrupts & ISR_SWI) {
1216            totalSwi++;
1217        }
1218        if (interrupts & ISR_RXIDLE) {
1219            totalRxIdle++;
1220        }
1221        if (interrupts & ISR_RXOK) {
1222            totalRxOk++;
1223        }
1224        if (interrupts & ISR_RXDESC) {
1225            totalRxDesc++;
1226        }
1227        if (interrupts & ISR_TXOK) {
1228            totalTxOk++;
1229        }
1230        if (interrupts & ISR_TXIDLE) {
1231            totalTxIdle++;
1232        }
1233        if (interrupts & ISR_TXDESC) {
1234            totalTxDesc++;
1235        }
1236        if (interrupts & ISR_RXORN) {
1237            totalRxOrn++;
1238        }
1239    }
1240
1241    DPRINTF(EthernetIntr,
1242            "interrupt written to ISR: intr=%#x isr=%#x imr=%#x\n",
1243            interrupts, regs.isr, regs.imr);
1244
1245    if ((regs.isr & regs.imr)) {
1246        Tick when = curTick;
1247        if ((regs.isr & regs.imr & ISR_NODELAY) == 0)
1248            when += intrDelay;
1249        cpuIntrPost(when);
1250    }
1251}
1252
1253/* writing this interrupt counting stats inside this means that this function
1254   is now limited to being used to clear all interrupts upon the kernel
1255   reading isr and servicing.  just telling you in case you were thinking
1256   of expanding use.
1257*/
1258void
1259NSGigE::devIntrClear(uint32_t interrupts)
1260{
1261    if (interrupts & ISR_RESERVE)
1262        panic("Cannot clear a reserved interrupt");
1263
1264    if (regs.isr & regs.imr & ISR_SWI) {
1265        postedSwi++;
1266    }
1267    if (regs.isr & regs.imr & ISR_RXIDLE) {
1268        postedRxIdle++;
1269    }
1270    if (regs.isr & regs.imr & ISR_RXOK) {
1271        postedRxOk++;
1272    }
1273    if (regs.isr & regs.imr & ISR_RXDESC) {
1274            postedRxDesc++;
1275    }
1276    if (regs.isr & regs.imr & ISR_TXOK) {
1277        postedTxOk++;
1278    }
1279    if (regs.isr & regs.imr & ISR_TXIDLE) {
1280        postedTxIdle++;
1281    }
1282    if (regs.isr & regs.imr & ISR_TXDESC) {
1283        postedTxDesc++;
1284    }
1285    if (regs.isr & regs.imr & ISR_RXORN) {
1286        postedRxOrn++;
1287    }
1288
1289    if (regs.isr & regs.imr & ISR_IMPL)
1290        postedInterrupts++;
1291
1292    interrupts &= ~ISR_NOIMPL;
1293    regs.isr &= ~interrupts;
1294
1295    DPRINTF(EthernetIntr,
1296            "interrupt cleared from ISR: intr=%x isr=%x imr=%x\n",
1297            interrupts, regs.isr, regs.imr);
1298
1299    if (!(regs.isr & regs.imr))
1300        cpuIntrClear();
1301}
1302
1303void
1304NSGigE::devIntrChangeMask()
1305{
1306    DPRINTF(EthernetIntr, "interrupt mask changed: isr=%x imr=%x masked=%x\n",
1307            regs.isr, regs.imr, regs.isr & regs.imr);
1308
1309    if (regs.isr & regs.imr)
1310        cpuIntrPost(curTick);
1311    else
1312        cpuIntrClear();
1313}
1314
1315void
1316NSGigE::cpuIntrPost(Tick when)
1317{
1318    // If the interrupt you want to post is later than an interrupt
1319    // already scheduled, just let it post in the coming one and don't
1320    // schedule another.
1321    // HOWEVER, must be sure that the scheduled intrTick is in the
1322    // future (this was formerly the source of a bug)
1323    /**
1324     * @todo this warning should be removed and the intrTick code should
1325     * be fixed.
1326     */
1327    assert(when >= curTick);
1328    assert(intrTick >= curTick || intrTick == 0);
1329    if (when > intrTick && intrTick != 0) {
1330        DPRINTF(EthernetIntr, "don't need to schedule event...intrTick=%d\n",
1331                intrTick);
1332        return;
1333    }
1334
1335    intrTick = when;
1336    if (intrTick < curTick) {
1337        debug_break();
1338        intrTick = curTick;
1339    }
1340
1341    DPRINTF(EthernetIntr, "going to schedule an interrupt for intrTick=%d\n",
1342            intrTick);
1343
1344    if (intrEvent)
1345        intrEvent->squash();
1346    intrEvent = new IntrEvent(this, true);
1347    intrEvent->schedule(intrTick);
1348}
1349
1350void
1351NSGigE::cpuInterrupt()
1352{
1353    assert(intrTick == curTick);
1354
1355    // Whether or not there's a pending interrupt, we don't care about
1356    // it anymore
1357    intrEvent = 0;
1358    intrTick = 0;
1359
1360    // Don't send an interrupt if there's already one
1361    if (cpuPendingIntr) {
1362        DPRINTF(EthernetIntr,
1363                "would send an interrupt now, but there's already pending\n");
1364    } else {
1365        // Send interrupt
1366        cpuPendingIntr = true;
1367
1368        DPRINTF(EthernetIntr, "posting interrupt\n");
1369        intrPost();
1370    }
1371}
1372
1373void
1374NSGigE::cpuIntrClear()
1375{
1376    if (!cpuPendingIntr)
1377        return;
1378
1379    if (intrEvent) {
1380        intrEvent->squash();
1381        intrEvent = 0;
1382    }
1383
1384    intrTick = 0;
1385
1386    cpuPendingIntr = false;
1387
1388    DPRINTF(EthernetIntr, "clearing interrupt\n");
1389    intrClear();
1390}
1391
1392bool
1393NSGigE::cpuIntrPending() const
1394{ return cpuPendingIntr; }
1395
1396void
1397NSGigE::txReset()
1398{
1399
1400    DPRINTF(Ethernet, "transmit reset\n");
1401
1402    CTDD = false;
1403    txEnable = false;;
1404    txFragPtr = 0;
1405    assert(txDescCnt == 0);
1406    txFifo.clear();
1407    txState = txIdle;
1408    assert(txDmaState == dmaIdle);
1409}
1410
1411void
1412NSGigE::rxReset()
1413{
1414    DPRINTF(Ethernet, "receive reset\n");
1415
1416    CRDD = false;
1417    assert(rxPktBytes == 0);
1418    rxEnable = false;
1419    rxFragPtr = 0;
1420    assert(rxDescCnt == 0);
1421    assert(rxDmaState == dmaIdle);
1422    rxFifo.clear();
1423    rxState = rxIdle;
1424}
1425
1426void
1427NSGigE::regsReset()
1428{
1429    memset(&regs, 0, sizeof(regs));
1430    regs.config = (CFGR_LNKSTS | CFGR_TBI_EN | CFGR_MODE_1000);
1431    regs.mear = 0x12;
1432    regs.txcfg = 0x120; // set drain threshold to 1024 bytes and
1433                        // fill threshold to 32 bytes
1434    regs.rxcfg = 0x4;   // set drain threshold to 16 bytes
1435    regs.srr = 0x0103;  // set the silicon revision to rev B or 0x103
1436    regs.mibc = MIBC_FRZ;
1437    regs.vdr = 0x81;    // set the vlan tag type to 802.1q
1438    regs.tesr = 0xc000; // TBI capable of both full and half duplex
1439    regs.brar = 0xffffffff;
1440
1441    extstsEnable = false;
1442    acceptBroadcast = false;
1443    acceptMulticast = false;
1444    acceptUnicast = false;
1445    acceptPerfect = false;
1446    acceptArp = false;
1447}
1448
1449void
1450NSGigE::rxDmaReadCopy()
1451{
1452    assert(rxDmaState == dmaReading);
1453
1454    physmem->dma_read((uint8_t *)rxDmaData, rxDmaAddr, rxDmaLen);
1455    rxDmaState = dmaIdle;
1456
1457    DPRINTF(EthernetDMA, "rx dma read  paddr=%#x len=%d\n",
1458            rxDmaAddr, rxDmaLen);
1459    DDUMP(EthernetDMA, rxDmaData, rxDmaLen);
1460}
1461
1462bool
1463NSGigE::doRxDmaRead()
1464{
1465    assert(rxDmaState == dmaIdle || rxDmaState == dmaReadWaiting);
1466    rxDmaState = dmaReading;
1467
1468    if (dmaInterface && !rxDmaFree) {
1469        if (dmaInterface->busy())
1470            rxDmaState = dmaReadWaiting;
1471        else
1472            dmaInterface->doDMA(Read, rxDmaAddr, rxDmaLen, curTick,
1473                                &rxDmaReadEvent, true);
1474        return true;
1475    }
1476
1477    if (dmaReadDelay == 0 && dmaReadFactor == 0) {
1478        rxDmaReadCopy();
1479        return false;
1480    }
1481
1482    Tick factor = ((rxDmaLen + ULL(63)) >> ULL(6)) * dmaReadFactor;
1483    Tick start = curTick + dmaReadDelay + factor;
1484    rxDmaReadEvent.schedule(start);
1485    return true;
1486}
1487
1488void
1489NSGigE::rxDmaReadDone()
1490{
1491    assert(rxDmaState == dmaReading);
1492    rxDmaReadCopy();
1493
1494    // If the transmit state machine has a pending DMA, let it go first
1495    if (txDmaState == dmaReadWaiting || txDmaState == dmaWriteWaiting)
1496        txKick();
1497
1498    rxKick();
1499}
1500
1501void
1502NSGigE::rxDmaWriteCopy()
1503{
1504    assert(rxDmaState == dmaWriting);
1505
1506    physmem->dma_write(rxDmaAddr, (uint8_t *)rxDmaData, rxDmaLen);
1507    rxDmaState = dmaIdle;
1508
1509    DPRINTF(EthernetDMA, "rx dma write paddr=%#x len=%d\n",
1510            rxDmaAddr, rxDmaLen);
1511    DDUMP(EthernetDMA, rxDmaData, rxDmaLen);
1512}
1513
1514bool
1515NSGigE::doRxDmaWrite()
1516{
1517    assert(rxDmaState == dmaIdle || rxDmaState == dmaWriteWaiting);
1518    rxDmaState = dmaWriting;
1519
1520    if (dmaInterface && !rxDmaFree) {
1521        if (dmaInterface->busy())
1522            rxDmaState = dmaWriteWaiting;
1523        else
1524            dmaInterface->doDMA(WriteInvalidate, rxDmaAddr, rxDmaLen, curTick,
1525                                &rxDmaWriteEvent, true);
1526        return true;
1527    }
1528
1529    if (dmaWriteDelay == 0 && dmaWriteFactor == 0) {
1530        rxDmaWriteCopy();
1531        return false;
1532    }
1533
1534    Tick factor = ((rxDmaLen + ULL(63)) >> ULL(6)) * dmaWriteFactor;
1535    Tick start = curTick + dmaWriteDelay + factor;
1536    rxDmaWriteEvent.schedule(start);
1537    return true;
1538}
1539
1540void
1541NSGigE::rxDmaWriteDone()
1542{
1543    assert(rxDmaState == dmaWriting);
1544    rxDmaWriteCopy();
1545
1546    // If the transmit state machine has a pending DMA, let it go first
1547    if (txDmaState == dmaReadWaiting || txDmaState == dmaWriteWaiting)
1548        txKick();
1549
1550    rxKick();
1551}
1552
1553void
1554NSGigE::rxKick()
1555{
1556    bool is64bit = (bool)(regs.config & CFGR_M64ADDR);
1557
1558    DPRINTF(EthernetSM,
1559            "receive kick rxState=%s (rxBuf.size=%d) %d-bit\n",
1560            NsRxStateStrings[rxState], rxFifo.size(), is64bit ? 64 : 32);
1561
1562    Addr link, bufptr;
1563    uint32_t &cmdsts = is64bit ? rxDesc64.cmdsts : rxDesc32.cmdsts;
1564    uint32_t &extsts = is64bit ? rxDesc64.extsts : rxDesc32.extsts;
1565
1566  next:
1567    if (clock) {
1568        if (rxKickTick > curTick) {
1569            DPRINTF(EthernetSM, "receive kick exiting, can't run till %d\n",
1570                    rxKickTick);
1571
1572            goto exit;
1573        }
1574
1575        // Go to the next state machine clock tick.
1576        rxKickTick = curTick + cycles(1);
1577    }
1578
1579    switch(rxDmaState) {
1580      case dmaReadWaiting:
1581        if (doRxDmaRead())
1582            goto exit;
1583        break;
1584      case dmaWriteWaiting:
1585        if (doRxDmaWrite())
1586            goto exit;
1587        break;
1588      default:
1589        break;
1590    }
1591
1592    link = is64bit ? (Addr)rxDesc64.link : (Addr)rxDesc32.link;
1593    bufptr = is64bit ? (Addr)rxDesc64.bufptr : (Addr)rxDesc32.bufptr;
1594
1595    // see state machine from spec for details
1596    // the way this works is, if you finish work on one state and can
1597    // go directly to another, you do that through jumping to the
1598    // label "next".  however, if you have intermediate work, like DMA
1599    // so that you can't go to the next state yet, you go to exit and
1600    // exit the loop.  however, when the DMA is done it will trigger
1601    // an event and come back to this loop.
1602    switch (rxState) {
1603      case rxIdle:
1604        if (!rxEnable) {
1605            DPRINTF(EthernetSM, "Receive Disabled! Nothing to do.\n");
1606            goto exit;
1607        }
1608
1609        if (CRDD) {
1610            rxState = rxDescRefr;
1611
1612            rxDmaAddr = regs.rxdp & 0x3fffffff;
1613            rxDmaData =
1614                is64bit ? (void *)&rxDesc64.link : (void *)&rxDesc32.link;
1615            rxDmaLen = is64bit ? sizeof(rxDesc64.link) : sizeof(rxDesc32.link);
1616            rxDmaFree = dmaDescFree;
1617
1618            descDmaReads++;
1619            descDmaRdBytes += rxDmaLen;
1620
1621            if (doRxDmaRead())
1622                goto exit;
1623        } else {
1624            rxState = rxDescRead;
1625
1626            rxDmaAddr = regs.rxdp & 0x3fffffff;
1627            rxDmaData = is64bit ? (void *)&rxDesc64 : (void *)&rxDesc32;
1628            rxDmaLen = is64bit ? sizeof(rxDesc64) : sizeof(rxDesc32);
1629            rxDmaFree = dmaDescFree;
1630
1631            descDmaReads++;
1632            descDmaRdBytes += rxDmaLen;
1633
1634            if (doRxDmaRead())
1635                goto exit;
1636        }
1637        break;
1638
1639      case rxDescRefr:
1640        if (rxDmaState != dmaIdle)
1641            goto exit;
1642
1643        rxState = rxAdvance;
1644        break;
1645
1646     case rxDescRead:
1647        if (rxDmaState != dmaIdle)
1648            goto exit;
1649
1650        DPRINTF(EthernetDesc, "rxDesc: addr=%08x read descriptor\n",
1651                regs.rxdp & 0x3fffffff);
1652        DPRINTF(EthernetDesc,
1653                "rxDesc: link=%#x bufptr=%#x cmdsts=%08x extsts=%08x\n",
1654                link, bufptr, cmdsts, extsts);
1655
1656        if (cmdsts & CMDSTS_OWN) {
1657            devIntrPost(ISR_RXIDLE);
1658            rxState = rxIdle;
1659            goto exit;
1660        } else {
1661            rxState = rxFifoBlock;
1662            rxFragPtr = bufptr;
1663            rxDescCnt = cmdsts & CMDSTS_LEN_MASK;
1664        }
1665        break;
1666
1667      case rxFifoBlock:
1668        if (!rxPacket) {
1669            /**
1670             * @todo in reality, we should be able to start processing
1671             * the packet as it arrives, and not have to wait for the
1672             * full packet ot be in the receive fifo.
1673             */
1674            if (rxFifo.empty())
1675                goto exit;
1676
1677            DPRINTF(EthernetSM, "****processing receive of new packet****\n");
1678
1679            // If we don't have a packet, grab a new one from the fifo.
1680            rxPacket = rxFifo.front();
1681            rxPktBytes = rxPacket->length;
1682            rxPacketBufPtr = rxPacket->data;
1683
1684#if TRACING_ON
1685            if (DTRACE(Ethernet)) {
1686                IpPtr ip(rxPacket);
1687                if (ip) {
1688                    DPRINTF(Ethernet, "ID is %d\n", ip->id());
1689                    TcpPtr tcp(ip);
1690                    if (tcp) {
1691                        DPRINTF(Ethernet,
1692                                "Src Port=%d, Dest Port=%d, Seq=%d, Ack=%d\n",
1693                                tcp->sport(), tcp->dport(), tcp->seq(),
1694                                tcp->ack());
1695                    }
1696                }
1697            }
1698#endif
1699
1700            // sanity check - i think the driver behaves like this
1701            assert(rxDescCnt >= rxPktBytes);
1702            rxFifo.pop();
1703        }
1704
1705
1706        // dont' need the && rxDescCnt > 0 if driver sanity check
1707        // above holds
1708        if (rxPktBytes > 0) {
1709            rxState = rxFragWrite;
1710            // don't need min<>(rxPktBytes,rxDescCnt) if above sanity
1711            // check holds
1712            rxXferLen = rxPktBytes;
1713
1714            rxDmaAddr = rxFragPtr & 0x3fffffff;
1715            rxDmaData = rxPacketBufPtr;
1716            rxDmaLen = rxXferLen;
1717            rxDmaFree = dmaDataFree;
1718
1719            if (doRxDmaWrite())
1720                goto exit;
1721
1722        } else {
1723            rxState = rxDescWrite;
1724
1725            //if (rxPktBytes == 0) {  /* packet is done */
1726            assert(rxPktBytes == 0);
1727            DPRINTF(EthernetSM, "done with receiving packet\n");
1728
1729            cmdsts |= CMDSTS_OWN;
1730            cmdsts &= ~CMDSTS_MORE;
1731            cmdsts |= CMDSTS_OK;
1732            cmdsts &= 0xffff0000;
1733            cmdsts += rxPacket->length;   //i.e. set CMDSTS_SIZE
1734
1735#if 0
1736            /*
1737             * all the driver uses these are for its own stats keeping
1738             * which we don't care about, aren't necessary for
1739             * functionality and doing this would just slow us down.
1740             * if they end up using this in a later version for
1741             * functional purposes, just undef
1742             */
1743            if (rxFilterEnable) {
1744                cmdsts &= ~CMDSTS_DEST_MASK;
1745                const EthAddr &dst = rxFifoFront()->dst();
1746                if (dst->unicast())
1747                    cmdsts |= CMDSTS_DEST_SELF;
1748                if (dst->multicast())
1749                    cmdsts |= CMDSTS_DEST_MULTI;
1750                if (dst->broadcast())
1751                    cmdsts |= CMDSTS_DEST_MASK;
1752            }
1753#endif
1754
1755            IpPtr ip(rxPacket);
1756            if (extstsEnable && ip) {
1757                extsts |= EXTSTS_IPPKT;
1758                rxIpChecksums++;
1759                if (cksum(ip) != 0) {
1760                    DPRINTF(EthernetCksum, "Rx IP Checksum Error\n");
1761                    extsts |= EXTSTS_IPERR;
1762                }
1763                TcpPtr tcp(ip);
1764                UdpPtr udp(ip);
1765                if (tcp) {
1766                    extsts |= EXTSTS_TCPPKT;
1767                    rxTcpChecksums++;
1768                    if (cksum(tcp) != 0) {
1769                        DPRINTF(EthernetCksum, "Rx TCP Checksum Error\n");
1770                        extsts |= EXTSTS_TCPERR;
1771
1772                    }
1773                } else if (udp) {
1774                    extsts |= EXTSTS_UDPPKT;
1775                    rxUdpChecksums++;
1776                    if (cksum(udp) != 0) {
1777                        DPRINTF(EthernetCksum, "Rx UDP Checksum Error\n");
1778                        extsts |= EXTSTS_UDPERR;
1779                    }
1780                }
1781            }
1782            rxPacket = 0;
1783
1784            /*
1785             * the driver seems to always receive into desc buffers
1786             * of size 1514, so you never have a pkt that is split
1787             * into multiple descriptors on the receive side, so
1788             * i don't implement that case, hence the assert above.
1789             */
1790
1791            DPRINTF(EthernetDesc,
1792                    "rxDesc: addr=%08x writeback cmdsts extsts\n",
1793                    regs.rxdp & 0x3fffffff);
1794            DPRINTF(EthernetDesc,
1795                    "rxDesc: link=%#x bufptr=%#x cmdsts=%08x extsts=%08x\n",
1796                    link, bufptr, cmdsts, extsts);
1797
1798            rxDmaAddr = regs.rxdp & 0x3fffffff;
1799            rxDmaData = &cmdsts;
1800            if (is64bit) {
1801                rxDmaAddr += offsetof(ns_desc64, cmdsts);
1802                rxDmaLen = sizeof(rxDesc64.cmdsts) + sizeof(rxDesc64.extsts);
1803            } else {
1804                rxDmaAddr += offsetof(ns_desc32, cmdsts);
1805                rxDmaLen = sizeof(rxDesc32.cmdsts) + sizeof(rxDesc32.extsts);
1806            }
1807            rxDmaFree = dmaDescFree;
1808
1809            descDmaWrites++;
1810            descDmaWrBytes += rxDmaLen;
1811
1812            if (doRxDmaWrite())
1813                goto exit;
1814        }
1815        break;
1816
1817      case rxFragWrite:
1818        if (rxDmaState != dmaIdle)
1819            goto exit;
1820
1821        rxPacketBufPtr += rxXferLen;
1822        rxFragPtr += rxXferLen;
1823        rxPktBytes -= rxXferLen;
1824
1825        rxState = rxFifoBlock;
1826        break;
1827
1828      case rxDescWrite:
1829        if (rxDmaState != dmaIdle)
1830            goto exit;
1831
1832        assert(cmdsts & CMDSTS_OWN);
1833
1834        assert(rxPacket == 0);
1835        devIntrPost(ISR_RXOK);
1836
1837        if (cmdsts & CMDSTS_INTR)
1838            devIntrPost(ISR_RXDESC);
1839
1840        if (!rxEnable) {
1841            DPRINTF(EthernetSM, "Halting the RX state machine\n");
1842            rxState = rxIdle;
1843            goto exit;
1844        } else
1845            rxState = rxAdvance;
1846        break;
1847
1848      case rxAdvance:
1849        if (link == 0) {
1850            devIntrPost(ISR_RXIDLE);
1851            rxState = rxIdle;
1852            CRDD = true;
1853            goto exit;
1854        } else {
1855            if (rxDmaState != dmaIdle)
1856                goto exit;
1857            rxState = rxDescRead;
1858            regs.rxdp = link;
1859            CRDD = false;
1860
1861            rxDmaAddr = regs.rxdp & 0x3fffffff;
1862            rxDmaData = is64bit ? (void *)&rxDesc64 : (void *)&rxDesc32;
1863            rxDmaLen = is64bit ? sizeof(rxDesc64) : sizeof(rxDesc32);
1864            rxDmaFree = dmaDescFree;
1865
1866            if (doRxDmaRead())
1867                goto exit;
1868        }
1869        break;
1870
1871      default:
1872        panic("Invalid rxState!");
1873    }
1874
1875    DPRINTF(EthernetSM, "entering next rxState=%s\n",
1876            NsRxStateStrings[rxState]);
1877    goto next;
1878
1879  exit:
1880    /**
1881     * @todo do we want to schedule a future kick?
1882     */
1883    DPRINTF(EthernetSM, "rx state machine exited rxState=%s\n",
1884            NsRxStateStrings[rxState]);
1885
1886    if (clock && !rxKickEvent.scheduled())
1887        rxKickEvent.schedule(rxKickTick);
1888}
1889
1890void
1891NSGigE::transmit()
1892{
1893    if (txFifo.empty()) {
1894        DPRINTF(Ethernet, "nothing to transmit\n");
1895        return;
1896    }
1897
1898    DPRINTF(Ethernet, "Attempt Pkt Transmit: txFifo length=%d\n",
1899            txFifo.size());
1900    if (interface->sendPacket(txFifo.front())) {
1901#if TRACING_ON
1902        if (DTRACE(Ethernet)) {
1903            IpPtr ip(txFifo.front());
1904            if (ip) {
1905                DPRINTF(Ethernet, "ID is %d\n", ip->id());
1906                TcpPtr tcp(ip);
1907                if (tcp) {
1908                    DPRINTF(Ethernet,
1909                            "Src Port=%d, Dest Port=%d, Seq=%d, Ack=%d\n",
1910                            tcp->sport(), tcp->dport(), tcp->seq(),
1911                            tcp->ack());
1912                }
1913            }
1914        }
1915#endif
1916
1917        DDUMP(EthernetData, txFifo.front()->data, txFifo.front()->length);
1918        txBytes += txFifo.front()->length;
1919        txPackets++;
1920
1921        DPRINTF(Ethernet, "Successful Xmit! now txFifoAvail is %d\n",
1922                txFifo.avail());
1923        txFifo.pop();
1924
1925        /*
1926         * normally do a writeback of the descriptor here, and ONLY
1927         * after that is done, send this interrupt.  but since our
1928         * stuff never actually fails, just do this interrupt here,
1929         * otherwise the code has to stray from this nice format.
1930         * besides, it's functionally the same.
1931         */
1932        devIntrPost(ISR_TXOK);
1933    }
1934
1935   if (!txFifo.empty() && !txEvent.scheduled()) {
1936       DPRINTF(Ethernet, "reschedule transmit\n");
1937       txEvent.schedule(curTick + retryTime);
1938   }
1939}
1940
1941void
1942NSGigE::txDmaReadCopy()
1943{
1944    assert(txDmaState == dmaReading);
1945
1946    physmem->dma_read((uint8_t *)txDmaData, txDmaAddr, txDmaLen);
1947    txDmaState = dmaIdle;
1948
1949    DPRINTF(EthernetDMA, "tx dma read  paddr=%#x len=%d\n",
1950            txDmaAddr, txDmaLen);
1951    DDUMP(EthernetDMA, txDmaData, txDmaLen);
1952}
1953
1954bool
1955NSGigE::doTxDmaRead()
1956{
1957    assert(txDmaState == dmaIdle || txDmaState == dmaReadWaiting);
1958    txDmaState = dmaReading;
1959
1960    if (dmaInterface && !txDmaFree) {
1961        if (dmaInterface->busy())
1962            txDmaState = dmaReadWaiting;
1963        else
1964            dmaInterface->doDMA(Read, txDmaAddr, txDmaLen, curTick,
1965                                &txDmaReadEvent, true);
1966        return true;
1967    }
1968
1969    if (dmaReadDelay == 0 && dmaReadFactor == 0.0) {
1970        txDmaReadCopy();
1971        return false;
1972    }
1973
1974    Tick factor = ((txDmaLen + ULL(63)) >> ULL(6)) * dmaReadFactor;
1975    Tick start = curTick + dmaReadDelay + factor;
1976    txDmaReadEvent.schedule(start);
1977    return true;
1978}
1979
1980void
1981NSGigE::txDmaReadDone()
1982{
1983    assert(txDmaState == dmaReading);
1984    txDmaReadCopy();
1985
1986    // If the receive state machine  has a pending DMA, let it go first
1987    if (rxDmaState == dmaReadWaiting || rxDmaState == dmaWriteWaiting)
1988        rxKick();
1989
1990    txKick();
1991}
1992
1993void
1994NSGigE::txDmaWriteCopy()
1995{
1996    assert(txDmaState == dmaWriting);
1997
1998    physmem->dma_write(txDmaAddr, (uint8_t *)txDmaData, txDmaLen);
1999    txDmaState = dmaIdle;
2000
2001    DPRINTF(EthernetDMA, "tx dma write paddr=%#x len=%d\n",
2002            txDmaAddr, txDmaLen);
2003    DDUMP(EthernetDMA, txDmaData, txDmaLen);
2004}
2005
2006bool
2007NSGigE::doTxDmaWrite()
2008{
2009    assert(txDmaState == dmaIdle || txDmaState == dmaWriteWaiting);
2010    txDmaState = dmaWriting;
2011
2012    if (dmaInterface && !txDmaFree) {
2013        if (dmaInterface->busy())
2014            txDmaState = dmaWriteWaiting;
2015        else
2016            dmaInterface->doDMA(WriteInvalidate, txDmaAddr, txDmaLen, curTick,
2017                                &txDmaWriteEvent, true);
2018        return true;
2019    }
2020
2021    if (dmaWriteDelay == 0 && dmaWriteFactor == 0.0) {
2022        txDmaWriteCopy();
2023        return false;
2024    }
2025
2026    Tick factor = ((txDmaLen + ULL(63)) >> ULL(6)) * dmaWriteFactor;
2027    Tick start = curTick + dmaWriteDelay + factor;
2028    txDmaWriteEvent.schedule(start);
2029    return true;
2030}
2031
2032void
2033NSGigE::txDmaWriteDone()
2034{
2035    assert(txDmaState == dmaWriting);
2036    txDmaWriteCopy();
2037
2038    // If the receive state machine  has a pending DMA, let it go first
2039    if (rxDmaState == dmaReadWaiting || rxDmaState == dmaWriteWaiting)
2040        rxKick();
2041
2042    txKick();
2043}
2044
2045void
2046NSGigE::txKick()
2047{
2048    bool is64bit = (bool)(regs.config & CFGR_M64ADDR);
2049
2050    DPRINTF(EthernetSM, "transmit kick txState=%s %d-bit\n",
2051            NsTxStateStrings[txState], is64bit ? 64 : 32);
2052
2053    Addr link, bufptr;
2054    uint32_t &cmdsts = is64bit ? txDesc64.cmdsts : txDesc32.cmdsts;
2055    uint32_t &extsts = is64bit ? txDesc64.extsts : txDesc32.extsts;
2056
2057  next:
2058    if (clock) {
2059        if (txKickTick > curTick) {
2060            DPRINTF(EthernetSM, "transmit kick exiting, can't run till %d\n",
2061                    txKickTick);
2062            goto exit;
2063        }
2064
2065        // Go to the next state machine clock tick.
2066        txKickTick = curTick + cycles(1);
2067    }
2068
2069    switch(txDmaState) {
2070      case dmaReadWaiting:
2071        if (doTxDmaRead())
2072            goto exit;
2073        break;
2074      case dmaWriteWaiting:
2075        if (doTxDmaWrite())
2076            goto exit;
2077        break;
2078      default:
2079        break;
2080    }
2081
2082    link = is64bit ? (Addr)txDesc64.link : (Addr)txDesc32.link;
2083    bufptr = is64bit ? (Addr)txDesc64.bufptr : (Addr)txDesc32.bufptr;
2084    switch (txState) {
2085      case txIdle:
2086        if (!txEnable) {
2087            DPRINTF(EthernetSM, "Transmit disabled.  Nothing to do.\n");
2088            goto exit;
2089        }
2090
2091        if (CTDD) {
2092            txState = txDescRefr;
2093
2094            txDmaAddr = regs.txdp & 0x3fffffff;
2095            txDmaData =
2096                is64bit ? (void *)&txDesc64.link : (void *)&txDesc32.link;
2097            txDmaLen = is64bit ? sizeof(txDesc64.link) : sizeof(txDesc32.link);
2098            txDmaFree = dmaDescFree;
2099
2100            descDmaReads++;
2101            descDmaRdBytes += txDmaLen;
2102
2103            if (doTxDmaRead())
2104                goto exit;
2105
2106        } else {
2107            txState = txDescRead;
2108
2109            txDmaAddr = regs.txdp & 0x3fffffff;
2110            txDmaData = is64bit ? (void *)&txDesc64 : (void *)&txDesc32;
2111            txDmaLen = is64bit ? sizeof(txDesc64) : sizeof(txDesc32);
2112            txDmaFree = dmaDescFree;
2113
2114            descDmaReads++;
2115            descDmaRdBytes += txDmaLen;
2116
2117            if (doTxDmaRead())
2118                goto exit;
2119        }
2120        break;
2121
2122      case txDescRefr:
2123        if (txDmaState != dmaIdle)
2124            goto exit;
2125
2126        txState = txAdvance;
2127        break;
2128
2129      case txDescRead:
2130        if (txDmaState != dmaIdle)
2131            goto exit;
2132
2133        DPRINTF(EthernetDesc, "txDesc: addr=%08x read descriptor\n",
2134                regs.txdp & 0x3fffffff);
2135        DPRINTF(EthernetDesc,
2136                "txDesc: link=%#x bufptr=%#x cmdsts=%#08x extsts=%#08x\n",
2137                link, bufptr, cmdsts, extsts);
2138
2139        if (cmdsts & CMDSTS_OWN) {
2140            txState = txFifoBlock;
2141            txFragPtr = bufptr;
2142            txDescCnt = cmdsts & CMDSTS_LEN_MASK;
2143        } else {
2144            devIntrPost(ISR_TXIDLE);
2145            txState = txIdle;
2146            goto exit;
2147        }
2148        break;
2149
2150      case txFifoBlock:
2151        if (!txPacket) {
2152            DPRINTF(EthernetSM, "****starting the tx of a new packet****\n");
2153            txPacket = new PacketData(16384);
2154            txPacketBufPtr = txPacket->data;
2155        }
2156
2157        if (txDescCnt == 0) {
2158            DPRINTF(EthernetSM, "the txDescCnt == 0, done with descriptor\n");
2159            if (cmdsts & CMDSTS_MORE) {
2160                DPRINTF(EthernetSM, "there are more descriptors to come\n");
2161                txState = txDescWrite;
2162
2163                cmdsts &= ~CMDSTS_OWN;
2164
2165                txDmaAddr = regs.txdp & 0x3fffffff;
2166                txDmaData = &cmdsts;
2167                if (is64bit) {
2168                    txDmaAddr += offsetof(ns_desc64, cmdsts);
2169                    txDmaLen = sizeof(txDesc64.cmdsts);
2170                } else {
2171                    txDmaAddr += offsetof(ns_desc32, cmdsts);
2172                    txDmaLen = sizeof(txDesc32.cmdsts);
2173                }
2174                txDmaFree = dmaDescFree;
2175
2176                if (doTxDmaWrite())
2177                    goto exit;
2178
2179            } else { /* this packet is totally done */
2180                DPRINTF(EthernetSM, "This packet is done, let's wrap it up\n");
2181                /* deal with the the packet that just finished */
2182                if ((regs.vtcr & VTCR_PPCHK) && extstsEnable) {
2183                    IpPtr ip(txPacket);
2184                    if (extsts & EXTSTS_UDPPKT) {
2185                        UdpPtr udp(ip);
2186                        udp->sum(0);
2187                        udp->sum(cksum(udp));
2188                        txUdpChecksums++;
2189                    } else if (extsts & EXTSTS_TCPPKT) {
2190                        TcpPtr tcp(ip);
2191                        tcp->sum(0);
2192                        tcp->sum(cksum(tcp));
2193                        txTcpChecksums++;
2194                    }
2195                    if (extsts & EXTSTS_IPPKT) {
2196                        ip->sum(0);
2197                        ip->sum(cksum(ip));
2198                        txIpChecksums++;
2199                    }
2200                }
2201
2202                txPacket->length = txPacketBufPtr - txPacket->data;
2203                // this is just because the receive can't handle a
2204                // packet bigger want to make sure
2205                if (txPacket->length > 1514)
2206                    panic("transmit packet too large, %s > 1514\n",
2207                          txPacket->length);
2208
2209#ifndef NDEBUG
2210                bool success =
2211#endif
2212                    txFifo.push(txPacket);
2213                assert(success);
2214
2215                /*
2216                 * this following section is not tqo spec, but
2217                 * functionally shouldn't be any different.  normally,
2218                 * the chip will wait til the transmit has occurred
2219                 * before writing back the descriptor because it has
2220                 * to wait to see that it was successfully transmitted
2221                 * to decide whether to set CMDSTS_OK or not.
2222                 * however, in the simulator since it is always
2223                 * successfully transmitted, and writing it exactly to
2224                 * spec would complicate the code, we just do it here
2225                 */
2226
2227                cmdsts &= ~CMDSTS_OWN;
2228                cmdsts |= CMDSTS_OK;
2229
2230                DPRINTF(EthernetDesc,
2231                        "txDesc writeback: cmdsts=%08x extsts=%08x\n",
2232                        cmdsts, extsts);
2233
2234                txDmaFree = dmaDescFree;
2235                txDmaAddr = regs.txdp & 0x3fffffff;
2236                txDmaData = &cmdsts;
2237                if (is64bit) {
2238                    txDmaAddr += offsetof(ns_desc64, cmdsts);
2239                    txDmaLen =
2240                        sizeof(txDesc64.cmdsts) + sizeof(txDesc64.extsts);
2241                } else {
2242                    txDmaAddr += offsetof(ns_desc32, cmdsts);
2243                    txDmaLen =
2244                        sizeof(txDesc32.cmdsts) + sizeof(txDesc32.extsts);
2245                }
2246
2247                descDmaWrites++;
2248                descDmaWrBytes += txDmaLen;
2249
2250                transmit();
2251                txPacket = 0;
2252
2253                if (!txEnable) {
2254                    DPRINTF(EthernetSM, "halting TX state machine\n");
2255                    txState = txIdle;
2256                    goto exit;
2257                } else
2258                    txState = txAdvance;
2259
2260                if (doTxDmaWrite())
2261                    goto exit;
2262            }
2263        } else {
2264            DPRINTF(EthernetSM, "this descriptor isn't done yet\n");
2265            if (!txFifo.full()) {
2266                txState = txFragRead;
2267
2268                /*
2269                 * The number of bytes transferred is either whatever
2270                 * is left in the descriptor (txDescCnt), or if there
2271                 * is not enough room in the fifo, just whatever room
2272                 * is left in the fifo
2273                 */
2274                txXferLen = min<uint32_t>(txDescCnt, txFifo.avail());
2275
2276                txDmaAddr = txFragPtr & 0x3fffffff;
2277                txDmaData = txPacketBufPtr;
2278                txDmaLen = txXferLen;
2279                txDmaFree = dmaDataFree;
2280
2281                if (doTxDmaRead())
2282                    goto exit;
2283            } else {
2284                txState = txFifoBlock;
2285                transmit();
2286
2287                goto exit;
2288            }
2289
2290        }
2291        break;
2292
2293      case txFragRead:
2294        if (txDmaState != dmaIdle)
2295            goto exit;
2296
2297        txPacketBufPtr += txXferLen;
2298        txFragPtr += txXferLen;
2299        txDescCnt -= txXferLen;
2300        txFifo.reserve(txXferLen);
2301
2302        txState = txFifoBlock;
2303        break;
2304
2305      case txDescWrite:
2306        if (txDmaState != dmaIdle)
2307            goto exit;
2308
2309        if (cmdsts & CMDSTS_INTR)
2310            devIntrPost(ISR_TXDESC);
2311
2312        if (!txEnable) {
2313            DPRINTF(EthernetSM, "halting TX state machine\n");
2314            txState = txIdle;
2315            goto exit;
2316        } else
2317            txState = txAdvance;
2318        break;
2319
2320      case txAdvance:
2321        if (link == 0) {
2322            devIntrPost(ISR_TXIDLE);
2323            txState = txIdle;
2324            goto exit;
2325        } else {
2326            if (txDmaState != dmaIdle)
2327                goto exit;
2328            txState = txDescRead;
2329            regs.txdp = link;
2330            CTDD = false;
2331
2332            txDmaAddr = link & 0x3fffffff;
2333            txDmaData = is64bit ? (void *)&txDesc64 : (void *)&txDesc32;
2334            txDmaLen = is64bit ? sizeof(txDesc64) : sizeof(txDesc32);
2335            txDmaFree = dmaDescFree;
2336
2337            if (doTxDmaRead())
2338                goto exit;
2339        }
2340        break;
2341
2342      default:
2343        panic("invalid state");
2344    }
2345
2346    DPRINTF(EthernetSM, "entering next txState=%s\n",
2347            NsTxStateStrings[txState]);
2348    goto next;
2349
2350  exit:
2351    /**
2352     * @todo do we want to schedule a future kick?
2353     */
2354    DPRINTF(EthernetSM, "tx state machine exited txState=%s\n",
2355            NsTxStateStrings[txState]);
2356
2357    if (clock && !txKickEvent.scheduled())
2358        txKickEvent.schedule(txKickTick);
2359}
2360
2361/**
2362 * Advance the EEPROM state machine
2363 * Called on rising edge of EEPROM clock bit in MEAR
2364 */
2365void
2366NSGigE::eepromKick()
2367{
2368    switch (eepromState) {
2369
2370      case eepromStart:
2371
2372        // Wait for start bit
2373        if (regs.mear & MEAR_EEDI) {
2374            // Set up to get 2 opcode bits
2375            eepromState = eepromGetOpcode;
2376            eepromBitsToRx = 2;
2377            eepromOpcode = 0;
2378        }
2379        break;
2380
2381      case eepromGetOpcode:
2382        eepromOpcode <<= 1;
2383        eepromOpcode += (regs.mear & MEAR_EEDI) ? 1 : 0;
2384        --eepromBitsToRx;
2385
2386        // Done getting opcode
2387        if (eepromBitsToRx == 0) {
2388            if (eepromOpcode != EEPROM_READ)
2389                panic("only EEPROM reads are implemented!");
2390
2391            // Set up to get address
2392            eepromState = eepromGetAddress;
2393            eepromBitsToRx = 6;
2394            eepromAddress = 0;
2395        }
2396        break;
2397
2398      case eepromGetAddress:
2399        eepromAddress <<= 1;
2400        eepromAddress += (regs.mear & MEAR_EEDI) ? 1 : 0;
2401        --eepromBitsToRx;
2402
2403        // Done getting address
2404        if (eepromBitsToRx == 0) {
2405
2406            if (eepromAddress >= EEPROM_SIZE)
2407                panic("EEPROM read access out of range!");
2408
2409            switch (eepromAddress) {
2410
2411              case EEPROM_PMATCH2_ADDR:
2412                eepromData = rom.perfectMatch[5];
2413                eepromData <<= 8;
2414                eepromData += rom.perfectMatch[4];
2415                break;
2416
2417              case EEPROM_PMATCH1_ADDR:
2418                eepromData = rom.perfectMatch[3];
2419                eepromData <<= 8;
2420                eepromData += rom.perfectMatch[2];
2421                break;
2422
2423              case EEPROM_PMATCH0_ADDR:
2424                eepromData = rom.perfectMatch[1];
2425                eepromData <<= 8;
2426                eepromData += rom.perfectMatch[0];
2427                break;
2428
2429              default:
2430                panic("FreeBSD driver only uses EEPROM to read PMATCH!");
2431            }
2432            // Set up to read data
2433            eepromState = eepromRead;
2434            eepromBitsToRx = 16;
2435
2436            // Clear data in bit
2437            regs.mear &= ~MEAR_EEDI;
2438        }
2439        break;
2440
2441      case eepromRead:
2442        // Clear Data Out bit
2443        regs.mear &= ~MEAR_EEDO;
2444        // Set bit to value of current EEPROM bit
2445        regs.mear |= (eepromData & 0x8000) ? MEAR_EEDO : 0x0;
2446
2447        eepromData <<= 1;
2448        --eepromBitsToRx;
2449
2450        // All done
2451        if (eepromBitsToRx == 0) {
2452            eepromState = eepromStart;
2453        }
2454        break;
2455
2456      default:
2457        panic("invalid EEPROM state");
2458    }
2459
2460}
2461
2462void
2463NSGigE::transferDone()
2464{
2465    if (txFifo.empty()) {
2466        DPRINTF(Ethernet, "transfer complete: txFifo empty...nothing to do\n");
2467        return;
2468    }
2469
2470    DPRINTF(Ethernet, "transfer complete: data in txFifo...schedule xmit\n");
2471
2472    if (txEvent.scheduled())
2473        txEvent.reschedule(curTick + cycles(1));
2474    else
2475        txEvent.schedule(curTick + cycles(1));
2476}
2477
2478bool
2479NSGigE::rxFilter(const PacketPtr &packet)
2480{
2481    EthPtr eth = packet;
2482    bool drop = true;
2483    string type;
2484
2485    const EthAddr &dst = eth->dst();
2486    if (dst.unicast()) {
2487        // If we're accepting all unicast addresses
2488        if (acceptUnicast)
2489            drop = false;
2490
2491        // If we make a perfect match
2492        if (acceptPerfect && dst == rom.perfectMatch)
2493            drop = false;
2494
2495        if (acceptArp && eth->type() == ETH_TYPE_ARP)
2496            drop = false;
2497
2498    } else if (dst.broadcast()) {
2499        // if we're accepting broadcasts
2500        if (acceptBroadcast)
2501            drop = false;
2502
2503    } else if (dst.multicast()) {
2504        // if we're accepting all multicasts
2505        if (acceptMulticast)
2506            drop = false;
2507
2508        // Multicast hashing faked - all packets accepted
2509        if (multicastHashEnable)
2510            drop = false;
2511    }
2512
2513    if (drop) {
2514        DPRINTF(Ethernet, "rxFilter drop\n");
2515        DDUMP(EthernetData, packet->data, packet->length);
2516    }
2517
2518    return drop;
2519}
2520
2521bool
2522NSGigE::recvPacket(PacketPtr packet)
2523{
2524    rxBytes += packet->length;
2525    rxPackets++;
2526
2527    DPRINTF(Ethernet, "Receiving packet from wire, rxFifoAvail=%d\n",
2528            rxFifo.avail());
2529
2530    if (!rxEnable) {
2531        DPRINTF(Ethernet, "receive disabled...packet dropped\n");
2532        interface->recvDone();
2533        return true;
2534    }
2535
2536    if (!rxFilterEnable) {
2537        DPRINTF(Ethernet,
2538            "receive packet filtering disabled . . . packet dropped\n");
2539        interface->recvDone();
2540        return true;
2541    }
2542
2543    if (rxFilter(packet)) {
2544        DPRINTF(Ethernet, "packet filtered...dropped\n");
2545        interface->recvDone();
2546        return true;
2547    }
2548
2549    if (rxFifo.avail() < packet->length) {
2550#if TRACING_ON
2551        IpPtr ip(packet);
2552        TcpPtr tcp(ip);
2553        if (ip) {
2554            DPRINTF(Ethernet,
2555                    "packet won't fit in receive buffer...pkt ID %d dropped\n",
2556                    ip->id());
2557            if (tcp) {
2558                DPRINTF(Ethernet, "Seq=%d\n", tcp->seq());
2559            }
2560        }
2561#endif
2562        droppedPackets++;
2563        devIntrPost(ISR_RXORN);
2564        return false;
2565    }
2566
2567    rxFifo.push(packet);
2568    interface->recvDone();
2569
2570    rxKick();
2571    return true;
2572}
2573
2574//=====================================================================
2575//
2576//
2577void
2578NSGigE::serialize(ostream &os)
2579{
2580    // Serialize the PciDev base class
2581    PciDev::serialize(os);
2582
2583    /*
2584     * Finalize any DMA events now.
2585     */
2586    if (rxDmaReadEvent.scheduled())
2587        rxDmaReadCopy();
2588    if (rxDmaWriteEvent.scheduled())
2589        rxDmaWriteCopy();
2590    if (txDmaReadEvent.scheduled())
2591        txDmaReadCopy();
2592    if (txDmaWriteEvent.scheduled())
2593        txDmaWriteCopy();
2594
2595    /*
2596     * Serialize the device registers
2597     */
2598    SERIALIZE_SCALAR(regs.command);
2599    SERIALIZE_SCALAR(regs.config);
2600    SERIALIZE_SCALAR(regs.mear);
2601    SERIALIZE_SCALAR(regs.ptscr);
2602    SERIALIZE_SCALAR(regs.isr);
2603    SERIALIZE_SCALAR(regs.imr);
2604    SERIALIZE_SCALAR(regs.ier);
2605    SERIALIZE_SCALAR(regs.ihr);
2606    SERIALIZE_SCALAR(regs.txdp);
2607    SERIALIZE_SCALAR(regs.txdp_hi);
2608    SERIALIZE_SCALAR(regs.txcfg);
2609    SERIALIZE_SCALAR(regs.gpior);
2610    SERIALIZE_SCALAR(regs.rxdp);
2611    SERIALIZE_SCALAR(regs.rxdp_hi);
2612    SERIALIZE_SCALAR(regs.rxcfg);
2613    SERIALIZE_SCALAR(regs.pqcr);
2614    SERIALIZE_SCALAR(regs.wcsr);
2615    SERIALIZE_SCALAR(regs.pcr);
2616    SERIALIZE_SCALAR(regs.rfcr);
2617    SERIALIZE_SCALAR(regs.rfdr);
2618    SERIALIZE_SCALAR(regs.brar);
2619    SERIALIZE_SCALAR(regs.brdr);
2620    SERIALIZE_SCALAR(regs.srr);
2621    SERIALIZE_SCALAR(regs.mibc);
2622    SERIALIZE_SCALAR(regs.vrcr);
2623    SERIALIZE_SCALAR(regs.vtcr);
2624    SERIALIZE_SCALAR(regs.vdr);
2625    SERIALIZE_SCALAR(regs.ccsr);
2626    SERIALIZE_SCALAR(regs.tbicr);
2627    SERIALIZE_SCALAR(regs.tbisr);
2628    SERIALIZE_SCALAR(regs.tanar);
2629    SERIALIZE_SCALAR(regs.tanlpar);
2630    SERIALIZE_SCALAR(regs.taner);
2631    SERIALIZE_SCALAR(regs.tesr);
2632
2633    SERIALIZE_ARRAY(rom.perfectMatch, ETH_ADDR_LEN);
2634    SERIALIZE_ARRAY(rom.filterHash, FHASH_SIZE);
2635
2636    SERIALIZE_SCALAR(ioEnable);
2637
2638    /*
2639     * Serialize the data Fifos
2640     */
2641    rxFifo.serialize("rxFifo", os);
2642    txFifo.serialize("txFifo", os);
2643
2644    /*
2645     * Serialize the various helper variables
2646     */
2647    bool txPacketExists = txPacket;
2648    SERIALIZE_SCALAR(txPacketExists);
2649    if (txPacketExists) {
2650        txPacket->length = txPacketBufPtr - txPacket->data;
2651        txPacket->serialize("txPacket", os);
2652        uint32_t txPktBufPtr = (uint32_t) (txPacketBufPtr - txPacket->data);
2653        SERIALIZE_SCALAR(txPktBufPtr);
2654    }
2655
2656    bool rxPacketExists = rxPacket;
2657    SERIALIZE_SCALAR(rxPacketExists);
2658    if (rxPacketExists) {
2659        rxPacket->serialize("rxPacket", os);
2660        uint32_t rxPktBufPtr = (uint32_t) (rxPacketBufPtr - rxPacket->data);
2661        SERIALIZE_SCALAR(rxPktBufPtr);
2662    }
2663
2664    SERIALIZE_SCALAR(txXferLen);
2665    SERIALIZE_SCALAR(rxXferLen);
2666
2667    /*
2668     * Serialize Cached Descriptors
2669     */
2670    SERIALIZE_SCALAR(rxDesc64.link);
2671    SERIALIZE_SCALAR(rxDesc64.bufptr);
2672    SERIALIZE_SCALAR(rxDesc64.cmdsts);
2673    SERIALIZE_SCALAR(rxDesc64.extsts);
2674    SERIALIZE_SCALAR(txDesc64.link);
2675    SERIALIZE_SCALAR(txDesc64.bufptr);
2676    SERIALIZE_SCALAR(txDesc64.cmdsts);
2677    SERIALIZE_SCALAR(txDesc64.extsts);
2678    SERIALIZE_SCALAR(rxDesc32.link);
2679    SERIALIZE_SCALAR(rxDesc32.bufptr);
2680    SERIALIZE_SCALAR(rxDesc32.cmdsts);
2681    SERIALIZE_SCALAR(rxDesc32.extsts);
2682    SERIALIZE_SCALAR(txDesc32.link);
2683    SERIALIZE_SCALAR(txDesc32.bufptr);
2684    SERIALIZE_SCALAR(txDesc32.cmdsts);
2685    SERIALIZE_SCALAR(txDesc32.extsts);
2686    SERIALIZE_SCALAR(extstsEnable);
2687
2688    /*
2689     * Serialize tx state machine
2690     */
2691    int txState = this->txState;
2692    SERIALIZE_SCALAR(txState);
2693    SERIALIZE_SCALAR(txEnable);
2694    SERIALIZE_SCALAR(CTDD);
2695    SERIALIZE_SCALAR(txFragPtr);
2696    SERIALIZE_SCALAR(txDescCnt);
2697    int txDmaState = this->txDmaState;
2698    SERIALIZE_SCALAR(txDmaState);
2699    SERIALIZE_SCALAR(txKickTick);
2700
2701    /*
2702     * Serialize rx state machine
2703     */
2704    int rxState = this->rxState;
2705    SERIALIZE_SCALAR(rxState);
2706    SERIALIZE_SCALAR(rxEnable);
2707    SERIALIZE_SCALAR(CRDD);
2708    SERIALIZE_SCALAR(rxPktBytes);
2709    SERIALIZE_SCALAR(rxFragPtr);
2710    SERIALIZE_SCALAR(rxDescCnt);
2711    int rxDmaState = this->rxDmaState;
2712    SERIALIZE_SCALAR(rxDmaState);
2713    SERIALIZE_SCALAR(rxKickTick);
2714
2715    /*
2716     * Serialize EEPROM state machine
2717     */
2718    int eepromState = this->eepromState;
2719    SERIALIZE_SCALAR(eepromState);
2720    SERIALIZE_SCALAR(eepromClk);
2721    SERIALIZE_SCALAR(eepromBitsToRx);
2722    SERIALIZE_SCALAR(eepromOpcode);
2723    SERIALIZE_SCALAR(eepromAddress);
2724    SERIALIZE_SCALAR(eepromData);
2725
2726    /*
2727     * If there's a pending transmit, store the time so we can
2728     * reschedule it later
2729     */
2730    Tick transmitTick = txEvent.scheduled() ? txEvent.when() - curTick : 0;
2731    SERIALIZE_SCALAR(transmitTick);
2732
2733    /*
2734     * receive address filter settings
2735     */
2736    SERIALIZE_SCALAR(rxFilterEnable);
2737    SERIALIZE_SCALAR(acceptBroadcast);
2738    SERIALIZE_SCALAR(acceptMulticast);
2739    SERIALIZE_SCALAR(acceptUnicast);
2740    SERIALIZE_SCALAR(acceptPerfect);
2741    SERIALIZE_SCALAR(acceptArp);
2742    SERIALIZE_SCALAR(multicastHashEnable);
2743
2744    /*
2745     * Keep track of pending interrupt status.
2746     */
2747    SERIALIZE_SCALAR(intrTick);
2748    SERIALIZE_SCALAR(cpuPendingIntr);
2749    Tick intrEventTick = 0;
2750    if (intrEvent)
2751        intrEventTick = intrEvent->when();
2752    SERIALIZE_SCALAR(intrEventTick);
2753
2754}
2755
2756void
2757NSGigE::unserialize(Checkpoint *cp, const std::string &section)
2758{
2759    // Unserialize the PciDev base class
2760    PciDev::unserialize(cp, section);
2761
2762    UNSERIALIZE_SCALAR(regs.command);
2763    UNSERIALIZE_SCALAR(regs.config);
2764    UNSERIALIZE_SCALAR(regs.mear);
2765    UNSERIALIZE_SCALAR(regs.ptscr);
2766    UNSERIALIZE_SCALAR(regs.isr);
2767    UNSERIALIZE_SCALAR(regs.imr);
2768    UNSERIALIZE_SCALAR(regs.ier);
2769    UNSERIALIZE_SCALAR(regs.ihr);
2770    UNSERIALIZE_SCALAR(regs.txdp);
2771    UNSERIALIZE_SCALAR(regs.txdp_hi);
2772    UNSERIALIZE_SCALAR(regs.txcfg);
2773    UNSERIALIZE_SCALAR(regs.gpior);
2774    UNSERIALIZE_SCALAR(regs.rxdp);
2775    UNSERIALIZE_SCALAR(regs.rxdp_hi);
2776    UNSERIALIZE_SCALAR(regs.rxcfg);
2777    UNSERIALIZE_SCALAR(regs.pqcr);
2778    UNSERIALIZE_SCALAR(regs.wcsr);
2779    UNSERIALIZE_SCALAR(regs.pcr);
2780    UNSERIALIZE_SCALAR(regs.rfcr);
2781    UNSERIALIZE_SCALAR(regs.rfdr);
2782    UNSERIALIZE_SCALAR(regs.brar);
2783    UNSERIALIZE_SCALAR(regs.brdr);
2784    UNSERIALIZE_SCALAR(regs.srr);
2785    UNSERIALIZE_SCALAR(regs.mibc);
2786    UNSERIALIZE_SCALAR(regs.vrcr);
2787    UNSERIALIZE_SCALAR(regs.vtcr);
2788    UNSERIALIZE_SCALAR(regs.vdr);
2789    UNSERIALIZE_SCALAR(regs.ccsr);
2790    UNSERIALIZE_SCALAR(regs.tbicr);
2791    UNSERIALIZE_SCALAR(regs.tbisr);
2792    UNSERIALIZE_SCALAR(regs.tanar);
2793    UNSERIALIZE_SCALAR(regs.tanlpar);
2794    UNSERIALIZE_SCALAR(regs.taner);
2795    UNSERIALIZE_SCALAR(regs.tesr);
2796
2797    UNSERIALIZE_ARRAY(rom.perfectMatch, ETH_ADDR_LEN);
2798    UNSERIALIZE_ARRAY(rom.filterHash, FHASH_SIZE);
2799
2800    UNSERIALIZE_SCALAR(ioEnable);
2801
2802    /*
2803     * unserialize the data fifos
2804     */
2805    rxFifo.unserialize("rxFifo", cp, section);
2806    txFifo.unserialize("txFifo", cp, section);
2807
2808    /*
2809     * unserialize the various helper variables
2810     */
2811    bool txPacketExists;
2812    UNSERIALIZE_SCALAR(txPacketExists);
2813    if (txPacketExists) {
2814        txPacket = new PacketData(16384);
2815        txPacket->unserialize("txPacket", cp, section);
2816        uint32_t txPktBufPtr;
2817        UNSERIALIZE_SCALAR(txPktBufPtr);
2818        txPacketBufPtr = (uint8_t *) txPacket->data + txPktBufPtr;
2819    } else
2820        txPacket = 0;
2821
2822    bool rxPacketExists;
2823    UNSERIALIZE_SCALAR(rxPacketExists);
2824    rxPacket = 0;
2825    if (rxPacketExists) {
2826        rxPacket = new PacketData(16384);
2827        rxPacket->unserialize("rxPacket", cp, section);
2828        uint32_t rxPktBufPtr;
2829        UNSERIALIZE_SCALAR(rxPktBufPtr);
2830        rxPacketBufPtr = (uint8_t *) rxPacket->data + rxPktBufPtr;
2831    } else
2832        rxPacket = 0;
2833
2834    UNSERIALIZE_SCALAR(txXferLen);
2835    UNSERIALIZE_SCALAR(rxXferLen);
2836
2837    /*
2838     * Unserialize Cached Descriptors
2839     */
2840    UNSERIALIZE_SCALAR(rxDesc64.link);
2841    UNSERIALIZE_SCALAR(rxDesc64.bufptr);
2842    UNSERIALIZE_SCALAR(rxDesc64.cmdsts);
2843    UNSERIALIZE_SCALAR(rxDesc64.extsts);
2844    UNSERIALIZE_SCALAR(txDesc64.link);
2845    UNSERIALIZE_SCALAR(txDesc64.bufptr);
2846    UNSERIALIZE_SCALAR(txDesc64.cmdsts);
2847    UNSERIALIZE_SCALAR(txDesc64.extsts);
2848    UNSERIALIZE_SCALAR(rxDesc32.link);
2849    UNSERIALIZE_SCALAR(rxDesc32.bufptr);
2850    UNSERIALIZE_SCALAR(rxDesc32.cmdsts);
2851    UNSERIALIZE_SCALAR(rxDesc32.extsts);
2852    UNSERIALIZE_SCALAR(txDesc32.link);
2853    UNSERIALIZE_SCALAR(txDesc32.bufptr);
2854    UNSERIALIZE_SCALAR(txDesc32.cmdsts);
2855    UNSERIALIZE_SCALAR(txDesc32.extsts);
2856    UNSERIALIZE_SCALAR(extstsEnable);
2857
2858    /*
2859     * unserialize tx state machine
2860     */
2861    int txState;
2862    UNSERIALIZE_SCALAR(txState);
2863    this->txState = (TxState) txState;
2864    UNSERIALIZE_SCALAR(txEnable);
2865    UNSERIALIZE_SCALAR(CTDD);
2866    UNSERIALIZE_SCALAR(txFragPtr);
2867    UNSERIALIZE_SCALAR(txDescCnt);
2868    int txDmaState;
2869    UNSERIALIZE_SCALAR(txDmaState);
2870    this->txDmaState = (DmaState) txDmaState;
2871    UNSERIALIZE_SCALAR(txKickTick);
2872    if (txKickTick)
2873        txKickEvent.schedule(txKickTick);
2874
2875    /*
2876     * unserialize rx state machine
2877     */
2878    int rxState;
2879    UNSERIALIZE_SCALAR(rxState);
2880    this->rxState = (RxState) rxState;
2881    UNSERIALIZE_SCALAR(rxEnable);
2882    UNSERIALIZE_SCALAR(CRDD);
2883    UNSERIALIZE_SCALAR(rxPktBytes);
2884    UNSERIALIZE_SCALAR(rxFragPtr);
2885    UNSERIALIZE_SCALAR(rxDescCnt);
2886    int rxDmaState;
2887    UNSERIALIZE_SCALAR(rxDmaState);
2888    this->rxDmaState = (DmaState) rxDmaState;
2889    UNSERIALIZE_SCALAR(rxKickTick);
2890    if (rxKickTick)
2891        rxKickEvent.schedule(rxKickTick);
2892
2893    /*
2894     * Unserialize EEPROM state machine
2895     */
2896    int eepromState;
2897    UNSERIALIZE_SCALAR(eepromState);
2898    this->eepromState = (EEPROMState) eepromState;
2899    UNSERIALIZE_SCALAR(eepromClk);
2900    UNSERIALIZE_SCALAR(eepromBitsToRx);
2901    UNSERIALIZE_SCALAR(eepromOpcode);
2902    UNSERIALIZE_SCALAR(eepromAddress);
2903    UNSERIALIZE_SCALAR(eepromData);
2904
2905    /*
2906     * If there's a pending transmit, reschedule it now
2907     */
2908    Tick transmitTick;
2909    UNSERIALIZE_SCALAR(transmitTick);
2910    if (transmitTick)
2911        txEvent.schedule(curTick + transmitTick);
2912
2913    /*
2914     * unserialize receive address filter settings
2915     */
2916    UNSERIALIZE_SCALAR(rxFilterEnable);
2917    UNSERIALIZE_SCALAR(acceptBroadcast);
2918    UNSERIALIZE_SCALAR(acceptMulticast);
2919    UNSERIALIZE_SCALAR(acceptUnicast);
2920    UNSERIALIZE_SCALAR(acceptPerfect);
2921    UNSERIALIZE_SCALAR(acceptArp);
2922    UNSERIALIZE_SCALAR(multicastHashEnable);
2923
2924    /*
2925     * Keep track of pending interrupt status.
2926     */
2927    UNSERIALIZE_SCALAR(intrTick);
2928    UNSERIALIZE_SCALAR(cpuPendingIntr);
2929    Tick intrEventTick;
2930    UNSERIALIZE_SCALAR(intrEventTick);
2931    if (intrEventTick) {
2932        intrEvent = new IntrEvent(this, true);
2933        intrEvent->schedule(intrEventTick);
2934    }
2935
2936    /*
2937     * re-add addrRanges to bus bridges
2938     */
2939    if (pioInterface) {
2940        pioInterface->addAddrRange(RangeSize(BARAddrs[0], BARSize[0]));
2941        pioInterface->addAddrRange(RangeSize(BARAddrs[1], BARSize[1]));
2942    }
2943}
2944
2945Tick
2946NSGigE::cacheAccess(MemReqPtr &req)
2947{
2948    DPRINTF(EthernetPIO, "timing access to paddr=%#x (daddr=%#x)\n",
2949            req->paddr, req->paddr - addr);
2950    return curTick + pioLatency;
2951}
2952
2953BEGIN_DECLARE_SIM_OBJECT_PARAMS(NSGigEInt)
2954
2955    SimObjectParam<EtherInt *> peer;
2956    SimObjectParam<NSGigE *> device;
2957
2958END_DECLARE_SIM_OBJECT_PARAMS(NSGigEInt)
2959
2960BEGIN_INIT_SIM_OBJECT_PARAMS(NSGigEInt)
2961
2962    INIT_PARAM_DFLT(peer, "peer interface", NULL),
2963    INIT_PARAM(device, "Ethernet device of this interface")
2964
2965END_INIT_SIM_OBJECT_PARAMS(NSGigEInt)
2966
2967CREATE_SIM_OBJECT(NSGigEInt)
2968{
2969    NSGigEInt *dev_int = new NSGigEInt(getInstanceName(), device);
2970
2971    EtherInt *p = (EtherInt *)peer;
2972    if (p) {
2973        dev_int->setPeer(p);
2974        p->setPeer(dev_int);
2975    }
2976
2977    return dev_int;
2978}
2979
2980REGISTER_SIM_OBJECT("NSGigEInt", NSGigEInt)
2981
2982
2983BEGIN_DECLARE_SIM_OBJECT_PARAMS(NSGigE)
2984
2985    Param<Addr> addr;
2986    Param<Tick> clock;
2987    Param<Tick> tx_delay;
2988    Param<Tick> rx_delay;
2989    Param<Tick> intr_delay;
2990    SimObjectParam<MemoryController *> mmu;
2991    SimObjectParam<PhysicalMemory *> physmem;
2992    Param<bool> rx_filter;
2993    Param<string> hardware_address;
2994    SimObjectParam<Bus*> io_bus;
2995    SimObjectParam<Bus*> payload_bus;
2996    SimObjectParam<HierParams *> hier;
2997    Param<Tick> pio_latency;
2998    Param<bool> dma_desc_free;
2999    Param<bool> dma_data_free;
3000    Param<Tick> dma_read_delay;
3001    Param<Tick> dma_write_delay;
3002    Param<Tick> dma_read_factor;
3003    Param<Tick> dma_write_factor;
3004    SimObjectParam<PciConfigAll *> configspace;
3005    SimObjectParam<PciConfigData *> configdata;
3006    SimObjectParam<Platform *> platform;
3007    Param<uint32_t> pci_bus;
3008    Param<uint32_t> pci_dev;
3009    Param<uint32_t> pci_func;
3010    Param<uint32_t> tx_fifo_size;
3011    Param<uint32_t> rx_fifo_size;
3012    Param<uint32_t> m5reg;
3013    Param<bool> dma_no_allocate;
3014
3015END_DECLARE_SIM_OBJECT_PARAMS(NSGigE)
3016
3017BEGIN_INIT_SIM_OBJECT_PARAMS(NSGigE)
3018
3019    INIT_PARAM(addr, "Device Address"),
3020    INIT_PARAM(clock, "State machine processor frequency"),
3021    INIT_PARAM(tx_delay, "Transmit Delay"),
3022    INIT_PARAM(rx_delay, "Receive Delay"),
3023    INIT_PARAM(intr_delay, "Interrupt Delay in microseconds"),
3024    INIT_PARAM(mmu, "Memory Controller"),
3025    INIT_PARAM(physmem, "Physical Memory"),
3026    INIT_PARAM_DFLT(rx_filter, "Enable Receive Filter", true),
3027    INIT_PARAM(hardware_address, "Ethernet Hardware Address"),
3028    INIT_PARAM_DFLT(io_bus, "The IO Bus to attach to for headers", NULL),
3029    INIT_PARAM_DFLT(payload_bus, "The IO Bus to attach to for payload", NULL),
3030    INIT_PARAM_DFLT(hier, "Hierarchy global variables", &defaultHierParams),
3031    INIT_PARAM_DFLT(pio_latency, "Programmed IO latency in bus cycles", 1),
3032    INIT_PARAM_DFLT(dma_desc_free, "DMA of Descriptors is free", false),
3033    INIT_PARAM_DFLT(dma_data_free, "DMA of Data is free", false),
3034    INIT_PARAM_DFLT(dma_read_delay, "fixed delay for dma reads", 0),
3035    INIT_PARAM_DFLT(dma_write_delay, "fixed delay for dma writes", 0),
3036    INIT_PARAM_DFLT(dma_read_factor, "multiplier for dma reads", 0),
3037    INIT_PARAM_DFLT(dma_write_factor, "multiplier for dma writes", 0),
3038    INIT_PARAM(configspace, "PCI Configspace"),
3039    INIT_PARAM(configdata, "PCI Config data"),
3040    INIT_PARAM(platform, "Platform"),
3041    INIT_PARAM(pci_bus, "PCI bus"),
3042    INIT_PARAM(pci_dev, "PCI device number"),
3043    INIT_PARAM(pci_func, "PCI function code"),
3044    INIT_PARAM_DFLT(tx_fifo_size, "max size in bytes of txFifo", 131072),
3045    INIT_PARAM_DFLT(rx_fifo_size, "max size in bytes of rxFifo", 131072),
3046    INIT_PARAM(m5reg, "m5 register"),
3047    INIT_PARAM_DFLT(dma_no_allocate, "Should DMA reads allocate cache lines", true)
3048
3049END_INIT_SIM_OBJECT_PARAMS(NSGigE)
3050
3051
3052CREATE_SIM_OBJECT(NSGigE)
3053{
3054    NSGigE::Params *params = new NSGigE::Params;
3055
3056    params->name = getInstanceName();
3057    params->mmu = mmu;
3058    params->configSpace = configspace;
3059    params->configData = configdata;
3060    params->plat = platform;
3061    params->busNum = pci_bus;
3062    params->deviceNum = pci_dev;
3063    params->functionNum = pci_func;
3064
3065    params->clock = clock;
3066    params->intr_delay = intr_delay;
3067    params->pmem = physmem;
3068    params->tx_delay = tx_delay;
3069    params->rx_delay = rx_delay;
3070    params->hier = hier;
3071    params->header_bus = io_bus;
3072    params->payload_bus = payload_bus;
3073    params->pio_latency = pio_latency;
3074    params->dma_desc_free = dma_desc_free;
3075    params->dma_data_free = dma_data_free;
3076    params->dma_read_delay = dma_read_delay;
3077    params->dma_write_delay = dma_write_delay;
3078    params->dma_read_factor = dma_read_factor;
3079    params->dma_write_factor = dma_write_factor;
3080    params->rx_filter = rx_filter;
3081    params->eaddr = hardware_address;
3082    params->tx_fifo_size = tx_fifo_size;
3083    params->rx_fifo_size = rx_fifo_size;
3084    params->m5reg = m5reg;
3085    params->dma_no_allocate = dma_no_allocate;
3086    return new NSGigE(params);
3087}
3088
3089REGISTER_SIM_OBJECT("NSGigE", NSGigE)
3090