ns_gige.cc revision 998
16657Snate@binkert.org/*
26657Snate@binkert.org * Copyright (c) 2004 The Regents of The University of Michigan
36657Snate@binkert.org * All rights reserved.
46657Snate@binkert.org *
56657Snate@binkert.org * Redistribution and use in source and binary forms, with or without
66657Snate@binkert.org * modification, are permitted provided that the following conditions are
76657Snate@binkert.org * met: redistributions of source code must retain the above copyright
86657Snate@binkert.org * notice, this list of conditions and the following disclaimer;
96657Snate@binkert.org * redistributions in binary form must reproduce the above copyright
106657Snate@binkert.org * notice, this list of conditions and the following disclaimer in the
116657Snate@binkert.org * documentation and/or other materials provided with the distribution;
126657Snate@binkert.org * neither the name of the copyright holders nor the names of its
136657Snate@binkert.org * contributors may be used to endorse or promote products derived from
146657Snate@binkert.org * this software without specific prior written permission.
156657Snate@binkert.org *
166657Snate@binkert.org * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
176657Snate@binkert.org * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
186657Snate@binkert.org * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
196657Snate@binkert.org * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
206657Snate@binkert.org * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
216657Snate@binkert.org * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
226657Snate@binkert.org * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
236657Snate@binkert.org * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
246657Snate@binkert.org * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
256657Snate@binkert.org * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
266657Snate@binkert.org * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
276657Snate@binkert.org */
286999Snate@binkert.org
296657Snate@binkert.org/* @file
306657Snate@binkert.org * Device module for modelling the National Semiconductor
316657Snate@binkert.org * DP83820 ethernet controller.  Does not support priority queueing
326657Snate@binkert.org */
338189SLisa.Hsu@amd.com#include <cstdio>
346657Snate@binkert.org#include <deque>
356882SBrad.Beckmann@amd.com#include <string>
367055Snate@binkert.org
376882SBrad.Beckmann@amd.com#include "base/inet.hh"
386882SBrad.Beckmann@amd.com#include "cpu/exec_context.hh"
398191SLisa.Hsu@amd.com#include "cpu/intr_control.hh"
406882SBrad.Beckmann@amd.com#include "dev/dma.hh"
416882SBrad.Beckmann@amd.com#include "dev/ns_gige.hh"
429102SNuwan.Jayasena@amd.com#include "dev/etherlink.hh"
436888SBrad.Beckmann@amd.com#include "mem/bus/bus.hh"
446882SBrad.Beckmann@amd.com#include "mem/bus/dma_interface.hh"
456882SBrad.Beckmann@amd.com#include "mem/bus/pio_interface.hh"
466657Snate@binkert.org#include "mem/bus/pio_interface_impl.hh"
476657Snate@binkert.org#include "mem/functional_mem/memory_control.hh"
486657Snate@binkert.org#include "mem/functional_mem/physical_memory.hh"
496657Snate@binkert.org#include "sim/builder.hh"
506657Snate@binkert.org#include "sim/host.hh"
517839Snilay@cs.wisc.edu#include "sim/sim_stats.hh"
526657Snate@binkert.org#include "targetarch/vtophys.hh"
536882SBrad.Beckmann@amd.com#include "dev/pciconfigall.hh"
546882SBrad.Beckmann@amd.com#include "dev/tsunami_cchip.hh"
556882SBrad.Beckmann@amd.com
566882SBrad.Beckmann@amd.comconst char *NsRxStateStrings[] =
576882SBrad.Beckmann@amd.com{
586882SBrad.Beckmann@amd.com    "rxIdle",
596657Snate@binkert.org    "rxDescRefr",
606657Snate@binkert.org    "rxDescRead",
616657Snate@binkert.org    "rxFifoBlock",
626657Snate@binkert.org    "rxFragWrite",
636657Snate@binkert.org    "rxDescWrite",
649104Shestness@cs.utexas.edu    "rxAdvance"
656657Snate@binkert.org};
666657Snate@binkert.org
676657Snate@binkert.orgconst char *NsTxStateStrings[] =
686657Snate@binkert.org{
697839Snilay@cs.wisc.edu    "txIdle",
707839Snilay@cs.wisc.edu    "txDescRefr",
716657Snate@binkert.org    "txDescRead",
726657Snate@binkert.org    "txFifoBlock",
736657Snate@binkert.org    "txFragRead",
746657Snate@binkert.org    "txDescWrite",
756657Snate@binkert.org    "txAdvance"
766657Snate@binkert.org};
776657Snate@binkert.org
786657Snate@binkert.orgconst char *NsDmaState[] =
796657Snate@binkert.org{
806657Snate@binkert.org    "dmaIdle",
816657Snate@binkert.org    "dmaReading",
826657Snate@binkert.org    "dmaWriting",
836657Snate@binkert.org    "dmaReadWaiting",
846657Snate@binkert.org    "dmaWriteWaiting"
856657Snate@binkert.org};
866657Snate@binkert.org
876657Snate@binkert.orgusing namespace std;
886657Snate@binkert.org
896657Snate@binkert.org//helper function declarations
906657Snate@binkert.org//These functions reverse Endianness so we can evaluate network data correctly
916779SBrad.Beckmann@amd.comuint16_t reverseEnd16(uint16_t);
926657Snate@binkert.orguint32_t reverseEnd32(uint32_t);
936657Snate@binkert.org
946657Snate@binkert.org///////////////////////////////////////////////////////////////////////
956657Snate@binkert.org//
966657Snate@binkert.org// NSGigE PCI Device
976657Snate@binkert.org//
986657Snate@binkert.orgNSGigE::NSGigE(const std::string &name, IntrControl *i, Tick intr_delay,
996657Snate@binkert.org               PhysicalMemory *pmem, Tick tx_delay, Tick rx_delay,
1006657Snate@binkert.org               MemoryController *mmu, HierParams *hier, Bus *header_bus,
1019104Shestness@cs.utexas.edu               Bus *payload_bus, Tick pio_latency, bool dma_desc_free,
1029104Shestness@cs.utexas.edu               bool dma_data_free, Tick dma_read_delay, Tick dma_write_delay,
1039104Shestness@cs.utexas.edu               Tick dma_read_factor, Tick dma_write_factor, PciConfigAll *cf,
1049104Shestness@cs.utexas.edu               PciConfigData *cd, Tsunami *t, uint32_t bus, uint32_t dev,
1056657Snate@binkert.org               uint32_t func, bool rx_filter, const int eaddr[6],
1066657Snate@binkert.org               uint32_t tx_fifo_size, uint32_t rx_fifo_size)
1076657Snate@binkert.org    : PciDev(name, mmu, cf, cd, bus, dev, func), tsunami(t), ioEnable(false),
1086657Snate@binkert.org      maxTxFifoSize(tx_fifo_size), maxRxFifoSize(rx_fifo_size),
1096657Snate@binkert.org      txPacket(0), rxPacket(0), txPacketBufPtr(NULL), rxPacketBufPtr(NULL),
1106657Snate@binkert.org      txXferLen(0), rxXferLen(0), txState(txIdle), CTDD(false),
1116657Snate@binkert.org      txFifoAvail(tx_fifo_size), txHalt(false),
1126657Snate@binkert.org      txFragPtr(0), txDescCnt(0), txDmaState(dmaIdle), rxState(rxIdle),
1136657Snate@binkert.org      CRDD(false), rxPktBytes(0), rxFifoCnt(0), rxHalt(false),
1146657Snate@binkert.org      rxFragPtr(0), rxDescCnt(0), rxDmaState(dmaIdle), extstsEnable(false),
1156657Snate@binkert.org      rxDmaReadEvent(this), rxDmaWriteEvent(this),
1166657Snate@binkert.org      txDmaReadEvent(this), txDmaWriteEvent(this),
1176657Snate@binkert.org      dmaDescFree(dma_desc_free), dmaDataFree(dma_data_free),
1186657Snate@binkert.org      txDelay(tx_delay), rxDelay(rx_delay), rxKickTick(0), txKickTick(0),
1196657Snate@binkert.org      txEvent(this), rxFilterEnable(rx_filter), acceptBroadcast(false),
1207839Snilay@cs.wisc.edu      acceptMulticast(false), acceptUnicast(false),
1217839Snilay@cs.wisc.edu      acceptPerfect(false), acceptArp(false),
1227839Snilay@cs.wisc.edu      physmem(pmem), intctrl(i), intrTick(0), cpuPendingIntr(false),
1237839Snilay@cs.wisc.edu      intrEvent(0), interface(0)
1247839Snilay@cs.wisc.edu{
1257839Snilay@cs.wisc.edu    tsunami->ethernet = this;
1267839Snilay@cs.wisc.edu
1277839Snilay@cs.wisc.edu    if (header_bus) {
1287839Snilay@cs.wisc.edu        pioInterface = newPioInterface(name, hier, header_bus, this,
1297839Snilay@cs.wisc.edu                                       &NSGigE::cacheAccess);
1307839Snilay@cs.wisc.edu
1317839Snilay@cs.wisc.edu        pioLatency = pio_latency * header_bus->clockRatio;
1327839Snilay@cs.wisc.edu
1337839Snilay@cs.wisc.edu        if (payload_bus)
1347839Snilay@cs.wisc.edu            dmaInterface = new DMAInterface<Bus>(name + ".dma",
1356657Snate@binkert.org                                                 header_bus, payload_bus, 1);
1366657Snate@binkert.org        else
1376657Snate@binkert.org            dmaInterface = new DMAInterface<Bus>(name + ".dma",
1386657Snate@binkert.org                                                 header_bus, header_bus, 1);
1396657Snate@binkert.org    } else if (payload_bus) {
1406657Snate@binkert.org        pioInterface = newPioInterface(name, hier, payload_bus, this,
1416657Snate@binkert.org                                       &NSGigE::cacheAccess);
1426657Snate@binkert.org
1436657Snate@binkert.org        pioLatency = pio_latency * payload_bus->clockRatio;
1446657Snate@binkert.org
1456657Snate@binkert.org        dmaInterface = new DMAInterface<Bus>(name + ".dma", payload_bus,
1466657Snate@binkert.org                                         payload_bus, 1);
1476657Snate@binkert.org    }
1486657Snate@binkert.org
1496657Snate@binkert.org
1506657Snate@binkert.org    intrDelay = US2Ticks(intr_delay);
1516657Snate@binkert.org    dmaReadDelay = dma_read_delay;
1526657Snate@binkert.org    dmaWriteDelay = dma_write_delay;
1536657Snate@binkert.org    dmaReadFactor = dma_read_factor;
1546657Snate@binkert.org    dmaWriteFactor = dma_write_factor;
1556657Snate@binkert.org
1566657Snate@binkert.org    regsReset();
1576657Snate@binkert.org    rom.perfectMatch[0] = eaddr[0];
1586657Snate@binkert.org    rom.perfectMatch[1] = eaddr[1];
1596657Snate@binkert.org    rom.perfectMatch[2] = eaddr[2];
1606657Snate@binkert.org    rom.perfectMatch[3] = eaddr[3];
1616657Snate@binkert.org    rom.perfectMatch[4] = eaddr[4];
1626657Snate@binkert.org    rom.perfectMatch[5] = eaddr[5];
1636657Snate@binkert.org}
1646657Snate@binkert.org
1659219Spower.jg@gmail.comNSGigE::~NSGigE()
1666877Ssteve.reinhardt@amd.com{}
1676657Snate@binkert.org
1689219Spower.jg@gmail.comvoid
1696657Snate@binkert.orgNSGigE::regStats()
1709219Spower.jg@gmail.com{
1716657Snate@binkert.org    txBytes
1726657Snate@binkert.org        .name(name() + ".txBytes")
1737542SBrad.Beckmann@amd.com        .desc("Bytes Transmitted")
1747542SBrad.Beckmann@amd.com        .prereq(txBytes)
1756657Snate@binkert.org        ;
1766877Ssteve.reinhardt@amd.com
1776999Snate@binkert.org    rxBytes
1786877Ssteve.reinhardt@amd.com        .name(name() + ".rxBytes")
1796877Ssteve.reinhardt@amd.com        .desc("Bytes Received")
1806877Ssteve.reinhardt@amd.com        .prereq(rxBytes)
1816877Ssteve.reinhardt@amd.com        ;
1826877Ssteve.reinhardt@amd.com
1836877Ssteve.reinhardt@amd.com    txPackets
1846877Ssteve.reinhardt@amd.com        .name(name() + ".txPackets")
1856877Ssteve.reinhardt@amd.com        .desc("Number of Packets Transmitted")
1866877Ssteve.reinhardt@amd.com        .prereq(txBytes)
1876877Ssteve.reinhardt@amd.com        ;
1886877Ssteve.reinhardt@amd.com
1896877Ssteve.reinhardt@amd.com    rxPackets
1906877Ssteve.reinhardt@amd.com        .name(name() + ".rxPackets")
1916877Ssteve.reinhardt@amd.com        .desc("Number of Packets Received")
1926877Ssteve.reinhardt@amd.com        .prereq(rxBytes)
1936877Ssteve.reinhardt@amd.com        ;
1946882SBrad.Beckmann@amd.com
1956882SBrad.Beckmann@amd.com    txIPChecksums
1966882SBrad.Beckmann@amd.com        .name(name() + ".txIPChecksums")
1976882SBrad.Beckmann@amd.com        .desc("Number of tx IP Checksums done by device")
1986882SBrad.Beckmann@amd.com        .precision(0)
1996882SBrad.Beckmann@amd.com        .prereq(txBytes)
2006882SBrad.Beckmann@amd.com        ;
2016877Ssteve.reinhardt@amd.com
2026877Ssteve.reinhardt@amd.com    rxIPChecksums
2036877Ssteve.reinhardt@amd.com        .name(name() + ".rxIPChecksums")
2046877Ssteve.reinhardt@amd.com        .desc("Number of rx IP Checksums done by device")
2056657Snate@binkert.org        .precision(0)
2066657Snate@binkert.org        .prereq(rxBytes)
2076999Snate@binkert.org        ;
2086657Snate@binkert.org
2096657Snate@binkert.org    txTCPChecksums
2106657Snate@binkert.org        .name(name() + ".txTCPChecksums")
2116657Snate@binkert.org        .desc("Number of tx TCP Checksums done by device")
2126657Snate@binkert.org        .precision(0)
2136657Snate@binkert.org        .prereq(txBytes)
2147007Snate@binkert.org        ;
2156657Snate@binkert.org
2166657Snate@binkert.org    rxTCPChecksums
2176657Snate@binkert.org        .name(name() + ".rxTCPChecksums")
2186657Snate@binkert.org        .desc("Number of rx TCP Checksums done by device")
2196657Snate@binkert.org        .precision(0)
2207007Snate@binkert.org        .prereq(rxBytes)
2217007Snate@binkert.org        ;
2226657Snate@binkert.org
2237002Snate@binkert.org    descDmaReads
2247002Snate@binkert.org        .name(name() + ".descDMAReads")
2257002Snate@binkert.org        .desc("Number of descriptors the device read w/ DMA")
2267002Snate@binkert.org        .precision(0)
2278229Snate@binkert.org        ;
2288229Snate@binkert.org
2296657Snate@binkert.org    descDmaWrites
2306657Snate@binkert.org        .name(name() + ".descDMAWrites")
2318229Snate@binkert.org        .desc("Number of descriptors the device wrote w/ DMA")
2328229Snate@binkert.org        .precision(0)
2338229Snate@binkert.org        ;
2348229Snate@binkert.org
2356657Snate@binkert.org    descDmaRdBytes
2366657Snate@binkert.org        .name(name() + ".descDmaReadBytes")
2376657Snate@binkert.org        .desc("number of descriptor bytes read w/ DMA")
2386657Snate@binkert.org        .precision(0)
2396793SBrad.Beckmann@amd.com        ;
2406657Snate@binkert.org
2416657Snate@binkert.org   descDmaWrBytes
2426657Snate@binkert.org        .name(name() + ".descDmaWriteBytes")
2436657Snate@binkert.org        .desc("number of descriptor bytes write w/ DMA")
2446657Snate@binkert.org        .precision(0)
2457002Snate@binkert.org        ;
2466657Snate@binkert.org
2477007Snate@binkert.org
2487007Snate@binkert.org    txBandwidth
2499271Snilay@cs.wisc.edu        .name(name() + ".txBandwidth")
2506877Ssteve.reinhardt@amd.com        .desc("Transmit Bandwidth (bits/s)")
2516877Ssteve.reinhardt@amd.com        .precision(0)
2526657Snate@binkert.org        .prereq(txBytes)
2536877Ssteve.reinhardt@amd.com        ;
2546657Snate@binkert.org
2556657Snate@binkert.org    rxBandwidth
2567002Snate@binkert.org        .name(name() + ".rxBandwidth")
2577002Snate@binkert.org        .desc("Receive Bandwidth (bits/s)")
2587567SBrad.Beckmann@amd.com        .precision(0)
2597567SBrad.Beckmann@amd.com        .prereq(rxBytes)
2607922SBrad.Beckmann@amd.com        ;
2616881SBrad.Beckmann@amd.com
2627002Snate@binkert.org    txPacketRate
2637002Snate@binkert.org        .name(name() + ".txPPS")
2646657Snate@binkert.org        .desc("Packet Tranmission Rate (packets/s)")
2657002Snate@binkert.org        .precision(0)
2666902SBrad.Beckmann@amd.com        .prereq(txBytes)
2676863Sdrh5@cs.wisc.edu        ;
2686863Sdrh5@cs.wisc.edu
2698683Snilay@cs.wisc.edu    rxPacketRate
2708683Snilay@cs.wisc.edu        .name(name() + ".rxPPS")
2717007Snate@binkert.org        .desc("Packet Reception Rate (packets/s)")
2729302Snilay@cs.wisc.edu        .precision(0)
2739302Snilay@cs.wisc.edu        .prereq(rxBytes)
2749302Snilay@cs.wisc.edu        ;
2756657Snate@binkert.org
2766657Snate@binkert.org    txBandwidth = txBytes * Stats::constant(8) / simSeconds;
2776657Snate@binkert.org    rxBandwidth = rxBytes * Stats::constant(8) / simSeconds;
2786657Snate@binkert.org    txPacketRate = txPackets / simSeconds;
2796657Snate@binkert.org    rxPacketRate = rxPackets / simSeconds;
2806657Snate@binkert.org}
2816882SBrad.Beckmann@amd.com
2826882SBrad.Beckmann@amd.com/**
2836882SBrad.Beckmann@amd.com * This is to read the PCI general configuration registers
2846882SBrad.Beckmann@amd.com */
2856657Snate@binkert.orgvoid
2866657Snate@binkert.orgNSGigE::ReadConfig(int offset, int size, uint8_t *data)
2876657Snate@binkert.org{
2886657Snate@binkert.org    if (offset < PCI_DEVICE_SPECIFIC)
2897007Snate@binkert.org        PciDev::ReadConfig(offset, size, data);
2907839Snilay@cs.wisc.edu    else
2917839Snilay@cs.wisc.edu        panic("Device specific PCI config space not implemented!\n");
2927839Snilay@cs.wisc.edu}
2937839Snilay@cs.wisc.edu
2947839Snilay@cs.wisc.edu/**
2957839Snilay@cs.wisc.edu * This is to write to the PCI general configuration registers
2967839Snilay@cs.wisc.edu */
2977839Snilay@cs.wisc.eduvoid
2987839Snilay@cs.wisc.eduNSGigE::WriteConfig(int offset, int size, uint32_t data)
2997839Snilay@cs.wisc.edu{
3007839Snilay@cs.wisc.edu    if (offset < PCI_DEVICE_SPECIFIC)
3017839Snilay@cs.wisc.edu        PciDev::WriteConfig(offset, size, data);
3027007Snate@binkert.org    else
3037007Snate@binkert.org        panic("Device specific PCI config space not implemented!\n");
3047007Snate@binkert.org
3057007Snate@binkert.org    // Need to catch writes to BARs to update the PIO interface
3067007Snate@binkert.org    switch (offset) {
3077839Snilay@cs.wisc.edu        //seems to work fine without all these PCI settings, but i put in the IO
3087839Snilay@cs.wisc.edu        //to double check, an assertion will fail if we need to properly
3097839Snilay@cs.wisc.edu        // implement it
3107839Snilay@cs.wisc.edu      case PCI_COMMAND:
3117839Snilay@cs.wisc.edu        if (config.data[offset] & PCI_CMD_IOSE)
3127839Snilay@cs.wisc.edu            ioEnable = true;
3137839Snilay@cs.wisc.edu        else
3147839Snilay@cs.wisc.edu            ioEnable = false;
3157839Snilay@cs.wisc.edu
3167839Snilay@cs.wisc.edu#if 0
3177839Snilay@cs.wisc.edu        if (config.data[offset] & PCI_CMD_BME) {
3187839Snilay@cs.wisc.edu            bmEnabled = true;
3197007Snate@binkert.org        }
3207007Snate@binkert.org        else {
3217002Snate@binkert.org            bmEnabled = false;
3226657Snate@binkert.org        }
3236657Snate@binkert.org
3246657Snate@binkert.org        if (config.data[offset] & PCI_CMD_MSE) {
3257055Snate@binkert.org            memEnable = true;
3266657Snate@binkert.org        }
3276657Snate@binkert.org        else {
3286657Snate@binkert.org            memEnable = false;
3296863Sdrh5@cs.wisc.edu        }
3307055Snate@binkert.org#endif
3317567SBrad.Beckmann@amd.com        break;
3328943Sandreas.hansson@arm.com
3337567SBrad.Beckmann@amd.com      case PCI0_BASE_ADDR0:
3347567SBrad.Beckmann@amd.com        if (BARAddrs[0] != 0) {
3357567SBrad.Beckmann@amd.com
3367542SBrad.Beckmann@amd.com            if (pioInterface)
3377542SBrad.Beckmann@amd.com                pioInterface->addAddrRange(BARAddrs[0], BARAddrs[0] + BARSize[0] - 1);
3386657Snate@binkert.org
3397007Snate@binkert.org            BARAddrs[0] &= PA_UNCACHED_MASK;
3406657Snate@binkert.org
3416657Snate@binkert.org        }
3426657Snate@binkert.org        break;
3436657Snate@binkert.org      case PCI0_BASE_ADDR1:
3446657Snate@binkert.org        if (BARAddrs[1] != 0) {
3456657Snate@binkert.org
3466657Snate@binkert.org            if (pioInterface)
3476657Snate@binkert.org                pioInterface->addAddrRange(BARAddrs[1], BARAddrs[1] + BARSize[1] - 1);
3487839Snilay@cs.wisc.edu
3497839Snilay@cs.wisc.edu            BARAddrs[1] &= PA_UNCACHED_MASK;
3507839Snilay@cs.wisc.edu
3517839Snilay@cs.wisc.edu        }
3527839Snilay@cs.wisc.edu        break;
3537839Snilay@cs.wisc.edu    }
3547839Snilay@cs.wisc.edu}
3557839Snilay@cs.wisc.edu
3567839Snilay@cs.wisc.edu/**
3577839Snilay@cs.wisc.edu * This reads the device registers, which are detailed in the NS83820
3587839Snilay@cs.wisc.edu * spec sheet
3597839Snilay@cs.wisc.edu */
3607839Snilay@cs.wisc.eduFault
3617839Snilay@cs.wisc.eduNSGigE::read(MemReqPtr &req, uint8_t *data)
3627839Snilay@cs.wisc.edu{
3637839Snilay@cs.wisc.edu    assert(ioEnable);
3646657Snate@binkert.org
3656657Snate@binkert.org    //The mask is to give you only the offset into the device register file
3666657Snate@binkert.org    Addr daddr = req->paddr & 0xfff;
3676657Snate@binkert.org    DPRINTF(EthernetPIO, "read  da=%#x pa=%#x va=%#x size=%d\n",
3687839Snilay@cs.wisc.edu            daddr, req->paddr, req->vaddr, req->size);
3697839Snilay@cs.wisc.edu
3707839Snilay@cs.wisc.edu
3717839Snilay@cs.wisc.edu    //there are some reserved registers, you can see ns_gige_reg.h and
3727839Snilay@cs.wisc.edu    //the spec sheet for details
3737839Snilay@cs.wisc.edu    if (daddr > LAST && daddr <=  RESERVED) {
3747839Snilay@cs.wisc.edu        panic("Accessing reserved register");
3757839Snilay@cs.wisc.edu    } else if (daddr > RESERVED && daddr <= 0x3FC) {
3767839Snilay@cs.wisc.edu        ReadConfig(daddr & 0xff, req->size, data);
3777839Snilay@cs.wisc.edu        return No_Fault;
3787839Snilay@cs.wisc.edu    } else if (daddr >= MIB_START && daddr <= MIB_END) {
3797839Snilay@cs.wisc.edu        // don't implement all the MIB's.  hopefully the kernel
3807839Snilay@cs.wisc.edu        // doesn't actually DEPEND upon their values
3817839Snilay@cs.wisc.edu        // MIB are just hardware stats keepers
3827839Snilay@cs.wisc.edu        uint32_t &reg = *(uint32_t *) data;
3837839Snilay@cs.wisc.edu        reg = 0;
3846657Snate@binkert.org        return No_Fault;
3856657Snate@binkert.org    } else if (daddr > 0x3FC)
3866657Snate@binkert.org        panic("Something is messed up!\n");
3876657Snate@binkert.org
3887007Snate@binkert.org    switch (req->size) {
3896657Snate@binkert.org      case sizeof(uint32_t):
3906657Snate@binkert.org        {
3919273Snilay@cs.wisc.edu            uint32_t &reg = *(uint32_t *)data;
3926657Snate@binkert.org
3936657Snate@binkert.org            switch (daddr) {
3946657Snate@binkert.org              case CR:
3956657Snate@binkert.org                reg = regs.command;
3966657Snate@binkert.org                //these are supposed to be cleared on a read
3976657Snate@binkert.org                reg &= ~(CR_RXD | CR_TXD | CR_TXR | CR_RXR);
3986657Snate@binkert.org                break;
3997007Snate@binkert.org
4006657Snate@binkert.org              case CFG:
4016657Snate@binkert.org                reg = regs.config;
4029219Spower.jg@gmail.com                break;
4036657Snate@binkert.org
4046657Snate@binkert.org              case MEAR:
4056999Snate@binkert.org                reg = regs.mear;
4066657Snate@binkert.org                break;
4076657Snate@binkert.org
4086657Snate@binkert.org              case PTSCR:
4096657Snate@binkert.org                reg = regs.ptscr;
4107007Snate@binkert.org                break;
4116657Snate@binkert.org
4126657Snate@binkert.org              case ISR:
4136657Snate@binkert.org                reg = regs.isr;
4146657Snate@binkert.org                devIntrClear(ISR_ALL);
4156657Snate@binkert.org                break;
4168946Sandreas.hansson@arm.com
4178946Sandreas.hansson@arm.com              case IMR:
4188946Sandreas.hansson@arm.com                reg = regs.imr;
4197832Snate@binkert.org                break;
4207002Snate@binkert.org
4217002Snate@binkert.org              case IER:
4227002Snate@binkert.org                reg = regs.ier;
4238641Snate@binkert.org                break;
4247056Snate@binkert.org
4258232Snate@binkert.org              case IHR:
4268232Snate@binkert.org                reg = regs.ihr;
4276657Snate@binkert.org                break;
4288229Snate@binkert.org
4296657Snate@binkert.org              case TXDP:
4306657Snate@binkert.org                reg = regs.txdp;
4317056Snate@binkert.org                break;
4326657Snate@binkert.org
4339219Spower.jg@gmail.com              case TXDP_HI:
4349219Spower.jg@gmail.com                reg = regs.txdp_hi;
4359219Spower.jg@gmail.com                break;
4369219Spower.jg@gmail.com
4379219Spower.jg@gmail.com              case TXCFG:
4387002Snate@binkert.org                reg = regs.txcfg;
4397002Snate@binkert.org                break;
4406657Snate@binkert.org
4416657Snate@binkert.org              case GPIOR:
4426657Snate@binkert.org                reg = regs.gpior;
4436657Snate@binkert.org                break;
4446657Snate@binkert.org
4456793SBrad.Beckmann@amd.com              case RXDP:
4466657Snate@binkert.org                reg = regs.rxdp;
4476657Snate@binkert.org                break;
4486657Snate@binkert.org
4496657Snate@binkert.org              case RXDP_HI:
4506877Ssteve.reinhardt@amd.com                reg = regs.rxdp_hi;
4516877Ssteve.reinhardt@amd.com                break;
4526877Ssteve.reinhardt@amd.com
4536877Ssteve.reinhardt@amd.com              case RXCFG:
4546877Ssteve.reinhardt@amd.com                reg = regs.rxcfg;
4556877Ssteve.reinhardt@amd.com                break;
4566657Snate@binkert.org
4577542SBrad.Beckmann@amd.com              case PQCR:
4586657Snate@binkert.org                reg = regs.pqcr;
4597007Snate@binkert.org                break;
4606657Snate@binkert.org
4616657Snate@binkert.org              case WCSR:
4627007Snate@binkert.org                reg = regs.wcsr;
4636657Snate@binkert.org                break;
4646877Ssteve.reinhardt@amd.com
4656877Ssteve.reinhardt@amd.com              case PCR:
4666657Snate@binkert.org                reg = regs.pcr;
4676877Ssteve.reinhardt@amd.com                break;
4686877Ssteve.reinhardt@amd.com
4696877Ssteve.reinhardt@amd.com                //see the spec sheet for how RFCR and RFDR work
4706877Ssteve.reinhardt@amd.com                //basically, you write to RFCR to tell the machine what you want to do next
4716877Ssteve.reinhardt@amd.com                //then you act upon RFDR, and the device will be prepared b/c
4726969SBrad.Beckmann@amd.com                //of what you wrote to RFCR
4738532SLisa.Hsu@amd.com              case RFCR:
4746657Snate@binkert.org                reg = regs.rfcr;
4757567SBrad.Beckmann@amd.com                break;
4767567SBrad.Beckmann@amd.com
4777567SBrad.Beckmann@amd.com              case RFDR:
4787567SBrad.Beckmann@amd.com                switch (regs.rfcr & RFCR_RFADDR) {
4797567SBrad.Beckmann@amd.com                  case 0x000:
4807567SBrad.Beckmann@amd.com                    reg = rom.perfectMatch[1];
4816657Snate@binkert.org                    reg = reg << 8;
4826882SBrad.Beckmann@amd.com                    reg += rom.perfectMatch[0];
4836882SBrad.Beckmann@amd.com                    break;
4846882SBrad.Beckmann@amd.com                  case 0x002:
4856882SBrad.Beckmann@amd.com                    reg = rom.perfectMatch[3] << 8;
4866882SBrad.Beckmann@amd.com                    reg += rom.perfectMatch[2];
4876882SBrad.Beckmann@amd.com                    break;
4886882SBrad.Beckmann@amd.com                  case 0x004:
4898189SLisa.Hsu@amd.com                    reg = rom.perfectMatch[5] << 8;
4908189SLisa.Hsu@amd.com                    reg += rom.perfectMatch[4];
4916877Ssteve.reinhardt@amd.com                    break;
4928189SLisa.Hsu@amd.com                  default:
4938189SLisa.Hsu@amd.com                    panic("reading from RFDR for something for other than PMATCH!\n");
4948189SLisa.Hsu@amd.com                    //didn't implement other RFDR functionality b/c driver didn't use
4958189SLisa.Hsu@amd.com                }
4966882SBrad.Beckmann@amd.com                break;
4976882SBrad.Beckmann@amd.com
4986882SBrad.Beckmann@amd.com              case SRR:
4996882SBrad.Beckmann@amd.com                reg = regs.srr;
5006882SBrad.Beckmann@amd.com                break;
5016882SBrad.Beckmann@amd.com
5026882SBrad.Beckmann@amd.com              case MIBC:
5036882SBrad.Beckmann@amd.com                reg = regs.mibc;
5046882SBrad.Beckmann@amd.com                reg &= ~(MIBC_MIBS | MIBC_ACLR);
5056882SBrad.Beckmann@amd.com                break;
5068189SLisa.Hsu@amd.com
5076882SBrad.Beckmann@amd.com              case VRCR:
5086882SBrad.Beckmann@amd.com                reg = regs.vrcr;
5096882SBrad.Beckmann@amd.com                break;
5108189SLisa.Hsu@amd.com
5118189SLisa.Hsu@amd.com              case VTCR:
5128189SLisa.Hsu@amd.com                reg = regs.vtcr;
5138189SLisa.Hsu@amd.com                break;
5148938SLisa.Hsu@amd.com
5158938SLisa.Hsu@amd.com              case VDR:
5168938SLisa.Hsu@amd.com                reg = regs.vdr;
5178938SLisa.Hsu@amd.com                break;
5188938SLisa.Hsu@amd.com
5198938SLisa.Hsu@amd.com              case CCSR:
5208938SLisa.Hsu@amd.com                reg = regs.ccsr;
5216888SBrad.Beckmann@amd.com                break;
5226888SBrad.Beckmann@amd.com
5236888SBrad.Beckmann@amd.com              case TBICR:
5246888SBrad.Beckmann@amd.com                reg = regs.tbicr;
5256888SBrad.Beckmann@amd.com                break;
5268189SLisa.Hsu@amd.com
5276888SBrad.Beckmann@amd.com              case TBISR:
5286888SBrad.Beckmann@amd.com                reg = regs.tbisr;
5296657Snate@binkert.org                break;
5306888SBrad.Beckmann@amd.com
5316888SBrad.Beckmann@amd.com              case TANAR:
5326888SBrad.Beckmann@amd.com                reg = regs.tanar;
5336888SBrad.Beckmann@amd.com                break;
5346657Snate@binkert.org
5356657Snate@binkert.org              case TANLPAR:
5366657Snate@binkert.org                reg = regs.tanlpar;
5376657Snate@binkert.org                break;
5386657Snate@binkert.org
5396657Snate@binkert.org              case TANER:
5406657Snate@binkert.org                reg = regs.taner;
5416657Snate@binkert.org                break;
5426657Snate@binkert.org
5437007Snate@binkert.org              case TESR:
5447007Snate@binkert.org                reg = regs.tesr;
5456657Snate@binkert.org                break;
5467007Snate@binkert.org
5477007Snate@binkert.org              default:
5487007Snate@binkert.org                panic("reading unimplemented register: addr = %#x", daddr);
5496657Snate@binkert.org            }
5506657Snate@binkert.org
5516657Snate@binkert.org            DPRINTF(EthernetPIO, "read from %#x: data=%d data=%#x\n",
5527007Snate@binkert.org                    daddr, reg, reg);
5537542SBrad.Beckmann@amd.com        }
5547542SBrad.Beckmann@amd.com        break;
5557007Snate@binkert.org
5566657Snate@binkert.org      default:
5576657Snate@binkert.org        panic("accessing register with invalid size: addr=%#x, size=%d",
5586657Snate@binkert.org              daddr, req->size);
5596657Snate@binkert.org    }
5606657Snate@binkert.org
5616657Snate@binkert.org    return No_Fault;
5626657Snate@binkert.org}
5636657Snate@binkert.org
5646657Snate@binkert.orgFault
5656657Snate@binkert.orgNSGigE::write(MemReqPtr &req, const uint8_t *data)
5666657Snate@binkert.org{
5676657Snate@binkert.org    assert(ioEnable);
5686657Snate@binkert.org
5696657Snate@binkert.org    Addr daddr = req->paddr & 0xfff;
5706657Snate@binkert.org    DPRINTF(EthernetPIO, "write da=%#x pa=%#x va=%#x size=%d\n",
5716657Snate@binkert.org            daddr, req->paddr, req->vaddr, req->size);
5726657Snate@binkert.org
5736657Snate@binkert.org    if (daddr > LAST && daddr <=  RESERVED) {
5749273Snilay@cs.wisc.edu        panic("Accessing reserved register");
5756657Snate@binkert.org    } else if (daddr > RESERVED && daddr <= 0x3FC) {
5766657Snate@binkert.org        WriteConfig(daddr & 0xff, req->size, *(uint32_t *)data);
5776657Snate@binkert.org        return No_Fault;
5786657Snate@binkert.org    } else if (daddr > 0x3FC)
5796657Snate@binkert.org        panic("Something is messed up!\n");
5806657Snate@binkert.org
5816657Snate@binkert.org    if (req->size == sizeof(uint32_t)) {
5826657Snate@binkert.org        uint32_t reg = *(uint32_t *)data;
5836657Snate@binkert.org        DPRINTF(EthernetPIO, "write data=%d data=%#x\n", reg, reg);
5847007Snate@binkert.org
5856657Snate@binkert.org        switch (daddr) {
5866657Snate@binkert.org          case CR:
5876657Snate@binkert.org            regs.command = reg;
5886657Snate@binkert.org            if ((reg & (CR_TXE | CR_TXD)) == (CR_TXE | CR_TXD)) {
5897007Snate@binkert.org                txHalt = true;
5906657Snate@binkert.org            } else if (reg & CR_TXE) {
5917007Snate@binkert.org                //the kernel is enabling the transmit machine
5927007Snate@binkert.org                if (txState == txIdle)
5936657Snate@binkert.org                    txKick();
5946657Snate@binkert.org            } else if (reg & CR_TXD) {
5956657Snate@binkert.org                txHalt = true;
5966657Snate@binkert.org            }
5976657Snate@binkert.org
5986657Snate@binkert.org            if ((reg & (CR_RXE | CR_RXD)) == (CR_RXE | CR_RXD)) {
5996657Snate@binkert.org                rxHalt = true;
6006657Snate@binkert.org            } else if (reg & CR_RXE) {
6016657Snate@binkert.org                if (rxState == rxIdle) {
6026657Snate@binkert.org                    rxKick();
6036657Snate@binkert.org                }
6046657Snate@binkert.org            } else if (reg & CR_RXD) {
6056657Snate@binkert.org                rxHalt = true;
6066657Snate@binkert.org            }
6076657Snate@binkert.org
6087566SBrad.Beckmann@amd.com            if (reg & CR_TXR)
6096657Snate@binkert.org                txReset();
6106657Snate@binkert.org
6116657Snate@binkert.org            if (reg & CR_RXR)
6126657Snate@binkert.org                rxReset();
6136657Snate@binkert.org
6148308Stushar@csail.mit.edu            if (reg & CR_SWI)
6156657Snate@binkert.org                devIntrPost(ISR_SWI);
6166657Snate@binkert.org
6176657Snate@binkert.org            if (reg & CR_RST) {
6187007Snate@binkert.org                txReset();
6197007Snate@binkert.org                rxReset();
6208308Stushar@csail.mit.edu
6216657Snate@binkert.org                regsReset();
6226657Snate@binkert.org            }
6236657Snate@binkert.org            break;
6246657Snate@binkert.org
6256657Snate@binkert.org          case CFG:
6266657Snate@binkert.org            if (reg & CFG_LNKSTS || reg & CFG_SPDSTS || reg & CFG_DUPSTS
6276657Snate@binkert.org                || reg & CFG_RESERVED || reg & CFG_T64ADDR
6286657Snate@binkert.org                || reg & CFG_PCI64_DET)
6296657Snate@binkert.org                panic("writing to read-only or reserved CFG bits!\n");
6306657Snate@binkert.org
6316657Snate@binkert.org            regs.config |= reg & ~(CFG_LNKSTS | CFG_SPDSTS | CFG_DUPSTS | CFG_RESERVED |
6326657Snate@binkert.org                                  CFG_T64ADDR | CFG_PCI64_DET);
6338187SLisa.Hsu@amd.com
6346657Snate@binkert.org// all these #if 0's are because i don't THINK the kernel needs to have these implemented
6356657Snate@binkert.org// if there is a problem relating to one of these, you may need to add functionality in
6366657Snate@binkert.org#if 0
6376657Snate@binkert.org              if (reg & CFG_TBI_EN) ;
6386657Snate@binkert.org              if (reg & CFG_MODE_1000) ;
6396657Snate@binkert.org#endif
6406657Snate@binkert.org
6416657Snate@binkert.org            if (reg & CFG_AUTO_1000)
6426657Snate@binkert.org                panic("CFG_AUTO_1000 not implemented!\n");
6437454Snate@binkert.org
6446657Snate@binkert.org#if 0
6456657Snate@binkert.org            if (reg & CFG_PINT_DUPSTS || reg & CFG_PINT_LNKSTS || reg & CFG_PINT_SPDSTS) ;
6466657Snate@binkert.org            if (reg & CFG_TMRTEST) ;
6476657Snate@binkert.org            if (reg & CFG_MRM_DIS) ;
6487007Snate@binkert.org            if (reg & CFG_MWI_DIS) ;
6497056Snate@binkert.org
6507007Snate@binkert.org            if (reg & CFG_T64ADDR)
6517007Snate@binkert.org                panic("CFG_T64ADDR is read only register!\n");
6526657Snate@binkert.org
6537566SBrad.Beckmann@amd.com            if (reg & CFG_PCI64_DET)
6547566SBrad.Beckmann@amd.com                panic("CFG_PCI64_DET is read only register!\n");
6557566SBrad.Beckmann@amd.com
6567566SBrad.Beckmann@amd.com            if (reg & CFG_DATA64_EN) ;
6577566SBrad.Beckmann@amd.com            if (reg & CFG_M64ADDR) ;
6587566SBrad.Beckmann@amd.com            if (reg & CFG_PHY_RST) ;
6597566SBrad.Beckmann@amd.com            if (reg & CFG_PHY_DIS) ;
6606657Snate@binkert.org#endif
6617672Snate@binkert.org
6626657Snate@binkert.org            if (reg & CFG_EXTSTS_EN)
6636657Snate@binkert.org                extstsEnable = true;
6646657Snate@binkert.org            else
6656657Snate@binkert.org                extstsEnable = false;
6667672Snate@binkert.org
6676657Snate@binkert.org#if 0
6687056Snate@binkert.org              if (reg & CFG_REQALG) ;
6696657Snate@binkert.org              if (reg & CFG_SB) ;
6706657Snate@binkert.org              if (reg & CFG_POW) ;
6717672Snate@binkert.org              if (reg & CFG_EXD) ;
6726657Snate@binkert.org              if (reg & CFG_PESEL) ;
6736657Snate@binkert.org              if (reg & CFG_BROM_DIS) ;
6746657Snate@binkert.org              if (reg & CFG_EXT_125) ;
6756657Snate@binkert.org              if (reg & CFG_BEM) ;
6766657Snate@binkert.org#endif
6776657Snate@binkert.org            break;
6786657Snate@binkert.org
6796657Snate@binkert.org          case MEAR:
6806657Snate@binkert.org            regs.mear = reg;
6816657Snate@binkert.org            /* since phy is completely faked, MEAR_MD* don't matter
6826657Snate@binkert.org               and since the driver never uses MEAR_EE*, they don't matter */
6837542SBrad.Beckmann@amd.com#if 0
6846657Snate@binkert.org            if (reg & MEAR_EEDI) ;
6856657Snate@binkert.org            if (reg & MEAR_EEDO) ; //this one is read only
6866657Snate@binkert.org            if (reg & MEAR_EECLK) ;
6876657Snate@binkert.org            if (reg & MEAR_EESEL) ;
6886657Snate@binkert.org            if (reg & MEAR_MDIO) ;
6896657Snate@binkert.org            if (reg & MEAR_MDDIR) ;
6906657Snate@binkert.org            if (reg & MEAR_MDC) ;
6916657Snate@binkert.org#endif
6926657Snate@binkert.org            break;
6936657Snate@binkert.org
6946657Snate@binkert.org          case PTSCR:
6956657Snate@binkert.org            regs.ptscr = reg & ~(PTSCR_RBIST_RDONLY);
6966657Snate@binkert.org            /* these control BISTs for various parts of chip - we don't care or do
6976657Snate@binkert.org               just fake that the BIST is done */
6988683Snilay@cs.wisc.edu            if (reg & PTSCR_RBIST_EN)
6998683Snilay@cs.wisc.edu                regs.ptscr |= PTSCR_RBIST_DONE;
7008683Snilay@cs.wisc.edu            if (reg & PTSCR_EEBIST_EN)
7018683Snilay@cs.wisc.edu                regs.ptscr &= ~PTSCR_EEBIST_EN;
7028683Snilay@cs.wisc.edu            if (reg & PTSCR_EELOAD_EN)
7038683Snilay@cs.wisc.edu                regs.ptscr &= ~PTSCR_EELOAD_EN;
7046657Snate@binkert.org            break;
7057007Snate@binkert.org
7067007Snate@binkert.org          case ISR: /* writing to the ISR has no effect */
7077007Snate@binkert.org            panic("ISR is a read only register!\n");
7086657Snate@binkert.org
7096657Snate@binkert.org          case IMR:
7106657Snate@binkert.org            regs.imr = reg;
7117007Snate@binkert.org            devIntrChangeMask();
7127007Snate@binkert.org            break;
7137007Snate@binkert.org
7146657Snate@binkert.org          case IER:
7156657Snate@binkert.org            regs.ier = reg;
7166657Snate@binkert.org            break;
7178683Snilay@cs.wisc.edu
7188683Snilay@cs.wisc.edu          case IHR:
7198683Snilay@cs.wisc.edu            regs.ihr = reg;
7208683Snilay@cs.wisc.edu            /* not going to implement real interrupt holdoff */
7218683Snilay@cs.wisc.edu            break;
7228683Snilay@cs.wisc.edu
7237007Snate@binkert.org          case TXDP:
7247007Snate@binkert.org            regs.txdp = (reg & 0xFFFFFFFC);
7257007Snate@binkert.org            assert(txState == txIdle);
7266657Snate@binkert.org            CTDD = false;
7276657Snate@binkert.org            break;
7286657Snate@binkert.org
7297007Snate@binkert.org          case TXDP_HI:
7307007Snate@binkert.org            regs.txdp_hi = reg;
7317007Snate@binkert.org            break;
7326657Snate@binkert.org
7336657Snate@binkert.org          case TXCFG:
7346657Snate@binkert.org            regs.txcfg = reg;
7357007Snate@binkert.org#if 0
7367007Snate@binkert.org            if (reg & TXCFG_CSI) ;
7377007Snate@binkert.org            if (reg & TXCFG_HBI) ;
7386657Snate@binkert.org            if (reg & TXCFG_MLB) ;
7396657Snate@binkert.org            if (reg & TXCFG_ATP) ;
7407007Snate@binkert.org            if (reg & TXCFG_ECRETRY) ;  /* this could easily be implemented, but
7417007Snate@binkert.org                                           considering the network is just a fake
7427567SBrad.Beckmann@amd.com                                           pipe, wouldn't make sense to do this */
7437567SBrad.Beckmann@amd.com
7447567SBrad.Beckmann@amd.com            if (reg & TXCFG_BRST_DIS) ;
7457567SBrad.Beckmann@amd.com#endif
7467567SBrad.Beckmann@amd.com
7477567SBrad.Beckmann@amd.com
7487567SBrad.Beckmann@amd.com            /* we handle our own DMA, ignore the kernel's exhortations */
7497567SBrad.Beckmann@amd.com            //if (reg & TXCFG_MXDMA) ;
7507567SBrad.Beckmann@amd.com
7517567SBrad.Beckmann@amd.com            //also, we currently don't care about fill/drain thresholds
7527567SBrad.Beckmann@amd.com            //though this may change in the future with more realistic
7537567SBrad.Beckmann@amd.com            //networks or a driver which changes it according to feedback
7547567SBrad.Beckmann@amd.com
7558155Snilay@cs.wisc.edu            break;
7568155Snilay@cs.wisc.edu
7578155Snilay@cs.wisc.edu          case GPIOR:
7588155Snilay@cs.wisc.edu            regs.gpior = reg;
7598155Snilay@cs.wisc.edu            /* these just control general purpose i/o pins, don't matter */
7608155Snilay@cs.wisc.edu            break;
7618155Snilay@cs.wisc.edu
7628155Snilay@cs.wisc.edu          case RXDP:
7638155Snilay@cs.wisc.edu            regs.rxdp = reg;
7648155Snilay@cs.wisc.edu            break;
7658155Snilay@cs.wisc.edu
7667567SBrad.Beckmann@amd.com          case RXDP_HI:
7678155Snilay@cs.wisc.edu            regs.rxdp_hi = reg;
7688155Snilay@cs.wisc.edu            break;
7697567SBrad.Beckmann@amd.com
7707567SBrad.Beckmann@amd.com          case RXCFG:
7717567SBrad.Beckmann@amd.com            regs.rxcfg = reg;
7727567SBrad.Beckmann@amd.com#if 0
7737922SBrad.Beckmann@amd.com            if (reg & RXCFG_AEP) ;
7747922SBrad.Beckmann@amd.com            if (reg & RXCFG_ARP) ;
7757922SBrad.Beckmann@amd.com            if (reg & RXCFG_STRIPCRC) ;
7767922SBrad.Beckmann@amd.com            if (reg & RXCFG_RX_RD) ;
7777922SBrad.Beckmann@amd.com            if (reg & RXCFG_ALP) ;
7787922SBrad.Beckmann@amd.com            if (reg & RXCFG_AIRL) ;
7797922SBrad.Beckmann@amd.com#endif
7807922SBrad.Beckmann@amd.com
7818154Snilay@cs.wisc.edu            /* we handle our own DMA, ignore what kernel says about it */
7828154Snilay@cs.wisc.edu            //if (reg & RXCFG_MXDMA) ;
7838154Snilay@cs.wisc.edu
7848154Snilay@cs.wisc.edu#if 0
7858154Snilay@cs.wisc.edu            //also, we currently don't care about fill/drain thresholds
7868154Snilay@cs.wisc.edu            //though this may change in the future with more realistic
7878154Snilay@cs.wisc.edu            //networks or a driver which changes it according to feedback
7888154Snilay@cs.wisc.edu            if (reg & (RXCFG_DRTH | RXCFG_DRTH0)) ;
7898154Snilay@cs.wisc.edu#endif
7908154Snilay@cs.wisc.edu            break;
7918154Snilay@cs.wisc.edu
7928154Snilay@cs.wisc.edu          case PQCR:
7938154Snilay@cs.wisc.edu            /* there is no priority queueing used in the linux 2.6 driver */
7948154Snilay@cs.wisc.edu            regs.pqcr = reg;
7958154Snilay@cs.wisc.edu            break;
7968154Snilay@cs.wisc.edu
7978154Snilay@cs.wisc.edu          case WCSR:
7988154Snilay@cs.wisc.edu            /* not going to implement wake on LAN */
7998154Snilay@cs.wisc.edu            regs.wcsr = reg;
8008154Snilay@cs.wisc.edu            break;
8018154Snilay@cs.wisc.edu
8027922SBrad.Beckmann@amd.com          case PCR:
8037922SBrad.Beckmann@amd.com            /* not going to implement pause control */
8047922SBrad.Beckmann@amd.com            regs.pcr = reg;
8057922SBrad.Beckmann@amd.com            break;
8067007Snate@binkert.org
8077007Snate@binkert.org          case RFCR:
8086863Sdrh5@cs.wisc.edu            regs.rfcr = reg;
8096863Sdrh5@cs.wisc.edu
8106863Sdrh5@cs.wisc.edu            rxFilterEnable = (reg & RFCR_RFEN) ? true : false;
8117007Snate@binkert.org            acceptBroadcast = (reg & RFCR_AAB) ? true : false;
8127007Snate@binkert.org            acceptMulticast = (reg & RFCR_AAM) ? true : false;
8137007Snate@binkert.org            acceptUnicast = (reg & RFCR_AAU) ? true : false;
8147007Snate@binkert.org            acceptPerfect = (reg & RFCR_APM) ? true : false;
8156863Sdrh5@cs.wisc.edu            acceptArp = (reg & RFCR_AARP) ? true : false;
8166863Sdrh5@cs.wisc.edu
8176863Sdrh5@cs.wisc.edu            if (reg & RFCR_APAT) ;
8186863Sdrh5@cs.wisc.edu//                panic("RFCR_APAT not implemented!\n");
8196863Sdrh5@cs.wisc.edu
8206863Sdrh5@cs.wisc.edu            if (reg & RFCR_MHEN || reg & RFCR_UHEN)
8217007Snate@binkert.org                panic("hash filtering not implemented!\n");
8227007Snate@binkert.org
8237007Snate@binkert.org            if (reg & RFCR_ULM)
8247007Snate@binkert.org                panic("RFCR_ULM not implemented!\n");
8257007Snate@binkert.org
8266657Snate@binkert.org            break;
8277007Snate@binkert.org
8287007Snate@binkert.org          case RFDR:
8297007Snate@binkert.org            panic("the driver never writes to RFDR, something is wrong!\n");
8306657Snate@binkert.org
8316657Snate@binkert.org          case BRAR:
8327007Snate@binkert.org            panic("the driver never uses BRAR, something is wrong!\n");
8337007Snate@binkert.org
8347007Snate@binkert.org          case BRDR:
8356657Snate@binkert.org            panic("the driver never uses BRDR, something is wrong!\n");
8366657Snate@binkert.org
8377007Snate@binkert.org          case SRR:
8387007Snate@binkert.org            panic("SRR is read only register!\n");
8397007Snate@binkert.org
8406902SBrad.Beckmann@amd.com          case MIBC:
8416902SBrad.Beckmann@amd.com            panic("the driver never uses MIBC, something is wrong!\n");
8426902SBrad.Beckmann@amd.com
8436902SBrad.Beckmann@amd.com          case VRCR:
8446902SBrad.Beckmann@amd.com            regs.vrcr = reg;
8456902SBrad.Beckmann@amd.com            break;
8466902SBrad.Beckmann@amd.com
8477025SBrad.Beckmann@amd.com          case VTCR:
8486902SBrad.Beckmann@amd.com            regs.vtcr = reg;
8496902SBrad.Beckmann@amd.com            break;
8506902SBrad.Beckmann@amd.com
8516902SBrad.Beckmann@amd.com          case VDR:
8526902SBrad.Beckmann@amd.com            panic("the driver never uses VDR, something is wrong!\n");
8537542SBrad.Beckmann@amd.com            break;
8547542SBrad.Beckmann@amd.com
8557542SBrad.Beckmann@amd.com          case CCSR:
8566902SBrad.Beckmann@amd.com            /* not going to implement clockrun stuff */
8576902SBrad.Beckmann@amd.com            regs.ccsr = reg;
8586902SBrad.Beckmann@amd.com            break;
8596902SBrad.Beckmann@amd.com
8606902SBrad.Beckmann@amd.com          case TBICR:
8616902SBrad.Beckmann@amd.com            regs.tbicr = reg;
8626902SBrad.Beckmann@amd.com            if (reg & TBICR_MR_LOOPBACK)
8636902SBrad.Beckmann@amd.com                panic("TBICR_MR_LOOPBACK never used, something wrong!\n");
8646902SBrad.Beckmann@amd.com
8656902SBrad.Beckmann@amd.com            if (reg & TBICR_MR_AN_ENABLE) {
8666902SBrad.Beckmann@amd.com                regs.tanlpar = regs.tanar;
8676902SBrad.Beckmann@amd.com                regs.tbisr |= (TBISR_MR_AN_COMPLETE | TBISR_MR_LINK_STATUS);
8686902SBrad.Beckmann@amd.com            }
8696902SBrad.Beckmann@amd.com
8706902SBrad.Beckmann@amd.com#if 0
8717542SBrad.Beckmann@amd.com            if (reg & TBICR_MR_RESTART_AN) ;
8726902SBrad.Beckmann@amd.com#endif
8737839Snilay@cs.wisc.edu
8747839Snilay@cs.wisc.edu            break;
8757839Snilay@cs.wisc.edu
8767839Snilay@cs.wisc.edu          case TBISR:
8777839Snilay@cs.wisc.edu            panic("TBISR is read only register!\n");
8787839Snilay@cs.wisc.edu
8797839Snilay@cs.wisc.edu          case TANAR:
8807839Snilay@cs.wisc.edu            regs.tanar = reg;
8817839Snilay@cs.wisc.edu            if (reg & TANAR_PS2)
8827839Snilay@cs.wisc.edu                panic("this isn't used in driver, something wrong!\n");
8837839Snilay@cs.wisc.edu
8847839Snilay@cs.wisc.edu            if (reg & TANAR_PS1)
8857839Snilay@cs.wisc.edu                panic("this isn't used in driver, something wrong!\n");
8867839Snilay@cs.wisc.edu            break;
8877839Snilay@cs.wisc.edu
8887839Snilay@cs.wisc.edu          case TANLPAR:
8897839Snilay@cs.wisc.edu            panic("this should only be written to by the fake phy!\n");
8907839Snilay@cs.wisc.edu
8917839Snilay@cs.wisc.edu          case TANER:
8927839Snilay@cs.wisc.edu            panic("TANER is read only register!\n");
8937839Snilay@cs.wisc.edu
8947839Snilay@cs.wisc.edu          case TESR:
8957839Snilay@cs.wisc.edu            regs.tesr = reg;
8967839Snilay@cs.wisc.edu            break;
8977839Snilay@cs.wisc.edu
8987839Snilay@cs.wisc.edu          default:
8997839Snilay@cs.wisc.edu            panic("thought i covered all the register, what is this? addr=%#x",
9007839Snilay@cs.wisc.edu                  daddr);
9017839Snilay@cs.wisc.edu        }
9027839Snilay@cs.wisc.edu    } else
9037839Snilay@cs.wisc.edu        panic("Invalid Request Size");
9047839Snilay@cs.wisc.edu
9057839Snilay@cs.wisc.edu    return No_Fault;
9067839Snilay@cs.wisc.edu}
9077839Snilay@cs.wisc.edu
9087839Snilay@cs.wisc.eduvoid
9097839Snilay@cs.wisc.eduNSGigE::devIntrPost(uint32_t interrupts)
9106902SBrad.Beckmann@amd.com{
9118683Snilay@cs.wisc.edu    bool delay = false;
9128683Snilay@cs.wisc.edu
9138683Snilay@cs.wisc.edu    if (interrupts & ISR_RESERVE)
9148683Snilay@cs.wisc.edu        panic("Cannot set a reserved interrupt");
9158683Snilay@cs.wisc.edu
9168683Snilay@cs.wisc.edu    if (interrupts & ISR_TXRCMP)
9178683Snilay@cs.wisc.edu        regs.isr |= ISR_TXRCMP;
9188683Snilay@cs.wisc.edu
9198683Snilay@cs.wisc.edu    if (interrupts & ISR_RXRCMP)
9208683Snilay@cs.wisc.edu        regs.isr |= ISR_RXRCMP;
9218683Snilay@cs.wisc.edu
9228683Snilay@cs.wisc.edu//ISR_DPERR  not implemented
9238683Snilay@cs.wisc.edu//ISR_SSERR not implemented
9248683Snilay@cs.wisc.edu//ISR_RMABT not implemented
9258683Snilay@cs.wisc.edu//ISR_RXSOVR not implemented
9268683Snilay@cs.wisc.edu//ISR_HIBINT not implemented
9278683Snilay@cs.wisc.edu//ISR_PHY not implemented
9286657Snate@binkert.org//ISR_PME not implemented
9296657Snate@binkert.org
9307839Snilay@cs.wisc.edu    if (interrupts & ISR_SWI)
9317839Snilay@cs.wisc.edu        regs.isr |= ISR_SWI;
9327839Snilay@cs.wisc.edu
9337839Snilay@cs.wisc.edu//ISR_MIB not implemented
9346657Snate@binkert.org//ISR_TXURN not implemented
9357839Snilay@cs.wisc.edu
9367839Snilay@cs.wisc.edu    if (interrupts & ISR_TXIDLE)
9377839Snilay@cs.wisc.edu        regs.isr |= ISR_TXIDLE;
9387839Snilay@cs.wisc.edu
9397839Snilay@cs.wisc.edu    if (interrupts & ISR_TXERR)
9408055Sksewell@umich.edu        regs.isr |= ISR_TXERR;
9417839Snilay@cs.wisc.edu
9427839Snilay@cs.wisc.edu    if (interrupts & ISR_TXDESC)
9436657Snate@binkert.org        regs.isr |= ISR_TXDESC;
9447839Snilay@cs.wisc.edu
9457839Snilay@cs.wisc.edu    if (interrupts & ISR_TXOK) {
9467839Snilay@cs.wisc.edu        regs.isr |= ISR_TXOK;
9477839Snilay@cs.wisc.edu        delay = true;
9487839Snilay@cs.wisc.edu    }
9497839Snilay@cs.wisc.edu
9507839Snilay@cs.wisc.edu    if (interrupts & ISR_RXORN)
9517839Snilay@cs.wisc.edu        regs.isr |= ISR_RXORN;
9527839Snilay@cs.wisc.edu
9537839Snilay@cs.wisc.edu    if (interrupts & ISR_RXIDLE)
9547839Snilay@cs.wisc.edu        regs.isr |= ISR_RXIDLE;
9558055Sksewell@umich.edu
9567839Snilay@cs.wisc.edu//ISR_RXEARLY not implemented
9577839Snilay@cs.wisc.edu
9587839Snilay@cs.wisc.edu    if (interrupts & ISR_RXERR)
9597839Snilay@cs.wisc.edu        regs.isr |= ISR_RXERR;
9607839Snilay@cs.wisc.edu
9617839Snilay@cs.wisc.edu    if (interrupts & ISR_RXDESC)
9627839Snilay@cs.wisc.edu        regs.isr |= ISR_RXDESC;
9637839Snilay@cs.wisc.edu
9647839Snilay@cs.wisc.edu    if (interrupts & ISR_RXOK) {
9657839Snilay@cs.wisc.edu        delay = true;
9667839Snilay@cs.wisc.edu        regs.isr |= ISR_RXOK;
9677839Snilay@cs.wisc.edu    }
9687839Snilay@cs.wisc.edu
9697839Snilay@cs.wisc.edu    if ((regs.isr & regs.imr)) {
9708055Sksewell@umich.edu        Tick when = curTick;
9717839Snilay@cs.wisc.edu        if (delay)
9727839Snilay@cs.wisc.edu            when += intrDelay;
9737839Snilay@cs.wisc.edu        cpuIntrPost(when);
9747839Snilay@cs.wisc.edu    }
9757839Snilay@cs.wisc.edu
9767839Snilay@cs.wisc.edu    DPRINTF(EthernetIntr, "**interrupt written to ISR: intr=%#x isr=%#x imr=%#x\n",
9777839Snilay@cs.wisc.edu            interrupts, regs.isr, regs.imr);
9787839Snilay@cs.wisc.edu}
9797839Snilay@cs.wisc.edu
9807839Snilay@cs.wisc.eduvoid
9816657Snate@binkert.orgNSGigE::devIntrClear(uint32_t interrupts)
9827007Snate@binkert.org{
9837007Snate@binkert.org    if (interrupts & ISR_RESERVE)
9846657Snate@binkert.org        panic("Cannot clear a reserved interrupt");
9858055Sksewell@umich.edu
9866657Snate@binkert.org    if (interrupts & ISR_TXRCMP)
9876657Snate@binkert.org        regs.isr &= ~ISR_TXRCMP;
9886657Snate@binkert.org
9896657Snate@binkert.org    if (interrupts & ISR_RXRCMP)
9908478Snilay@cs.wisc.edu        regs.isr &= ~ISR_RXRCMP;
9918478Snilay@cs.wisc.edu
9928478Snilay@cs.wisc.edu//ISR_DPERR  not implemented
9939302Snilay@cs.wisc.edu//ISR_SSERR not implemented
9949302Snilay@cs.wisc.edu//ISR_RMABT not implemented
9959302Snilay@cs.wisc.edu//ISR_RXSOVR not implemented
9969302Snilay@cs.wisc.edu//ISR_HIBINT not implemented
9979302Snilay@cs.wisc.edu//ISR_PHY not implemented
9989302Snilay@cs.wisc.edu//ISR_PME not implemented
9999302Snilay@cs.wisc.edu
10009302Snilay@cs.wisc.edu    if (interrupts & ISR_SWI)
10019302Snilay@cs.wisc.edu        regs.isr &= ~ISR_SWI;
10029302Snilay@cs.wisc.edu
10039302Snilay@cs.wisc.edu//ISR_MIB not implemented
10049302Snilay@cs.wisc.edu//ISR_TXURN not implemented
10059302Snilay@cs.wisc.edu
10069302Snilay@cs.wisc.edu    if (interrupts & ISR_TXIDLE)
10079302Snilay@cs.wisc.edu        regs.isr &= ~ISR_TXIDLE;
10089302Snilay@cs.wisc.edu
10099302Snilay@cs.wisc.edu    if (interrupts & ISR_TXERR)
10109302Snilay@cs.wisc.edu        regs.isr &= ~ISR_TXERR;
10119302Snilay@cs.wisc.edu
10129302Snilay@cs.wisc.edu    if (interrupts & ISR_TXDESC)
10139302Snilay@cs.wisc.edu        regs.isr &= ~ISR_TXDESC;
10149302Snilay@cs.wisc.edu
10159302Snilay@cs.wisc.edu    if (interrupts & ISR_TXOK)
10169302Snilay@cs.wisc.edu        regs.isr &= ~ISR_TXOK;
10179302Snilay@cs.wisc.edu
10189302Snilay@cs.wisc.edu    if (interrupts & ISR_RXORN)
10199302Snilay@cs.wisc.edu        regs.isr &= ~ISR_RXORN;
10209302Snilay@cs.wisc.edu
10219302Snilay@cs.wisc.edu    if (interrupts & ISR_RXIDLE)
10229302Snilay@cs.wisc.edu        regs.isr &= ~ISR_RXIDLE;
10239302Snilay@cs.wisc.edu
10249302Snilay@cs.wisc.edu//ISR_RXEARLY not implemented
10259302Snilay@cs.wisc.edu
10266657Snate@binkert.org    if (interrupts & ISR_RXERR)
10276657Snate@binkert.org        regs.isr &= ~ISR_RXERR;
10289219Spower.jg@gmail.com
10296657Snate@binkert.org    if (interrupts & ISR_RXDESC)
10306657Snate@binkert.org        regs.isr &= ~ISR_RXDESC;
10316999Snate@binkert.org
10326657Snate@binkert.org    if (interrupts & ISR_RXOK)
10336657Snate@binkert.org        regs.isr &= ~ISR_RXOK;
10349104Shestness@cs.utexas.edu
10359104Shestness@cs.utexas.edu    if (!(regs.isr & regs.imr))
10369104Shestness@cs.utexas.edu        cpuIntrClear();
10379104Shestness@cs.utexas.edu
10386657Snate@binkert.org    DPRINTF(EthernetIntr, "**interrupt cleared from ISR: intr=%x isr=%x imr=%x\n",
10396657Snate@binkert.org            interrupts, regs.isr, regs.imr);
10406657Snate@binkert.org}
10416657Snate@binkert.org
10428946Sandreas.hansson@arm.comvoid
10438946Sandreas.hansson@arm.comNSGigE::devIntrChangeMask()
10448946Sandreas.hansson@arm.com{
10457832Snate@binkert.org    DPRINTF(EthernetIntr, "interrupt mask changed\n");
10467832Snate@binkert.org
10477007Snate@binkert.org    if (regs.isr & regs.imr)
10488232Snate@binkert.org        cpuIntrPost(curTick);
10498229Snate@binkert.org    else
10508229Snate@binkert.org        cpuIntrClear();
10518229Snate@binkert.org}
10529104Shestness@cs.utexas.edu
10539104Shestness@cs.utexas.eduvoid
10549104Shestness@cs.utexas.eduNSGigE::cpuIntrPost(Tick when)
10559104Shestness@cs.utexas.edu{
10569104Shestness@cs.utexas.edu    //If the interrupt you want to post is later than an
10579104Shestness@cs.utexas.edu    //interrupt already scheduled, just let it post in the coming one and
10588229Snate@binkert.org    //don't schedule another.
10596657Snate@binkert.org    //HOWEVER, must be sure that the scheduled intrTick is in the future
10606657Snate@binkert.org    //(this was formerly the source of a bug)
10619219Spower.jg@gmail.com    assert((intrTick >= curTick) || (intrTick == 0));
10629219Spower.jg@gmail.com    if (when > intrTick && intrTick != 0)
10639219Spower.jg@gmail.com        return;
10649219Spower.jg@gmail.com
10659219Spower.jg@gmail.com    intrTick = when;
10669219Spower.jg@gmail.com
10679219Spower.jg@gmail.com    if (intrEvent) {
10686657Snate@binkert.org        intrEvent->squash();
10697055Snate@binkert.org        intrEvent = 0;
10707055Snate@binkert.org    }
10717007Snate@binkert.org
10727007Snate@binkert.org    if (when < curTick) {
10736657Snate@binkert.org        cpuInterrupt();
10746657Snate@binkert.org    } else {
10756657Snate@binkert.org        DPRINTF(EthernetIntr, "going to schedule an interrupt for intrTick=%d\n",
10766657Snate@binkert.org                intrTick);
10776657Snate@binkert.org        intrEvent = new IntrEvent(this, true);
10786657Snate@binkert.org        intrEvent->schedule(intrTick);
10797007Snate@binkert.org    }
10807007Snate@binkert.org}
10817007Snate@binkert.org
10827007Snate@binkert.orgvoid
10839230Snilay@cs.wisc.eduNSGigE::cpuInterrupt()
10846657Snate@binkert.org{
10856657Snate@binkert.org    // Don't send an interrupt if there's already one
10866657Snate@binkert.org    if (cpuPendingIntr) {
10876657Snate@binkert.org        DPRINTF(EthernetIntr,
10886657Snate@binkert.org                "would send an interrupt now, but there's already pending\n");
10896657Snate@binkert.org        intrTick = 0;
10906657Snate@binkert.org        return;
10916657Snate@binkert.org    }
10926657Snate@binkert.org    // Don't send an interrupt if it's supposed to be delayed
10936657Snate@binkert.org    if (intrTick > curTick) {
10946657Snate@binkert.org        DPRINTF(EthernetIntr, "an interrupt is scheduled for %d, wait til then\n",
10956657Snate@binkert.org                intrTick);
10967567SBrad.Beckmann@amd.com        return;
10977567SBrad.Beckmann@amd.com    }
10987567SBrad.Beckmann@amd.com
10997567SBrad.Beckmann@amd.com    // Whether or not there's a pending interrupt, we don't care about
11006657Snate@binkert.org    // it anymore
11016657Snate@binkert.org    intrEvent = 0;
11026657Snate@binkert.org    intrTick = 0;
11036657Snate@binkert.org
11046657Snate@binkert.org    // Send interrupt
11056657Snate@binkert.org    cpuPendingIntr = true;
11066657Snate@binkert.org    /** @todo rework the intctrl to be tsunami ok */
11076657Snate@binkert.org    //intctrl->post(TheISA::INTLEVEL_IRQ1, TheISA::INTINDEX_ETHERNET);
11086657Snate@binkert.org    DPRINTF(EthernetIntr, "Posting interrupts to cchip!\n");
11096657Snate@binkert.org    tsunami->cchip->postDRIR(configData->config.hdr.pci0.interruptLine);
11106657Snate@binkert.org}
11116657Snate@binkert.org
11126657Snate@binkert.orgvoid
11136657Snate@binkert.orgNSGigE::cpuIntrClear()
11146657Snate@binkert.org{
11156657Snate@binkert.org    if (cpuPendingIntr) {
11166657Snate@binkert.org        cpuPendingIntr = false;
11176657Snate@binkert.org        /** @todo rework the intctrl to be tsunami ok */
11186999Snate@binkert.org        //intctrl->clear(TheISA::INTLEVEL_IRQ1, TheISA::INTINDEX_ETHERNET);
11196657Snate@binkert.org        DPRINTF(EthernetIntr, "clearing all interrupts from cchip\n");
11206657Snate@binkert.org        tsunami->cchip->clearDRIR(configData->config.hdr.pci0.interruptLine);
11216657Snate@binkert.org    }
11226657Snate@binkert.org}
11236657Snate@binkert.org
11246657Snate@binkert.orgbool
11257832Snate@binkert.orgNSGigE::cpuIntrPending() const
11267832Snate@binkert.org{ return cpuPendingIntr; }
11277805Snilay@cs.wisc.edu
11287832Snate@binkert.orgvoid
11298232Snate@binkert.orgNSGigE::txReset()
11308232Snate@binkert.org{
11318229Snate@binkert.org
11328229Snate@binkert.org    DPRINTF(Ethernet, "transmit reset\n");
11338229Snate@binkert.org
11348229Snate@binkert.org    CTDD = false;
11356657Snate@binkert.org    txFifoAvail = maxTxFifoSize;
11366657Snate@binkert.org    txHalt = false;
11376657Snate@binkert.org    txFragPtr = 0;
11386657Snate@binkert.org    assert(txDescCnt == 0);
11396657Snate@binkert.org    txFifo.clear();
11406657Snate@binkert.org    regs.command &= ~CR_TXE;
11416657Snate@binkert.org    txState = txIdle;
11426657Snate@binkert.org    assert(txDmaState == dmaIdle);
11437007Snate@binkert.org}
11447007Snate@binkert.org
11457839Snilay@cs.wisc.eduvoid
11467839Snilay@cs.wisc.eduNSGigE::rxReset()
11477839Snilay@cs.wisc.edu{
11487839Snilay@cs.wisc.edu    DPRINTF(Ethernet, "receive reset\n");
11497839Snilay@cs.wisc.edu
11507839Snilay@cs.wisc.edu    CRDD = false;
11517839Snilay@cs.wisc.edu    assert(rxPktBytes == 0);
11527839Snilay@cs.wisc.edu    rxFifoCnt = 0;
11537839Snilay@cs.wisc.edu    rxHalt = false;
11547839Snilay@cs.wisc.edu    rxFragPtr = 0;
11557007Snate@binkert.org    assert(rxDescCnt == 0);
11566657Snate@binkert.org    assert(rxDmaState == dmaIdle);
11577839Snilay@cs.wisc.edu    rxFifo.clear();
11587839Snilay@cs.wisc.edu    regs.command &= ~CR_RXE;
11598337Snilay@cs.wisc.edu    rxState = rxIdle;
11607839Snilay@cs.wisc.edu}
11618337Snilay@cs.wisc.edu
11627839Snilay@cs.wisc.eduvoid NSGigE::regsReset()
11638337Snilay@cs.wisc.edu{
11647839Snilay@cs.wisc.edu    memset(&regs, 0, sizeof(regs));
11658337Snilay@cs.wisc.edu    regs.config = 0x80000000;
11667839Snilay@cs.wisc.edu    regs.mear = 0x12;
11677839Snilay@cs.wisc.edu    regs.isr = 0x00608000;
11686657Snate@binkert.org    regs.txcfg = 0x120;
11696657Snate@binkert.org    regs.rxcfg = 0x4;
11707780Snilay@cs.wisc.edu    regs.srr = 0x0103;
11719171Snilay@cs.wisc.edu    regs.mibc = 0x2;
11729171Snilay@cs.wisc.edu    regs.vdr = 0x81;
11736657Snate@binkert.org    regs.tesr = 0xc000;
11747007Snate@binkert.org
11757839Snilay@cs.wisc.edu    extstsEnable = false;
11767839Snilay@cs.wisc.edu    acceptBroadcast = false;
11777839Snilay@cs.wisc.edu    acceptMulticast = false;
11787839Snilay@cs.wisc.edu    acceptUnicast = false;
11797839Snilay@cs.wisc.edu    acceptPerfect = false;
11807839Snilay@cs.wisc.edu    acceptArp = false;
11817839Snilay@cs.wisc.edu}
11827839Snilay@cs.wisc.edu
11837839Snilay@cs.wisc.eduvoid
11846657Snate@binkert.orgNSGigE::rxDmaReadCopy()
11857839Snilay@cs.wisc.edu{
11866657Snate@binkert.org    assert(rxDmaState == dmaReading);
11877780Snilay@cs.wisc.edu
11887780Snilay@cs.wisc.edu    memcpy(rxDmaData, physmem->dma_addr(rxDmaAddr, rxDmaLen), rxDmaLen);
11897542SBrad.Beckmann@amd.com    rxDmaState = dmaIdle;
11908266Sksewell@umich.edu
11918266Sksewell@umich.edu    DPRINTF(EthernetDMA, "rx dma read  paddr=%#x len=%d\n",
11928266Sksewell@umich.edu            rxDmaAddr, rxDmaLen);
11938266Sksewell@umich.edu    DDUMP(EthernetDMA, rxDmaData, rxDmaLen);
11948266Sksewell@umich.edu}
11958266Sksewell@umich.edu
11966657Snate@binkert.orgbool
11977832Snate@binkert.orgNSGigE::doRxDmaRead()
11987839Snilay@cs.wisc.edu{
11997839Snilay@cs.wisc.edu    assert(rxDmaState == dmaIdle || rxDmaState == dmaReadWaiting);
12008337Snilay@cs.wisc.edu    rxDmaState = dmaReading;
12018341Snilay@cs.wisc.edu
12027839Snilay@cs.wisc.edu    if (dmaInterface && !rxDmaFree) {
12038337Snilay@cs.wisc.edu        if (dmaInterface->busy())
12048341Snilay@cs.wisc.edu            rxDmaState = dmaReadWaiting;
12057839Snilay@cs.wisc.edu        else
12068337Snilay@cs.wisc.edu            dmaInterface->doDMA(Read, rxDmaAddr, rxDmaLen, curTick,
12078341Snilay@cs.wisc.edu                                &rxDmaReadEvent, true);
12087839Snilay@cs.wisc.edu        return true;
12098337Snilay@cs.wisc.edu    }
12108341Snilay@cs.wisc.edu
12117839Snilay@cs.wisc.edu    if (dmaReadDelay == 0 && dmaReadFactor == 0) {
12127839Snilay@cs.wisc.edu        rxDmaReadCopy();
12136657Snate@binkert.org        return false;
12148266Sksewell@umich.edu    }
12158266Sksewell@umich.edu
12168266Sksewell@umich.edu    Tick factor = ((rxDmaLen + ULL(63)) >> ULL(6)) * dmaReadFactor;
12178266Sksewell@umich.edu    Tick start = curTick + dmaReadDelay + factor;
12188266Sksewell@umich.edu    rxDmaReadEvent.schedule(start);
12198266Sksewell@umich.edu    return true;
12206657Snate@binkert.org}
12217780Snilay@cs.wisc.edu
12228266Sksewell@umich.eduvoid
12238266Sksewell@umich.eduNSGigE::rxDmaReadDone()
12248266Sksewell@umich.edu{
12258266Sksewell@umich.edu    assert(rxDmaState == dmaReading);
12268266Sksewell@umich.edu    rxDmaReadCopy();
12278266Sksewell@umich.edu
12286657Snate@binkert.org    // If the transmit state machine has a pending DMA, let it go first
12296657Snate@binkert.org    if (txDmaState == dmaReadWaiting || txDmaState == dmaWriteWaiting)
12306657Snate@binkert.org        txKick();
12316657Snate@binkert.org
12326657Snate@binkert.org    rxKick();
12337007Snate@binkert.org}
12347007Snate@binkert.org
12357007Snate@binkert.orgvoid
12367007Snate@binkert.orgNSGigE::rxDmaWriteCopy()
12377839Snilay@cs.wisc.edu{
12387839Snilay@cs.wisc.edu    assert(rxDmaState == dmaWriting);
12397839Snilay@cs.wisc.edu
12407839Snilay@cs.wisc.edu    memcpy(physmem->dma_addr(rxDmaAddr, rxDmaLen), rxDmaData, rxDmaLen);
12417839Snilay@cs.wisc.edu    rxDmaState = dmaIdle;
12427839Snilay@cs.wisc.edu
12437839Snilay@cs.wisc.edu    DPRINTF(EthernetDMA, "rx dma write paddr=%#x len=%d\n",
12447839Snilay@cs.wisc.edu            rxDmaAddr, rxDmaLen);
12457839Snilay@cs.wisc.edu    DDUMP(EthernetDMA, rxDmaData, rxDmaLen);
12467839Snilay@cs.wisc.edu}
12477839Snilay@cs.wisc.edu
12487007Snate@binkert.orgbool
12496657Snate@binkert.orgNSGigE::doRxDmaWrite()
12506657Snate@binkert.org{
12516657Snate@binkert.org    assert(rxDmaState == dmaIdle || rxDmaState == dmaWriteWaiting);
12526657Snate@binkert.org    rxDmaState = dmaWriting;
12536657Snate@binkert.org
12546657Snate@binkert.org    if (dmaInterface && !rxDmaFree) {
12556657Snate@binkert.org        if (dmaInterface->busy())
12566657Snate@binkert.org            rxDmaState = dmaWriteWaiting;
12576657Snate@binkert.org        else
12586657Snate@binkert.org            dmaInterface->doDMA(WriteInvalidate, rxDmaAddr, rxDmaLen, curTick,
12596657Snate@binkert.org                                &rxDmaWriteEvent, true);
12606999Snate@binkert.org        return true;
12616657Snate@binkert.org    }
12626657Snate@binkert.org
12636657Snate@binkert.org    if (dmaWriteDelay == 0 && dmaWriteFactor == 0) {
12646657Snate@binkert.org        rxDmaWriteCopy();
12656657Snate@binkert.org        return false;
12666657Snate@binkert.org    }
12679104Shestness@cs.utexas.edu
12686657Snate@binkert.org    Tick factor = ((rxDmaLen + ULL(63)) >> ULL(6)) * dmaWriteFactor;
12696657Snate@binkert.org    Tick start = curTick + dmaWriteDelay + factor;
12706657Snate@binkert.org    rxDmaWriteEvent.schedule(start);
12716657Snate@binkert.org    return true;
12726657Snate@binkert.org}
12736657Snate@binkert.org
12746657Snate@binkert.orgvoid
12757007Snate@binkert.orgNSGigE::rxDmaWriteDone()
12766657Snate@binkert.org{
12776657Snate@binkert.org    assert(rxDmaState == dmaWriting);
12786657Snate@binkert.org    rxDmaWriteCopy();
12796657Snate@binkert.org
12809105SBrad.Beckmann@amd.com    // If the transmit state machine has a pending DMA, let it go first
12819105SBrad.Beckmann@amd.com    if (txDmaState == dmaReadWaiting || txDmaState == dmaWriteWaiting)
12829105SBrad.Beckmann@amd.com        txKick();
12839105SBrad.Beckmann@amd.com
12849105SBrad.Beckmann@amd.com    rxKick();
12859105SBrad.Beckmann@amd.com}
12869105SBrad.Beckmann@amd.com
12879105SBrad.Beckmann@amd.comvoid
12886657Snate@binkert.orgNSGigE::rxKick()
12896657Snate@binkert.org{
12906657Snate@binkert.org    DPRINTF(EthernetSM, "receive kick state=%s (rxBuf.size=%d)\n",
12916657Snate@binkert.org            NsRxStateStrings[rxState], rxFifo.size());
12926657Snate@binkert.org
12936657Snate@binkert.org    if (rxKickTick > curTick) {
12946657Snate@binkert.org        DPRINTF(EthernetSM, "receive kick exiting, can't run till %d\n",
12959104Shestness@cs.utexas.edu                rxKickTick);
12969104Shestness@cs.utexas.edu        return;
12979104Shestness@cs.utexas.edu    }
12989104Shestness@cs.utexas.edu
12996657Snate@binkert.org  next:
13006657Snate@binkert.org    switch(rxDmaState) {
13016657Snate@binkert.org      case dmaReadWaiting:
13026657Snate@binkert.org        if (doRxDmaRead())
13036657Snate@binkert.org            goto exit;
13046657Snate@binkert.org        break;
13056657Snate@binkert.org      case dmaWriteWaiting:
13066657Snate@binkert.org        if (doRxDmaWrite())
13076657Snate@binkert.org            goto exit;
13086657Snate@binkert.org        break;
13097839Snilay@cs.wisc.edu      default:
13107839Snilay@cs.wisc.edu        break;
13117839Snilay@cs.wisc.edu    }
13127839Snilay@cs.wisc.edu
13137839Snilay@cs.wisc.edu    // see state machine from spec for details
13147839Snilay@cs.wisc.edu    // the way this works is, if you finish work on one state and can go directly to
13157839Snilay@cs.wisc.edu    // another, you do that through jumping to the label "next".  however, if you have
13167839Snilay@cs.wisc.edu    // intermediate work, like DMA so that you can't go to the next state yet, you go to
13177839Snilay@cs.wisc.edu    // exit and exit the loop.  however, when the DMA is done it will trigger an
13187839Snilay@cs.wisc.edu    // event and come back to this loop.
13197839Snilay@cs.wisc.edu    switch (rxState) {
13207839Snilay@cs.wisc.edu      case rxIdle:
13216657Snate@binkert.org        if (!regs.command & CR_RXE) {
13226657Snate@binkert.org            DPRINTF(EthernetSM, "Receive Disabled! Nothing to do.\n");
13236657Snate@binkert.org            goto exit;
13246657Snate@binkert.org        }
13256657Snate@binkert.org
13266657Snate@binkert.org        if (CRDD) {
13276657Snate@binkert.org            rxState = rxDescRefr;
13286657Snate@binkert.org
13296657Snate@binkert.org            rxDmaAddr = regs.rxdp & 0x3fffffff;
13306657Snate@binkert.org            rxDmaData = &rxDescCache + offsetof(ns_desc, link);
13316657Snate@binkert.org            rxDmaLen = sizeof(rxDescCache.link);
13326657Snate@binkert.org            rxDmaFree = dmaDescFree;
13336657Snate@binkert.org
13346657Snate@binkert.org            descDmaReads++;
13356657Snate@binkert.org            descDmaRdBytes += rxDmaLen;
13366657Snate@binkert.org
13376657Snate@binkert.org            if (doRxDmaRead())
13386657Snate@binkert.org                goto exit;
13396657Snate@binkert.org        } else {
13406657Snate@binkert.org            rxState = rxDescRead;
13416657Snate@binkert.org
13427805Snilay@cs.wisc.edu            rxDmaAddr = regs.rxdp & 0x3fffffff;
13438159SBrad.Beckmann@amd.com            rxDmaData = &rxDescCache;
13449171Snilay@cs.wisc.edu            rxDmaLen = sizeof(ns_desc);
13456657Snate@binkert.org            rxDmaFree = dmaDescFree;
13466657Snate@binkert.org
13476657Snate@binkert.org            descDmaReads++;
13486657Snate@binkert.org            descDmaRdBytes += rxDmaLen;
13496657Snate@binkert.org
13506657Snate@binkert.org            if (doRxDmaRead())
13517542SBrad.Beckmann@amd.com                goto exit;
13527542SBrad.Beckmann@amd.com        }
13537542SBrad.Beckmann@amd.com        break;
13547542SBrad.Beckmann@amd.com
13557542SBrad.Beckmann@amd.com      case rxDescRefr:
13567542SBrad.Beckmann@amd.com        if (rxDmaState != dmaIdle)
13577542SBrad.Beckmann@amd.com            goto exit;
13587542SBrad.Beckmann@amd.com
13597542SBrad.Beckmann@amd.com        rxState = rxAdvance;
13607542SBrad.Beckmann@amd.com        break;
13617542SBrad.Beckmann@amd.com
13627832Snate@binkert.org     case rxDescRead:
13637542SBrad.Beckmann@amd.com        if (rxDmaState != dmaIdle)
13647542SBrad.Beckmann@amd.com            goto exit;
13657542SBrad.Beckmann@amd.com
13668229Snate@binkert.org        DPRINTF(EthernetDesc,
13677542SBrad.Beckmann@amd.com                "rxDescCache:\n\tlink=%08x\n\tbufptr=%08x\n\tcmdsts=%08x\n\textsts=%08x\n"
13687542SBrad.Beckmann@amd.com                ,rxDescCache.link, rxDescCache.bufptr, rxDescCache.cmdsts,
13697542SBrad.Beckmann@amd.com                rxDescCache.extsts);
13707542SBrad.Beckmann@amd.com
13717542SBrad.Beckmann@amd.com        if (rxDescCache.cmdsts & CMDSTS_OWN) {
13727542SBrad.Beckmann@amd.com            rxState = rxIdle;
13737542SBrad.Beckmann@amd.com        } else {
13747542SBrad.Beckmann@amd.com            rxState = rxFifoBlock;
13757542SBrad.Beckmann@amd.com            rxFragPtr = rxDescCache.bufptr;
13767542SBrad.Beckmann@amd.com            rxDescCnt = rxDescCache.cmdsts & CMDSTS_LEN_MASK;
13777542SBrad.Beckmann@amd.com        }
13787542SBrad.Beckmann@amd.com        break;
13797542SBrad.Beckmann@amd.com
13807542SBrad.Beckmann@amd.com      case rxFifoBlock:
13817542SBrad.Beckmann@amd.com        if (!rxPacket) {
13827542SBrad.Beckmann@amd.com            /**
13837542SBrad.Beckmann@amd.com             * @todo in reality, we should be able to start processing
13847542SBrad.Beckmann@amd.com             * the packet as it arrives, and not have to wait for the
13857542SBrad.Beckmann@amd.com             * full packet ot be in the receive fifo.
13867542SBrad.Beckmann@amd.com             */
13877542SBrad.Beckmann@amd.com            if (rxFifo.empty())
13887542SBrad.Beckmann@amd.com                goto exit;
13897542SBrad.Beckmann@amd.com
13907542SBrad.Beckmann@amd.com            DPRINTF(EthernetSM, "\n\n*****processing receive of new packet\n");
13917542SBrad.Beckmann@amd.com
13927542SBrad.Beckmann@amd.com            // If we don't have a packet, grab a new one from the fifo.
13937542SBrad.Beckmann@amd.com            rxPacket = rxFifo.front();
13947542SBrad.Beckmann@amd.com            rxPktBytes = rxPacket->length;
13957542SBrad.Beckmann@amd.com            rxPacketBufPtr = rxPacket->data;
13967542SBrad.Beckmann@amd.com
13977542SBrad.Beckmann@amd.com            if (DTRACE(Ethernet)) {
13987542SBrad.Beckmann@amd.com                if (rxPacket->isIpPkt()) {
13997542SBrad.Beckmann@amd.com                    ip_header *ip = rxPacket->getIpHdr();
14007542SBrad.Beckmann@amd.com                    DPRINTF(Ethernet, "ID is %d\n", reverseEnd16(ip->ID));
14017542SBrad.Beckmann@amd.com                    if (rxPacket->isTcpPkt()) {
14027542SBrad.Beckmann@amd.com                        tcp_header *tcp = rxPacket->getTcpHdr(ip);
14037542SBrad.Beckmann@amd.com                        DPRINTF(Ethernet, "Src Port = %d, Dest Port = %d\n",
14047542SBrad.Beckmann@amd.com                                reverseEnd16(tcp->src_port_num),
14057542SBrad.Beckmann@amd.com                                reverseEnd16(tcp->dest_port_num));
14067542SBrad.Beckmann@amd.com                    }
14077542SBrad.Beckmann@amd.com                }
14087542SBrad.Beckmann@amd.com            }
14097542SBrad.Beckmann@amd.com
14107542SBrad.Beckmann@amd.com            // sanity check - i think the driver behaves like this
14117542SBrad.Beckmann@amd.com            assert(rxDescCnt >= rxPktBytes);
14127542SBrad.Beckmann@amd.com
14137542SBrad.Beckmann@amd.com            // Must clear the value before popping to decrement the
14147542SBrad.Beckmann@amd.com            // reference count
14157542SBrad.Beckmann@amd.com            rxFifo.front() = NULL;
14167542SBrad.Beckmann@amd.com            rxFifo.pop_front();
14177542SBrad.Beckmann@amd.com            rxFifoCnt -= rxPacket->length;
14187542SBrad.Beckmann@amd.com        }
14197542SBrad.Beckmann@amd.com
14207542SBrad.Beckmann@amd.com
14217542SBrad.Beckmann@amd.com        // dont' need the && rxDescCnt > 0 if driver sanity check above holds
14227542SBrad.Beckmann@amd.com        if (rxPktBytes > 0) {
14237542SBrad.Beckmann@amd.com            rxState = rxFragWrite;
14247542SBrad.Beckmann@amd.com            // don't need min<>(rxPktBytes,rxDescCnt) if above sanity check holds
14257542SBrad.Beckmann@amd.com            rxXferLen = rxPktBytes;
14267542SBrad.Beckmann@amd.com
14277542SBrad.Beckmann@amd.com            rxDmaAddr = rxFragPtr & 0x3fffffff;
14287542SBrad.Beckmann@amd.com            rxDmaData = rxPacketBufPtr;
14297542SBrad.Beckmann@amd.com            rxDmaLen = rxXferLen;
14307542SBrad.Beckmann@amd.com            rxDmaFree = dmaDataFree;
14317542SBrad.Beckmann@amd.com
14327542SBrad.Beckmann@amd.com            if (doRxDmaWrite())
14337542SBrad.Beckmann@amd.com                goto exit;
14347542SBrad.Beckmann@amd.com
14357542SBrad.Beckmann@amd.com        } else {
14367542SBrad.Beckmann@amd.com            rxState = rxDescWrite;
14377542SBrad.Beckmann@amd.com
14387542SBrad.Beckmann@amd.com            //if (rxPktBytes == 0) {  /* packet is done */
14397542SBrad.Beckmann@amd.com            assert(rxPktBytes == 0);
14407542SBrad.Beckmann@amd.com            DPRINTF(EthernetSM, "done with receiving packet\n");
14417542SBrad.Beckmann@amd.com
14427542SBrad.Beckmann@amd.com            rxDescCache.cmdsts |= CMDSTS_OWN;
14437542SBrad.Beckmann@amd.com            rxDescCache.cmdsts &= ~CMDSTS_MORE;
14447542SBrad.Beckmann@amd.com            rxDescCache.cmdsts |= CMDSTS_OK;
14457542SBrad.Beckmann@amd.com            rxDescCache.cmdsts &= 0xffff0000;
14467542SBrad.Beckmann@amd.com            rxDescCache.cmdsts += rxPacket->length;   //i.e. set CMDSTS_SIZE
14476657Snate@binkert.org
14486999Snate@binkert.org#if 0
14496657Snate@binkert.org            /* all the driver uses these are for its own stats keeping
14506657Snate@binkert.org               which we don't care about, aren't necessary for functionality
14516657Snate@binkert.org               and doing this would just slow us down.  if they end up using
14526657Snate@binkert.org               this in a later version for functional purposes, just undef
14536657Snate@binkert.org            */
14546657Snate@binkert.org            if (rxFilterEnable) {
14557542SBrad.Beckmann@amd.com                rxDescCache.cmdsts &= ~CMDSTS_DEST_MASK;
14567542SBrad.Beckmann@amd.com                if (rxFifo.front()->IsUnicast())
14576657Snate@binkert.org                    rxDescCache.cmdsts |= CMDSTS_DEST_SELF;
14587832Snate@binkert.org                if (rxFifo.front()->IsMulticast())
14597002Snate@binkert.org                    rxDescCache.cmdsts |= CMDSTS_DEST_MULTI;
14607002Snate@binkert.org                if (rxFifo.front()->IsBroadcast())
14618229Snate@binkert.org                    rxDescCache.cmdsts |= CMDSTS_DEST_MASK;
14628229Snate@binkert.org            }
14638608Snilay@cs.wisc.edu#endif
14646657Snate@binkert.org
14657007Snate@binkert.org            if (rxPacket->isIpPkt() && extstsEnable) {
14667007Snate@binkert.org                rxDescCache.extsts |= EXTSTS_IPPKT;
14676657Snate@binkert.org                rxIPChecksums++;
14686657Snate@binkert.org                if (!ipChecksum(rxPacket, false)) {
14696657Snate@binkert.org                    DPRINTF(EthernetCksum, "Rx IP Checksum Error\n");
14706657Snate@binkert.org                    rxDescCache.extsts |= EXTSTS_IPERR;
14716657Snate@binkert.org                }
14727542SBrad.Beckmann@amd.com                if (rxPacket->isTcpPkt()) {
14737542SBrad.Beckmann@amd.com                    rxDescCache.extsts |= EXTSTS_TCPPKT;
14747542SBrad.Beckmann@amd.com                    rxTCPChecksums++;
14756657Snate@binkert.org                    if (!tcpChecksum(rxPacket, false)) {
14766657Snate@binkert.org                        DPRINTF(EthernetCksum, "Rx TCP Checksum Error\n");
14776657Snate@binkert.org                        rxDescCache.extsts |= EXTSTS_TCPERR;
14786657Snate@binkert.org
14796657Snate@binkert.org                    }
14806657Snate@binkert.org                } else if (rxPacket->isUdpPkt()) {
14816657Snate@binkert.org                    rxDescCache.extsts |= EXTSTS_UDPPKT;
14826657Snate@binkert.org                    if (!udpChecksum(rxPacket, false)) {
14836657Snate@binkert.org                        DPRINTF(EthernetCksum, "Rx UDP Checksum Error\n");
14847007Snate@binkert.org                        rxDescCache.extsts |= EXTSTS_UDPERR;
14856657Snate@binkert.org                    }
14866657Snate@binkert.org                }
14876657Snate@binkert.org            }
14886657Snate@binkert.org            rxPacket = 0;
14896999Snate@binkert.org
14906657Snate@binkert.org            /* the driver seems to always receive into desc buffers
14916657Snate@binkert.org               of size 1514, so you never have a pkt that is split
14926657Snate@binkert.org               into multiple descriptors on the receive side, so
14936657Snate@binkert.org               i don't implement that case, hence the assert above.
14946657Snate@binkert.org            */
14956657Snate@binkert.org
14967832Snate@binkert.org            DPRINTF(EthernetDesc, "rxDesc writeback:\n\tcmdsts=%08x\n\textsts=%08x\n",
14977832Snate@binkert.org                    rxDescCache.cmdsts, rxDescCache.extsts);
14986657Snate@binkert.org
14996657Snate@binkert.org            rxDmaAddr = (regs.rxdp + offsetof(ns_desc, cmdsts)) & 0x3fffffff;
15006657Snate@binkert.org            rxDmaData = &(rxDescCache.cmdsts);
15016657Snate@binkert.org            rxDmaLen = sizeof(rxDescCache.cmdsts) + sizeof(rxDescCache.extsts);
15026657Snate@binkert.org            rxDmaFree = dmaDescFree;
15036657Snate@binkert.org
15046657Snate@binkert.org            descDmaWrites++;
15056657Snate@binkert.org            descDmaWrBytes += rxDmaLen;
15066657Snate@binkert.org
15076657Snate@binkert.org            if (doRxDmaWrite())
15086657Snate@binkert.org                goto exit;
15096657Snate@binkert.org        }
15106657Snate@binkert.org        break;
15116657Snate@binkert.org
15127007Snate@binkert.org      case rxFragWrite:
15137007Snate@binkert.org        if (rxDmaState != dmaIdle)
15147007Snate@binkert.org            goto exit;
15156657Snate@binkert.org
15166657Snate@binkert.org        rxPacketBufPtr += rxXferLen;
15176657Snate@binkert.org        rxFragPtr += rxXferLen;
15187007Snate@binkert.org        rxPktBytes -= rxXferLen;
15197007Snate@binkert.org
15207007Snate@binkert.org        rxState = rxFifoBlock;
15216657Snate@binkert.org        break;
15226657Snate@binkert.org
15236657Snate@binkert.org      case rxDescWrite:
15246657Snate@binkert.org        if (rxDmaState != dmaIdle)
15256657Snate@binkert.org            goto exit;
15266657Snate@binkert.org
15276657Snate@binkert.org        assert(rxDescCache.cmdsts & CMDSTS_OWN);
15286657Snate@binkert.org
15296657Snate@binkert.org        assert(rxPacket == 0);
15306657Snate@binkert.org        devIntrPost(ISR_RXOK);
15316657Snate@binkert.org
15327007Snate@binkert.org        if (rxDescCache.cmdsts & CMDSTS_INTR)
15337007Snate@binkert.org            devIntrPost(ISR_RXDESC);
15346657Snate@binkert.org
15356657Snate@binkert.org        if (rxHalt) {
15366657Snate@binkert.org            DPRINTF(EthernetSM, "Halting the RX state machine\n");
15376657Snate@binkert.org            rxState = rxIdle;
15386657Snate@binkert.org            rxHalt = false;
15397007Snate@binkert.org        } else
15407007Snate@binkert.org            rxState = rxAdvance;
15417007Snate@binkert.org        break;
15426657Snate@binkert.org
15436657Snate@binkert.org      case rxAdvance:
15446657Snate@binkert.org        if (rxDescCache.link == 0) {
15457007Snate@binkert.org            rxState = rxIdle;
15467542SBrad.Beckmann@amd.com            return;
15477542SBrad.Beckmann@amd.com        } else {
15486657Snate@binkert.org            rxState = rxDescRead;
15497542SBrad.Beckmann@amd.com            regs.rxdp = rxDescCache.link;
15507542SBrad.Beckmann@amd.com            CRDD = false;
15517002Snate@binkert.org
15527542SBrad.Beckmann@amd.com            rxDmaAddr = regs.rxdp & 0x3fffffff;
15537542SBrad.Beckmann@amd.com            rxDmaData = &rxDescCache;
15547542SBrad.Beckmann@amd.com            rxDmaLen = sizeof(ns_desc);
15557542SBrad.Beckmann@amd.com            rxDmaFree = dmaDescFree;
15566657Snate@binkert.org
15577542SBrad.Beckmann@amd.com            if (doRxDmaRead())
15587542SBrad.Beckmann@amd.com                goto exit;
15597542SBrad.Beckmann@amd.com        }
15607542SBrad.Beckmann@amd.com        break;
15617542SBrad.Beckmann@amd.com
15627542SBrad.Beckmann@amd.com      default:
15637542SBrad.Beckmann@amd.com        panic("Invalid rxState!");
15647542SBrad.Beckmann@amd.com    }
15656657Snate@binkert.org
15666657Snate@binkert.org
15676657Snate@binkert.org    DPRINTF(EthernetSM, "entering next rx state = %s\n",
15686657Snate@binkert.org            NsRxStateStrings[rxState]);
15696657Snate@binkert.org
15706657Snate@binkert.org    if (rxState == rxIdle) {
15717007Snate@binkert.org        regs.command &= ~CR_RXE;
15726999Snate@binkert.org        devIntrPost(ISR_RXIDLE);
15737007Snate@binkert.org        return;
15747007Snate@binkert.org    }
15757007Snate@binkert.org
15767007Snate@binkert.org    goto next;
15777007Snate@binkert.org
15787007Snate@binkert.org  exit:
15796657Snate@binkert.org    /**
15806657Snate@binkert.org     * @todo do we want to schedule a future kick?
15816657Snate@binkert.org     */
15826657Snate@binkert.org    DPRINTF(EthernetSM, "rx state machine exited state=%s\n",
15836657Snate@binkert.org            NsRxStateStrings[rxState]);
15846657Snate@binkert.org}
15856657Snate@binkert.org
15866657Snate@binkert.orgvoid
15876657Snate@binkert.orgNSGigE::transmit()
15886657Snate@binkert.org{
15896657Snate@binkert.org    if (txFifo.empty()) {
15906657Snate@binkert.org        DPRINTF(Ethernet, "nothing to transmit\n");
15916657Snate@binkert.org        return;
15926657Snate@binkert.org    }
15936657Snate@binkert.org
15946657Snate@binkert.org    DPRINTF(Ethernet, "\n\nAttempt Pkt Transmit: txFifo length = %d\n",
15956657Snate@binkert.org            maxTxFifoSize - txFifoAvail);
15966657Snate@binkert.org    if (interface->sendPacket(txFifo.front())) {
15976657Snate@binkert.org        if (DTRACE(Ethernet)) {
15986657Snate@binkert.org            if (txFifo.front()->isIpPkt()) {
15996657Snate@binkert.org                ip_header *ip = txFifo.front()->getIpHdr();
16006657Snate@binkert.org                DPRINTF(Ethernet, "ID is %d\n", reverseEnd16(ip->ID));
16016657Snate@binkert.org                if (txFifo.front()->isTcpPkt()) {
16026657Snate@binkert.org                    tcp_header *tcp = txFifo.front()->getTcpHdr(ip);
16036657Snate@binkert.org                    DPRINTF(Ethernet, "Src Port = %d, Dest Port = %d\n",
16046657Snate@binkert.org                            reverseEnd16(tcp->src_port_num),
16056657Snate@binkert.org                            reverseEnd16(tcp->dest_port_num));
16066657Snate@binkert.org                }
16076657Snate@binkert.org            }
16086999Snate@binkert.org        }
16096657Snate@binkert.org
16106657Snate@binkert.org        DDUMP(Ethernet, txFifo.front()->data, txFifo.front()->length);
16117007Snate@binkert.org        txBytes += txFifo.front()->length;
16127007Snate@binkert.org        txPackets++;
16136657Snate@binkert.org
16146657Snate@binkert.org        txFifoAvail += txFifo.front()->length;
16156657Snate@binkert.org
16166657Snate@binkert.org        DPRINTF(Ethernet, "Successful Xmit! now txFifoAvail is %d\n", txFifoAvail);
16176657Snate@binkert.org        txFifo.front() = NULL;
16186657Snate@binkert.org        txFifo.pop_front();
16196657Snate@binkert.org
16206657Snate@binkert.org        /* normally do a writeback of the descriptor here, and ONLY after that is
16216657Snate@binkert.org           done, send this interrupt.  but since our stuff never actually fails,
16226657Snate@binkert.org           just do this interrupt here, otherwise the code has to stray from this
16236657Snate@binkert.org           nice format.  besides, it's functionally the same.
16246657Snate@binkert.org        */
16256657Snate@binkert.org        devIntrPost(ISR_TXOK);
16266657Snate@binkert.org    } else
16276657Snate@binkert.org        DPRINTF(Ethernet, "May need to rethink always sending the descriptors back?\n");
16286657Snate@binkert.org
16296657Snate@binkert.org   if (!txFifo.empty() && !txEvent.scheduled()) {
16306657Snate@binkert.org       DPRINTF(Ethernet, "reschedule transmit\n");
16316657Snate@binkert.org       txEvent.schedule(curTick + 1000);
16326657Snate@binkert.org   }
16336657Snate@binkert.org}
16346657Snate@binkert.org
16356657Snate@binkert.orgvoid
16366657Snate@binkert.orgNSGigE::txDmaReadCopy()
16376657Snate@binkert.org{
16386657Snate@binkert.org    assert(txDmaState == dmaReading);
16396657Snate@binkert.org
16406657Snate@binkert.org    memcpy(txDmaData, physmem->dma_addr(txDmaAddr, txDmaLen), txDmaLen);
16416657Snate@binkert.org    txDmaState = dmaIdle;
16426657Snate@binkert.org
16436657Snate@binkert.org    DPRINTF(EthernetDMA, "tx dma read  paddr=%#x len=%d\n",
16446657Snate@binkert.org            txDmaAddr, txDmaLen);
16456657Snate@binkert.org    DDUMP(EthernetDMA, txDmaData, txDmaLen);
16466657Snate@binkert.org}
16476657Snate@binkert.org
16486657Snate@binkert.orgbool
16496657Snate@binkert.orgNSGigE::doTxDmaRead()
16506657Snate@binkert.org{
16516657Snate@binkert.org    assert(txDmaState == dmaIdle || txDmaState == dmaReadWaiting);
16526657Snate@binkert.org    txDmaState = dmaReading;
16536657Snate@binkert.org
16546657Snate@binkert.org    if (dmaInterface && !txDmaFree) {
16556657Snate@binkert.org        if (dmaInterface->busy())
16566657Snate@binkert.org            txDmaState = dmaReadWaiting;
16576657Snate@binkert.org        else
16586657Snate@binkert.org            dmaInterface->doDMA(Read, txDmaAddr, txDmaLen, curTick,
16596657Snate@binkert.org                                &txDmaReadEvent, true);
16606657Snate@binkert.org        return true;
16616657Snate@binkert.org    }
16626657Snate@binkert.org
16636657Snate@binkert.org    if (dmaReadDelay == 0 && dmaReadFactor == 0.0) {
16646657Snate@binkert.org        txDmaReadCopy();
16656657Snate@binkert.org        return false;
16666657Snate@binkert.org    }
16676657Snate@binkert.org
16686657Snate@binkert.org    Tick factor = ((txDmaLen + ULL(63)) >> ULL(6)) * dmaReadFactor;
16696657Snate@binkert.org    Tick start = curTick + dmaReadDelay + factor;
16706657Snate@binkert.org    txDmaReadEvent.schedule(start);
16716657Snate@binkert.org    return true;
16726657Snate@binkert.org}
16736657Snate@binkert.org
16746657Snate@binkert.orgvoid
16756657Snate@binkert.orgNSGigE::txDmaReadDone()
16766657Snate@binkert.org{
16776657Snate@binkert.org    assert(txDmaState == dmaReading);
16786657Snate@binkert.org    txDmaReadCopy();
16796657Snate@binkert.org
16806657Snate@binkert.org    // If the receive state machine  has a pending DMA, let it go first
16816657Snate@binkert.org    if (rxDmaState == dmaReadWaiting || rxDmaState == dmaWriteWaiting)
16826657Snate@binkert.org        rxKick();
16836657Snate@binkert.org
16846657Snate@binkert.org    txKick();
16856657Snate@binkert.org}
16866657Snate@binkert.org
16876657Snate@binkert.orgvoid
16886657Snate@binkert.orgNSGigE::txDmaWriteCopy()
16896657Snate@binkert.org{
16906657Snate@binkert.org    assert(txDmaState == dmaWriting);
16916657Snate@binkert.org
16926657Snate@binkert.org    memcpy(physmem->dma_addr(txDmaAddr, txDmaLen), txDmaData, txDmaLen);
16936657Snate@binkert.org    txDmaState = dmaIdle;
16946657Snate@binkert.org
16956657Snate@binkert.org    DPRINTF(EthernetDMA, "tx dma write paddr=%#x len=%d\n",
16966657Snate@binkert.org            txDmaAddr, txDmaLen);
16976657Snate@binkert.org    DDUMP(EthernetDMA, txDmaData, txDmaLen);
16986657Snate@binkert.org}
16996657Snate@binkert.org
17006657Snate@binkert.orgbool
17017007Snate@binkert.orgNSGigE::doTxDmaWrite()
17026657Snate@binkert.org{
17036657Snate@binkert.org    assert(txDmaState == dmaIdle || txDmaState == dmaWriteWaiting);
17046657Snate@binkert.org    txDmaState = dmaWriting;
17056657Snate@binkert.org
17066657Snate@binkert.org    if (dmaInterface && !txDmaFree) {
17076657Snate@binkert.org        if (dmaInterface->busy())
17086657Snate@binkert.org            txDmaState = dmaWriteWaiting;
17097007Snate@binkert.org        else
17106657Snate@binkert.org            dmaInterface->doDMA(WriteInvalidate, txDmaAddr, txDmaLen, curTick,
17116657Snate@binkert.org                                &txDmaWriteEvent, true);
17126657Snate@binkert.org        return true;
17136657Snate@binkert.org    }
17146657Snate@binkert.org
17156657Snate@binkert.org    if (dmaWriteDelay == 0 && dmaWriteFactor == 0.0) {
17166657Snate@binkert.org        txDmaWriteCopy();
17176657Snate@binkert.org        return false;
17186657Snate@binkert.org    }
17196657Snate@binkert.org
17206657Snate@binkert.org    Tick factor = ((txDmaLen + ULL(63)) >> ULL(6)) * dmaWriteFactor;
17216657Snate@binkert.org    Tick start = curTick + dmaWriteDelay + factor;
17226657Snate@binkert.org    txDmaWriteEvent.schedule(start);
17236657Snate@binkert.org    return true;
17246657Snate@binkert.org}
17257007Snate@binkert.org
17266657Snate@binkert.orgvoid
17276657Snate@binkert.orgNSGigE::txDmaWriteDone()
17286657Snate@binkert.org{
17296657Snate@binkert.org    assert(txDmaState == dmaWriting);
17306657Snate@binkert.org    txDmaWriteCopy();
17316657Snate@binkert.org
17326657Snate@binkert.org    // If the receive state machine  has a pending DMA, let it go first
17336657Snate@binkert.org    if (rxDmaState == dmaReadWaiting || rxDmaState == dmaWriteWaiting)
17346657Snate@binkert.org        rxKick();
17356657Snate@binkert.org
17366657Snate@binkert.org    txKick();
17376657Snate@binkert.org}
17386657Snate@binkert.org
17396657Snate@binkert.orgvoid
17406657Snate@binkert.orgNSGigE::txKick()
17416657Snate@binkert.org{
17426657Snate@binkert.org    DPRINTF(EthernetSM, "transmit kick state=%s\n", NsTxStateStrings[txState]);
17436657Snate@binkert.org
17446657Snate@binkert.org    if (txKickTick > curTick) {
17456657Snate@binkert.org        DPRINTF(EthernetSM, "transmit kick exiting, can't run till %d\n",
17466657Snate@binkert.org                txKickTick);
17476657Snate@binkert.org
1748        return;
1749    }
1750
1751  next:
1752    switch(txDmaState) {
1753      case dmaReadWaiting:
1754        if (doTxDmaRead())
1755            goto exit;
1756        break;
1757      case dmaWriteWaiting:
1758        if (doTxDmaWrite())
1759            goto exit;
1760        break;
1761      default:
1762        break;
1763    }
1764
1765    switch (txState) {
1766      case txIdle:
1767        if (!regs.command & CR_TXE) {
1768            DPRINTF(EthernetSM, "Transmit disabled.  Nothing to do.\n");
1769            goto exit;
1770        }
1771
1772        if (CTDD) {
1773            txState = txDescRefr;
1774
1775            txDmaAddr = regs.txdp & 0x3fffffff;
1776            txDmaData = &txDescCache + offsetof(ns_desc, link);
1777            txDmaLen = sizeof(txDescCache.link);
1778            txDmaFree = dmaDescFree;
1779
1780            descDmaReads++;
1781            descDmaRdBytes += txDmaLen;
1782
1783            if (doTxDmaRead())
1784                goto exit;
1785
1786        } else {
1787            txState = txDescRead;
1788
1789            txDmaAddr = regs.txdp & 0x3fffffff;
1790            txDmaData = &txDescCache;
1791            txDmaLen = sizeof(ns_desc);
1792            txDmaFree = dmaDescFree;
1793
1794            descDmaReads++;
1795            descDmaRdBytes += txDmaLen;
1796
1797            if (doTxDmaRead())
1798                goto exit;
1799        }
1800        break;
1801
1802      case txDescRefr:
1803        if (txDmaState != dmaIdle)
1804            goto exit;
1805
1806        txState = txAdvance;
1807        break;
1808
1809      case txDescRead:
1810        if (txDmaState != dmaIdle)
1811            goto exit;
1812
1813        DPRINTF(EthernetDesc,
1814                "txDescCache data:\n\tlink=%08x\n\tbufptr=%08x\n\tcmdsts=%08x\n\textsts=%08x\n"
1815                ,txDescCache.link, txDescCache.bufptr, txDescCache.cmdsts,
1816                txDescCache.extsts);
1817
1818        if (txDescCache.cmdsts & CMDSTS_OWN) {
1819            txState = txFifoBlock;
1820            txFragPtr = txDescCache.bufptr;
1821            txDescCnt = txDescCache.cmdsts & CMDSTS_LEN_MASK;
1822        } else {
1823            txState = txIdle;
1824        }
1825        break;
1826
1827      case txFifoBlock:
1828        if (!txPacket) {
1829            DPRINTF(EthernetSM, "\n\n*****starting the tx of a new packet\n");
1830            txPacket = new EtherPacket;
1831            txPacket->data = new uint8_t[16384];
1832            txPacketBufPtr = txPacket->data;
1833        }
1834
1835        if (txDescCnt == 0) {
1836            DPRINTF(EthernetSM, "the txDescCnt == 0, done with descriptor\n");
1837            if (txDescCache.cmdsts & CMDSTS_MORE) {
1838                DPRINTF(EthernetSM, "there are more descriptors to come\n");
1839                txState = txDescWrite;
1840
1841                txDescCache.cmdsts &= ~CMDSTS_OWN;
1842
1843                txDmaAddr = (regs.txdp + offsetof(ns_desc, cmdsts)) & 0x3fffffff;
1844                txDmaData = &(txDescCache.cmdsts);
1845                txDmaLen = sizeof(txDescCache.cmdsts);
1846                txDmaFree = dmaDescFree;
1847
1848                if (doTxDmaWrite())
1849                    goto exit;
1850
1851            } else { /* this packet is totally done */
1852                DPRINTF(EthernetSM, "This packet is done, let's wrap it up\n");
1853                /* deal with the the packet that just finished */
1854                if ((regs.vtcr & VTCR_PPCHK) && extstsEnable) {
1855                    if (txDescCache.extsts & EXTSTS_UDPPKT) {
1856                        udpChecksum(txPacket, true);
1857                    } else if (txDescCache.extsts & EXTSTS_TCPPKT) {
1858                        tcpChecksum(txPacket, true);
1859                        txTCPChecksums++;
1860                    }
1861                    if (txDescCache.extsts & EXTSTS_IPPKT) {
1862                        ipChecksum(txPacket, true);
1863                        txIPChecksums++;
1864                    }
1865                }
1866
1867                txPacket->length = txPacketBufPtr - txPacket->data;
1868                /* this is just because the receive can't handle a packet bigger
1869                   want to make sure */
1870                assert(txPacket->length <= 1514);
1871                txFifo.push_back(txPacket);
1872
1873                /* this following section is not to spec, but functionally shouldn't
1874                   be any different.  normally, the chip will wait til the transmit has
1875                   occurred before writing back the descriptor because it has to wait
1876                   to see that it was successfully transmitted to decide whether to set
1877                   CMDSTS_OK or not.  however, in the simulator since it is always
1878                   successfully transmitted, and writing it exactly to spec would
1879                   complicate the code, we just do it here
1880                */
1881
1882                txDescCache.cmdsts &= ~CMDSTS_OWN;
1883                txDescCache.cmdsts |= CMDSTS_OK;
1884
1885                DPRINTF(EthernetDesc,
1886                        "txDesc writeback:\n\tcmdsts=%08x\n\textsts=%08x\n",
1887                        txDescCache.cmdsts, txDescCache.extsts);
1888
1889                txDmaAddr = (regs.txdp + offsetof(ns_desc, cmdsts)) & 0x3fffffff;
1890                txDmaData = &(txDescCache.cmdsts);
1891                txDmaLen = sizeof(txDescCache.cmdsts) + sizeof(txDescCache.extsts);
1892                txDmaFree = dmaDescFree;
1893
1894                descDmaWrites++;
1895                descDmaWrBytes += txDmaLen;
1896
1897                transmit();
1898                txPacket = 0;
1899
1900                if (txHalt) {
1901                    DPRINTF(EthernetSM, "halting TX state machine\n");
1902                    txState = txIdle;
1903                    txHalt = false;
1904                } else
1905                    txState = txAdvance;
1906
1907                if (doTxDmaWrite())
1908                    goto exit;
1909            }
1910        } else {
1911            DPRINTF(EthernetSM, "this descriptor isn't done yet\n");
1912            if (txFifoAvail) {
1913                txState = txFragRead;
1914
1915                /* The number of bytes transferred is either whatever is left
1916                   in the descriptor (txDescCnt), or if there is not enough
1917                   room in the fifo, just whatever room is left in the fifo
1918                */
1919                txXferLen = min<uint32_t>(txDescCnt, txFifoAvail);
1920
1921                txDmaAddr = txFragPtr & 0x3fffffff;
1922                txDmaData = txPacketBufPtr;
1923                txDmaLen = txXferLen;
1924                txDmaFree = dmaDataFree;
1925
1926                if (doTxDmaRead())
1927                    goto exit;
1928            } else {
1929                txState = txFifoBlock;
1930                transmit();
1931
1932                goto exit;
1933            }
1934
1935        }
1936        break;
1937
1938      case txFragRead:
1939        if (txDmaState != dmaIdle)
1940            goto exit;
1941
1942        txPacketBufPtr += txXferLen;
1943        txFragPtr += txXferLen;
1944        txDescCnt -= txXferLen;
1945        txFifoAvail -= txXferLen;
1946
1947        txState = txFifoBlock;
1948        break;
1949
1950      case txDescWrite:
1951        if (txDmaState != dmaIdle)
1952            goto exit;
1953
1954        if (txDescCache.cmdsts & CMDSTS_INTR) {
1955            devIntrPost(ISR_TXDESC);
1956        }
1957
1958        txState = txAdvance;
1959        break;
1960
1961      case txAdvance:
1962        if (txDescCache.link == 0) {
1963            txState = txIdle;
1964        } else {
1965            txState = txDescRead;
1966            regs.txdp = txDescCache.link;
1967            CTDD = false;
1968
1969            txDmaAddr = txDescCache.link & 0x3fffffff;
1970            txDmaData = &txDescCache;
1971            txDmaLen = sizeof(ns_desc);
1972            txDmaFree = dmaDescFree;
1973
1974            if (doTxDmaRead())
1975                goto exit;
1976        }
1977        break;
1978
1979      default:
1980        panic("invalid state");
1981    }
1982
1983    DPRINTF(EthernetSM, "entering next tx state=%s\n",
1984            NsTxStateStrings[txState]);
1985
1986    if (txState == txIdle) {
1987        regs.command &= ~CR_TXE;
1988        devIntrPost(ISR_TXIDLE);
1989        return;
1990    }
1991
1992    goto next;
1993
1994  exit:
1995    /**
1996     * @todo do we want to schedule a future kick?
1997     */
1998    DPRINTF(EthernetSM, "tx state machine exited state=%s\n",
1999            NsTxStateStrings[txState]);
2000}
2001
2002void
2003NSGigE::transferDone()
2004{
2005    if (txFifo.empty())
2006        return;
2007
2008    if (txEvent.scheduled())
2009        txEvent.reschedule(curTick + 1);
2010    else
2011        txEvent.schedule(curTick + 1);
2012}
2013
2014bool
2015NSGigE::rxFilter(PacketPtr packet)
2016{
2017    bool drop = true;
2018    string type;
2019
2020    if (packet->IsUnicast()) {
2021        type = "unicast";
2022
2023        // If we're accepting all unicast addresses
2024        if (acceptUnicast)
2025            drop = false;
2026
2027        // If we make a perfect match
2028        if ((acceptPerfect)
2029            && (memcmp(rom.perfectMatch, packet->data, sizeof(rom.perfectMatch)) == 0))
2030            drop = false;
2031
2032        eth_header *eth = (eth_header *) packet->data;
2033        if ((acceptArp) && (eth->type == 0x608))
2034            drop = false;
2035
2036    } else if (packet->IsBroadcast()) {
2037        type = "broadcast";
2038
2039        // if we're accepting broadcasts
2040        if (acceptBroadcast)
2041            drop = false;
2042
2043    } else if (packet->IsMulticast()) {
2044        type = "multicast";
2045
2046        // if we're accepting all multicasts
2047        if (acceptMulticast)
2048            drop = false;
2049
2050    } else {
2051        type = "unknown";
2052
2053        // oh well, punt on this one
2054    }
2055
2056    if (drop) {
2057        DPRINTF(Ethernet, "rxFilter drop\n");
2058        DDUMP(EthernetData, packet->data, packet->length);
2059    }
2060
2061    return drop;
2062}
2063
2064bool
2065NSGigE::recvPacket(PacketPtr packet)
2066{
2067    rxBytes += packet->length;
2068    rxPackets++;
2069
2070    DPRINTF(Ethernet, "\n\nReceiving packet from wire, rxFifoAvail = %d\n", maxRxFifoSize - rxFifoCnt);
2071
2072    if (rxState == rxIdle) {
2073        DPRINTF(Ethernet, "receive disabled...packet dropped\n");
2074        interface->recvDone();
2075        return true;
2076    }
2077
2078    if (rxFilterEnable && rxFilter(packet)) {
2079        DPRINTF(Ethernet, "packet filtered...dropped\n");
2080        interface->recvDone();
2081        return true;
2082    }
2083
2084    if ((rxFifoCnt + packet->length) >= maxRxFifoSize) {
2085        DPRINTF(Ethernet,
2086                "packet will not fit in receive buffer...packet dropped\n");
2087        devIntrPost(ISR_RXORN);
2088        return false;
2089    }
2090
2091    rxFifo.push_back(packet);
2092    rxFifoCnt += packet->length;
2093    interface->recvDone();
2094
2095    rxKick();
2096    return true;
2097}
2098
2099/**
2100 * does a udp checksum.  if gen is true, then it generates it and puts it in the right place
2101 * else, it just checks what it calculates against the value in the header in packet
2102 */
2103bool
2104NSGigE::udpChecksum(PacketPtr packet, bool gen)
2105{
2106    ip_header *ip = packet->getIpHdr();
2107    udp_header *hdr = packet->getUdpHdr(ip);
2108
2109    pseudo_header *pseudo = new pseudo_header;
2110
2111    pseudo->src_ip_addr = ip->src_ip_addr;
2112    pseudo->dest_ip_addr = ip->dest_ip_addr;
2113    pseudo->protocol = ip->protocol;
2114    pseudo->len = hdr->len;
2115
2116    uint16_t cksum = checksumCalc((uint16_t *) pseudo, (uint16_t *) hdr,
2117                                  (uint32_t) hdr->len);
2118
2119    delete pseudo;
2120    if (gen)
2121        hdr->chksum = cksum;
2122    else
2123        if (cksum != 0)
2124            return false;
2125
2126    return true;
2127}
2128
2129bool
2130NSGigE::tcpChecksum(PacketPtr packet, bool gen)
2131{
2132    ip_header *ip = packet->getIpHdr();
2133    tcp_header *hdr = packet->getTcpHdr(ip);
2134
2135    uint16_t cksum;
2136    pseudo_header *pseudo = new pseudo_header;
2137    if (!gen) {
2138        pseudo->src_ip_addr = ip->src_ip_addr;
2139        pseudo->dest_ip_addr = ip->dest_ip_addr;
2140        pseudo->protocol = reverseEnd16(ip->protocol);
2141        pseudo->len = reverseEnd16(reverseEnd16(ip->dgram_len) - (ip->vers_len & 0xf)*4);
2142
2143        cksum = checksumCalc((uint16_t *) pseudo, (uint16_t *) hdr,
2144                                  (uint32_t) reverseEnd16(pseudo->len));
2145    } else {
2146        pseudo->src_ip_addr = 0;
2147        pseudo->dest_ip_addr = 0;
2148        pseudo->protocol = hdr->chksum;
2149        pseudo->len = 0;
2150        hdr->chksum = 0;
2151        cksum = checksumCalc((uint16_t *) pseudo, (uint16_t *) hdr,
2152                             (uint32_t) (reverseEnd16(ip->dgram_len) - (ip->vers_len & 0xf)*4));
2153    }
2154
2155    delete pseudo;
2156    if (gen)
2157        hdr->chksum = cksum;
2158    else
2159        if (cksum != 0)
2160            return false;
2161
2162    return true;
2163}
2164
2165bool
2166NSGigE::ipChecksum(PacketPtr packet, bool gen)
2167{
2168    ip_header *hdr = packet->getIpHdr();
2169
2170    uint16_t cksum = checksumCalc(NULL, (uint16_t *) hdr, (hdr->vers_len & 0xf)*4);
2171
2172    if (gen) {
2173        DPRINTF(EthernetCksum, "generated checksum: %#x\n", cksum);
2174        hdr->hdr_chksum = cksum;
2175    }
2176    else
2177        if (cksum != 0)
2178            return false;
2179
2180    return true;
2181}
2182
2183uint16_t
2184NSGigE::checksumCalc(uint16_t *pseudo, uint16_t *buf, uint32_t len)
2185{
2186    uint32_t sum = 0;
2187
2188    uint16_t last_pad = 0;
2189    if (len & 1) {
2190        last_pad = buf[len/2] & 0xff;
2191        len--;
2192        sum += last_pad;
2193    }
2194
2195    if (pseudo) {
2196        sum = pseudo[0] + pseudo[1] + pseudo[2] +
2197            pseudo[3] + pseudo[4] + pseudo[5];
2198    }
2199
2200    for (int i=0; i < (len/2); ++i) {
2201        sum += buf[i];
2202    }
2203
2204    while (sum >> 16)
2205        sum = (sum >> 16) + (sum & 0xffff);
2206
2207    return ~sum;
2208}
2209
2210//=====================================================================
2211//
2212//
2213void
2214NSGigE::serialize(ostream &os)
2215{
2216    // Serialize the PciDev base class
2217    PciDev::serialize(os);
2218
2219    /*
2220     * Finalize any DMA events now.
2221     */
2222    if (rxDmaReadEvent.scheduled())
2223        rxDmaReadCopy();
2224    if (rxDmaWriteEvent.scheduled())
2225        rxDmaWriteCopy();
2226    if (txDmaReadEvent.scheduled())
2227        txDmaReadCopy();
2228    if (txDmaWriteEvent.scheduled())
2229        txDmaWriteCopy();
2230
2231    /*
2232     * Serialize the device registers
2233     */
2234    SERIALIZE_SCALAR(regs.command);
2235    SERIALIZE_SCALAR(regs.config);
2236    SERIALIZE_SCALAR(regs.mear);
2237    SERIALIZE_SCALAR(regs.ptscr);
2238    SERIALIZE_SCALAR(regs.isr);
2239    SERIALIZE_SCALAR(regs.imr);
2240    SERIALIZE_SCALAR(regs.ier);
2241    SERIALIZE_SCALAR(regs.ihr);
2242    SERIALIZE_SCALAR(regs.txdp);
2243    SERIALIZE_SCALAR(regs.txdp_hi);
2244    SERIALIZE_SCALAR(regs.txcfg);
2245    SERIALIZE_SCALAR(regs.gpior);
2246    SERIALIZE_SCALAR(regs.rxdp);
2247    SERIALIZE_SCALAR(regs.rxdp_hi);
2248    SERIALIZE_SCALAR(regs.rxcfg);
2249    SERIALIZE_SCALAR(regs.pqcr);
2250    SERIALIZE_SCALAR(regs.wcsr);
2251    SERIALIZE_SCALAR(regs.pcr);
2252    SERIALIZE_SCALAR(regs.rfcr);
2253    SERIALIZE_SCALAR(regs.rfdr);
2254    SERIALIZE_SCALAR(regs.srr);
2255    SERIALIZE_SCALAR(regs.mibc);
2256    SERIALIZE_SCALAR(regs.vrcr);
2257    SERIALIZE_SCALAR(regs.vtcr);
2258    SERIALIZE_SCALAR(regs.vdr);
2259    SERIALIZE_SCALAR(regs.ccsr);
2260    SERIALIZE_SCALAR(regs.tbicr);
2261    SERIALIZE_SCALAR(regs.tbisr);
2262    SERIALIZE_SCALAR(regs.tanar);
2263    SERIALIZE_SCALAR(regs.tanlpar);
2264    SERIALIZE_SCALAR(regs.taner);
2265    SERIALIZE_SCALAR(regs.tesr);
2266
2267    SERIALIZE_ARRAY(rom.perfectMatch, EADDR_LEN);
2268
2269    SERIALIZE_SCALAR(ioEnable);
2270
2271    /*
2272     * Serialize the data Fifos
2273     */
2274    int txNumPkts = txFifo.size();
2275    SERIALIZE_SCALAR(txNumPkts);
2276    int i = 0;
2277    pktiter_t end = txFifo.end();
2278    for (pktiter_t p = txFifo.begin(); p != end; ++p) {
2279        nameOut(os, csprintf("%s.txFifo%d", name(), i++));
2280        (*p)->serialize(os);
2281    }
2282
2283    int rxNumPkts = rxFifo.size();
2284    SERIALIZE_SCALAR(rxNumPkts);
2285    i = 0;
2286    end = rxFifo.end();
2287    for (pktiter_t p = rxFifo.begin(); p != end; ++p) {
2288        nameOut(os, csprintf("%s.rxFifo%d", name(), i++));
2289        (*p)->serialize(os);
2290    }
2291
2292    /*
2293     * Serialize the various helper variables
2294     */
2295    bool txPacketExists = txPacket;
2296    SERIALIZE_SCALAR(txPacketExists);
2297    if (txPacketExists) {
2298        nameOut(os, csprintf("%s.txPacket", name()));
2299        txPacket->serialize(os);
2300        uint32_t txPktBufPtr = (uint32_t) (txPacketBufPtr - txPacket->data);
2301        SERIALIZE_SCALAR(txPktBufPtr);
2302    }
2303
2304    bool rxPacketExists = rxPacket;
2305    SERIALIZE_SCALAR(rxPacketExists);
2306    if (rxPacketExists) {
2307        nameOut(os, csprintf("%s.rxPacket", name()));
2308        rxPacket->serialize(os);
2309        uint32_t rxPktBufPtr = (uint32_t) (rxPacketBufPtr - rxPacket->data);
2310        SERIALIZE_SCALAR(rxPktBufPtr);
2311    }
2312
2313    SERIALIZE_SCALAR(txXferLen);
2314    SERIALIZE_SCALAR(rxXferLen);
2315
2316    /*
2317     * Serialize DescCaches
2318     */
2319    SERIALIZE_SCALAR(txDescCache.link);
2320    SERIALIZE_SCALAR(txDescCache.bufptr);
2321    SERIALIZE_SCALAR(txDescCache.cmdsts);
2322    SERIALIZE_SCALAR(txDescCache.extsts);
2323    SERIALIZE_SCALAR(rxDescCache.link);
2324    SERIALIZE_SCALAR(rxDescCache.bufptr);
2325    SERIALIZE_SCALAR(rxDescCache.cmdsts);
2326    SERIALIZE_SCALAR(rxDescCache.extsts);
2327
2328    /*
2329     * Serialize tx state machine
2330     */
2331    int txState = this->txState;
2332    SERIALIZE_SCALAR(txState);
2333    SERIALIZE_SCALAR(CTDD);
2334    SERIALIZE_SCALAR(txFifoAvail);
2335    SERIALIZE_SCALAR(txHalt);
2336    SERIALIZE_SCALAR(txFragPtr);
2337    SERIALIZE_SCALAR(txDescCnt);
2338    int txDmaState = this->txDmaState;
2339    SERIALIZE_SCALAR(txDmaState);
2340
2341    /*
2342     * Serialize rx state machine
2343     */
2344    int rxState = this->rxState;
2345    SERIALIZE_SCALAR(rxState);
2346    SERIALIZE_SCALAR(CRDD);
2347    SERIALIZE_SCALAR(rxPktBytes);
2348    SERIALIZE_SCALAR(rxFifoCnt);
2349    SERIALIZE_SCALAR(rxHalt);
2350    SERIALIZE_SCALAR(rxDescCnt);
2351    int rxDmaState = this->rxDmaState;
2352    SERIALIZE_SCALAR(rxDmaState);
2353
2354    SERIALIZE_SCALAR(extstsEnable);
2355
2356    /*
2357     * If there's a pending transmit, store the time so we can
2358     * reschedule it later
2359     */
2360    Tick transmitTick = txEvent.scheduled() ? txEvent.when() - curTick : 0;
2361    SERIALIZE_SCALAR(transmitTick);
2362
2363    /*
2364     * receive address filter settings
2365     */
2366    SERIALIZE_SCALAR(rxFilterEnable);
2367    SERIALIZE_SCALAR(acceptBroadcast);
2368    SERIALIZE_SCALAR(acceptMulticast);
2369    SERIALIZE_SCALAR(acceptUnicast);
2370    SERIALIZE_SCALAR(acceptPerfect);
2371    SERIALIZE_SCALAR(acceptArp);
2372
2373    /*
2374     * Keep track of pending interrupt status.
2375     */
2376    SERIALIZE_SCALAR(intrTick);
2377    SERIALIZE_SCALAR(cpuPendingIntr);
2378    Tick intrEventTick = 0;
2379    if (intrEvent)
2380        intrEventTick = intrEvent->when();
2381    SERIALIZE_SCALAR(intrEventTick);
2382
2383}
2384
2385void
2386NSGigE::unserialize(Checkpoint *cp, const std::string &section)
2387{
2388    // Unserialize the PciDev base class
2389    PciDev::unserialize(cp, section);
2390
2391    UNSERIALIZE_SCALAR(regs.command);
2392    UNSERIALIZE_SCALAR(regs.config);
2393    UNSERIALIZE_SCALAR(regs.mear);
2394    UNSERIALIZE_SCALAR(regs.ptscr);
2395    UNSERIALIZE_SCALAR(regs.isr);
2396    UNSERIALIZE_SCALAR(regs.imr);
2397    UNSERIALIZE_SCALAR(regs.ier);
2398    UNSERIALIZE_SCALAR(regs.ihr);
2399    UNSERIALIZE_SCALAR(regs.txdp);
2400    UNSERIALIZE_SCALAR(regs.txdp_hi);
2401    UNSERIALIZE_SCALAR(regs.txcfg);
2402    UNSERIALIZE_SCALAR(regs.gpior);
2403    UNSERIALIZE_SCALAR(regs.rxdp);
2404    UNSERIALIZE_SCALAR(regs.rxdp_hi);
2405    UNSERIALIZE_SCALAR(regs.rxcfg);
2406    UNSERIALIZE_SCALAR(regs.pqcr);
2407    UNSERIALIZE_SCALAR(regs.wcsr);
2408    UNSERIALIZE_SCALAR(regs.pcr);
2409    UNSERIALIZE_SCALAR(regs.rfcr);
2410    UNSERIALIZE_SCALAR(regs.rfdr);
2411    UNSERIALIZE_SCALAR(regs.srr);
2412    UNSERIALIZE_SCALAR(regs.mibc);
2413    UNSERIALIZE_SCALAR(regs.vrcr);
2414    UNSERIALIZE_SCALAR(regs.vtcr);
2415    UNSERIALIZE_SCALAR(regs.vdr);
2416    UNSERIALIZE_SCALAR(regs.ccsr);
2417    UNSERIALIZE_SCALAR(regs.tbicr);
2418    UNSERIALIZE_SCALAR(regs.tbisr);
2419    UNSERIALIZE_SCALAR(regs.tanar);
2420    UNSERIALIZE_SCALAR(regs.tanlpar);
2421    UNSERIALIZE_SCALAR(regs.taner);
2422    UNSERIALIZE_SCALAR(regs.tesr);
2423
2424    UNSERIALIZE_ARRAY(rom.perfectMatch, EADDR_LEN);
2425
2426    UNSERIALIZE_SCALAR(ioEnable);
2427
2428    /*
2429     * unserialize the data fifos
2430     */
2431    int txNumPkts;
2432    UNSERIALIZE_SCALAR(txNumPkts);
2433    int i;
2434    for (i = 0; i < txNumPkts; ++i) {
2435        PacketPtr p = new EtherPacket;
2436        p->unserialize(cp, csprintf("%s.rxFifo%d", section, i));
2437        txFifo.push_back(p);
2438    }
2439
2440    int rxNumPkts;
2441    UNSERIALIZE_SCALAR(rxNumPkts);
2442    for (i = 0; i < rxNumPkts; ++i) {
2443        PacketPtr p = new EtherPacket;
2444        p->unserialize(cp, csprintf("%s.rxFifo%d", section, i));
2445        rxFifo.push_back(p);
2446    }
2447
2448    /*
2449     * unserialize the various helper variables
2450     */
2451    bool txPacketExists;
2452    UNSERIALIZE_SCALAR(txPacketExists);
2453    if (txPacketExists) {
2454        txPacket = new EtherPacket;
2455        txPacket->unserialize(cp, csprintf("%s.txPacket", section));
2456        uint32_t txPktBufPtr;
2457        UNSERIALIZE_SCALAR(txPktBufPtr);
2458        txPacketBufPtr = (uint8_t *) txPacket->data + txPktBufPtr;
2459    } else
2460        txPacket = 0;
2461
2462    bool rxPacketExists;
2463    UNSERIALIZE_SCALAR(rxPacketExists);
2464    rxPacket = 0;
2465    if (rxPacketExists) {
2466        rxPacket = new EtherPacket;
2467        rxPacket->unserialize(cp, csprintf("%s.rxPacket", section));
2468        uint32_t rxPktBufPtr;
2469        UNSERIALIZE_SCALAR(rxPktBufPtr);
2470        rxPacketBufPtr = (uint8_t *) rxPacket->data + rxPktBufPtr;
2471    } else
2472        rxPacket = 0;
2473
2474    UNSERIALIZE_SCALAR(txXferLen);
2475    UNSERIALIZE_SCALAR(rxXferLen);
2476
2477    /*
2478     * Unserialize DescCaches
2479     */
2480    UNSERIALIZE_SCALAR(txDescCache.link);
2481    UNSERIALIZE_SCALAR(txDescCache.bufptr);
2482    UNSERIALIZE_SCALAR(txDescCache.cmdsts);
2483    UNSERIALIZE_SCALAR(txDescCache.extsts);
2484    UNSERIALIZE_SCALAR(rxDescCache.link);
2485    UNSERIALIZE_SCALAR(rxDescCache.bufptr);
2486    UNSERIALIZE_SCALAR(rxDescCache.cmdsts);
2487    UNSERIALIZE_SCALAR(rxDescCache.extsts);
2488
2489    /*
2490     * unserialize tx state machine
2491     */
2492    int txState;
2493    UNSERIALIZE_SCALAR(txState);
2494    this->txState = (TxState) txState;
2495    UNSERIALIZE_SCALAR(CTDD);
2496    UNSERIALIZE_SCALAR(txFifoAvail);
2497    UNSERIALIZE_SCALAR(txHalt);
2498    UNSERIALIZE_SCALAR(txFragPtr);
2499    UNSERIALIZE_SCALAR(txDescCnt);
2500    int txDmaState;
2501    UNSERIALIZE_SCALAR(txDmaState);
2502    this->txDmaState = (DmaState) txDmaState;
2503
2504    /*
2505     * unserialize rx state machine
2506     */
2507    int rxState;
2508    UNSERIALIZE_SCALAR(rxState);
2509    this->rxState = (RxState) rxState;
2510    UNSERIALIZE_SCALAR(CRDD);
2511    UNSERIALIZE_SCALAR(rxPktBytes);
2512    UNSERIALIZE_SCALAR(rxFifoCnt);
2513    UNSERIALIZE_SCALAR(rxHalt);
2514    UNSERIALIZE_SCALAR(rxDescCnt);
2515    int rxDmaState;
2516    UNSERIALIZE_SCALAR(rxDmaState);
2517    this->rxDmaState = (DmaState) rxDmaState;
2518
2519    UNSERIALIZE_SCALAR(extstsEnable);
2520
2521     /*
2522     * If there's a pending transmit, reschedule it now
2523     */
2524    Tick transmitTick;
2525    UNSERIALIZE_SCALAR(transmitTick);
2526    if (transmitTick)
2527        txEvent.schedule(curTick + transmitTick);
2528
2529    /*
2530     * unserialize receive address filter settings
2531     */
2532    UNSERIALIZE_SCALAR(rxFilterEnable);
2533    UNSERIALIZE_SCALAR(acceptBroadcast);
2534    UNSERIALIZE_SCALAR(acceptMulticast);
2535    UNSERIALIZE_SCALAR(acceptUnicast);
2536    UNSERIALIZE_SCALAR(acceptPerfect);
2537    UNSERIALIZE_SCALAR(acceptArp);
2538
2539    /*
2540     * Keep track of pending interrupt status.
2541     */
2542    UNSERIALIZE_SCALAR(intrTick);
2543    UNSERIALIZE_SCALAR(cpuPendingIntr);
2544    Tick intrEventTick;
2545    UNSERIALIZE_SCALAR(intrEventTick);
2546    if (intrEventTick) {
2547        intrEvent = new IntrEvent(this, true);
2548        intrEvent->schedule(intrEventTick);
2549    }
2550
2551    /*
2552     * re-add addrRanges to bus bridges
2553     */
2554    if (pioInterface) {
2555        pioInterface->addAddrRange(BARAddrs[0], BARAddrs[0] + BARSize[0] - 1);
2556        pioInterface->addAddrRange(BARAddrs[1], BARAddrs[1] + BARSize[1] - 1);
2557    }
2558}
2559
2560Tick
2561NSGigE::cacheAccess(MemReqPtr &req)
2562{
2563    DPRINTF(EthernetPIO, "timing access to paddr=%#x (daddr=%#x)\n",
2564            req->paddr, req->paddr - addr);
2565    return curTick + pioLatency;
2566}
2567//=====================================================================
2568
2569
2570//********** helper functions******************************************
2571
2572uint16_t reverseEnd16(uint16_t num)
2573{
2574    uint16_t reverse = (num & 0xff)<<8;
2575    reverse += ((num & 0xff00) >> 8);
2576    return reverse;
2577}
2578
2579uint32_t reverseEnd32(uint32_t num)
2580{
2581    uint32_t reverse = (reverseEnd16(num & 0xffff)) << 16;
2582    reverse += reverseEnd16((uint16_t) ((num & 0xffff0000) >> 8));
2583    return reverse;
2584}
2585
2586
2587
2588//=====================================================================
2589
2590BEGIN_DECLARE_SIM_OBJECT_PARAMS(NSGigEInt)
2591
2592    SimObjectParam<EtherInt *> peer;
2593    SimObjectParam<NSGigE *> device;
2594
2595END_DECLARE_SIM_OBJECT_PARAMS(NSGigEInt)
2596
2597BEGIN_INIT_SIM_OBJECT_PARAMS(NSGigEInt)
2598
2599    INIT_PARAM_DFLT(peer, "peer interface", NULL),
2600    INIT_PARAM(device, "Ethernet device of this interface")
2601
2602END_INIT_SIM_OBJECT_PARAMS(NSGigEInt)
2603
2604CREATE_SIM_OBJECT(NSGigEInt)
2605{
2606    NSGigEInt *dev_int = new NSGigEInt(getInstanceName(), device);
2607
2608    EtherInt *p = (EtherInt *)peer;
2609    if (p) {
2610        dev_int->setPeer(p);
2611        p->setPeer(dev_int);
2612    }
2613
2614    return dev_int;
2615}
2616
2617REGISTER_SIM_OBJECT("NSGigEInt", NSGigEInt)
2618
2619
2620BEGIN_DECLARE_SIM_OBJECT_PARAMS(NSGigE)
2621
2622    Param<Tick> tx_delay;
2623    Param<Tick> rx_delay;
2624    SimObjectParam<IntrControl *> intr_ctrl;
2625    Param<Tick> intr_delay;
2626    SimObjectParam<MemoryController *> mmu;
2627    SimObjectParam<PhysicalMemory *> physmem;
2628    Param<bool> rx_filter;
2629    Param<string> hardware_address;
2630    SimObjectParam<Bus*> header_bus;
2631    SimObjectParam<Bus*> payload_bus;
2632    SimObjectParam<HierParams *> hier;
2633    Param<Tick> pio_latency;
2634    Param<bool> dma_desc_free;
2635    Param<bool> dma_data_free;
2636    Param<Tick> dma_read_delay;
2637    Param<Tick> dma_write_delay;
2638    Param<Tick> dma_read_factor;
2639    Param<Tick> dma_write_factor;
2640    SimObjectParam<PciConfigAll *> configspace;
2641    SimObjectParam<PciConfigData *> configdata;
2642    SimObjectParam<Tsunami *> tsunami;
2643    Param<uint32_t> pci_bus;
2644    Param<uint32_t> pci_dev;
2645    Param<uint32_t> pci_func;
2646    Param<uint32_t> tx_fifo_size;
2647    Param<uint32_t> rx_fifo_size;
2648
2649END_DECLARE_SIM_OBJECT_PARAMS(NSGigE)
2650
2651BEGIN_INIT_SIM_OBJECT_PARAMS(NSGigE)
2652
2653    INIT_PARAM_DFLT(tx_delay, "Transmit Delay", 1000),
2654    INIT_PARAM_DFLT(rx_delay, "Receive Delay", 1000),
2655    INIT_PARAM(intr_ctrl, "Interrupt Controller"),
2656    INIT_PARAM_DFLT(intr_delay, "Interrupt Delay in microseconds", 0),
2657    INIT_PARAM(mmu, "Memory Controller"),
2658    INIT_PARAM(physmem, "Physical Memory"),
2659    INIT_PARAM_DFLT(rx_filter, "Enable Receive Filter", true),
2660    INIT_PARAM_DFLT(hardware_address, "Ethernet Hardware Address",
2661                    "00:99:00:00:00:01"),
2662    INIT_PARAM_DFLT(header_bus, "The IO Bus to attach to for headers", NULL),
2663    INIT_PARAM_DFLT(payload_bus, "The IO Bus to attach to for payload", NULL),
2664    INIT_PARAM_DFLT(hier, "Hierarchy global variables", &defaultHierParams),
2665    INIT_PARAM_DFLT(pio_latency, "Programmed IO latency in bus cycles", 1),
2666    INIT_PARAM_DFLT(dma_desc_free, "DMA of Descriptors is free", false),
2667    INIT_PARAM_DFLT(dma_data_free, "DMA of Data is free", false),
2668    INIT_PARAM_DFLT(dma_read_delay, "fixed delay for dma reads", 0),
2669    INIT_PARAM_DFLT(dma_write_delay, "fixed delay for dma writes", 0),
2670    INIT_PARAM_DFLT(dma_read_factor, "multiplier for dma reads", 0),
2671    INIT_PARAM_DFLT(dma_write_factor, "multiplier for dma writes", 0),
2672    INIT_PARAM(configspace, "PCI Configspace"),
2673    INIT_PARAM(configdata, "PCI Config data"),
2674    INIT_PARAM(tsunami, "Tsunami"),
2675    INIT_PARAM(pci_bus, "PCI bus"),
2676    INIT_PARAM(pci_dev, "PCI device number"),
2677    INIT_PARAM(pci_func, "PCI function code"),
2678    INIT_PARAM_DFLT(tx_fifo_size, "max size in bytes of txFifo", 131072),
2679    INIT_PARAM_DFLT(rx_fifo_size, "max size in bytes of rxFifo", 131072)
2680
2681END_INIT_SIM_OBJECT_PARAMS(NSGigE)
2682
2683
2684CREATE_SIM_OBJECT(NSGigE)
2685{
2686    int eaddr[6];
2687    sscanf(((string)hardware_address).c_str(), "%x:%x:%x:%x:%x:%x",
2688           &eaddr[0], &eaddr[1], &eaddr[2], &eaddr[3], &eaddr[4], &eaddr[5]);
2689
2690    return new NSGigE(getInstanceName(), intr_ctrl, intr_delay,
2691                      physmem, tx_delay, rx_delay, mmu, hier, header_bus,
2692                      payload_bus, pio_latency, dma_desc_free, dma_data_free,
2693                      dma_read_delay, dma_write_delay, dma_read_factor,
2694                      dma_write_factor, configspace, configdata,
2695                      tsunami, pci_bus, pci_dev, pci_func, rx_filter, eaddr,
2696                      tx_fifo_size, rx_fifo_size);
2697}
2698
2699REGISTER_SIM_OBJECT("NSGigE", NSGigE)
2700