ns_gige.cc revision 1027
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>
369364Snilay@cs.wisc.edu
377055Snate@binkert.org#include "base/inet.hh"
386882SBrad.Beckmann@amd.com#include "cpu/exec_context.hh"
396882SBrad.Beckmann@amd.com#include "cpu/intr_control.hh"
408191SLisa.Hsu@amd.com#include "dev/dma.hh"
416882SBrad.Beckmann@amd.com#include "dev/etherlink.hh"
426882SBrad.Beckmann@amd.com#include "dev/ns_gige.hh"
439102SNuwan.Jayasena@amd.com#include "dev/pciconfigall.hh"
449366Snilay@cs.wisc.edu#include "dev/tsunami_cchip.hh"
459366Snilay@cs.wisc.edu#include "mem/bus/bus.hh"
466882SBrad.Beckmann@amd.com#include "mem/bus/dma_interface.hh"
476882SBrad.Beckmann@amd.com#include "mem/bus/pio_interface.hh"
486657Snate@binkert.org#include "mem/bus/pio_interface_impl.hh"
496657Snate@binkert.org#include "mem/functional_mem/memory_control.hh"
506657Snate@binkert.org#include "mem/functional_mem/physical_memory.hh"
516657Snate@binkert.org#include "sim/builder.hh"
526657Snate@binkert.org#include "sim/host.hh"
539366Snilay@cs.wisc.edu#include "sim/sim_stats.hh"
547839Snilay@cs.wisc.edu#include "targetarch/vtophys.hh"
556657Snate@binkert.org
566882SBrad.Beckmann@amd.comconst char *NsRxStateStrings[] =
576882SBrad.Beckmann@amd.com{
586882SBrad.Beckmann@amd.com    "rxIdle",
596882SBrad.Beckmann@amd.com    "rxDescRefr",
606882SBrad.Beckmann@amd.com    "rxDescRead",
616882SBrad.Beckmann@amd.com    "rxFifoBlock",
626657Snate@binkert.org    "rxFragWrite",
639366Snilay@cs.wisc.edu    "rxDescWrite",
649366Snilay@cs.wisc.edu    "rxAdvance"
656657Snate@binkert.org};
666657Snate@binkert.org
676657Snate@binkert.orgconst char *NsTxStateStrings[] =
686657Snate@binkert.org{
699104Shestness@cs.utexas.edu    "txIdle",
706657Snate@binkert.org    "txDescRefr",
716657Snate@binkert.org    "txDescRead",
726657Snate@binkert.org    "txFifoBlock",
736657Snate@binkert.org    "txFragRead",
747839Snilay@cs.wisc.edu    "txDescWrite",
757839Snilay@cs.wisc.edu    "txAdvance"
769366Snilay@cs.wisc.edu};
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
916657Snate@binkert.org// correctly
926657Snate@binkert.orguint16_t reverseEnd16(uint16_t);
936657Snate@binkert.orguint32_t reverseEnd32(uint32_t);
946657Snate@binkert.org
956657Snate@binkert.org///////////////////////////////////////////////////////////////////////
966779SBrad.Beckmann@amd.com//
976657Snate@binkert.org// NSGigE PCI Device
986657Snate@binkert.org//
996657Snate@binkert.orgNSGigE::NSGigE(const std::string &name, IntrControl *i, Tick intr_delay,
1006657Snate@binkert.org               PhysicalMemory *pmem, Tick tx_delay, Tick rx_delay,
1016657Snate@binkert.org               MemoryController *mmu, HierParams *hier, Bus *header_bus,
1026657Snate@binkert.org               Bus *payload_bus, Tick pio_latency, bool dma_desc_free,
1036657Snate@binkert.org               bool dma_data_free, Tick dma_read_delay, Tick dma_write_delay,
1046657Snate@binkert.org               Tick dma_read_factor, Tick dma_write_factor, PciConfigAll *cf,
1056657Snate@binkert.org               PciConfigData *cd, Tsunami *t, uint32_t bus, uint32_t dev,
1069104Shestness@cs.utexas.edu               uint32_t func, bool rx_filter, const int eaddr[6],
1079104Shestness@cs.utexas.edu               uint32_t tx_fifo_size, uint32_t rx_fifo_size)
1089104Shestness@cs.utexas.edu    : PciDev(name, mmu, cf, cd, bus, dev, func), tsunami(t), ioEnable(false),
1099104Shestness@cs.utexas.edu      maxTxFifoSize(tx_fifo_size), maxRxFifoSize(rx_fifo_size),
1106657Snate@binkert.org      txPacket(0), rxPacket(0), txPacketBufPtr(NULL), rxPacketBufPtr(NULL),
1116657Snate@binkert.org      txXferLen(0), rxXferLen(0), txState(txIdle), CTDD(false),
1126657Snate@binkert.org      txFifoAvail(tx_fifo_size), txHalt(false),
1136657Snate@binkert.org      txFragPtr(0), txDescCnt(0), txDmaState(dmaIdle), rxState(rxIdle),
1146657Snate@binkert.org      CRDD(false), rxPktBytes(0), rxFifoCnt(0), rxHalt(false),
1156657Snate@binkert.org      rxFragPtr(0), rxDescCnt(0), rxDmaState(dmaIdle), extstsEnable(false),
1166657Snate@binkert.org      rxDmaReadEvent(this), rxDmaWriteEvent(this),
1176657Snate@binkert.org      txDmaReadEvent(this), txDmaWriteEvent(this),
1186657Snate@binkert.org      dmaDescFree(dma_desc_free), dmaDataFree(dma_data_free),
1196657Snate@binkert.org      txDelay(tx_delay), rxDelay(rx_delay), rxKickTick(0), txKickTick(0),
1206657Snate@binkert.org      txEvent(this), rxFilterEnable(rx_filter), acceptBroadcast(false),
1216657Snate@binkert.org      acceptMulticast(false), acceptUnicast(false),
1226657Snate@binkert.org      acceptPerfect(false), acceptArp(false),
1236657Snate@binkert.org      physmem(pmem), intctrl(i), intrTick(0), cpuPendingIntr(false),
1246657Snate@binkert.org      intrEvent(0), interface(0)
1257839Snilay@cs.wisc.edu{
1267839Snilay@cs.wisc.edu    tsunami->ethernet = this;
1277839Snilay@cs.wisc.edu
1287839Snilay@cs.wisc.edu    if (header_bus) {
1297839Snilay@cs.wisc.edu        pioInterface = newPioInterface(name, hier, header_bus, this,
1307839Snilay@cs.wisc.edu                                       &NSGigE::cacheAccess);
1317839Snilay@cs.wisc.edu
1327839Snilay@cs.wisc.edu        pioLatency = pio_latency * header_bus->clockRatio;
1337839Snilay@cs.wisc.edu
1347839Snilay@cs.wisc.edu        if (payload_bus)
1357839Snilay@cs.wisc.edu            dmaInterface = new DMAInterface<Bus>(name + ".dma",
1367839Snilay@cs.wisc.edu                                                 header_bus, payload_bus, 1);
1377839Snilay@cs.wisc.edu        else
1387839Snilay@cs.wisc.edu            dmaInterface = new DMAInterface<Bus>(name + ".dma",
1397839Snilay@cs.wisc.edu                                                 header_bus, header_bus, 1);
1406657Snate@binkert.org    } else if (payload_bus) {
1416657Snate@binkert.org        pioInterface = newPioInterface(name, hier, payload_bus, this,
1426657Snate@binkert.org                                       &NSGigE::cacheAccess);
1436657Snate@binkert.org
1446657Snate@binkert.org        pioLatency = pio_latency * payload_bus->clockRatio;
1456657Snate@binkert.org
1466657Snate@binkert.org        dmaInterface = new DMAInterface<Bus>(name + ".dma", payload_bus,
1476657Snate@binkert.org                                         payload_bus, 1);
1486657Snate@binkert.org    }
1496657Snate@binkert.org
1506657Snate@binkert.org
1516657Snate@binkert.org    intrDelay = US2Ticks(intr_delay);
1526657Snate@binkert.org    dmaReadDelay = dma_read_delay;
1536657Snate@binkert.org    dmaWriteDelay = dma_write_delay;
1546657Snate@binkert.org    dmaReadFactor = dma_read_factor;
1556657Snate@binkert.org    dmaWriteFactor = dma_write_factor;
1566657Snate@binkert.org
1576657Snate@binkert.org    regsReset();
1586657Snate@binkert.org    rom.perfectMatch[0] = eaddr[0];
1596657Snate@binkert.org    rom.perfectMatch[1] = eaddr[1];
1606657Snate@binkert.org    rom.perfectMatch[2] = eaddr[2];
1616657Snate@binkert.org    rom.perfectMatch[3] = eaddr[3];
1626657Snate@binkert.org    rom.perfectMatch[4] = eaddr[4];
1636657Snate@binkert.org    rom.perfectMatch[5] = eaddr[5];
1646657Snate@binkert.org}
1656657Snate@binkert.org
1666657Snate@binkert.orgNSGigE::~NSGigE()
1676657Snate@binkert.org{}
1686657Snate@binkert.org
1696657Snate@binkert.orgvoid
1709219Spower.jg@gmail.comNSGigE::regStats()
1716877Ssteve.reinhardt@amd.com{
1726657Snate@binkert.org    txBytes
1739219Spower.jg@gmail.com        .name(name() + ".txBytes")
1746657Snate@binkert.org        .desc("Bytes Transmitted")
1759219Spower.jg@gmail.com        .prereq(txBytes)
1766657Snate@binkert.org        ;
1776657Snate@binkert.org
1787542SBrad.Beckmann@amd.com    rxBytes
1797542SBrad.Beckmann@amd.com        .name(name() + ".rxBytes")
1806657Snate@binkert.org        .desc("Bytes Received")
1816877Ssteve.reinhardt@amd.com        .prereq(rxBytes)
1826999Snate@binkert.org        ;
1836877Ssteve.reinhardt@amd.com
1846877Ssteve.reinhardt@amd.com    txPackets
1856877Ssteve.reinhardt@amd.com        .name(name() + ".txPackets")
1866877Ssteve.reinhardt@amd.com        .desc("Number of Packets Transmitted")
1876877Ssteve.reinhardt@amd.com        .prereq(txBytes)
1886877Ssteve.reinhardt@amd.com        ;
1896877Ssteve.reinhardt@amd.com
1906877Ssteve.reinhardt@amd.com    rxPackets
1916877Ssteve.reinhardt@amd.com        .name(name() + ".rxPackets")
1926877Ssteve.reinhardt@amd.com        .desc("Number of Packets Received")
1939338SAndreas.Sandberg@arm.com        .prereq(rxBytes)
1946877Ssteve.reinhardt@amd.com        ;
1956877Ssteve.reinhardt@amd.com
1966877Ssteve.reinhardt@amd.com    txIPChecksums
1976877Ssteve.reinhardt@amd.com        .name(name() + ".txIPChecksums")
1986877Ssteve.reinhardt@amd.com        .desc("Number of tx IP Checksums done by device")
1996877Ssteve.reinhardt@amd.com        .precision(0)
2006882SBrad.Beckmann@amd.com        .prereq(txBytes)
2016882SBrad.Beckmann@amd.com        ;
2026882SBrad.Beckmann@amd.com
2036882SBrad.Beckmann@amd.com    rxIPChecksums
2046882SBrad.Beckmann@amd.com        .name(name() + ".rxIPChecksums")
2056882SBrad.Beckmann@amd.com        .desc("Number of rx IP Checksums done by device")
2066882SBrad.Beckmann@amd.com        .precision(0)
2076877Ssteve.reinhardt@amd.com        .prereq(rxBytes)
2086877Ssteve.reinhardt@amd.com        ;
2096877Ssteve.reinhardt@amd.com
2106877Ssteve.reinhardt@amd.com    txTCPChecksums
2116657Snate@binkert.org        .name(name() + ".txTCPChecksums")
2126657Snate@binkert.org        .desc("Number of tx TCP Checksums done by device")
2136999Snate@binkert.org        .precision(0)
2146657Snate@binkert.org        .prereq(txBytes)
2156657Snate@binkert.org        ;
2166657Snate@binkert.org
2176657Snate@binkert.org    rxTCPChecksums
2186657Snate@binkert.org        .name(name() + ".rxTCPChecksums")
2196657Snate@binkert.org        .desc("Number of rx TCP Checksums done by device")
2207007Snate@binkert.org        .precision(0)
2216657Snate@binkert.org        .prereq(rxBytes)
2226657Snate@binkert.org        ;
2236657Snate@binkert.org
2246657Snate@binkert.org    descDmaReads
2256657Snate@binkert.org        .name(name() + ".descDMAReads")
2267007Snate@binkert.org        .desc("Number of descriptors the device read w/ DMA")
2277007Snate@binkert.org        .precision(0)
2286657Snate@binkert.org        ;
2297002Snate@binkert.org
2307002Snate@binkert.org    descDmaWrites
2317002Snate@binkert.org        .name(name() + ".descDMAWrites")
2327002Snate@binkert.org        .desc("Number of descriptors the device wrote w/ DMA")
2338229Snate@binkert.org        .precision(0)
2348229Snate@binkert.org        ;
2356657Snate@binkert.org
2366657Snate@binkert.org    descDmaRdBytes
2378229Snate@binkert.org        .name(name() + ".descDmaReadBytes")
2388229Snate@binkert.org        .desc("number of descriptor bytes read w/ DMA")
2398229Snate@binkert.org        .precision(0)
2408229Snate@binkert.org        ;
2416657Snate@binkert.org
2426657Snate@binkert.org   descDmaWrBytes
2436657Snate@binkert.org        .name(name() + ".descDmaWriteBytes")
2446657Snate@binkert.org        .desc("number of descriptor bytes write w/ DMA")
2456793SBrad.Beckmann@amd.com        .precision(0)
2466657Snate@binkert.org        ;
2476657Snate@binkert.org
2486657Snate@binkert.org
2496657Snate@binkert.org    txBandwidth
2506657Snate@binkert.org        .name(name() + ".txBandwidth")
2517002Snate@binkert.org        .desc("Transmit Bandwidth (bits/s)")
2526657Snate@binkert.org        .precision(0)
2537007Snate@binkert.org        .prereq(txBytes)
2547007Snate@binkert.org        ;
2559271Snilay@cs.wisc.edu
2566877Ssteve.reinhardt@amd.com    rxBandwidth
2576877Ssteve.reinhardt@amd.com        .name(name() + ".rxBandwidth")
2586657Snate@binkert.org        .desc("Receive Bandwidth (bits/s)")
2596877Ssteve.reinhardt@amd.com        .precision(0)
2606657Snate@binkert.org        .prereq(rxBytes)
2616657Snate@binkert.org        ;
2627002Snate@binkert.org
2637002Snate@binkert.org    txPacketRate
2647567SBrad.Beckmann@amd.com        .name(name() + ".txPPS")
2657567SBrad.Beckmann@amd.com        .desc("Packet Tranmission Rate (packets/s)")
2667922SBrad.Beckmann@amd.com        .precision(0)
2676881SBrad.Beckmann@amd.com        .prereq(txBytes)
2687002Snate@binkert.org        ;
2696657Snate@binkert.org
2707002Snate@binkert.org    rxPacketRate
2716902SBrad.Beckmann@amd.com        .name(name() + ".rxPPS")
2726863Sdrh5@cs.wisc.edu        .desc("Packet Reception Rate (packets/s)")
2736863Sdrh5@cs.wisc.edu        .precision(0)
2748683Snilay@cs.wisc.edu        .prereq(rxBytes)
2758683Snilay@cs.wisc.edu        ;
2767007Snate@binkert.org
2779302Snilay@cs.wisc.edu    txBandwidth = txBytes * Stats::constant(8) / simSeconds;
2789302Snilay@cs.wisc.edu    rxBandwidth = rxBytes * Stats::constant(8) / simSeconds;
2799302Snilay@cs.wisc.edu    txPacketRate = txPackets / simSeconds;
2806657Snate@binkert.org    rxPacketRate = rxPackets / simSeconds;
2816657Snate@binkert.org}
2826657Snate@binkert.org
2836657Snate@binkert.org/**
2846657Snate@binkert.org * This is to read the PCI general configuration registers
2856657Snate@binkert.org */
2866882SBrad.Beckmann@amd.comvoid
2876882SBrad.Beckmann@amd.comNSGigE::ReadConfig(int offset, int size, uint8_t *data)
2886882SBrad.Beckmann@amd.com{
2896882SBrad.Beckmann@amd.com    if (offset < PCI_DEVICE_SPECIFIC)
2906657Snate@binkert.org        PciDev::ReadConfig(offset, size, data);
2916657Snate@binkert.org    else
2927007Snate@binkert.org        panic("Device specific PCI config space not implemented!\n");
2937839Snilay@cs.wisc.edu}
2947839Snilay@cs.wisc.edu
2957839Snilay@cs.wisc.edu/**
2967839Snilay@cs.wisc.edu * This is to write to the PCI general configuration registers
2977839Snilay@cs.wisc.edu */
2987839Snilay@cs.wisc.eduvoid
2997839Snilay@cs.wisc.eduNSGigE::WriteConfig(int offset, int size, uint32_t data)
3007839Snilay@cs.wisc.edu{
3017839Snilay@cs.wisc.edu    if (offset < PCI_DEVICE_SPECIFIC)
3027839Snilay@cs.wisc.edu        PciDev::WriteConfig(offset, size, data);
3037839Snilay@cs.wisc.edu    else
3047839Snilay@cs.wisc.edu        panic("Device specific PCI config space not implemented!\n");
3057007Snate@binkert.org
3067007Snate@binkert.org    // Need to catch writes to BARs to update the PIO interface
3077007Snate@binkert.org    switch (offset) {
3087007Snate@binkert.org        // seems to work fine without all these PCI settings, but i
3097007Snate@binkert.org        // put in the IO to double check, an assertion will fail if we
3107839Snilay@cs.wisc.edu        // need to properly implement it
3117839Snilay@cs.wisc.edu      case PCI_COMMAND:
3127839Snilay@cs.wisc.edu        if (config.data[offset] & PCI_CMD_IOSE)
3137839Snilay@cs.wisc.edu            ioEnable = true;
3147839Snilay@cs.wisc.edu        else
3157839Snilay@cs.wisc.edu            ioEnable = false;
3167839Snilay@cs.wisc.edu
3177839Snilay@cs.wisc.edu#if 0
3187839Snilay@cs.wisc.edu        if (config.data[offset] & PCI_CMD_BME) {
3197839Snilay@cs.wisc.edu            bmEnabled = true;
3207839Snilay@cs.wisc.edu        }
3217839Snilay@cs.wisc.edu        else {
3227007Snate@binkert.org            bmEnabled = false;
3237007Snate@binkert.org        }
3247542SBrad.Beckmann@amd.com
3257542SBrad.Beckmann@amd.com        if (config.data[offset] & PCI_CMD_MSE) {
3266657Snate@binkert.org            memEnable = true;
3277007Snate@binkert.org        }
3286657Snate@binkert.org        else {
3296657Snate@binkert.org            memEnable = false;
3306657Snate@binkert.org        }
3316657Snate@binkert.org#endif
3326657Snate@binkert.org        break;
3336657Snate@binkert.org
3346657Snate@binkert.org      case PCI0_BASE_ADDR0:
3356657Snate@binkert.org        if (BARAddrs[0] != 0) {
3367839Snilay@cs.wisc.edu            if (pioInterface)
3377839Snilay@cs.wisc.edu                pioInterface->addAddrRange(BARAddrs[0],
3387839Snilay@cs.wisc.edu                                           BARAddrs[0] + BARSize[0] - 1);
3397839Snilay@cs.wisc.edu
3407839Snilay@cs.wisc.edu            BARAddrs[0] &= PA_UNCACHED_MASK;
3417839Snilay@cs.wisc.edu        }
3427839Snilay@cs.wisc.edu        break;
3437839Snilay@cs.wisc.edu      case PCI0_BASE_ADDR1:
3447839Snilay@cs.wisc.edu        if (BARAddrs[1] != 0) {
3457839Snilay@cs.wisc.edu            if (pioInterface)
3467839Snilay@cs.wisc.edu                pioInterface->addAddrRange(BARAddrs[1],
3477839Snilay@cs.wisc.edu                                           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        break;
3526657Snate@binkert.org    }
3536657Snate@binkert.org}
3546657Snate@binkert.org
3556657Snate@binkert.org/**
3567839Snilay@cs.wisc.edu * This reads the device registers, which are detailed in the NS83820
3577839Snilay@cs.wisc.edu * spec sheet
3587839Snilay@cs.wisc.edu */
3597839Snilay@cs.wisc.eduFault
3607839Snilay@cs.wisc.eduNSGigE::read(MemReqPtr &req, uint8_t *data)
3617839Snilay@cs.wisc.edu{
3627839Snilay@cs.wisc.edu    assert(ioEnable);
3637839Snilay@cs.wisc.edu
3647839Snilay@cs.wisc.edu    //The mask is to give you only the offset into the device register file
3657839Snilay@cs.wisc.edu    Addr daddr = req->paddr & 0xfff;
3667839Snilay@cs.wisc.edu    DPRINTF(EthernetPIO, "read  da=%#x pa=%#x va=%#x size=%d\n",
3677839Snilay@cs.wisc.edu            daddr, req->paddr, req->vaddr, req->size);
3687839Snilay@cs.wisc.edu
3697839Snilay@cs.wisc.edu
3707839Snilay@cs.wisc.edu    // there are some reserved registers, you can see ns_gige_reg.h and
3717839Snilay@cs.wisc.edu    // the spec sheet for details
3726657Snate@binkert.org    if (daddr > LAST && daddr <=  RESERVED) {
3736657Snate@binkert.org        panic("Accessing reserved register");
3746657Snate@binkert.org    } else if (daddr > RESERVED && daddr <= 0x3FC) {
3756657Snate@binkert.org        ReadConfig(daddr & 0xff, req->size, data);
3767007Snate@binkert.org        return No_Fault;
3776657Snate@binkert.org    } else if (daddr >= MIB_START && daddr <= MIB_END) {
3786657Snate@binkert.org        // don't implement all the MIB's.  hopefully the kernel
3799273Snilay@cs.wisc.edu        // doesn't actually DEPEND upon their values
3806657Snate@binkert.org        // MIB are just hardware stats keepers
3816657Snate@binkert.org        uint32_t &reg = *(uint32_t *) data;
3826657Snate@binkert.org        reg = 0;
3836657Snate@binkert.org        return No_Fault;
3846657Snate@binkert.org    } else if (daddr > 0x3FC)
3856657Snate@binkert.org        panic("Something is messed up!\n");
3866657Snate@binkert.org
3877007Snate@binkert.org    switch (req->size) {
3886657Snate@binkert.org      case sizeof(uint32_t):
3896657Snate@binkert.org        {
3909219Spower.jg@gmail.com            uint32_t &reg = *(uint32_t *)data;
3916657Snate@binkert.org
3926657Snate@binkert.org            switch (daddr) {
3936999Snate@binkert.org              case CR:
3946657Snate@binkert.org                reg = regs.command;
3956657Snate@binkert.org                //these are supposed to be cleared on a read
3966657Snate@binkert.org                reg &= ~(CR_RXD | CR_TXD | CR_TXR | CR_RXR);
3976657Snate@binkert.org                break;
3987007Snate@binkert.org
3996657Snate@binkert.org              case CFG:
4006657Snate@binkert.org                reg = regs.config;
4016657Snate@binkert.org                break;
4026657Snate@binkert.org
4036657Snate@binkert.org              case MEAR:
4048946Sandreas.hansson@arm.com                reg = regs.mear;
4058946Sandreas.hansson@arm.com                break;
4068946Sandreas.hansson@arm.com
4077832Snate@binkert.org              case PTSCR:
4087002Snate@binkert.org                reg = regs.ptscr;
4097002Snate@binkert.org                break;
4107002Snate@binkert.org
4118641Snate@binkert.org              case ISR:
4127056Snate@binkert.org                reg = regs.isr;
4138232Snate@binkert.org                devIntrClear(ISR_ALL);
4148232Snate@binkert.org                break;
4156657Snate@binkert.org
4168229Snate@binkert.org              case IMR:
4176657Snate@binkert.org                reg = regs.imr;
4186657Snate@binkert.org                break;
4197056Snate@binkert.org
4206657Snate@binkert.org              case IER:
4219219Spower.jg@gmail.com                reg = regs.ier;
4229219Spower.jg@gmail.com                break;
4239219Spower.jg@gmail.com
4249219Spower.jg@gmail.com              case IHR:
4259219Spower.jg@gmail.com                reg = regs.ihr;
4267002Snate@binkert.org                break;
4277002Snate@binkert.org
4286657Snate@binkert.org              case TXDP:
4296657Snate@binkert.org                reg = regs.txdp;
4306657Snate@binkert.org                break;
4316657Snate@binkert.org
4326657Snate@binkert.org              case TXDP_HI:
4336793SBrad.Beckmann@amd.com                reg = regs.txdp_hi;
4346657Snate@binkert.org                break;
4356657Snate@binkert.org
4366657Snate@binkert.org              case TXCFG:
4376657Snate@binkert.org                reg = regs.txcfg;
4386877Ssteve.reinhardt@amd.com                break;
4396877Ssteve.reinhardt@amd.com
4406877Ssteve.reinhardt@amd.com              case GPIOR:
4416877Ssteve.reinhardt@amd.com                reg = regs.gpior;
4426877Ssteve.reinhardt@amd.com                break;
4436877Ssteve.reinhardt@amd.com
4446657Snate@binkert.org              case RXDP:
4457542SBrad.Beckmann@amd.com                reg = regs.rxdp;
4466657Snate@binkert.org                break;
4477007Snate@binkert.org
4486657Snate@binkert.org              case RXDP_HI:
4496657Snate@binkert.org                reg = regs.rxdp_hi;
4507007Snate@binkert.org                break;
4516657Snate@binkert.org
4526877Ssteve.reinhardt@amd.com              case RXCFG:
4536877Ssteve.reinhardt@amd.com                reg = regs.rxcfg;
4546657Snate@binkert.org                break;
4558532SLisa.Hsu@amd.com
4566657Snate@binkert.org              case PQCR:
4577567SBrad.Beckmann@amd.com                reg = regs.pqcr;
4587567SBrad.Beckmann@amd.com                break;
4597567SBrad.Beckmann@amd.com
4607567SBrad.Beckmann@amd.com              case WCSR:
4617567SBrad.Beckmann@amd.com                reg = regs.wcsr;
4627567SBrad.Beckmann@amd.com                break;
4636657Snate@binkert.org
4646882SBrad.Beckmann@amd.com              case PCR:
4656882SBrad.Beckmann@amd.com                reg = regs.pcr;
4666882SBrad.Beckmann@amd.com                break;
4676882SBrad.Beckmann@amd.com
4686882SBrad.Beckmann@amd.com                // see the spec sheet for how RFCR and RFDR work
4696882SBrad.Beckmann@amd.com                // basically, you write to RFCR to tell the machine
4706882SBrad.Beckmann@amd.com                // what you want to do next, then you act upon RFDR,
4718189SLisa.Hsu@amd.com                // and the device will be prepared b/c of what you
4728189SLisa.Hsu@amd.com                // wrote to RFCR
4736877Ssteve.reinhardt@amd.com              case RFCR:
4748189SLisa.Hsu@amd.com                reg = regs.rfcr;
4758189SLisa.Hsu@amd.com                break;
4768189SLisa.Hsu@amd.com
4778189SLisa.Hsu@amd.com              case RFDR:
4786882SBrad.Beckmann@amd.com                switch (regs.rfcr & RFCR_RFADDR) {
4796882SBrad.Beckmann@amd.com                  case 0x000:
4806882SBrad.Beckmann@amd.com                    reg = rom.perfectMatch[1];
4816882SBrad.Beckmann@amd.com                    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;
4888189SLisa.Hsu@amd.com                  case 0x004:
4896882SBrad.Beckmann@amd.com                    reg = rom.perfectMatch[5] << 8;
4906882SBrad.Beckmann@amd.com                    reg += rom.perfectMatch[4];
4916882SBrad.Beckmann@amd.com                    break;
4928189SLisa.Hsu@amd.com                  default:
4938189SLisa.Hsu@amd.com                    panic("reading RFDR for something other than PMATCH!\n");
4948189SLisa.Hsu@amd.com                    // didn't implement other RFDR functionality b/c
4958189SLisa.Hsu@amd.com                    // driver didn't use it
4968938SLisa.Hsu@amd.com                }
4978938SLisa.Hsu@amd.com                break;
4988938SLisa.Hsu@amd.com
4998938SLisa.Hsu@amd.com              case SRR:
5008938SLisa.Hsu@amd.com                reg = regs.srr;
5018938SLisa.Hsu@amd.com                break;
5028938SLisa.Hsu@amd.com
5036888SBrad.Beckmann@amd.com              case MIBC:
5046888SBrad.Beckmann@amd.com                reg = regs.mibc;
5056888SBrad.Beckmann@amd.com                reg &= ~(MIBC_MIBS | MIBC_ACLR);
5066888SBrad.Beckmann@amd.com                break;
5076888SBrad.Beckmann@amd.com
5088189SLisa.Hsu@amd.com              case VRCR:
5096888SBrad.Beckmann@amd.com                reg = regs.vrcr;
5106888SBrad.Beckmann@amd.com                break;
5116657Snate@binkert.org
5126888SBrad.Beckmann@amd.com              case VTCR:
5136888SBrad.Beckmann@amd.com                reg = regs.vtcr;
5146888SBrad.Beckmann@amd.com                break;
5156888SBrad.Beckmann@amd.com
5166657Snate@binkert.org              case VDR:
5176657Snate@binkert.org                reg = regs.vdr;
5186657Snate@binkert.org                break;
5196657Snate@binkert.org
5206657Snate@binkert.org              case CCSR:
5216657Snate@binkert.org                reg = regs.ccsr;
5226657Snate@binkert.org                break;
5236657Snate@binkert.org
5246657Snate@binkert.org              case TBICR:
5257007Snate@binkert.org                reg = regs.tbicr;
5267007Snate@binkert.org                break;
5276657Snate@binkert.org
5287007Snate@binkert.org              case TBISR:
5297007Snate@binkert.org                reg = regs.tbisr;
5309465Snilay@cs.wisc.edu                break;
5319465Snilay@cs.wisc.edu
5327007Snate@binkert.org              case TANAR:
5336657Snate@binkert.org                reg = regs.tanar;
5346657Snate@binkert.org                break;
5356657Snate@binkert.org
5367007Snate@binkert.org              case TANLPAR:
5377542SBrad.Beckmann@amd.com                reg = regs.tanlpar;
5387542SBrad.Beckmann@amd.com                break;
5397007Snate@binkert.org
5406657Snate@binkert.org              case TANER:
5416657Snate@binkert.org                reg = regs.taner;
5426657Snate@binkert.org                break;
5436657Snate@binkert.org
5446657Snate@binkert.org              case TESR:
5456657Snate@binkert.org                reg = regs.tesr;
5466657Snate@binkert.org                break;
5476657Snate@binkert.org
5486657Snate@binkert.org              default:
5496657Snate@binkert.org                panic("reading unimplemented register: addr = %#x", daddr);
5506657Snate@binkert.org            }
5516657Snate@binkert.org
5526657Snate@binkert.org            DPRINTF(EthernetPIO, "read from %#x: data=%d data=%#x\n",
5536657Snate@binkert.org                    daddr, reg, reg);
5546657Snate@binkert.org        }
5556657Snate@binkert.org        break;
5566657Snate@binkert.org
5576657Snate@binkert.org      default:
5589273Snilay@cs.wisc.edu        panic("accessing register with invalid size: addr=%#x, size=%d",
5596657Snate@binkert.org              daddr, req->size);
5606657Snate@binkert.org    }
5616657Snate@binkert.org
5629364Snilay@cs.wisc.edu    return No_Fault;
5637007Snate@binkert.org}
5646657Snate@binkert.org
5656657Snate@binkert.orgFault
5666657Snate@binkert.orgNSGigE::write(MemReqPtr &req, const uint8_t *data)
5676657Snate@binkert.org{
5687007Snate@binkert.org    assert(ioEnable);
5696657Snate@binkert.org
5707007Snate@binkert.org    Addr daddr = req->paddr & 0xfff;
5717007Snate@binkert.org    DPRINTF(EthernetPIO, "write da=%#x pa=%#x va=%#x size=%d\n",
5726657Snate@binkert.org            daddr, req->paddr, req->vaddr, req->size);
5736657Snate@binkert.org
5746657Snate@binkert.org    if (daddr > LAST && daddr <=  RESERVED) {
5756657Snate@binkert.org        panic("Accessing reserved register");
5766657Snate@binkert.org    } else if (daddr > RESERVED && daddr <= 0x3FC) {
5776657Snate@binkert.org        WriteConfig(daddr & 0xff, req->size, *(uint32_t *)data);
5786657Snate@binkert.org        return No_Fault;
5796657Snate@binkert.org    } else if (daddr > 0x3FC)
5806657Snate@binkert.org        panic("Something is messed up!\n");
5816657Snate@binkert.org
5826657Snate@binkert.org    if (req->size == sizeof(uint32_t)) {
5836657Snate@binkert.org        uint32_t reg = *(uint32_t *)data;
5846657Snate@binkert.org        DPRINTF(EthernetPIO, "write data=%d data=%#x\n", reg, reg);
5856657Snate@binkert.org
5866657Snate@binkert.org        switch (daddr) {
5877566SBrad.Beckmann@amd.com          case CR:
5886657Snate@binkert.org            regs.command = reg;
5896657Snate@binkert.org            if ((reg & (CR_TXE | CR_TXD)) == (CR_TXE | CR_TXD)) {
5906657Snate@binkert.org                txHalt = true;
5916657Snate@binkert.org            } else if (reg & CR_TXE) {
5926657Snate@binkert.org                //the kernel is enabling the transmit machine
5938308Stushar@csail.mit.edu                if (txState == txIdle)
5946657Snate@binkert.org                    txKick();
5956657Snate@binkert.org            } else if (reg & CR_TXD) {
5966657Snate@binkert.org                txHalt = true;
5978308Stushar@csail.mit.edu            }
5986657Snate@binkert.org
5996657Snate@binkert.org            if ((reg & (CR_RXE | CR_RXD)) == (CR_RXE | CR_RXD)) {
6006657Snate@binkert.org                rxHalt = true;
6016657Snate@binkert.org            } else if (reg & CR_RXE) {
6026657Snate@binkert.org                if (rxState == rxIdle) {
6036657Snate@binkert.org                    rxKick();
6046657Snate@binkert.org                }
6056657Snate@binkert.org            } else if (reg & CR_RXD) {
6066657Snate@binkert.org                rxHalt = true;
6076657Snate@binkert.org            }
6086657Snate@binkert.org
6096657Snate@binkert.org            if (reg & CR_TXR)
6108187SLisa.Hsu@amd.com                txReset();
6116657Snate@binkert.org
6126657Snate@binkert.org            if (reg & CR_RXR)
6136657Snate@binkert.org                rxReset();
6146657Snate@binkert.org
6156657Snate@binkert.org            if (reg & CR_SWI)
6166657Snate@binkert.org                devIntrPost(ISR_SWI);
6176657Snate@binkert.org
6186657Snate@binkert.org            if (reg & CR_RST) {
6196657Snate@binkert.org                txReset();
6207454Snate@binkert.org                rxReset();
6216657Snate@binkert.org
6226657Snate@binkert.org                regsReset();
6236657Snate@binkert.org            }
6246657Snate@binkert.org            break;
6257007Snate@binkert.org
6267056Snate@binkert.org          case CFG:
6277007Snate@binkert.org            if (reg & CFG_LNKSTS ||
6287007Snate@binkert.org                reg & CFG_SPDSTS ||
6296657Snate@binkert.org                reg & CFG_DUPSTS ||
6307566SBrad.Beckmann@amd.com                reg & CFG_RESERVED ||
6317566SBrad.Beckmann@amd.com                reg & CFG_T64ADDR ||
6327566SBrad.Beckmann@amd.com                reg & CFG_PCI64_DET)
6337566SBrad.Beckmann@amd.com                panic("writing to read-only or reserved CFG bits!\n");
6347566SBrad.Beckmann@amd.com
6357566SBrad.Beckmann@amd.com            regs.config |= reg & ~(CFG_LNKSTS | CFG_SPDSTS | CFG_DUPSTS |
6369366Snilay@cs.wisc.edu                                   CFG_RESERVED | CFG_T64ADDR | CFG_PCI64_DET);
6379366Snilay@cs.wisc.edu
6389366Snilay@cs.wisc.edu// all these #if 0's are because i don't THINK the kernel needs to
6399366Snilay@cs.wisc.edu// have these implemented. if there is a problem relating to one of
6407566SBrad.Beckmann@amd.com// these, you may need to add functionality in.
6417672Snate@binkert.org#if 0
6426657Snate@binkert.org            if (reg & CFG_TBI_EN) ;
6439465Snilay@cs.wisc.edu            if (reg & CFG_MODE_1000) ;
6446657Snate@binkert.org#endif
6459465Snilay@cs.wisc.edu
6467056Snate@binkert.org            if (reg & CFG_AUTO_1000)
6479465Snilay@cs.wisc.edu                panic("CFG_AUTO_1000 not implemented!\n");
6489465Snilay@cs.wisc.edu
6496657Snate@binkert.org#if 0
6506657Snate@binkert.org            if (reg & CFG_PINT_DUPSTS ||
6517672Snate@binkert.org                reg & CFG_PINT_LNKSTS ||
6526657Snate@binkert.org                reg & CFG_PINT_SPDSTS)
6536657Snate@binkert.org                ;
6546657Snate@binkert.org
6556657Snate@binkert.org            if (reg & CFG_TMRTEST) ;
6566657Snate@binkert.org            if (reg & CFG_MRM_DIS) ;
6576657Snate@binkert.org            if (reg & CFG_MWI_DIS) ;
6586657Snate@binkert.org
6596657Snate@binkert.org            if (reg & CFG_T64ADDR)
6606657Snate@binkert.org                panic("CFG_T64ADDR is read only register!\n");
6616657Snate@binkert.org
6626657Snate@binkert.org            if (reg & CFG_PCI64_DET)
6637542SBrad.Beckmann@amd.com                panic("CFG_PCI64_DET is read only register!\n");
6646657Snate@binkert.org
6656657Snate@binkert.org            if (reg & CFG_DATA64_EN) ;
6669496Snilay@cs.wisc.edu            if (reg & CFG_M64ADDR) ;
6679496Snilay@cs.wisc.edu            if (reg & CFG_PHY_RST) ;
6689496Snilay@cs.wisc.edu            if (reg & CFG_PHY_DIS) ;
6699496Snilay@cs.wisc.edu#endif
6709496Snilay@cs.wisc.edu
6716657Snate@binkert.org            if (reg & CFG_EXTSTS_EN)
6726657Snate@binkert.org                extstsEnable = true;
6736657Snate@binkert.org            else
6746657Snate@binkert.org                extstsEnable = false;
6756657Snate@binkert.org
6766657Snate@binkert.org#if 0
6776657Snate@binkert.org              if (reg & CFG_REQALG) ;
6786657Snate@binkert.org              if (reg & CFG_SB) ;
6796657Snate@binkert.org              if (reg & CFG_POW) ;
6806657Snate@binkert.org              if (reg & CFG_EXD) ;
6816657Snate@binkert.org              if (reg & CFG_PESEL) ;
6828683Snilay@cs.wisc.edu              if (reg & CFG_BROM_DIS) ;
6838683Snilay@cs.wisc.edu              if (reg & CFG_EXT_125) ;
6848683Snilay@cs.wisc.edu              if (reg & CFG_BEM) ;
6858683Snilay@cs.wisc.edu#endif
6868683Snilay@cs.wisc.edu            break;
6878683Snilay@cs.wisc.edu
6886657Snate@binkert.org          case MEAR:
6897007Snate@binkert.org            regs.mear = reg;
6907007Snate@binkert.org            // since phy is completely faked, MEAR_MD* don't matter
6917007Snate@binkert.org            // and since the driver never uses MEAR_EE*, they don't
6926657Snate@binkert.org            // matter
6936657Snate@binkert.org#if 0
6946657Snate@binkert.org            if (reg & MEAR_EEDI) ;
6957007Snate@binkert.org            if (reg & MEAR_EEDO) ; // this one is read only
6967007Snate@binkert.org            if (reg & MEAR_EECLK) ;
6977007Snate@binkert.org            if (reg & MEAR_EESEL) ;
6986657Snate@binkert.org            if (reg & MEAR_MDIO) ;
6996657Snate@binkert.org            if (reg & MEAR_MDDIR) ;
7006657Snate@binkert.org            if (reg & MEAR_MDC) ;
7018683Snilay@cs.wisc.edu#endif
7028683Snilay@cs.wisc.edu            break;
7038683Snilay@cs.wisc.edu
7048683Snilay@cs.wisc.edu          case PTSCR:
7058683Snilay@cs.wisc.edu            regs.ptscr = reg & ~(PTSCR_RBIST_RDONLY);
7068683Snilay@cs.wisc.edu            // these control BISTs for various parts of chip - we
7077007Snate@binkert.org            // don't care or do just fake that the BIST is done
7087007Snate@binkert.org            if (reg & PTSCR_RBIST_EN)
7097007Snate@binkert.org                regs.ptscr |= PTSCR_RBIST_DONE;
7106657Snate@binkert.org            if (reg & PTSCR_EEBIST_EN)
7116657Snate@binkert.org                regs.ptscr &= ~PTSCR_EEBIST_EN;
7126657Snate@binkert.org            if (reg & PTSCR_EELOAD_EN)
7137007Snate@binkert.org                regs.ptscr &= ~PTSCR_EELOAD_EN;
7147007Snate@binkert.org            break;
7157007Snate@binkert.org
7166657Snate@binkert.org          case ISR: /* writing to the ISR has no effect */
7176657Snate@binkert.org            panic("ISR is a read only register!\n");
7186657Snate@binkert.org
7197007Snate@binkert.org          case IMR:
7207007Snate@binkert.org            regs.imr = reg;
7217007Snate@binkert.org            devIntrChangeMask();
7226657Snate@binkert.org            break;
7236657Snate@binkert.org
7247007Snate@binkert.org          case IER:
7257007Snate@binkert.org            regs.ier = reg;
7267567SBrad.Beckmann@amd.com            break;
7277567SBrad.Beckmann@amd.com
7287567SBrad.Beckmann@amd.com          case IHR:
7297567SBrad.Beckmann@amd.com            regs.ihr = reg;
7307567SBrad.Beckmann@amd.com            /* not going to implement real interrupt holdoff */
7317567SBrad.Beckmann@amd.com            break;
7327567SBrad.Beckmann@amd.com
7337567SBrad.Beckmann@amd.com          case TXDP:
7347567SBrad.Beckmann@amd.com            regs.txdp = (reg & 0xFFFFFFFC);
7357567SBrad.Beckmann@amd.com            assert(txState == txIdle);
7367567SBrad.Beckmann@amd.com            CTDD = false;
7377567SBrad.Beckmann@amd.com            break;
7387567SBrad.Beckmann@amd.com
7398155Snilay@cs.wisc.edu          case TXDP_HI:
7408155Snilay@cs.wisc.edu            regs.txdp_hi = reg;
7418155Snilay@cs.wisc.edu            break;
7428155Snilay@cs.wisc.edu
7438155Snilay@cs.wisc.edu          case TXCFG:
7448155Snilay@cs.wisc.edu            regs.txcfg = reg;
7458155Snilay@cs.wisc.edu#if 0
7468155Snilay@cs.wisc.edu            if (reg & TXCFG_CSI) ;
7478155Snilay@cs.wisc.edu            if (reg & TXCFG_HBI) ;
7488155Snilay@cs.wisc.edu            if (reg & TXCFG_MLB) ;
7498155Snilay@cs.wisc.edu            if (reg & TXCFG_ATP) ;
7507567SBrad.Beckmann@amd.com            if (reg & TXCFG_ECRETRY) {
7518155Snilay@cs.wisc.edu                /*
7528155Snilay@cs.wisc.edu                 * this could easily be implemented, but considering
7537567SBrad.Beckmann@amd.com                 * the network is just a fake pipe, wouldn't make
7547567SBrad.Beckmann@amd.com                 * sense to do this
7557567SBrad.Beckmann@amd.com                 */
7567567SBrad.Beckmann@amd.com            }
7577922SBrad.Beckmann@amd.com
7587922SBrad.Beckmann@amd.com            if (reg & TXCFG_BRST_DIS) ;
7597922SBrad.Beckmann@amd.com#endif
7607922SBrad.Beckmann@amd.com
7617922SBrad.Beckmann@amd.com#if 0
7627922SBrad.Beckmann@amd.com            /* we handle our own DMA, ignore the kernel's exhortations */
7637922SBrad.Beckmann@amd.com            if (reg & TXCFG_MXDMA) ;
7647922SBrad.Beckmann@amd.com#endif
7658154Snilay@cs.wisc.edu
7668154Snilay@cs.wisc.edu            // also, we currently don't care about fill/drain
7678154Snilay@cs.wisc.edu            // thresholds though this may change in the future with
7688154Snilay@cs.wisc.edu            // more realistic networks or a driver which changes it
7698154Snilay@cs.wisc.edu            // according to feedback
7708154Snilay@cs.wisc.edu
7718154Snilay@cs.wisc.edu            break;
7728154Snilay@cs.wisc.edu
7738154Snilay@cs.wisc.edu          case GPIOR:
7748154Snilay@cs.wisc.edu            regs.gpior = reg;
7758154Snilay@cs.wisc.edu            /* these just control general purpose i/o pins, don't matter */
7768154Snilay@cs.wisc.edu            break;
7778154Snilay@cs.wisc.edu
7788154Snilay@cs.wisc.edu          case RXDP:
7798154Snilay@cs.wisc.edu            regs.rxdp = reg;
7808154Snilay@cs.wisc.edu            break;
7818154Snilay@cs.wisc.edu
7828154Snilay@cs.wisc.edu          case RXDP_HI:
7838154Snilay@cs.wisc.edu            regs.rxdp_hi = reg;
7848154Snilay@cs.wisc.edu            break;
7858154Snilay@cs.wisc.edu
7867922SBrad.Beckmann@amd.com          case RXCFG:
7877922SBrad.Beckmann@amd.com            regs.rxcfg = reg;
7887922SBrad.Beckmann@amd.com#if 0
7897922SBrad.Beckmann@amd.com            if (reg & RXCFG_AEP) ;
7907007Snate@binkert.org            if (reg & RXCFG_ARP) ;
7917007Snate@binkert.org            if (reg & RXCFG_STRIPCRC) ;
7926863Sdrh5@cs.wisc.edu            if (reg & RXCFG_RX_RD) ;
7936863Sdrh5@cs.wisc.edu            if (reg & RXCFG_ALP) ;
7946863Sdrh5@cs.wisc.edu            if (reg & RXCFG_AIRL) ;
7957007Snate@binkert.org
7967007Snate@binkert.org            /* we handle our own DMA, ignore what kernel says about it */
7977007Snate@binkert.org            if (reg & RXCFG_MXDMA) ;
7987007Snate@binkert.org
7996863Sdrh5@cs.wisc.edu            //also, we currently don't care about fill/drain thresholds
8006863Sdrh5@cs.wisc.edu            //though this may change in the future with more realistic
8016863Sdrh5@cs.wisc.edu            //networks or a driver which changes it according to feedback
8026863Sdrh5@cs.wisc.edu            if (reg & (RXCFG_DRTH | RXCFG_DRTH0)) ;
8036863Sdrh5@cs.wisc.edu#endif
8046863Sdrh5@cs.wisc.edu            break;
8057007Snate@binkert.org
8067007Snate@binkert.org          case PQCR:
8077007Snate@binkert.org            /* there is no priority queueing used in the linux 2.6 driver */
8087007Snate@binkert.org            regs.pqcr = reg;
8097007Snate@binkert.org            break;
8106657Snate@binkert.org
8117007Snate@binkert.org          case WCSR:
8127007Snate@binkert.org            /* not going to implement wake on LAN */
8137007Snate@binkert.org            regs.wcsr = reg;
8146902SBrad.Beckmann@amd.com            break;
8156902SBrad.Beckmann@amd.com
8166902SBrad.Beckmann@amd.com          case PCR:
8176902SBrad.Beckmann@amd.com            /* not going to implement pause control */
8186902SBrad.Beckmann@amd.com            regs.pcr = reg;
8196902SBrad.Beckmann@amd.com            break;
8206902SBrad.Beckmann@amd.com
8217025SBrad.Beckmann@amd.com          case RFCR:
8226902SBrad.Beckmann@amd.com            regs.rfcr = reg;
8236902SBrad.Beckmann@amd.com
8246902SBrad.Beckmann@amd.com            rxFilterEnable = (reg & RFCR_RFEN) ? true : false;
8256902SBrad.Beckmann@amd.com            acceptBroadcast = (reg & RFCR_AAB) ? true : false;
8266902SBrad.Beckmann@amd.com            acceptMulticast = (reg & RFCR_AAM) ? true : false;
8277542SBrad.Beckmann@amd.com            acceptUnicast = (reg & RFCR_AAU) ? true : false;
8287542SBrad.Beckmann@amd.com            acceptPerfect = (reg & RFCR_APM) ? true : false;
8297542SBrad.Beckmann@amd.com            acceptArp = (reg & RFCR_AARP) ? true : false;
8306902SBrad.Beckmann@amd.com
8316902SBrad.Beckmann@amd.com#if 0
8326902SBrad.Beckmann@amd.com            if (reg & RFCR_APAT)
8336902SBrad.Beckmann@amd.com                panic("RFCR_APAT not implemented!\n");
8346902SBrad.Beckmann@amd.com#endif
8356902SBrad.Beckmann@amd.com
8366902SBrad.Beckmann@amd.com            if (reg & RFCR_MHEN || reg & RFCR_UHEN)
8376902SBrad.Beckmann@amd.com                panic("hash filtering not implemented!\n");
8386902SBrad.Beckmann@amd.com
8396902SBrad.Beckmann@amd.com            if (reg & RFCR_ULM)
8406902SBrad.Beckmann@amd.com                panic("RFCR_ULM not implemented!\n");
8416902SBrad.Beckmann@amd.com
8426902SBrad.Beckmann@amd.com            break;
8436902SBrad.Beckmann@amd.com
8446902SBrad.Beckmann@amd.com          case RFDR:
8457542SBrad.Beckmann@amd.com            panic("the driver never writes to RFDR, something is wrong!\n");
8469496Snilay@cs.wisc.edu
8476902SBrad.Beckmann@amd.com          case BRAR:
8487839Snilay@cs.wisc.edu            panic("the driver never uses BRAR, something is wrong!\n");
8497839Snilay@cs.wisc.edu
8507839Snilay@cs.wisc.edu          case BRDR:
8517839Snilay@cs.wisc.edu            panic("the driver never uses BRDR, something is wrong!\n");
8527839Snilay@cs.wisc.edu
8537839Snilay@cs.wisc.edu          case SRR:
8547839Snilay@cs.wisc.edu            panic("SRR is read only register!\n");
8557839Snilay@cs.wisc.edu
8567839Snilay@cs.wisc.edu          case MIBC:
8577839Snilay@cs.wisc.edu            panic("the driver never uses MIBC, something is wrong!\n");
8587839Snilay@cs.wisc.edu
8597839Snilay@cs.wisc.edu          case VRCR:
8607839Snilay@cs.wisc.edu            regs.vrcr = reg;
8617839Snilay@cs.wisc.edu            break;
8627839Snilay@cs.wisc.edu
8637839Snilay@cs.wisc.edu          case VTCR:
8647839Snilay@cs.wisc.edu            regs.vtcr = reg;
8657839Snilay@cs.wisc.edu            break;
8667839Snilay@cs.wisc.edu
8677839Snilay@cs.wisc.edu          case VDR:
8687839Snilay@cs.wisc.edu            panic("the driver never uses VDR, something is wrong!\n");
8697839Snilay@cs.wisc.edu            break;
8707839Snilay@cs.wisc.edu
8717839Snilay@cs.wisc.edu          case CCSR:
8727839Snilay@cs.wisc.edu            /* not going to implement clockrun stuff */
8737839Snilay@cs.wisc.edu            regs.ccsr = reg;
8747839Snilay@cs.wisc.edu            break;
8757839Snilay@cs.wisc.edu
8767839Snilay@cs.wisc.edu          case TBICR:
8777839Snilay@cs.wisc.edu            regs.tbicr = reg;
8787839Snilay@cs.wisc.edu            if (reg & TBICR_MR_LOOPBACK)
8797839Snilay@cs.wisc.edu                panic("TBICR_MR_LOOPBACK never used, something wrong!\n");
8807839Snilay@cs.wisc.edu
8817839Snilay@cs.wisc.edu            if (reg & TBICR_MR_AN_ENABLE) {
8827839Snilay@cs.wisc.edu                regs.tanlpar = regs.tanar;
8837839Snilay@cs.wisc.edu                regs.tbisr |= (TBISR_MR_AN_COMPLETE | TBISR_MR_LINK_STATUS);
8847839Snilay@cs.wisc.edu            }
8856902SBrad.Beckmann@amd.com
8868683Snilay@cs.wisc.edu#if 0
8878683Snilay@cs.wisc.edu            if (reg & TBICR_MR_RESTART_AN) ;
8888683Snilay@cs.wisc.edu#endif
8898683Snilay@cs.wisc.edu
8908683Snilay@cs.wisc.edu            break;
8918683Snilay@cs.wisc.edu
8928683Snilay@cs.wisc.edu          case TBISR:
8938683Snilay@cs.wisc.edu            panic("TBISR is read only register!\n");
8948683Snilay@cs.wisc.edu
8958683Snilay@cs.wisc.edu          case TANAR:
8968683Snilay@cs.wisc.edu            regs.tanar = reg;
8978683Snilay@cs.wisc.edu            if (reg & TANAR_PS2)
8988683Snilay@cs.wisc.edu                panic("this isn't used in driver, something wrong!\n");
8998683Snilay@cs.wisc.edu
9008683Snilay@cs.wisc.edu            if (reg & TANAR_PS1)
9018683Snilay@cs.wisc.edu                panic("this isn't used in driver, something wrong!\n");
9028683Snilay@cs.wisc.edu            break;
9036657Snate@binkert.org
9046657Snate@binkert.org          case TANLPAR:
9057839Snilay@cs.wisc.edu            panic("this should only be written to by the fake phy!\n");
9067839Snilay@cs.wisc.edu
9077839Snilay@cs.wisc.edu          case TANER:
9087839Snilay@cs.wisc.edu            panic("TANER is read only register!\n");
9096657Snate@binkert.org
9107839Snilay@cs.wisc.edu          case TESR:
9117839Snilay@cs.wisc.edu            regs.tesr = reg;
9127839Snilay@cs.wisc.edu            break;
9137839Snilay@cs.wisc.edu
9147839Snilay@cs.wisc.edu          default:
9158055Sksewell@umich.edu            panic("invalid register access daddr=%#x", daddr);
9167839Snilay@cs.wisc.edu        }
9177839Snilay@cs.wisc.edu    } else {
9186657Snate@binkert.org        panic("Invalid Request Size");
9197839Snilay@cs.wisc.edu    }
9207839Snilay@cs.wisc.edu
9217839Snilay@cs.wisc.edu    return No_Fault;
9227839Snilay@cs.wisc.edu}
9237839Snilay@cs.wisc.edu
9247839Snilay@cs.wisc.eduvoid
9257839Snilay@cs.wisc.eduNSGigE::devIntrPost(uint32_t interrupts)
9267839Snilay@cs.wisc.edu{
9277839Snilay@cs.wisc.edu    bool delay = false;
9287839Snilay@cs.wisc.edu
9297839Snilay@cs.wisc.edu    if (interrupts & ISR_RESERVE)
9308055Sksewell@umich.edu        panic("Cannot set a reserved interrupt");
9317839Snilay@cs.wisc.edu
9327839Snilay@cs.wisc.edu    if (interrupts & ISR_TXRCMP)
9337839Snilay@cs.wisc.edu        regs.isr |= ISR_TXRCMP;
9347839Snilay@cs.wisc.edu
9357839Snilay@cs.wisc.edu    if (interrupts & ISR_RXRCMP)
9367839Snilay@cs.wisc.edu        regs.isr |= ISR_RXRCMP;
9377839Snilay@cs.wisc.edu
9387839Snilay@cs.wisc.edu//ISR_DPERR  not implemented
9397839Snilay@cs.wisc.edu//ISR_SSERR not implemented
9407839Snilay@cs.wisc.edu//ISR_RMABT not implemented
9417839Snilay@cs.wisc.edu//ISR_RXSOVR not implemented
9427839Snilay@cs.wisc.edu//ISR_HIBINT not implemented
9437839Snilay@cs.wisc.edu//ISR_PHY not implemented
9447839Snilay@cs.wisc.edu//ISR_PME not implemented
9458055Sksewell@umich.edu
9467839Snilay@cs.wisc.edu    if (interrupts & ISR_SWI)
9477839Snilay@cs.wisc.edu        regs.isr |= ISR_SWI;
9487839Snilay@cs.wisc.edu
9497839Snilay@cs.wisc.edu//ISR_MIB not implemented
9507839Snilay@cs.wisc.edu//ISR_TXURN not implemented
9517839Snilay@cs.wisc.edu
9527839Snilay@cs.wisc.edu    if (interrupts & ISR_TXIDLE)
9537839Snilay@cs.wisc.edu        regs.isr |= ISR_TXIDLE;
9547839Snilay@cs.wisc.edu
9557839Snilay@cs.wisc.edu    if (interrupts & ISR_TXERR)
9566657Snate@binkert.org        regs.isr |= ISR_TXERR;
9577007Snate@binkert.org
9587007Snate@binkert.org    if (interrupts & ISR_TXDESC)
9596657Snate@binkert.org        regs.isr |= ISR_TXDESC;
9608055Sksewell@umich.edu
9616657Snate@binkert.org    if (interrupts & ISR_TXOK) {
9626657Snate@binkert.org        regs.isr |= ISR_TXOK;
9636657Snate@binkert.org        delay = true;
9646657Snate@binkert.org    }
9658478Snilay@cs.wisc.edu
9668478Snilay@cs.wisc.edu    if (interrupts & ISR_RXORN)
9678478Snilay@cs.wisc.edu        regs.isr |= ISR_RXORN;
9689302Snilay@cs.wisc.edu
9699302Snilay@cs.wisc.edu    if (interrupts & ISR_RXIDLE)
9709302Snilay@cs.wisc.edu        regs.isr |= ISR_RXIDLE;
9719302Snilay@cs.wisc.edu
9729302Snilay@cs.wisc.edu//ISR_RXEARLY not implemented
9739302Snilay@cs.wisc.edu
9749302Snilay@cs.wisc.edu    if (interrupts & ISR_RXERR)
9759302Snilay@cs.wisc.edu        regs.isr |= ISR_RXERR;
9769302Snilay@cs.wisc.edu
9779302Snilay@cs.wisc.edu    if (interrupts & ISR_RXDESC)
9789302Snilay@cs.wisc.edu        regs.isr |= ISR_RXDESC;
9799302Snilay@cs.wisc.edu
9809302Snilay@cs.wisc.edu    if (interrupts & ISR_RXOK) {
9819302Snilay@cs.wisc.edu        delay = true;
9829302Snilay@cs.wisc.edu        regs.isr |= ISR_RXOK;
9839302Snilay@cs.wisc.edu    }
9849302Snilay@cs.wisc.edu
9859302Snilay@cs.wisc.edu    if ((regs.isr & regs.imr)) {
9869302Snilay@cs.wisc.edu        Tick when = curTick;
9879302Snilay@cs.wisc.edu        if (delay)
9889302Snilay@cs.wisc.edu            when += intrDelay;
9899302Snilay@cs.wisc.edu        cpuIntrPost(when);
9909302Snilay@cs.wisc.edu    }
9919302Snilay@cs.wisc.edu
9929302Snilay@cs.wisc.edu    DPRINTF(EthernetIntr,
9939302Snilay@cs.wisc.edu            "interrupt written to ISR: intr=%#x isr=%#x imr=%#x\n",
9949302Snilay@cs.wisc.edu            interrupts, regs.isr, regs.imr);
9959302Snilay@cs.wisc.edu}
9969302Snilay@cs.wisc.edu
9979302Snilay@cs.wisc.eduvoid
9989302Snilay@cs.wisc.eduNSGigE::devIntrClear(uint32_t interrupts)
9999302Snilay@cs.wisc.edu{
10009302Snilay@cs.wisc.edu    if (interrupts & ISR_RESERVE)
10016657Snate@binkert.org        panic("Cannot clear a reserved interrupt");
10026657Snate@binkert.org
10039219Spower.jg@gmail.com    if (interrupts & ISR_TXRCMP)
10046657Snate@binkert.org        regs.isr &= ~ISR_TXRCMP;
10056657Snate@binkert.org
10066999Snate@binkert.org    if (interrupts & ISR_RXRCMP)
10076657Snate@binkert.org        regs.isr &= ~ISR_RXRCMP;
10086657Snate@binkert.org
10099104Shestness@cs.utexas.edu//ISR_DPERR  not implemented
10109104Shestness@cs.utexas.edu//ISR_SSERR not implemented
10119104Shestness@cs.utexas.edu//ISR_RMABT not implemented
10129104Shestness@cs.utexas.edu//ISR_RXSOVR not implemented
10136657Snate@binkert.org//ISR_HIBINT not implemented
10146657Snate@binkert.org//ISR_PHY not implemented
10156657Snate@binkert.org//ISR_PME not implemented
10166657Snate@binkert.org
10178946Sandreas.hansson@arm.com    if (interrupts & ISR_SWI)
10188946Sandreas.hansson@arm.com        regs.isr &= ~ISR_SWI;
10198946Sandreas.hansson@arm.com
10207832Snate@binkert.org//ISR_MIB not implemented
10217832Snate@binkert.org//ISR_TXURN not implemented
10227007Snate@binkert.org
10238232Snate@binkert.org    if (interrupts & ISR_TXIDLE)
10248229Snate@binkert.org        regs.isr &= ~ISR_TXIDLE;
10258229Snate@binkert.org
10268229Snate@binkert.org    if (interrupts & ISR_TXERR)
10279104Shestness@cs.utexas.edu        regs.isr &= ~ISR_TXERR;
10289104Shestness@cs.utexas.edu
10299104Shestness@cs.utexas.edu    if (interrupts & ISR_TXDESC)
10309104Shestness@cs.utexas.edu        regs.isr &= ~ISR_TXDESC;
10319104Shestness@cs.utexas.edu
10329104Shestness@cs.utexas.edu    if (interrupts & ISR_TXOK)
10338229Snate@binkert.org        regs.isr &= ~ISR_TXOK;
10346657Snate@binkert.org
10356657Snate@binkert.org    if (interrupts & ISR_RXORN)
10369219Spower.jg@gmail.com        regs.isr &= ~ISR_RXORN;
10379219Spower.jg@gmail.com
10389219Spower.jg@gmail.com    if (interrupts & ISR_RXIDLE)
10399219Spower.jg@gmail.com        regs.isr &= ~ISR_RXIDLE;
10409219Spower.jg@gmail.com
10419219Spower.jg@gmail.com//ISR_RXEARLY not implemented
10429219Spower.jg@gmail.com
10436657Snate@binkert.org    if (interrupts & ISR_RXERR)
10447055Snate@binkert.org        regs.isr &= ~ISR_RXERR;
10457055Snate@binkert.org
10467007Snate@binkert.org    if (interrupts & ISR_RXDESC)
10477007Snate@binkert.org        regs.isr &= ~ISR_RXDESC;
10486657Snate@binkert.org
10496657Snate@binkert.org    if (interrupts & ISR_RXOK)
10506657Snate@binkert.org        regs.isr &= ~ISR_RXOK;
10516657Snate@binkert.org
10526657Snate@binkert.org    if (!(regs.isr & regs.imr))
10536657Snate@binkert.org        cpuIntrClear();
10547007Snate@binkert.org
10559496Snilay@cs.wisc.edu    DPRINTF(EthernetIntr,
10567007Snate@binkert.org            "interrupt cleared from ISR: intr=%x isr=%x imr=%x\n",
10577007Snate@binkert.org            interrupts, regs.isr, regs.imr);
10589230Snilay@cs.wisc.edu}
10596657Snate@binkert.org
10606657Snate@binkert.orgvoid
10616657Snate@binkert.orgNSGigE::devIntrChangeMask()
10626657Snate@binkert.org{
10636657Snate@binkert.org    DPRINTF(EthernetIntr, "interrupt mask changed\n");
10646657Snate@binkert.org
10656657Snate@binkert.org    if (regs.isr & regs.imr)
10666657Snate@binkert.org        cpuIntrPost(curTick);
10676657Snate@binkert.org    else
10686657Snate@binkert.org        cpuIntrClear();
10696657Snate@binkert.org}
10706657Snate@binkert.org
10717567SBrad.Beckmann@amd.comvoid
10727567SBrad.Beckmann@amd.comNSGigE::cpuIntrPost(Tick when)
10737567SBrad.Beckmann@amd.com{
10747567SBrad.Beckmann@amd.com    // If the interrupt you want to post is later than an interrupt
10756657Snate@binkert.org    // already scheduled, just let it post in the coming one and don't
10766657Snate@binkert.org    // schedule another.
10776657Snate@binkert.org    // HOWEVER, must be sure that the scheduled intrTick is in the
10786657Snate@binkert.org    // future (this was formerly the source of a bug)
10796657Snate@binkert.org    assert((intrTick >= curTick) || (intrTick == 0));
10806657Snate@binkert.org    if (when > intrTick && intrTick != 0)
10816657Snate@binkert.org        return;
10826657Snate@binkert.org
10836657Snate@binkert.org    intrTick = when;
10846657Snate@binkert.org
10856657Snate@binkert.org    if (intrEvent) {
10866657Snate@binkert.org        intrEvent->squash();
10876657Snate@binkert.org        intrEvent = 0;
10886657Snate@binkert.org    }
10896657Snate@binkert.org
10906657Snate@binkert.org    if (when < curTick) {
10916657Snate@binkert.org        cpuInterrupt();
10926657Snate@binkert.org    } else {
10936999Snate@binkert.org        DPRINTF(EthernetIntr,
10946657Snate@binkert.org                "going to schedule an interrupt for intrTick=%d\n",
10956657Snate@binkert.org                intrTick);
10966657Snate@binkert.org        intrEvent = new IntrEvent(this, true);
10976657Snate@binkert.org        intrEvent->schedule(intrTick);
10986657Snate@binkert.org    }
10996657Snate@binkert.org}
11007832Snate@binkert.org
11017832Snate@binkert.orgvoid
11027805Snilay@cs.wisc.eduNSGigE::cpuInterrupt()
11037832Snate@binkert.org{
11048232Snate@binkert.org    // Don't send an interrupt if there's already one
11058232Snate@binkert.org    if (cpuPendingIntr) {
11068229Snate@binkert.org        DPRINTF(EthernetIntr,
11078229Snate@binkert.org                "would send an interrupt now, but there's already pending\n");
11088229Snate@binkert.org        intrTick = 0;
11098229Snate@binkert.org        return;
11106657Snate@binkert.org    }
11116657Snate@binkert.org    // Don't send an interrupt if it's supposed to be delayed
11126657Snate@binkert.org    if (intrTick > curTick) {
11136657Snate@binkert.org        DPRINTF(EthernetIntr,
11146657Snate@binkert.org                "an interrupt is scheduled for %d, wait til then\n",
11156657Snate@binkert.org                intrTick);
11166657Snate@binkert.org        return;
11176657Snate@binkert.org    }
11187007Snate@binkert.org
11197007Snate@binkert.org    // Whether or not there's a pending interrupt, we don't care about
11207839Snilay@cs.wisc.edu    // it anymore
11217839Snilay@cs.wisc.edu    intrEvent = 0;
11227839Snilay@cs.wisc.edu    intrTick = 0;
11237839Snilay@cs.wisc.edu
11247839Snilay@cs.wisc.edu    // Send interrupt
11257839Snilay@cs.wisc.edu    cpuPendingIntr = true;
11267839Snilay@cs.wisc.edu    /** @todo rework the intctrl to be tsunami ok */
11277839Snilay@cs.wisc.edu    //intctrl->post(TheISA::INTLEVEL_IRQ1, TheISA::INTINDEX_ETHERNET);
11287839Snilay@cs.wisc.edu    DPRINTF(EthernetIntr, "Posting interrupts to cchip!\n");
11297839Snilay@cs.wisc.edu    tsunami->cchip->postDRIR(configData->config.hdr.pci0.interruptLine);
11307007Snate@binkert.org}
11316657Snate@binkert.org
11327839Snilay@cs.wisc.eduvoid
11337839Snilay@cs.wisc.eduNSGigE::cpuIntrClear()
11348337Snilay@cs.wisc.edu{
11357839Snilay@cs.wisc.edu    if (!cpuPendingIntr)
11368337Snilay@cs.wisc.edu        return;
11377839Snilay@cs.wisc.edu
11388337Snilay@cs.wisc.edu    cpuPendingIntr = false;
11397839Snilay@cs.wisc.edu    /** @todo rework the intctrl to be tsunami ok */
11408337Snilay@cs.wisc.edu    //intctrl->clear(TheISA::INTLEVEL_IRQ1, TheISA::INTINDEX_ETHERNET);
11417839Snilay@cs.wisc.edu    DPRINTF(EthernetIntr, "clearing all interrupts from cchip\n");
11427839Snilay@cs.wisc.edu    tsunami->cchip->clearDRIR(configData->config.hdr.pci0.interruptLine);
11436657Snate@binkert.org}
11446657Snate@binkert.org
11457780Snilay@cs.wisc.edubool
11469465Snilay@cs.wisc.eduNSGigE::cpuIntrPending() const
11479171Snilay@cs.wisc.edu{ return cpuPendingIntr; }
11486657Snate@binkert.org
11497007Snate@binkert.orgvoid
11507839Snilay@cs.wisc.eduNSGigE::txReset()
11517839Snilay@cs.wisc.edu{
11527839Snilay@cs.wisc.edu
11537839Snilay@cs.wisc.edu    DPRINTF(Ethernet, "transmit reset\n");
11547839Snilay@cs.wisc.edu
11557839Snilay@cs.wisc.edu    CTDD = false;
11567839Snilay@cs.wisc.edu    txFifoAvail = maxTxFifoSize;
11577839Snilay@cs.wisc.edu    txHalt = false;
11587839Snilay@cs.wisc.edu    txFragPtr = 0;
11596657Snate@binkert.org    assert(txDescCnt == 0);
11607839Snilay@cs.wisc.edu    txFifo.clear();
11616657Snate@binkert.org    regs.command &= ~CR_TXE;
11627780Snilay@cs.wisc.edu    txState = txIdle;
11637780Snilay@cs.wisc.edu    assert(txDmaState == dmaIdle);
11647542SBrad.Beckmann@amd.com}
11658266Sksewell@umich.edu
11668266Sksewell@umich.eduvoid
11678266Sksewell@umich.eduNSGigE::rxReset()
11688266Sksewell@umich.edu{
11698266Sksewell@umich.edu    DPRINTF(Ethernet, "receive reset\n");
11708266Sksewell@umich.edu
11716657Snate@binkert.org    CRDD = false;
11727832Snate@binkert.org    assert(rxPktBytes == 0);
11737839Snilay@cs.wisc.edu    rxFifoCnt = 0;
11747839Snilay@cs.wisc.edu    rxHalt = false;
11758337Snilay@cs.wisc.edu    rxFragPtr = 0;
11768341Snilay@cs.wisc.edu    assert(rxDescCnt == 0);
11777839Snilay@cs.wisc.edu    assert(rxDmaState == dmaIdle);
11788337Snilay@cs.wisc.edu    rxFifo.clear();
11798341Snilay@cs.wisc.edu    regs.command &= ~CR_RXE;
11807839Snilay@cs.wisc.edu    rxState = rxIdle;
11818337Snilay@cs.wisc.edu}
11828341Snilay@cs.wisc.edu
11837839Snilay@cs.wisc.eduvoid NSGigE::regsReset()
11848337Snilay@cs.wisc.edu{
11858341Snilay@cs.wisc.edu    memset(&regs, 0, sizeof(regs));
11867839Snilay@cs.wisc.edu    regs.config = 0x80000000;
11877839Snilay@cs.wisc.edu    regs.mear = 0x12;
11886657Snate@binkert.org    regs.isr = 0x00608000;
11898266Sksewell@umich.edu    regs.txcfg = 0x120;
11908266Sksewell@umich.edu    regs.rxcfg = 0x4;
11918266Sksewell@umich.edu    regs.srr = 0x0103;
11928266Sksewell@umich.edu    regs.mibc = 0x2;
11938266Sksewell@umich.edu    regs.vdr = 0x81;
11948266Sksewell@umich.edu    regs.tesr = 0xc000;
11956657Snate@binkert.org
11967780Snilay@cs.wisc.edu    extstsEnable = false;
11978266Sksewell@umich.edu    acceptBroadcast = false;
11988266Sksewell@umich.edu    acceptMulticast = false;
11998266Sksewell@umich.edu    acceptUnicast = false;
12008266Sksewell@umich.edu    acceptPerfect = false;
12018266Sksewell@umich.edu    acceptArp = false;
12028266Sksewell@umich.edu}
12036657Snate@binkert.org
12046657Snate@binkert.orgvoid
12056657Snate@binkert.orgNSGigE::rxDmaReadCopy()
12066657Snate@binkert.org{
12076657Snate@binkert.org    assert(rxDmaState == dmaReading);
12087007Snate@binkert.org
12097007Snate@binkert.org    memcpy(rxDmaData, physmem->dma_addr(rxDmaAddr, rxDmaLen), rxDmaLen);
12107007Snate@binkert.org    rxDmaState = dmaIdle;
12117007Snate@binkert.org
12127839Snilay@cs.wisc.edu    DPRINTF(EthernetDMA, "rx dma read  paddr=%#x len=%d\n",
12137839Snilay@cs.wisc.edu            rxDmaAddr, rxDmaLen);
12147839Snilay@cs.wisc.edu    DDUMP(EthernetDMA, rxDmaData, rxDmaLen);
12157839Snilay@cs.wisc.edu}
12167839Snilay@cs.wisc.edu
12177839Snilay@cs.wisc.edubool
12187839Snilay@cs.wisc.eduNSGigE::doRxDmaRead()
12197839Snilay@cs.wisc.edu{
12207839Snilay@cs.wisc.edu    assert(rxDmaState == dmaIdle || rxDmaState == dmaReadWaiting);
12217839Snilay@cs.wisc.edu    rxDmaState = dmaReading;
12227839Snilay@cs.wisc.edu
12237007Snate@binkert.org    if (dmaInterface && !rxDmaFree) {
12246657Snate@binkert.org        if (dmaInterface->busy())
12256657Snate@binkert.org            rxDmaState = dmaReadWaiting;
12266657Snate@binkert.org        else
12276657Snate@binkert.org            dmaInterface->doDMA(Read, rxDmaAddr, rxDmaLen, curTick,
12286657Snate@binkert.org                                &rxDmaReadEvent, true);
12296657Snate@binkert.org        return true;
12306657Snate@binkert.org    }
12316657Snate@binkert.org
12326657Snate@binkert.org    if (dmaReadDelay == 0 && dmaReadFactor == 0) {
12336657Snate@binkert.org        rxDmaReadCopy();
12346657Snate@binkert.org        return false;
12356999Snate@binkert.org    }
12366657Snate@binkert.org
12376657Snate@binkert.org    Tick factor = ((rxDmaLen + ULL(63)) >> ULL(6)) * dmaReadFactor;
12386657Snate@binkert.org    Tick start = curTick + dmaReadDelay + factor;
12396657Snate@binkert.org    rxDmaReadEvent.schedule(start);
12406657Snate@binkert.org    return true;
12416657Snate@binkert.org}
12429104Shestness@cs.utexas.edu
12436657Snate@binkert.orgvoid
12446657Snate@binkert.orgNSGigE::rxDmaReadDone()
12456657Snate@binkert.org{
12466657Snate@binkert.org    assert(rxDmaState == dmaReading);
12476657Snate@binkert.org    rxDmaReadCopy();
12486657Snate@binkert.org
12496657Snate@binkert.org    // If the transmit state machine has a pending DMA, let it go first
12507007Snate@binkert.org    if (txDmaState == dmaReadWaiting || txDmaState == dmaWriteWaiting)
12516657Snate@binkert.org        txKick();
12526657Snate@binkert.org
12536657Snate@binkert.org    rxKick();
12546657Snate@binkert.org}
12559105SBrad.Beckmann@amd.com
12569105SBrad.Beckmann@amd.comvoid
12579105SBrad.Beckmann@amd.comNSGigE::rxDmaWriteCopy()
12589105SBrad.Beckmann@amd.com{
12599105SBrad.Beckmann@amd.com    assert(rxDmaState == dmaWriting);
12609105SBrad.Beckmann@amd.com
12619105SBrad.Beckmann@amd.com    memcpy(physmem->dma_addr(rxDmaAddr, rxDmaLen), rxDmaData, rxDmaLen);
12629105SBrad.Beckmann@amd.com    rxDmaState = dmaIdle;
12636657Snate@binkert.org
12646657Snate@binkert.org    DPRINTF(EthernetDMA, "rx dma write paddr=%#x len=%d\n",
12656657Snate@binkert.org            rxDmaAddr, rxDmaLen);
12666657Snate@binkert.org    DDUMP(EthernetDMA, rxDmaData, rxDmaLen);
12676657Snate@binkert.org}
12686657Snate@binkert.org
12696657Snate@binkert.orgbool
12709104Shestness@cs.utexas.eduNSGigE::doRxDmaWrite()
12719104Shestness@cs.utexas.edu{
12729104Shestness@cs.utexas.edu    assert(rxDmaState == dmaIdle || rxDmaState == dmaWriteWaiting);
12739104Shestness@cs.utexas.edu    rxDmaState = dmaWriting;
12746657Snate@binkert.org
12756657Snate@binkert.org    if (dmaInterface && !rxDmaFree) {
12766657Snate@binkert.org        if (dmaInterface->busy())
12776657Snate@binkert.org            rxDmaState = dmaWriteWaiting;
12786657Snate@binkert.org        else
12796657Snate@binkert.org            dmaInterface->doDMA(WriteInvalidate, rxDmaAddr, rxDmaLen, curTick,
12806657Snate@binkert.org                                &rxDmaWriteEvent, true);
12816657Snate@binkert.org        return true;
12826657Snate@binkert.org    }
12836657Snate@binkert.org
12847839Snilay@cs.wisc.edu    if (dmaWriteDelay == 0 && dmaWriteFactor == 0) {
12857839Snilay@cs.wisc.edu        rxDmaWriteCopy();
12867839Snilay@cs.wisc.edu        return false;
12877839Snilay@cs.wisc.edu    }
12887839Snilay@cs.wisc.edu
12897839Snilay@cs.wisc.edu    Tick factor = ((rxDmaLen + ULL(63)) >> ULL(6)) * dmaWriteFactor;
12907839Snilay@cs.wisc.edu    Tick start = curTick + dmaWriteDelay + factor;
12917839Snilay@cs.wisc.edu    rxDmaWriteEvent.schedule(start);
12927839Snilay@cs.wisc.edu    return true;
12937839Snilay@cs.wisc.edu}
12947839Snilay@cs.wisc.edu
12957839Snilay@cs.wisc.eduvoid
12966657Snate@binkert.orgNSGigE::rxDmaWriteDone()
12976657Snate@binkert.org{
12986657Snate@binkert.org    assert(rxDmaState == dmaWriting);
12996657Snate@binkert.org    rxDmaWriteCopy();
13006657Snate@binkert.org
13016657Snate@binkert.org    // If the transmit state machine has a pending DMA, let it go first
13026657Snate@binkert.org    if (txDmaState == dmaReadWaiting || txDmaState == dmaWriteWaiting)
13036657Snate@binkert.org        txKick();
13046657Snate@binkert.org
13056657Snate@binkert.org    rxKick();
13066657Snate@binkert.org}
13076657Snate@binkert.org
13086657Snate@binkert.orgvoid
13096657Snate@binkert.orgNSGigE::rxKick()
13106657Snate@binkert.org{
13116657Snate@binkert.org    DPRINTF(EthernetSM, "receive kick state=%s (rxBuf.size=%d)\n",
13126657Snate@binkert.org            NsRxStateStrings[rxState], rxFifo.size());
13136657Snate@binkert.org
13146657Snate@binkert.org    if (rxKickTick > curTick) {
13156657Snate@binkert.org        DPRINTF(EthernetSM, "receive kick exiting, can't run till %d\n",
13166657Snate@binkert.org                rxKickTick);
13177805Snilay@cs.wisc.edu        return;
13188159SBrad.Beckmann@amd.com    }
13199465Snilay@cs.wisc.edu
13206657Snate@binkert.org  next:
13216657Snate@binkert.org    switch(rxDmaState) {
13226657Snate@binkert.org      case dmaReadWaiting:
13236657Snate@binkert.org        if (doRxDmaRead())
13246657Snate@binkert.org            goto exit;
13256657Snate@binkert.org        break;
13267542SBrad.Beckmann@amd.com      case dmaWriteWaiting:
13277542SBrad.Beckmann@amd.com        if (doRxDmaWrite())
13287542SBrad.Beckmann@amd.com            goto exit;
13297542SBrad.Beckmann@amd.com        break;
13307542SBrad.Beckmann@amd.com      default:
13317542SBrad.Beckmann@amd.com        break;
13327542SBrad.Beckmann@amd.com    }
13337542SBrad.Beckmann@amd.com
13347542SBrad.Beckmann@amd.com    // see state machine from spec for details
13357542SBrad.Beckmann@amd.com    // the way this works is, if you finish work on one state and can
13367542SBrad.Beckmann@amd.com    // go directly to another, you do that through jumping to the
13377832Snate@binkert.org    // label "next".  however, if you have intermediate work, like DMA
13387542SBrad.Beckmann@amd.com    // so that you can't go to the next state yet, you go to exit and
13397542SBrad.Beckmann@amd.com    // exit the loop.  however, when the DMA is done it will trigger
13407542SBrad.Beckmann@amd.com    // an event and come back to this loop.
13418229Snate@binkert.org    switch (rxState) {
13427542SBrad.Beckmann@amd.com      case rxIdle:
13437542SBrad.Beckmann@amd.com        if (!regs.command & CR_RXE) {
13447542SBrad.Beckmann@amd.com            DPRINTF(EthernetSM, "Receive Disabled! Nothing to do.\n");
13457542SBrad.Beckmann@amd.com            goto exit;
13467542SBrad.Beckmann@amd.com        }
13477542SBrad.Beckmann@amd.com
13487542SBrad.Beckmann@amd.com        if (CRDD) {
13497542SBrad.Beckmann@amd.com            rxState = rxDescRefr;
13507542SBrad.Beckmann@amd.com
13517542SBrad.Beckmann@amd.com            rxDmaAddr = regs.rxdp & 0x3fffffff;
13527542SBrad.Beckmann@amd.com            rxDmaData = &rxDescCache + offsetof(ns_desc, link);
13537542SBrad.Beckmann@amd.com            rxDmaLen = sizeof(rxDescCache.link);
13547542SBrad.Beckmann@amd.com            rxDmaFree = dmaDescFree;
13557542SBrad.Beckmann@amd.com
13567542SBrad.Beckmann@amd.com            descDmaReads++;
13577542SBrad.Beckmann@amd.com            descDmaRdBytes += rxDmaLen;
13587542SBrad.Beckmann@amd.com
13597542SBrad.Beckmann@amd.com            if (doRxDmaRead())
13607542SBrad.Beckmann@amd.com                goto exit;
13617542SBrad.Beckmann@amd.com        } else {
13627542SBrad.Beckmann@amd.com            rxState = rxDescRead;
13637542SBrad.Beckmann@amd.com
13647542SBrad.Beckmann@amd.com            rxDmaAddr = regs.rxdp & 0x3fffffff;
13657542SBrad.Beckmann@amd.com            rxDmaData = &rxDescCache;
13667542SBrad.Beckmann@amd.com            rxDmaLen = sizeof(ns_desc);
13677542SBrad.Beckmann@amd.com            rxDmaFree = dmaDescFree;
13687542SBrad.Beckmann@amd.com
13697542SBrad.Beckmann@amd.com            descDmaReads++;
13707542SBrad.Beckmann@amd.com            descDmaRdBytes += rxDmaLen;
13717542SBrad.Beckmann@amd.com
13727542SBrad.Beckmann@amd.com            if (doRxDmaRead())
13737542SBrad.Beckmann@amd.com                goto exit;
13747542SBrad.Beckmann@amd.com        }
13757542SBrad.Beckmann@amd.com        break;
13767542SBrad.Beckmann@amd.com
13777542SBrad.Beckmann@amd.com      case rxDescRefr:
13787542SBrad.Beckmann@amd.com        if (rxDmaState != dmaIdle)
13797542SBrad.Beckmann@amd.com            goto exit;
13807542SBrad.Beckmann@amd.com
13817542SBrad.Beckmann@amd.com        rxState = rxAdvance;
13827542SBrad.Beckmann@amd.com        break;
13837542SBrad.Beckmann@amd.com
13847542SBrad.Beckmann@amd.com     case rxDescRead:
13857542SBrad.Beckmann@amd.com        if (rxDmaState != dmaIdle)
13867542SBrad.Beckmann@amd.com            goto exit;
13877542SBrad.Beckmann@amd.com
13887542SBrad.Beckmann@amd.com        DPRINTF(EthernetDesc,
13897542SBrad.Beckmann@amd.com                "rxDescCache:\n"
13907542SBrad.Beckmann@amd.com                "\tlink=%08x\n"
13917542SBrad.Beckmann@amd.com                "\tbufptr=%08x\n"
13927542SBrad.Beckmann@amd.com                "\tcmdsts=%08x\n"
13937542SBrad.Beckmann@amd.com                "\textsts=%08x\n",
13947542SBrad.Beckmann@amd.com                rxDescCache.link, rxDescCache.bufptr, rxDescCache.cmdsts,
13957542SBrad.Beckmann@amd.com                rxDescCache.extsts);
13967542SBrad.Beckmann@amd.com
13977542SBrad.Beckmann@amd.com        if (rxDescCache.cmdsts & CMDSTS_OWN) {
13987542SBrad.Beckmann@amd.com            rxState = rxIdle;
13997542SBrad.Beckmann@amd.com        } else {
14007542SBrad.Beckmann@amd.com            rxState = rxFifoBlock;
14017542SBrad.Beckmann@amd.com            rxFragPtr = rxDescCache.bufptr;
14027542SBrad.Beckmann@amd.com            rxDescCnt = rxDescCache.cmdsts & CMDSTS_LEN_MASK;
14037542SBrad.Beckmann@amd.com        }
14047542SBrad.Beckmann@amd.com        break;
14057542SBrad.Beckmann@amd.com
14067542SBrad.Beckmann@amd.com      case rxFifoBlock:
14077542SBrad.Beckmann@amd.com        if (!rxPacket) {
14087542SBrad.Beckmann@amd.com            /**
14097542SBrad.Beckmann@amd.com             * @todo in reality, we should be able to start processing
14107542SBrad.Beckmann@amd.com             * the packet as it arrives, and not have to wait for the
14117542SBrad.Beckmann@amd.com             * full packet ot be in the receive fifo.
14127542SBrad.Beckmann@amd.com             */
14137542SBrad.Beckmann@amd.com            if (rxFifo.empty())
14147542SBrad.Beckmann@amd.com                goto exit;
14157542SBrad.Beckmann@amd.com
14167542SBrad.Beckmann@amd.com            DPRINTF(EthernetSM, "\n\n*****processing receive of new packet\n");
14177542SBrad.Beckmann@amd.com
14187542SBrad.Beckmann@amd.com            // If we don't have a packet, grab a new one from the fifo.
14197542SBrad.Beckmann@amd.com            rxPacket = rxFifo.front();
14207542SBrad.Beckmann@amd.com            rxPktBytes = rxPacket->length;
14217542SBrad.Beckmann@amd.com            rxPacketBufPtr = rxPacket->data;
14226657Snate@binkert.org
14236999Snate@binkert.org#if TRACING_ON
14246657Snate@binkert.org            if (DTRACE(Ethernet)) {
14256657Snate@binkert.org                if (rxPacket->isIpPkt()) {
14266657Snate@binkert.org                    ip_header *ip = rxPacket->getIpHdr();
14276657Snate@binkert.org                    DPRINTF(Ethernet, "ID is %d\n", reverseEnd16(ip->ID));
14286657Snate@binkert.org                    if (rxPacket->isTcpPkt()) {
14296657Snate@binkert.org                        tcp_header *tcp = rxPacket->getTcpHdr(ip);
14307542SBrad.Beckmann@amd.com                        DPRINTF(Ethernet, "Src Port = %d, Dest Port = %d\n",
14317542SBrad.Beckmann@amd.com                                reverseEnd16(tcp->src_port_num),
14326657Snate@binkert.org                                reverseEnd16(tcp->dest_port_num));
14337832Snate@binkert.org                    }
14347002Snate@binkert.org                }
14357002Snate@binkert.org            }
14368229Snate@binkert.org#endif
14378229Snate@binkert.org
14388608Snilay@cs.wisc.edu            // sanity check - i think the driver behaves like this
14396657Snate@binkert.org            assert(rxDescCnt >= rxPktBytes);
14407007Snate@binkert.org
14417007Snate@binkert.org            // Must clear the value before popping to decrement the
14426657Snate@binkert.org            // reference count
14436657Snate@binkert.org            rxFifo.front() = NULL;
14446657Snate@binkert.org            rxFifo.pop_front();
14456657Snate@binkert.org            rxFifoCnt -= rxPacket->length;
14466657Snate@binkert.org        }
14477542SBrad.Beckmann@amd.com
14487542SBrad.Beckmann@amd.com
14497542SBrad.Beckmann@amd.com        // dont' need the && rxDescCnt > 0 if driver sanity check
14506657Snate@binkert.org        // above holds
14516657Snate@binkert.org        if (rxPktBytes > 0) {
14526657Snate@binkert.org            rxState = rxFragWrite;
14536657Snate@binkert.org            // don't need min<>(rxPktBytes,rxDescCnt) if above sanity
14546657Snate@binkert.org            // check holds
14556657Snate@binkert.org            rxXferLen = rxPktBytes;
14566657Snate@binkert.org
14576657Snate@binkert.org            rxDmaAddr = rxFragPtr & 0x3fffffff;
14586657Snate@binkert.org            rxDmaData = rxPacketBufPtr;
14597007Snate@binkert.org            rxDmaLen = rxXferLen;
14606657Snate@binkert.org            rxDmaFree = dmaDataFree;
14616657Snate@binkert.org
14626657Snate@binkert.org            if (doRxDmaWrite())
14636657Snate@binkert.org                goto exit;
14646999Snate@binkert.org
14656657Snate@binkert.org        } else {
14666657Snate@binkert.org            rxState = rxDescWrite;
14676657Snate@binkert.org
14686657Snate@binkert.org            //if (rxPktBytes == 0) {  /* packet is done */
14696657Snate@binkert.org            assert(rxPktBytes == 0);
14706657Snate@binkert.org            DPRINTF(EthernetSM, "done with receiving packet\n");
14717832Snate@binkert.org
14727832Snate@binkert.org            rxDescCache.cmdsts |= CMDSTS_OWN;
14736657Snate@binkert.org            rxDescCache.cmdsts &= ~CMDSTS_MORE;
14746657Snate@binkert.org            rxDescCache.cmdsts |= CMDSTS_OK;
14756657Snate@binkert.org            rxDescCache.cmdsts &= 0xffff0000;
14766657Snate@binkert.org            rxDescCache.cmdsts += rxPacket->length;   //i.e. set CMDSTS_SIZE
14776657Snate@binkert.org
14786657Snate@binkert.org#if 0
14796657Snate@binkert.org            /*
14806657Snate@binkert.org             * all the driver uses these are for its own stats keeping
14816657Snate@binkert.org             * which we don't care about, aren't necessary for
14826657Snate@binkert.org             * functionality and doing this would just slow us down.
14836657Snate@binkert.org             * if they end up using this in a later version for
14846657Snate@binkert.org             * functional purposes, just undef
14856657Snate@binkert.org             */
14866657Snate@binkert.org            if (rxFilterEnable) {
14877007Snate@binkert.org                rxDescCache.cmdsts &= ~CMDSTS_DEST_MASK;
14887007Snate@binkert.org                if (rxFifo.front()->IsUnicast())
14897007Snate@binkert.org                    rxDescCache.cmdsts |= CMDSTS_DEST_SELF;
14906657Snate@binkert.org                if (rxFifo.front()->IsMulticast())
14916657Snate@binkert.org                    rxDescCache.cmdsts |= CMDSTS_DEST_MULTI;
14926657Snate@binkert.org                if (rxFifo.front()->IsBroadcast())
14937007Snate@binkert.org                    rxDescCache.cmdsts |= CMDSTS_DEST_MASK;
14947007Snate@binkert.org            }
14957007Snate@binkert.org#endif
14966657Snate@binkert.org
14976657Snate@binkert.org            if (rxPacket->isIpPkt() && extstsEnable) {
14986657Snate@binkert.org                rxDescCache.extsts |= EXTSTS_IPPKT;
14996657Snate@binkert.org                rxIPChecksums++;
15006657Snate@binkert.org                if (!ipChecksum(rxPacket, false)) {
15016657Snate@binkert.org                    DPRINTF(EthernetCksum, "Rx IP Checksum Error\n");
15026657Snate@binkert.org                    rxDescCache.extsts |= EXTSTS_IPERR;
15036657Snate@binkert.org                }
15046657Snate@binkert.org                if (rxPacket->isTcpPkt()) {
15056657Snate@binkert.org                    rxDescCache.extsts |= EXTSTS_TCPPKT;
15066657Snate@binkert.org                    rxTCPChecksums++;
15077007Snate@binkert.org                    if (!tcpChecksum(rxPacket, false)) {
15087007Snate@binkert.org                        DPRINTF(EthernetCksum, "Rx TCP Checksum Error\n");
15096657Snate@binkert.org                        rxDescCache.extsts |= EXTSTS_TCPERR;
15106657Snate@binkert.org
15116657Snate@binkert.org                    }
15126657Snate@binkert.org                } else if (rxPacket->isUdpPkt()) {
15136657Snate@binkert.org                    rxDescCache.extsts |= EXTSTS_UDPPKT;
15147007Snate@binkert.org                    if (!udpChecksum(rxPacket, false)) {
15157007Snate@binkert.org                        DPRINTF(EthernetCksum, "Rx UDP Checksum Error\n");
15167007Snate@binkert.org                        rxDescCache.extsts |= EXTSTS_UDPERR;
15176657Snate@binkert.org                    }
15186657Snate@binkert.org                }
15196657Snate@binkert.org            }
15207007Snate@binkert.org            rxPacket = 0;
15217542SBrad.Beckmann@amd.com
15227542SBrad.Beckmann@amd.com            /*
15236657Snate@binkert.org             * the driver seems to always receive into desc buffers
15247542SBrad.Beckmann@amd.com             * of size 1514, so you never have a pkt that is split
15257542SBrad.Beckmann@amd.com             * into multiple descriptors on the receive side, so
15267002Snate@binkert.org             * i don't implement that case, hence the assert above.
15277542SBrad.Beckmann@amd.com             */
15287542SBrad.Beckmann@amd.com
15297542SBrad.Beckmann@amd.com            DPRINTF(EthernetDesc,
15307542SBrad.Beckmann@amd.com                    "rxDesc writeback:\n\tcmdsts=%08x\n\textsts=%08x\n",
15316657Snate@binkert.org                    rxDescCache.cmdsts, rxDescCache.extsts);
15327542SBrad.Beckmann@amd.com
15337542SBrad.Beckmann@amd.com            rxDmaAddr = (regs.rxdp + offsetof(ns_desc, cmdsts)) & 0x3fffffff;
15347542SBrad.Beckmann@amd.com            rxDmaData = &(rxDescCache.cmdsts);
15357542SBrad.Beckmann@amd.com            rxDmaLen = sizeof(rxDescCache.cmdsts) + sizeof(rxDescCache.extsts);
15367542SBrad.Beckmann@amd.com            rxDmaFree = dmaDescFree;
15377542SBrad.Beckmann@amd.com
15387542SBrad.Beckmann@amd.com            descDmaWrites++;
15397542SBrad.Beckmann@amd.com            descDmaWrBytes += rxDmaLen;
15406657Snate@binkert.org
15416657Snate@binkert.org            if (doRxDmaWrite())
15426657Snate@binkert.org                goto exit;
15436657Snate@binkert.org        }
15446657Snate@binkert.org        break;
15456657Snate@binkert.org
15467007Snate@binkert.org      case rxFragWrite:
15476999Snate@binkert.org        if (rxDmaState != dmaIdle)
15487007Snate@binkert.org            goto exit;
15497007Snate@binkert.org
15507007Snate@binkert.org        rxPacketBufPtr += rxXferLen;
15517007Snate@binkert.org        rxFragPtr += rxXferLen;
15527007Snate@binkert.org        rxPktBytes -= rxXferLen;
15537007Snate@binkert.org
15546657Snate@binkert.org        rxState = rxFifoBlock;
15556657Snate@binkert.org        break;
15566657Snate@binkert.org
15576657Snate@binkert.org      case rxDescWrite:
15586657Snate@binkert.org        if (rxDmaState != dmaIdle)
15596657Snate@binkert.org            goto exit;
15606657Snate@binkert.org
15616657Snate@binkert.org        assert(rxDescCache.cmdsts & CMDSTS_OWN);
15626657Snate@binkert.org
15636657Snate@binkert.org        assert(rxPacket == 0);
15646657Snate@binkert.org        devIntrPost(ISR_RXOK);
15656657Snate@binkert.org
15666657Snate@binkert.org        if (rxDescCache.cmdsts & CMDSTS_INTR)
15676657Snate@binkert.org            devIntrPost(ISR_RXDESC);
15686657Snate@binkert.org
15696657Snate@binkert.org        if (rxHalt) {
15706657Snate@binkert.org            DPRINTF(EthernetSM, "Halting the RX state machine\n");
15716657Snate@binkert.org            rxState = rxIdle;
15726657Snate@binkert.org            rxHalt = false;
15736657Snate@binkert.org        } else
15746657Snate@binkert.org            rxState = rxAdvance;
15756657Snate@binkert.org        break;
15766657Snate@binkert.org
15776657Snate@binkert.org      case rxAdvance:
15786657Snate@binkert.org        if (rxDescCache.link == 0) {
15796657Snate@binkert.org            rxState = rxIdle;
15806657Snate@binkert.org            return;
15816657Snate@binkert.org        } else {
15826657Snate@binkert.org            rxState = rxDescRead;
15836999Snate@binkert.org            regs.rxdp = rxDescCache.link;
15846657Snate@binkert.org            CRDD = false;
15856657Snate@binkert.org
15867007Snate@binkert.org            rxDmaAddr = regs.rxdp & 0x3fffffff;
15877007Snate@binkert.org            rxDmaData = &rxDescCache;
15886657Snate@binkert.org            rxDmaLen = sizeof(ns_desc);
15896657Snate@binkert.org            rxDmaFree = dmaDescFree;
15906657Snate@binkert.org
15916657Snate@binkert.org            if (doRxDmaRead())
15926657Snate@binkert.org                goto exit;
15936657Snate@binkert.org        }
15946657Snate@binkert.org        break;
15956657Snate@binkert.org
15966657Snate@binkert.org      default:
15976657Snate@binkert.org        panic("Invalid rxState!");
15986657Snate@binkert.org    }
15996657Snate@binkert.org
16006657Snate@binkert.org
16016657Snate@binkert.org    DPRINTF(EthernetSM, "entering next rx state = %s\n",
16026657Snate@binkert.org            NsRxStateStrings[rxState]);
16036657Snate@binkert.org
16046657Snate@binkert.org    if (rxState == rxIdle) {
16056657Snate@binkert.org        regs.command &= ~CR_RXE;
16066657Snate@binkert.org        devIntrPost(ISR_RXIDLE);
16076657Snate@binkert.org        return;
16086657Snate@binkert.org    }
16096657Snate@binkert.org
16106657Snate@binkert.org    goto next;
16116657Snate@binkert.org
16126657Snate@binkert.org  exit:
16136657Snate@binkert.org    /**
16146657Snate@binkert.org     * @todo do we want to schedule a future kick?
16156657Snate@binkert.org     */
16166657Snate@binkert.org    DPRINTF(EthernetSM, "rx state machine exited state=%s\n",
16176657Snate@binkert.org            NsRxStateStrings[rxState]);
16186657Snate@binkert.org}
16196657Snate@binkert.org
16206657Snate@binkert.orgvoid
16216657Snate@binkert.orgNSGigE::transmit()
16226657Snate@binkert.org{
16236657Snate@binkert.org    if (txFifo.empty()) {
16246657Snate@binkert.org        DPRINTF(Ethernet, "nothing to transmit\n");
16256657Snate@binkert.org        return;
16266657Snate@binkert.org    }
16276657Snate@binkert.org
16286657Snate@binkert.org    DPRINTF(Ethernet, "\n\nAttempt Pkt Transmit: txFifo length = %d\n",
16296657Snate@binkert.org            maxTxFifoSize - txFifoAvail);
16306657Snate@binkert.org    if (interface->sendPacket(txFifo.front())) {
16316657Snate@binkert.org#if TRACING_ON
16326657Snate@binkert.org        if (DTRACE(Ethernet)) {
16336657Snate@binkert.org            if (txFifo.front()->isIpPkt()) {
16346657Snate@binkert.org                ip_header *ip = txFifo.front()->getIpHdr();
16356657Snate@binkert.org                DPRINTF(Ethernet, "ID is %d\n", reverseEnd16(ip->ID));
16366657Snate@binkert.org                if (txFifo.front()->isTcpPkt()) {
16376657Snate@binkert.org                    tcp_header *tcp = txFifo.front()->getTcpHdr(ip);
16386657Snate@binkert.org                    DPRINTF(Ethernet, "Src Port = %d, Dest Port = %d\n",
16396657Snate@binkert.org                            reverseEnd16(tcp->src_port_num),
16406657Snate@binkert.org                            reverseEnd16(tcp->dest_port_num));
16416657Snate@binkert.org                }
16426657Snate@binkert.org            }
16436657Snate@binkert.org        }
16446657Snate@binkert.org#endif
16456657Snate@binkert.org
16466657Snate@binkert.org        DDUMP(Ethernet, txFifo.front()->data, txFifo.front()->length);
16476657Snate@binkert.org        txBytes += txFifo.front()->length;
16486657Snate@binkert.org        txPackets++;
16496657Snate@binkert.org
16506657Snate@binkert.org        txFifoAvail += txFifo.front()->length;
16516657Snate@binkert.org
16526657Snate@binkert.org        DPRINTF(Ethernet, "Successful Xmit! now txFifoAvail is %d\n",
16536657Snate@binkert.org                txFifoAvail);
16546657Snate@binkert.org        txFifo.front() = NULL;
16556657Snate@binkert.org        txFifo.pop_front();
16566657Snate@binkert.org
16576657Snate@binkert.org        /*
16586657Snate@binkert.org         * normally do a writeback of the descriptor here, and ONLY
16596657Snate@binkert.org         * after that is done, send this interrupt.  but since our
16606657Snate@binkert.org         * stuff never actually fails, just do this interrupt here,
16616657Snate@binkert.org         * otherwise the code has to stray from this nice format.
16626657Snate@binkert.org         * besides, it's functionally the same.
16636657Snate@binkert.org         */
16646657Snate@binkert.org        devIntrPost(ISR_TXOK);
16656657Snate@binkert.org    } else {
16666657Snate@binkert.org        DPRINTF(Ethernet,
16676657Snate@binkert.org                "May need to rethink always sending the descriptors back?\n");
16686657Snate@binkert.org    }
16696657Snate@binkert.org
16706657Snate@binkert.org   if (!txFifo.empty() && !txEvent.scheduled()) {
16716657Snate@binkert.org       DPRINTF(Ethernet, "reschedule transmit\n");
16726657Snate@binkert.org       txEvent.schedule(curTick + 1000);
16736657Snate@binkert.org   }
16746657Snate@binkert.org}
16756657Snate@binkert.org
16767007Snate@binkert.orgvoid
16776657Snate@binkert.orgNSGigE::txDmaReadCopy()
16786657Snate@binkert.org{
16796657Snate@binkert.org    assert(txDmaState == dmaReading);
16806657Snate@binkert.org
16816657Snate@binkert.org    memcpy(txDmaData, physmem->dma_addr(txDmaAddr, txDmaLen), txDmaLen);
16826657Snate@binkert.org    txDmaState = dmaIdle;
16836657Snate@binkert.org
16847007Snate@binkert.org    DPRINTF(EthernetDMA, "tx dma read  paddr=%#x len=%d\n",
16856657Snate@binkert.org            txDmaAddr, txDmaLen);
16866657Snate@binkert.org    DDUMP(EthernetDMA, txDmaData, txDmaLen);
16876657Snate@binkert.org}
16886657Snate@binkert.org
16896657Snate@binkert.orgbool
16906657Snate@binkert.orgNSGigE::doTxDmaRead()
16916657Snate@binkert.org{
16926657Snate@binkert.org    assert(txDmaState == dmaIdle || txDmaState == dmaReadWaiting);
16936657Snate@binkert.org    txDmaState = dmaReading;
16946657Snate@binkert.org
16956657Snate@binkert.org    if (dmaInterface && !txDmaFree) {
16966657Snate@binkert.org        if (dmaInterface->busy())
16976657Snate@binkert.org            txDmaState = dmaReadWaiting;
16986657Snate@binkert.org        else
16996657Snate@binkert.org            dmaInterface->doDMA(Read, txDmaAddr, txDmaLen, curTick,
17007007Snate@binkert.org                                &txDmaReadEvent, true);
17016657Snate@binkert.org        return true;
17026657Snate@binkert.org    }
17036657Snate@binkert.org
17046657Snate@binkert.org    if (dmaReadDelay == 0 && dmaReadFactor == 0.0) {
17056657Snate@binkert.org        txDmaReadCopy();
17066657Snate@binkert.org        return false;
17076657Snate@binkert.org    }
17086657Snate@binkert.org
17096657Snate@binkert.org    Tick factor = ((txDmaLen + ULL(63)) >> ULL(6)) * dmaReadFactor;
17106657Snate@binkert.org    Tick start = curTick + dmaReadDelay + factor;
17116657Snate@binkert.org    txDmaReadEvent.schedule(start);
17126657Snate@binkert.org    return true;
17136657Snate@binkert.org}
17146657Snate@binkert.org
17156657Snate@binkert.orgvoid
17166657Snate@binkert.orgNSGigE::txDmaReadDone()
17176657Snate@binkert.org{
17186657Snate@binkert.org    assert(txDmaState == dmaReading);
17196657Snate@binkert.org    txDmaReadCopy();
17206657Snate@binkert.org
17216657Snate@binkert.org    // If the receive state machine  has a pending DMA, let it go first
17226657Snate@binkert.org    if (rxDmaState == dmaReadWaiting || rxDmaState == dmaWriteWaiting)
1723        rxKick();
1724
1725    txKick();
1726}
1727
1728void
1729NSGigE::txDmaWriteCopy()
1730{
1731    assert(txDmaState == dmaWriting);
1732
1733    memcpy(physmem->dma_addr(txDmaAddr, txDmaLen), txDmaData, txDmaLen);
1734    txDmaState = dmaIdle;
1735
1736    DPRINTF(EthernetDMA, "tx dma write paddr=%#x len=%d\n",
1737            txDmaAddr, txDmaLen);
1738    DDUMP(EthernetDMA, txDmaData, txDmaLen);
1739}
1740
1741bool
1742NSGigE::doTxDmaWrite()
1743{
1744    assert(txDmaState == dmaIdle || txDmaState == dmaWriteWaiting);
1745    txDmaState = dmaWriting;
1746
1747    if (dmaInterface && !txDmaFree) {
1748        if (dmaInterface->busy())
1749            txDmaState = dmaWriteWaiting;
1750        else
1751            dmaInterface->doDMA(WriteInvalidate, txDmaAddr, txDmaLen, curTick,
1752                                &txDmaWriteEvent, true);
1753        return true;
1754    }
1755
1756    if (dmaWriteDelay == 0 && dmaWriteFactor == 0.0) {
1757        txDmaWriteCopy();
1758        return false;
1759    }
1760
1761    Tick factor = ((txDmaLen + ULL(63)) >> ULL(6)) * dmaWriteFactor;
1762    Tick start = curTick + dmaWriteDelay + factor;
1763    txDmaWriteEvent.schedule(start);
1764    return true;
1765}
1766
1767void
1768NSGigE::txDmaWriteDone()
1769{
1770    assert(txDmaState == dmaWriting);
1771    txDmaWriteCopy();
1772
1773    // If the receive state machine  has a pending DMA, let it go first
1774    if (rxDmaState == dmaReadWaiting || rxDmaState == dmaWriteWaiting)
1775        rxKick();
1776
1777    txKick();
1778}
1779
1780void
1781NSGigE::txKick()
1782{
1783    DPRINTF(EthernetSM, "transmit kick state=%s\n", NsTxStateStrings[txState]);
1784
1785    if (txKickTick > curTick) {
1786        DPRINTF(EthernetSM, "transmit kick exiting, can't run till %d\n",
1787                txKickTick);
1788
1789        return;
1790    }
1791
1792  next:
1793    switch(txDmaState) {
1794      case dmaReadWaiting:
1795        if (doTxDmaRead())
1796            goto exit;
1797        break;
1798      case dmaWriteWaiting:
1799        if (doTxDmaWrite())
1800            goto exit;
1801        break;
1802      default:
1803        break;
1804    }
1805
1806    switch (txState) {
1807      case txIdle:
1808        if (!regs.command & CR_TXE) {
1809            DPRINTF(EthernetSM, "Transmit disabled.  Nothing to do.\n");
1810            goto exit;
1811        }
1812
1813        if (CTDD) {
1814            txState = txDescRefr;
1815
1816            txDmaAddr = regs.txdp & 0x3fffffff;
1817            txDmaData = &txDescCache + offsetof(ns_desc, link);
1818            txDmaLen = sizeof(txDescCache.link);
1819            txDmaFree = dmaDescFree;
1820
1821            descDmaReads++;
1822            descDmaRdBytes += txDmaLen;
1823
1824            if (doTxDmaRead())
1825                goto exit;
1826
1827        } else {
1828            txState = txDescRead;
1829
1830            txDmaAddr = regs.txdp & 0x3fffffff;
1831            txDmaData = &txDescCache;
1832            txDmaLen = sizeof(ns_desc);
1833            txDmaFree = dmaDescFree;
1834
1835            descDmaReads++;
1836            descDmaRdBytes += txDmaLen;
1837
1838            if (doTxDmaRead())
1839                goto exit;
1840        }
1841        break;
1842
1843      case txDescRefr:
1844        if (txDmaState != dmaIdle)
1845            goto exit;
1846
1847        txState = txAdvance;
1848        break;
1849
1850      case txDescRead:
1851        if (txDmaState != dmaIdle)
1852            goto exit;
1853
1854        DPRINTF(EthernetDesc,
1855                "txDescCache data:\n"
1856                "\tlink=%08x\n"
1857                "\tbufptr=%08x\n"
1858                "\tcmdsts=%08x\n"
1859                "\textsts=%08x\n",
1860                txDescCache.link, txDescCache.bufptr, txDescCache.cmdsts,
1861                txDescCache.extsts);
1862
1863        if (txDescCache.cmdsts & CMDSTS_OWN) {
1864            txState = txFifoBlock;
1865            txFragPtr = txDescCache.bufptr;
1866            txDescCnt = txDescCache.cmdsts & CMDSTS_LEN_MASK;
1867        } else {
1868            txState = txIdle;
1869        }
1870        break;
1871
1872      case txFifoBlock:
1873        if (!txPacket) {
1874            DPRINTF(EthernetSM, "\n\n*****starting the tx of a new packet\n");
1875            txPacket = new EtherPacket;
1876            txPacket->data = new uint8_t[16384];
1877            txPacketBufPtr = txPacket->data;
1878        }
1879
1880        if (txDescCnt == 0) {
1881            DPRINTF(EthernetSM, "the txDescCnt == 0, done with descriptor\n");
1882            if (txDescCache.cmdsts & CMDSTS_MORE) {
1883                DPRINTF(EthernetSM, "there are more descriptors to come\n");
1884                txState = txDescWrite;
1885
1886                txDescCache.cmdsts &= ~CMDSTS_OWN;
1887
1888                txDmaAddr = regs.txdp + offsetof(ns_desc, cmdsts);
1889                txDmaAddr &= 0x3fffffff;
1890                txDmaData = &(txDescCache.cmdsts);
1891                txDmaLen = sizeof(txDescCache.cmdsts);
1892                txDmaFree = dmaDescFree;
1893
1894                if (doTxDmaWrite())
1895                    goto exit;
1896
1897            } else { /* this packet is totally done */
1898                DPRINTF(EthernetSM, "This packet is done, let's wrap it up\n");
1899                /* deal with the the packet that just finished */
1900                if ((regs.vtcr & VTCR_PPCHK) && extstsEnable) {
1901                    if (txDescCache.extsts & EXTSTS_UDPPKT) {
1902                        udpChecksum(txPacket, true);
1903                    } else if (txDescCache.extsts & EXTSTS_TCPPKT) {
1904                        tcpChecksum(txPacket, true);
1905                        txTCPChecksums++;
1906                    }
1907                    if (txDescCache.extsts & EXTSTS_IPPKT) {
1908                        ipChecksum(txPacket, true);
1909                        txIPChecksums++;
1910                    }
1911                }
1912
1913                txPacket->length = txPacketBufPtr - txPacket->data;
1914                // this is just because the receive can't handle a
1915                // packet bigger want to make sure
1916                assert(txPacket->length <= 1514);
1917                txFifo.push_back(txPacket);
1918
1919                /*
1920                 * this following section is not tqo spec, but
1921                 * functionally shouldn't be any different.  normally,
1922                 * the chip will wait til the transmit has occurred
1923                 * before writing back the descriptor because it has
1924                 * to wait to see that it was successfully transmitted
1925                 * to decide whether to set CMDSTS_OK or not.
1926                 * however, in the simulator since it is always
1927                 * successfully transmitted, and writing it exactly to
1928                 * spec would complicate the code, we just do it here
1929                 */
1930
1931                txDescCache.cmdsts &= ~CMDSTS_OWN;
1932                txDescCache.cmdsts |= CMDSTS_OK;
1933
1934                DPRINTF(EthernetDesc,
1935                        "txDesc writeback:\n\tcmdsts=%08x\n\textsts=%08x\n",
1936                        txDescCache.cmdsts, txDescCache.extsts);
1937
1938                txDmaAddr = regs.txdp + offsetof(ns_desc, cmdsts);
1939                txDmaAddr &= 0x3fffffff;
1940                txDmaData = &(txDescCache.cmdsts);
1941                txDmaLen = sizeof(txDescCache.cmdsts) +
1942                    sizeof(txDescCache.extsts);
1943                txDmaFree = dmaDescFree;
1944
1945                descDmaWrites++;
1946                descDmaWrBytes += txDmaLen;
1947
1948                transmit();
1949                txPacket = 0;
1950
1951                if (txHalt) {
1952                    DPRINTF(EthernetSM, "halting TX state machine\n");
1953                    txState = txIdle;
1954                    txHalt = false;
1955                } else
1956                    txState = txAdvance;
1957
1958                if (doTxDmaWrite())
1959                    goto exit;
1960            }
1961        } else {
1962            DPRINTF(EthernetSM, "this descriptor isn't done yet\n");
1963            if (txFifoAvail) {
1964                txState = txFragRead;
1965
1966                /*
1967                 * The number of bytes transferred is either whatever
1968                 * is left in the descriptor (txDescCnt), or if there
1969                 * is not enough room in the fifo, just whatever room
1970                 * is left in the fifo
1971                 */
1972                txXferLen = min<uint32_t>(txDescCnt, txFifoAvail);
1973
1974                txDmaAddr = txFragPtr & 0x3fffffff;
1975                txDmaData = txPacketBufPtr;
1976                txDmaLen = txXferLen;
1977                txDmaFree = dmaDataFree;
1978
1979                if (doTxDmaRead())
1980                    goto exit;
1981            } else {
1982                txState = txFifoBlock;
1983                transmit();
1984
1985                goto exit;
1986            }
1987
1988        }
1989        break;
1990
1991      case txFragRead:
1992        if (txDmaState != dmaIdle)
1993            goto exit;
1994
1995        txPacketBufPtr += txXferLen;
1996        txFragPtr += txXferLen;
1997        txDescCnt -= txXferLen;
1998        txFifoAvail -= txXferLen;
1999
2000        txState = txFifoBlock;
2001        break;
2002
2003      case txDescWrite:
2004        if (txDmaState != dmaIdle)
2005            goto exit;
2006
2007        if (txDescCache.cmdsts & CMDSTS_INTR) {
2008            devIntrPost(ISR_TXDESC);
2009        }
2010
2011        txState = txAdvance;
2012        break;
2013
2014      case txAdvance:
2015        if (txDescCache.link == 0) {
2016            txState = txIdle;
2017        } else {
2018            txState = txDescRead;
2019            regs.txdp = txDescCache.link;
2020            CTDD = false;
2021
2022            txDmaAddr = txDescCache.link & 0x3fffffff;
2023            txDmaData = &txDescCache;
2024            txDmaLen = sizeof(ns_desc);
2025            txDmaFree = dmaDescFree;
2026
2027            if (doTxDmaRead())
2028                goto exit;
2029        }
2030        break;
2031
2032      default:
2033        panic("invalid state");
2034    }
2035
2036    DPRINTF(EthernetSM, "entering next tx state=%s\n",
2037            NsTxStateStrings[txState]);
2038
2039    if (txState == txIdle) {
2040        regs.command &= ~CR_TXE;
2041        devIntrPost(ISR_TXIDLE);
2042        return;
2043    }
2044
2045    goto next;
2046
2047  exit:
2048    /**
2049     * @todo do we want to schedule a future kick?
2050     */
2051    DPRINTF(EthernetSM, "tx state machine exited state=%s\n",
2052            NsTxStateStrings[txState]);
2053}
2054
2055void
2056NSGigE::transferDone()
2057{
2058    if (txFifo.empty())
2059        return;
2060
2061    if (txEvent.scheduled())
2062        txEvent.reschedule(curTick + 1);
2063    else
2064        txEvent.schedule(curTick + 1);
2065}
2066
2067bool
2068NSGigE::rxFilter(PacketPtr packet)
2069{
2070    bool drop = true;
2071    string type;
2072
2073    if (packet->IsUnicast()) {
2074        type = "unicast";
2075
2076        // If we're accepting all unicast addresses
2077        if (acceptUnicast)
2078            drop = false;
2079
2080        // If we make a perfect match
2081        if (acceptPerfect &&
2082            memcmp(rom.perfectMatch, packet->data, EADDR_LEN) == 0)
2083            drop = false;
2084
2085        eth_header *eth = (eth_header *) packet->data;
2086        if ((acceptArp) && (eth->type == 0x608))
2087            drop = false;
2088
2089    } else if (packet->IsBroadcast()) {
2090        type = "broadcast";
2091
2092        // if we're accepting broadcasts
2093        if (acceptBroadcast)
2094            drop = false;
2095
2096    } else if (packet->IsMulticast()) {
2097        type = "multicast";
2098
2099        // if we're accepting all multicasts
2100        if (acceptMulticast)
2101            drop = false;
2102
2103    } else {
2104        type = "unknown";
2105
2106        // oh well, punt on this one
2107    }
2108
2109    if (drop) {
2110        DPRINTF(Ethernet, "rxFilter drop\n");
2111        DDUMP(EthernetData, packet->data, packet->length);
2112    }
2113
2114    return drop;
2115}
2116
2117bool
2118NSGigE::recvPacket(PacketPtr packet)
2119{
2120    rxBytes += packet->length;
2121    rxPackets++;
2122
2123    DPRINTF(Ethernet, "\n\nReceiving packet from wire, rxFifoAvail=%d\n",
2124            maxRxFifoSize - rxFifoCnt);
2125
2126    if (rxState == rxIdle) {
2127        DPRINTF(Ethernet, "receive disabled...packet dropped\n");
2128        interface->recvDone();
2129        return true;
2130    }
2131
2132    if (rxFilterEnable && rxFilter(packet)) {
2133        DPRINTF(Ethernet, "packet filtered...dropped\n");
2134        interface->recvDone();
2135        return true;
2136    }
2137
2138    if ((rxFifoCnt + packet->length) >= maxRxFifoSize) {
2139        DPRINTF(Ethernet,
2140                "packet will not fit in receive buffer...packet dropped\n");
2141        devIntrPost(ISR_RXORN);
2142        return false;
2143    }
2144
2145    rxFifo.push_back(packet);
2146    rxFifoCnt += packet->length;
2147    interface->recvDone();
2148
2149    rxKick();
2150    return true;
2151}
2152
2153/**
2154 * does a udp checksum.  if gen is true, then it generates it and puts
2155 * it in the right place else, it just checks what it calculates
2156 * against the value in the header in packet
2157 */
2158bool
2159NSGigE::udpChecksum(PacketPtr packet, bool gen)
2160{
2161    ip_header *ip = packet->getIpHdr();
2162    udp_header *hdr = packet->getUdpHdr(ip);
2163
2164    pseudo_header *pseudo = new pseudo_header;
2165
2166    pseudo->src_ip_addr = ip->src_ip_addr;
2167    pseudo->dest_ip_addr = ip->dest_ip_addr;
2168    pseudo->protocol = ip->protocol;
2169    pseudo->len = hdr->len;
2170
2171    uint16_t cksum = checksumCalc((uint16_t *) pseudo, (uint16_t *) hdr,
2172                                  (uint32_t) hdr->len);
2173
2174    delete pseudo;
2175    if (gen)
2176        hdr->chksum = cksum;
2177    else
2178        if (cksum != 0)
2179            return false;
2180
2181    return true;
2182}
2183
2184bool
2185NSGigE::tcpChecksum(PacketPtr packet, bool gen)
2186{
2187    ip_header *ip = packet->getIpHdr();
2188    tcp_header *hdr = packet->getTcpHdr(ip);
2189
2190    uint16_t cksum;
2191    pseudo_header *pseudo = new pseudo_header;
2192    if (!gen) {
2193        pseudo->src_ip_addr = ip->src_ip_addr;
2194        pseudo->dest_ip_addr = ip->dest_ip_addr;
2195        pseudo->protocol = reverseEnd16(ip->protocol);
2196        pseudo->len = reverseEnd16(reverseEnd16(ip->dgram_len) -
2197                                   (ip->vers_len & 0xf)*4);
2198
2199        cksum = checksumCalc((uint16_t *) pseudo, (uint16_t *) hdr,
2200                             (uint32_t) reverseEnd16(pseudo->len));
2201    } else {
2202        pseudo->src_ip_addr = 0;
2203        pseudo->dest_ip_addr = 0;
2204        pseudo->protocol = hdr->chksum;
2205        pseudo->len = 0;
2206        hdr->chksum = 0;
2207        cksum = checksumCalc((uint16_t *) pseudo, (uint16_t *) hdr,
2208                             (uint32_t) (reverseEnd16(ip->dgram_len) -
2209                                         (ip->vers_len & 0xf)*4));
2210    }
2211
2212    delete pseudo;
2213    if (gen)
2214        hdr->chksum = cksum;
2215    else
2216        if (cksum != 0)
2217            return false;
2218
2219    return true;
2220}
2221
2222bool
2223NSGigE::ipChecksum(PacketPtr packet, bool gen)
2224{
2225    ip_header *hdr = packet->getIpHdr();
2226
2227    uint16_t cksum = checksumCalc(NULL, (uint16_t *) hdr,
2228                                  (hdr->vers_len & 0xf)*4);
2229
2230    if (gen) {
2231        DPRINTF(EthernetCksum, "generated checksum: %#x\n", cksum);
2232        hdr->hdr_chksum = cksum;
2233    }
2234    else
2235        if (cksum != 0)
2236            return false;
2237
2238    return true;
2239}
2240
2241uint16_t
2242NSGigE::checksumCalc(uint16_t *pseudo, uint16_t *buf, uint32_t len)
2243{
2244    uint32_t sum = 0;
2245
2246    uint16_t last_pad = 0;
2247    if (len & 1) {
2248        last_pad = buf[len/2] & 0xff;
2249        len--;
2250        sum += last_pad;
2251    }
2252
2253    if (pseudo) {
2254        sum = pseudo[0] + pseudo[1] + pseudo[2] +
2255            pseudo[3] + pseudo[4] + pseudo[5];
2256    }
2257
2258    for (int i=0; i < (len/2); ++i) {
2259        sum += buf[i];
2260    }
2261
2262    while (sum >> 16)
2263        sum = (sum >> 16) + (sum & 0xffff);
2264
2265    return ~sum;
2266}
2267
2268//=====================================================================
2269//
2270//
2271void
2272NSGigE::serialize(ostream &os)
2273{
2274    // Serialize the PciDev base class
2275    PciDev::serialize(os);
2276
2277    /*
2278     * Finalize any DMA events now.
2279     */
2280    if (rxDmaReadEvent.scheduled())
2281        rxDmaReadCopy();
2282    if (rxDmaWriteEvent.scheduled())
2283        rxDmaWriteCopy();
2284    if (txDmaReadEvent.scheduled())
2285        txDmaReadCopy();
2286    if (txDmaWriteEvent.scheduled())
2287        txDmaWriteCopy();
2288
2289    /*
2290     * Serialize the device registers
2291     */
2292    SERIALIZE_SCALAR(regs.command);
2293    SERIALIZE_SCALAR(regs.config);
2294    SERIALIZE_SCALAR(regs.mear);
2295    SERIALIZE_SCALAR(regs.ptscr);
2296    SERIALIZE_SCALAR(regs.isr);
2297    SERIALIZE_SCALAR(regs.imr);
2298    SERIALIZE_SCALAR(regs.ier);
2299    SERIALIZE_SCALAR(regs.ihr);
2300    SERIALIZE_SCALAR(regs.txdp);
2301    SERIALIZE_SCALAR(regs.txdp_hi);
2302    SERIALIZE_SCALAR(regs.txcfg);
2303    SERIALIZE_SCALAR(regs.gpior);
2304    SERIALIZE_SCALAR(regs.rxdp);
2305    SERIALIZE_SCALAR(regs.rxdp_hi);
2306    SERIALIZE_SCALAR(regs.rxcfg);
2307    SERIALIZE_SCALAR(regs.pqcr);
2308    SERIALIZE_SCALAR(regs.wcsr);
2309    SERIALIZE_SCALAR(regs.pcr);
2310    SERIALIZE_SCALAR(regs.rfcr);
2311    SERIALIZE_SCALAR(regs.rfdr);
2312    SERIALIZE_SCALAR(regs.srr);
2313    SERIALIZE_SCALAR(regs.mibc);
2314    SERIALIZE_SCALAR(regs.vrcr);
2315    SERIALIZE_SCALAR(regs.vtcr);
2316    SERIALIZE_SCALAR(regs.vdr);
2317    SERIALIZE_SCALAR(regs.ccsr);
2318    SERIALIZE_SCALAR(regs.tbicr);
2319    SERIALIZE_SCALAR(regs.tbisr);
2320    SERIALIZE_SCALAR(regs.tanar);
2321    SERIALIZE_SCALAR(regs.tanlpar);
2322    SERIALIZE_SCALAR(regs.taner);
2323    SERIALIZE_SCALAR(regs.tesr);
2324
2325    SERIALIZE_ARRAY(rom.perfectMatch, EADDR_LEN);
2326
2327    SERIALIZE_SCALAR(ioEnable);
2328
2329    /*
2330     * Serialize the data Fifos
2331     */
2332    int txNumPkts = txFifo.size();
2333    SERIALIZE_SCALAR(txNumPkts);
2334    int i = 0;
2335    pktiter_t end = txFifo.end();
2336    for (pktiter_t p = txFifo.begin(); p != end; ++p) {
2337        nameOut(os, csprintf("%s.txFifo%d", name(), i++));
2338        (*p)->serialize(os);
2339    }
2340
2341    int rxNumPkts = rxFifo.size();
2342    SERIALIZE_SCALAR(rxNumPkts);
2343    i = 0;
2344    end = rxFifo.end();
2345    for (pktiter_t p = rxFifo.begin(); p != end; ++p) {
2346        nameOut(os, csprintf("%s.rxFifo%d", name(), i++));
2347        (*p)->serialize(os);
2348    }
2349
2350    /*
2351     * Serialize the various helper variables
2352     */
2353    bool txPacketExists = txPacket;
2354    SERIALIZE_SCALAR(txPacketExists);
2355    if (txPacketExists) {
2356        nameOut(os, csprintf("%s.txPacket", name()));
2357        txPacket->serialize(os);
2358        uint32_t txPktBufPtr = (uint32_t) (txPacketBufPtr - txPacket->data);
2359        SERIALIZE_SCALAR(txPktBufPtr);
2360    }
2361
2362    bool rxPacketExists = rxPacket;
2363    SERIALIZE_SCALAR(rxPacketExists);
2364    if (rxPacketExists) {
2365        nameOut(os, csprintf("%s.rxPacket", name()));
2366        rxPacket->serialize(os);
2367        uint32_t rxPktBufPtr = (uint32_t) (rxPacketBufPtr - rxPacket->data);
2368        SERIALIZE_SCALAR(rxPktBufPtr);
2369    }
2370
2371    SERIALIZE_SCALAR(txXferLen);
2372    SERIALIZE_SCALAR(rxXferLen);
2373
2374    /*
2375     * Serialize DescCaches
2376     */
2377    SERIALIZE_SCALAR(txDescCache.link);
2378    SERIALIZE_SCALAR(txDescCache.bufptr);
2379    SERIALIZE_SCALAR(txDescCache.cmdsts);
2380    SERIALIZE_SCALAR(txDescCache.extsts);
2381    SERIALIZE_SCALAR(rxDescCache.link);
2382    SERIALIZE_SCALAR(rxDescCache.bufptr);
2383    SERIALIZE_SCALAR(rxDescCache.cmdsts);
2384    SERIALIZE_SCALAR(rxDescCache.extsts);
2385
2386    /*
2387     * Serialize tx state machine
2388     */
2389    int txState = this->txState;
2390    SERIALIZE_SCALAR(txState);
2391    SERIALIZE_SCALAR(CTDD);
2392    SERIALIZE_SCALAR(txFifoAvail);
2393    SERIALIZE_SCALAR(txHalt);
2394    SERIALIZE_SCALAR(txFragPtr);
2395    SERIALIZE_SCALAR(txDescCnt);
2396    int txDmaState = this->txDmaState;
2397    SERIALIZE_SCALAR(txDmaState);
2398
2399    /*
2400     * Serialize rx state machine
2401     */
2402    int rxState = this->rxState;
2403    SERIALIZE_SCALAR(rxState);
2404    SERIALIZE_SCALAR(CRDD);
2405    SERIALIZE_SCALAR(rxPktBytes);
2406    SERIALIZE_SCALAR(rxFifoCnt);
2407    SERIALIZE_SCALAR(rxHalt);
2408    SERIALIZE_SCALAR(rxDescCnt);
2409    int rxDmaState = this->rxDmaState;
2410    SERIALIZE_SCALAR(rxDmaState);
2411
2412    SERIALIZE_SCALAR(extstsEnable);
2413
2414    /*
2415     * If there's a pending transmit, store the time so we can
2416     * reschedule it later
2417     */
2418    Tick transmitTick = txEvent.scheduled() ? txEvent.when() - curTick : 0;
2419    SERIALIZE_SCALAR(transmitTick);
2420
2421    /*
2422     * receive address filter settings
2423     */
2424    SERIALIZE_SCALAR(rxFilterEnable);
2425    SERIALIZE_SCALAR(acceptBroadcast);
2426    SERIALIZE_SCALAR(acceptMulticast);
2427    SERIALIZE_SCALAR(acceptUnicast);
2428    SERIALIZE_SCALAR(acceptPerfect);
2429    SERIALIZE_SCALAR(acceptArp);
2430
2431    /*
2432     * Keep track of pending interrupt status.
2433     */
2434    SERIALIZE_SCALAR(intrTick);
2435    SERIALIZE_SCALAR(cpuPendingIntr);
2436    Tick intrEventTick = 0;
2437    if (intrEvent)
2438        intrEventTick = intrEvent->when();
2439    SERIALIZE_SCALAR(intrEventTick);
2440
2441}
2442
2443void
2444NSGigE::unserialize(Checkpoint *cp, const std::string &section)
2445{
2446    // Unserialize the PciDev base class
2447    PciDev::unserialize(cp, section);
2448
2449    UNSERIALIZE_SCALAR(regs.command);
2450    UNSERIALIZE_SCALAR(regs.config);
2451    UNSERIALIZE_SCALAR(regs.mear);
2452    UNSERIALIZE_SCALAR(regs.ptscr);
2453    UNSERIALIZE_SCALAR(regs.isr);
2454    UNSERIALIZE_SCALAR(regs.imr);
2455    UNSERIALIZE_SCALAR(regs.ier);
2456    UNSERIALIZE_SCALAR(regs.ihr);
2457    UNSERIALIZE_SCALAR(regs.txdp);
2458    UNSERIALIZE_SCALAR(regs.txdp_hi);
2459    UNSERIALIZE_SCALAR(regs.txcfg);
2460    UNSERIALIZE_SCALAR(regs.gpior);
2461    UNSERIALIZE_SCALAR(regs.rxdp);
2462    UNSERIALIZE_SCALAR(regs.rxdp_hi);
2463    UNSERIALIZE_SCALAR(regs.rxcfg);
2464    UNSERIALIZE_SCALAR(regs.pqcr);
2465    UNSERIALIZE_SCALAR(regs.wcsr);
2466    UNSERIALIZE_SCALAR(regs.pcr);
2467    UNSERIALIZE_SCALAR(regs.rfcr);
2468    UNSERIALIZE_SCALAR(regs.rfdr);
2469    UNSERIALIZE_SCALAR(regs.srr);
2470    UNSERIALIZE_SCALAR(regs.mibc);
2471    UNSERIALIZE_SCALAR(regs.vrcr);
2472    UNSERIALIZE_SCALAR(regs.vtcr);
2473    UNSERIALIZE_SCALAR(regs.vdr);
2474    UNSERIALIZE_SCALAR(regs.ccsr);
2475    UNSERIALIZE_SCALAR(regs.tbicr);
2476    UNSERIALIZE_SCALAR(regs.tbisr);
2477    UNSERIALIZE_SCALAR(regs.tanar);
2478    UNSERIALIZE_SCALAR(regs.tanlpar);
2479    UNSERIALIZE_SCALAR(regs.taner);
2480    UNSERIALIZE_SCALAR(regs.tesr);
2481
2482    UNSERIALIZE_ARRAY(rom.perfectMatch, EADDR_LEN);
2483
2484    UNSERIALIZE_SCALAR(ioEnable);
2485
2486    /*
2487     * unserialize the data fifos
2488     */
2489    int txNumPkts;
2490    UNSERIALIZE_SCALAR(txNumPkts);
2491    int i;
2492    for (i = 0; i < txNumPkts; ++i) {
2493        PacketPtr p = new EtherPacket;
2494        p->unserialize(cp, csprintf("%s.rxFifo%d", section, i));
2495        txFifo.push_back(p);
2496    }
2497
2498    int rxNumPkts;
2499    UNSERIALIZE_SCALAR(rxNumPkts);
2500    for (i = 0; i < rxNumPkts; ++i) {
2501        PacketPtr p = new EtherPacket;
2502        p->unserialize(cp, csprintf("%s.rxFifo%d", section, i));
2503        rxFifo.push_back(p);
2504    }
2505
2506    /*
2507     * unserialize the various helper variables
2508     */
2509    bool txPacketExists;
2510    UNSERIALIZE_SCALAR(txPacketExists);
2511    if (txPacketExists) {
2512        txPacket = new EtherPacket;
2513        txPacket->unserialize(cp, csprintf("%s.txPacket", section));
2514        uint32_t txPktBufPtr;
2515        UNSERIALIZE_SCALAR(txPktBufPtr);
2516        txPacketBufPtr = (uint8_t *) txPacket->data + txPktBufPtr;
2517    } else
2518        txPacket = 0;
2519
2520    bool rxPacketExists;
2521    UNSERIALIZE_SCALAR(rxPacketExists);
2522    rxPacket = 0;
2523    if (rxPacketExists) {
2524        rxPacket = new EtherPacket;
2525        rxPacket->unserialize(cp, csprintf("%s.rxPacket", section));
2526        uint32_t rxPktBufPtr;
2527        UNSERIALIZE_SCALAR(rxPktBufPtr);
2528        rxPacketBufPtr = (uint8_t *) rxPacket->data + rxPktBufPtr;
2529    } else
2530        rxPacket = 0;
2531
2532    UNSERIALIZE_SCALAR(txXferLen);
2533    UNSERIALIZE_SCALAR(rxXferLen);
2534
2535    /*
2536     * Unserialize DescCaches
2537     */
2538    UNSERIALIZE_SCALAR(txDescCache.link);
2539    UNSERIALIZE_SCALAR(txDescCache.bufptr);
2540    UNSERIALIZE_SCALAR(txDescCache.cmdsts);
2541    UNSERIALIZE_SCALAR(txDescCache.extsts);
2542    UNSERIALIZE_SCALAR(rxDescCache.link);
2543    UNSERIALIZE_SCALAR(rxDescCache.bufptr);
2544    UNSERIALIZE_SCALAR(rxDescCache.cmdsts);
2545    UNSERIALIZE_SCALAR(rxDescCache.extsts);
2546
2547    /*
2548     * unserialize tx state machine
2549     */
2550    int txState;
2551    UNSERIALIZE_SCALAR(txState);
2552    this->txState = (TxState) txState;
2553    UNSERIALIZE_SCALAR(CTDD);
2554    UNSERIALIZE_SCALAR(txFifoAvail);
2555    UNSERIALIZE_SCALAR(txHalt);
2556    UNSERIALIZE_SCALAR(txFragPtr);
2557    UNSERIALIZE_SCALAR(txDescCnt);
2558    int txDmaState;
2559    UNSERIALIZE_SCALAR(txDmaState);
2560    this->txDmaState = (DmaState) txDmaState;
2561
2562    /*
2563     * unserialize rx state machine
2564     */
2565    int rxState;
2566    UNSERIALIZE_SCALAR(rxState);
2567    this->rxState = (RxState) rxState;
2568    UNSERIALIZE_SCALAR(CRDD);
2569    UNSERIALIZE_SCALAR(rxPktBytes);
2570    UNSERIALIZE_SCALAR(rxFifoCnt);
2571    UNSERIALIZE_SCALAR(rxHalt);
2572    UNSERIALIZE_SCALAR(rxDescCnt);
2573    int rxDmaState;
2574    UNSERIALIZE_SCALAR(rxDmaState);
2575    this->rxDmaState = (DmaState) rxDmaState;
2576
2577    UNSERIALIZE_SCALAR(extstsEnable);
2578
2579     /*
2580     * If there's a pending transmit, reschedule it now
2581     */
2582    Tick transmitTick;
2583    UNSERIALIZE_SCALAR(transmitTick);
2584    if (transmitTick)
2585        txEvent.schedule(curTick + transmitTick);
2586
2587    /*
2588     * unserialize receive address filter settings
2589     */
2590    UNSERIALIZE_SCALAR(rxFilterEnable);
2591    UNSERIALIZE_SCALAR(acceptBroadcast);
2592    UNSERIALIZE_SCALAR(acceptMulticast);
2593    UNSERIALIZE_SCALAR(acceptUnicast);
2594    UNSERIALIZE_SCALAR(acceptPerfect);
2595    UNSERIALIZE_SCALAR(acceptArp);
2596
2597    /*
2598     * Keep track of pending interrupt status.
2599     */
2600    UNSERIALIZE_SCALAR(intrTick);
2601    UNSERIALIZE_SCALAR(cpuPendingIntr);
2602    Tick intrEventTick;
2603    UNSERIALIZE_SCALAR(intrEventTick);
2604    if (intrEventTick) {
2605        intrEvent = new IntrEvent(this, true);
2606        intrEvent->schedule(intrEventTick);
2607    }
2608
2609    /*
2610     * re-add addrRanges to bus bridges
2611     */
2612    if (pioInterface) {
2613        pioInterface->addAddrRange(BARAddrs[0], BARAddrs[0] + BARSize[0] - 1);
2614        pioInterface->addAddrRange(BARAddrs[1], BARAddrs[1] + BARSize[1] - 1);
2615    }
2616}
2617
2618Tick
2619NSGigE::cacheAccess(MemReqPtr &req)
2620{
2621    DPRINTF(EthernetPIO, "timing access to paddr=%#x (daddr=%#x)\n",
2622            req->paddr, req->paddr - addr);
2623    return curTick + pioLatency;
2624}
2625//=====================================================================
2626
2627
2628//********** helper functions******************************************
2629
2630uint16_t reverseEnd16(uint16_t num)
2631{
2632    uint16_t reverse = (num & 0xff)<<8;
2633    reverse += ((num & 0xff00) >> 8);
2634    return reverse;
2635}
2636
2637uint32_t reverseEnd32(uint32_t num)
2638{
2639    uint32_t reverse = (reverseEnd16(num & 0xffff)) << 16;
2640    reverse += reverseEnd16((uint16_t) ((num & 0xffff0000) >> 8));
2641    return reverse;
2642}
2643
2644
2645
2646//=====================================================================
2647
2648BEGIN_DECLARE_SIM_OBJECT_PARAMS(NSGigEInt)
2649
2650    SimObjectParam<EtherInt *> peer;
2651    SimObjectParam<NSGigE *> device;
2652
2653END_DECLARE_SIM_OBJECT_PARAMS(NSGigEInt)
2654
2655BEGIN_INIT_SIM_OBJECT_PARAMS(NSGigEInt)
2656
2657    INIT_PARAM_DFLT(peer, "peer interface", NULL),
2658    INIT_PARAM(device, "Ethernet device of this interface")
2659
2660END_INIT_SIM_OBJECT_PARAMS(NSGigEInt)
2661
2662CREATE_SIM_OBJECT(NSGigEInt)
2663{
2664    NSGigEInt *dev_int = new NSGigEInt(getInstanceName(), device);
2665
2666    EtherInt *p = (EtherInt *)peer;
2667    if (p) {
2668        dev_int->setPeer(p);
2669        p->setPeer(dev_int);
2670    }
2671
2672    return dev_int;
2673}
2674
2675REGISTER_SIM_OBJECT("NSGigEInt", NSGigEInt)
2676
2677
2678BEGIN_DECLARE_SIM_OBJECT_PARAMS(NSGigE)
2679
2680    Param<Tick> tx_delay;
2681    Param<Tick> rx_delay;
2682    SimObjectParam<IntrControl *> intr_ctrl;
2683    Param<Tick> intr_delay;
2684    SimObjectParam<MemoryController *> mmu;
2685    SimObjectParam<PhysicalMemory *> physmem;
2686    Param<bool> rx_filter;
2687    Param<string> hardware_address;
2688    SimObjectParam<Bus*> header_bus;
2689    SimObjectParam<Bus*> payload_bus;
2690    SimObjectParam<HierParams *> hier;
2691    Param<Tick> pio_latency;
2692    Param<bool> dma_desc_free;
2693    Param<bool> dma_data_free;
2694    Param<Tick> dma_read_delay;
2695    Param<Tick> dma_write_delay;
2696    Param<Tick> dma_read_factor;
2697    Param<Tick> dma_write_factor;
2698    SimObjectParam<PciConfigAll *> configspace;
2699    SimObjectParam<PciConfigData *> configdata;
2700    SimObjectParam<Tsunami *> tsunami;
2701    Param<uint32_t> pci_bus;
2702    Param<uint32_t> pci_dev;
2703    Param<uint32_t> pci_func;
2704    Param<uint32_t> tx_fifo_size;
2705    Param<uint32_t> rx_fifo_size;
2706
2707END_DECLARE_SIM_OBJECT_PARAMS(NSGigE)
2708
2709BEGIN_INIT_SIM_OBJECT_PARAMS(NSGigE)
2710
2711    INIT_PARAM_DFLT(tx_delay, "Transmit Delay", 1000),
2712    INIT_PARAM_DFLT(rx_delay, "Receive Delay", 1000),
2713    INIT_PARAM(intr_ctrl, "Interrupt Controller"),
2714    INIT_PARAM_DFLT(intr_delay, "Interrupt Delay in microseconds", 0),
2715    INIT_PARAM(mmu, "Memory Controller"),
2716    INIT_PARAM(physmem, "Physical Memory"),
2717    INIT_PARAM_DFLT(rx_filter, "Enable Receive Filter", true),
2718    INIT_PARAM_DFLT(hardware_address, "Ethernet Hardware Address",
2719                    "00:99:00:00:00:01"),
2720    INIT_PARAM_DFLT(header_bus, "The IO Bus to attach to for headers", NULL),
2721    INIT_PARAM_DFLT(payload_bus, "The IO Bus to attach to for payload", NULL),
2722    INIT_PARAM_DFLT(hier, "Hierarchy global variables", &defaultHierParams),
2723    INIT_PARAM_DFLT(pio_latency, "Programmed IO latency in bus cycles", 1),
2724    INIT_PARAM_DFLT(dma_desc_free, "DMA of Descriptors is free", false),
2725    INIT_PARAM_DFLT(dma_data_free, "DMA of Data is free", false),
2726    INIT_PARAM_DFLT(dma_read_delay, "fixed delay for dma reads", 0),
2727    INIT_PARAM_DFLT(dma_write_delay, "fixed delay for dma writes", 0),
2728    INIT_PARAM_DFLT(dma_read_factor, "multiplier for dma reads", 0),
2729    INIT_PARAM_DFLT(dma_write_factor, "multiplier for dma writes", 0),
2730    INIT_PARAM(configspace, "PCI Configspace"),
2731    INIT_PARAM(configdata, "PCI Config data"),
2732    INIT_PARAM(tsunami, "Tsunami"),
2733    INIT_PARAM(pci_bus, "PCI bus"),
2734    INIT_PARAM(pci_dev, "PCI device number"),
2735    INIT_PARAM(pci_func, "PCI function code"),
2736    INIT_PARAM_DFLT(tx_fifo_size, "max size in bytes of txFifo", 131072),
2737    INIT_PARAM_DFLT(rx_fifo_size, "max size in bytes of rxFifo", 131072)
2738
2739END_INIT_SIM_OBJECT_PARAMS(NSGigE)
2740
2741
2742CREATE_SIM_OBJECT(NSGigE)
2743{
2744    int eaddr[6];
2745    sscanf(((string)hardware_address).c_str(), "%x:%x:%x:%x:%x:%x",
2746           &eaddr[0], &eaddr[1], &eaddr[2], &eaddr[3], &eaddr[4], &eaddr[5]);
2747
2748    return new NSGigE(getInstanceName(), intr_ctrl, intr_delay,
2749                      physmem, tx_delay, rx_delay, mmu, hier, header_bus,
2750                      payload_bus, pio_latency, dma_desc_free, dma_data_free,
2751                      dma_read_delay, dma_write_delay, dma_read_factor,
2752                      dma_write_factor, configspace, configdata,
2753                      tsunami, pci_bus, pci_dev, pci_func, rx_filter, eaddr,
2754                      tx_fifo_size, rx_fifo_size);
2755}
2756
2757REGISTER_SIM_OBJECT("NSGigE", NSGigE)
2758