ns_gige.cc revision 1205
16657Snate@binkert.org/*
26657Snate@binkert.org * Copyright (c) 2004 The Regents of The University of Michigan
36657Snate@binkert.org * All rights reserved.
46657Snate@binkert.org *
56657Snate@binkert.org * Redistribution and use in source and binary forms, with or without
66657Snate@binkert.org * modification, are permitted provided that the following conditions are
76657Snate@binkert.org * met: redistributions of source code must retain the above copyright
86657Snate@binkert.org * notice, this list of conditions and the following disclaimer;
96657Snate@binkert.org * redistributions in binary form must reproduce the above copyright
106657Snate@binkert.org * notice, this list of conditions and the following disclaimer in the
116657Snate@binkert.org * documentation and/or other materials provided with the distribution;
126657Snate@binkert.org * neither the name of the copyright holders nor the names of its
136657Snate@binkert.org * contributors may be used to endorse or promote products derived from
146657Snate@binkert.org * this software without specific prior written permission.
156657Snate@binkert.org *
166657Snate@binkert.org * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
176657Snate@binkert.org * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
186657Snate@binkert.org * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
196657Snate@binkert.org * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
206657Snate@binkert.org * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
216657Snate@binkert.org * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
226657Snate@binkert.org * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
236657Snate@binkert.org * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
246657Snate@binkert.org * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
256657Snate@binkert.org * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
266657Snate@binkert.org * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
276657Snate@binkert.org */
286999Snate@binkert.org
296657Snate@binkert.org/* @file
306657Snate@binkert.org * Device module for modelling the National Semiconductor
316657Snate@binkert.org * DP83820 ethernet controller.  Does not support priority queueing
326657Snate@binkert.org */
338189SLisa.Hsu@amd.com#include <cstdio>
346657Snate@binkert.org#include <deque>
356882SBrad.Beckmann@amd.com#include <string>
367055Snate@binkert.org
376882SBrad.Beckmann@amd.com#include "base/inet.hh"
386882SBrad.Beckmann@amd.com#include "cpu/exec_context.hh"
398191SLisa.Hsu@amd.com#include "cpu/intr_control.hh"
406882SBrad.Beckmann@amd.com#include "dev/dma.hh"
416882SBrad.Beckmann@amd.com#include "dev/etherlink.hh"
426882SBrad.Beckmann@amd.com#include "dev/ns_gige.hh"
436888SBrad.Beckmann@amd.com#include "dev/pciconfigall.hh"
446882SBrad.Beckmann@amd.com#include "mem/bus/bus.hh"
456882SBrad.Beckmann@amd.com#include "mem/bus/dma_interface.hh"
466657Snate@binkert.org#include "mem/bus/pio_interface.hh"
476657Snate@binkert.org#include "mem/bus/pio_interface_impl.hh"
486657Snate@binkert.org#include "mem/functional_mem/memory_control.hh"
496657Snate@binkert.org#include "mem/functional_mem/physical_memory.hh"
506657Snate@binkert.org#include "sim/builder.hh"
517839Snilay@cs.wisc.edu#include "sim/debug.hh"
526657Snate@binkert.org#include "sim/host.hh"
536882SBrad.Beckmann@amd.com#include "sim/stats.hh"
546882SBrad.Beckmann@amd.com#include "targetarch/vtophys.hh"
556882SBrad.Beckmann@amd.com
566882SBrad.Beckmann@amd.comconst char *NsRxStateStrings[] =
576882SBrad.Beckmann@amd.com{
586882SBrad.Beckmann@amd.com    "rxIdle",
596657Snate@binkert.org    "rxDescRefr",
606657Snate@binkert.org    "rxDescRead",
616657Snate@binkert.org    "rxFifoBlock",
626657Snate@binkert.org    "rxFragWrite",
636657Snate@binkert.org    "rxDescWrite",
646657Snate@binkert.org    "rxAdvance"
656657Snate@binkert.org};
666657Snate@binkert.org
676657Snate@binkert.orgconst char *NsTxStateStrings[] =
687839Snilay@cs.wisc.edu{
697839Snilay@cs.wisc.edu    "txIdle",
706657Snate@binkert.org    "txDescRefr",
716657Snate@binkert.org    "txDescRead",
726657Snate@binkert.org    "txFifoBlock",
736657Snate@binkert.org    "txFragRead",
746657Snate@binkert.org    "txDescWrite",
756657Snate@binkert.org    "txAdvance"
766657Snate@binkert.org};
776657Snate@binkert.org
786657Snate@binkert.orgconst char *NsDmaState[] =
796657Snate@binkert.org{
806657Snate@binkert.org    "dmaIdle",
816657Snate@binkert.org    "dmaReading",
826657Snate@binkert.org    "dmaWriting",
836657Snate@binkert.org    "dmaReadWaiting",
846657Snate@binkert.org    "dmaWriteWaiting"
856657Snate@binkert.org};
866657Snate@binkert.org
876657Snate@binkert.orgusing namespace std;
886657Snate@binkert.orgusing namespace Net;
896657Snate@binkert.org
906779SBrad.Beckmann@amd.com///////////////////////////////////////////////////////////////////////
916657Snate@binkert.org//
926657Snate@binkert.org// NSGigE PCI Device
936657Snate@binkert.org//
946657Snate@binkert.orgNSGigE::NSGigE(Params *p)
956657Snate@binkert.org    : PciDev(p), ioEnable(false),
966657Snate@binkert.org      txFifo(p->tx_fifo_size), rxFifo(p->rx_fifo_size),
976657Snate@binkert.org      txPacket(0), rxPacket(0), txPacketBufPtr(NULL), rxPacketBufPtr(NULL),
986657Snate@binkert.org      txXferLen(0), rxXferLen(0), txState(txIdle), txEnable(false),
996657Snate@binkert.org      CTDD(false),
1006657Snate@binkert.org      txFragPtr(0), txDescCnt(0), txDmaState(dmaIdle), rxState(rxIdle),
1016657Snate@binkert.org      rxEnable(false), CRDD(false), rxPktBytes(0),
1026657Snate@binkert.org      rxFragPtr(0), rxDescCnt(0), rxDmaState(dmaIdle), extstsEnable(false),
1036657Snate@binkert.org      rxDmaReadEvent(this), rxDmaWriteEvent(this),
1046657Snate@binkert.org      txDmaReadEvent(this), txDmaWriteEvent(this),
1056657Snate@binkert.org      dmaDescFree(p->dma_desc_free), dmaDataFree(p->dma_data_free),
1066657Snate@binkert.org      txDelay(p->tx_delay), rxDelay(p->rx_delay),
1076657Snate@binkert.org      rxKickTick(0), txKickTick(0),
1086657Snate@binkert.org      txEvent(this), rxFilterEnable(p->rx_filter), acceptBroadcast(false),
1096657Snate@binkert.org      acceptMulticast(false), acceptUnicast(false),
1106657Snate@binkert.org      acceptPerfect(false), acceptArp(false),
1116657Snate@binkert.org      physmem(p->pmem), intrTick(0), cpuPendingIntr(false),
1126657Snate@binkert.org      intrEvent(0), interface(0)
1136657Snate@binkert.org{
1146657Snate@binkert.org    if (p->header_bus) {
1157839Snilay@cs.wisc.edu        pioInterface = newPioInterface(name(), p->hier,
1167839Snilay@cs.wisc.edu                                       p->header_bus, this,
1177839Snilay@cs.wisc.edu                                       &NSGigE::cacheAccess);
1187839Snilay@cs.wisc.edu
1197839Snilay@cs.wisc.edu        pioLatency = p->pio_latency * p->header_bus->clockRatio;
1207839Snilay@cs.wisc.edu
1217839Snilay@cs.wisc.edu        if (p->payload_bus)
1227839Snilay@cs.wisc.edu            dmaInterface = new DMAInterface<Bus>(name() + ".dma",
1237839Snilay@cs.wisc.edu                                                 p->header_bus,
1247839Snilay@cs.wisc.edu                                                 p->payload_bus, 1);
1257839Snilay@cs.wisc.edu        else
1267839Snilay@cs.wisc.edu            dmaInterface = new DMAInterface<Bus>(name() + ".dma",
1277839Snilay@cs.wisc.edu                                                 p->header_bus,
1287839Snilay@cs.wisc.edu                                                 p->header_bus, 1);
1297839Snilay@cs.wisc.edu    } else if (p->payload_bus) {
1306657Snate@binkert.org        pioInterface = newPioInterface(name(), p->hier,
1316657Snate@binkert.org                                       p->payload_bus, this,
1326657Snate@binkert.org                                       &NSGigE::cacheAccess);
1336657Snate@binkert.org
1346657Snate@binkert.org        pioLatency = p->pio_latency * p->payload_bus->clockRatio;
1356657Snate@binkert.org
1366657Snate@binkert.org        dmaInterface = new DMAInterface<Bus>(name() + ".dma",
1376657Snate@binkert.org                                             p->payload_bus,
1386657Snate@binkert.org                                             p->payload_bus, 1);
1396657Snate@binkert.org    }
1406657Snate@binkert.org
1416657Snate@binkert.org
1426657Snate@binkert.org    intrDelay = US2Ticks(p->intr_delay);
1436657Snate@binkert.org    dmaReadDelay = p->dma_read_delay;
1446657Snate@binkert.org    dmaWriteDelay = p->dma_write_delay;
1456657Snate@binkert.org    dmaReadFactor = p->dma_read_factor;
1466657Snate@binkert.org    dmaWriteFactor = p->dma_write_factor;
1476657Snate@binkert.org
1486657Snate@binkert.org    regsReset();
1496657Snate@binkert.org    memcpy(&rom.perfectMatch, p->eaddr.bytes(), ETH_ADDR_LEN);
1506657Snate@binkert.org}
1516657Snate@binkert.org
1526657Snate@binkert.orgNSGigE::~NSGigE()
1536657Snate@binkert.org{}
1546657Snate@binkert.org
1556657Snate@binkert.orgvoid
1566657Snate@binkert.orgNSGigE::regStats()
1576657Snate@binkert.org{
1586657Snate@binkert.org    txBytes
1596657Snate@binkert.org        .name(name() + ".txBytes")
1606657Snate@binkert.org        .desc("Bytes Transmitted")
1616877Ssteve.reinhardt@amd.com        .prereq(txBytes)
1626657Snate@binkert.org        ;
1636657Snate@binkert.org
1646657Snate@binkert.org    rxBytes
1656657Snate@binkert.org        .name(name() + ".rxBytes")
1666657Snate@binkert.org        .desc("Bytes Received")
1676657Snate@binkert.org        .prereq(rxBytes)
1687542SBrad.Beckmann@amd.com        ;
1697542SBrad.Beckmann@amd.com
1706657Snate@binkert.org    txPackets
1716657Snate@binkert.org        .name(name() + ".txPackets")
1726657Snate@binkert.org        .desc("Number of Packets Transmitted")
1736657Snate@binkert.org        .prereq(txBytes)
1746877Ssteve.reinhardt@amd.com        ;
1756999Snate@binkert.org
1766877Ssteve.reinhardt@amd.com    rxPackets
1776877Ssteve.reinhardt@amd.com        .name(name() + ".rxPackets")
1786877Ssteve.reinhardt@amd.com        .desc("Number of Packets Received")
1796877Ssteve.reinhardt@amd.com        .prereq(rxBytes)
1806877Ssteve.reinhardt@amd.com        ;
1816877Ssteve.reinhardt@amd.com
1826877Ssteve.reinhardt@amd.com    txIpChecksums
1836877Ssteve.reinhardt@amd.com        .name(name() + ".txIpChecksums")
1846877Ssteve.reinhardt@amd.com        .desc("Number of tx IP Checksums done by device")
1856877Ssteve.reinhardt@amd.com        .precision(0)
1866877Ssteve.reinhardt@amd.com        .prereq(txBytes)
1876877Ssteve.reinhardt@amd.com        ;
1886877Ssteve.reinhardt@amd.com
1896877Ssteve.reinhardt@amd.com    rxIpChecksums
1906877Ssteve.reinhardt@amd.com        .name(name() + ".rxIpChecksums")
1916877Ssteve.reinhardt@amd.com        .desc("Number of rx IP Checksums done by device")
1926882SBrad.Beckmann@amd.com        .precision(0)
1936882SBrad.Beckmann@amd.com        .prereq(rxBytes)
1946882SBrad.Beckmann@amd.com        ;
1956882SBrad.Beckmann@amd.com
1966882SBrad.Beckmann@amd.com    txTcpChecksums
1976882SBrad.Beckmann@amd.com        .name(name() + ".txTcpChecksums")
1986882SBrad.Beckmann@amd.com        .desc("Number of tx TCP Checksums done by device")
1996877Ssteve.reinhardt@amd.com        .precision(0)
2006877Ssteve.reinhardt@amd.com        .prereq(txBytes)
2016877Ssteve.reinhardt@amd.com        ;
2026877Ssteve.reinhardt@amd.com
2036657Snate@binkert.org    rxTcpChecksums
2046657Snate@binkert.org        .name(name() + ".rxTcpChecksums")
2056999Snate@binkert.org        .desc("Number of rx TCP Checksums done by device")
2066657Snate@binkert.org        .precision(0)
2076657Snate@binkert.org        .prereq(rxBytes)
2086657Snate@binkert.org        ;
2096657Snate@binkert.org
2106657Snate@binkert.org    txUdpChecksums
2116657Snate@binkert.org        .name(name() + ".txUdpChecksums")
2127007Snate@binkert.org        .desc("Number of tx UDP Checksums done by device")
2136657Snate@binkert.org        .precision(0)
2146657Snate@binkert.org        .prereq(txBytes)
2156657Snate@binkert.org        ;
2166657Snate@binkert.org
2176657Snate@binkert.org    rxUdpChecksums
2187007Snate@binkert.org        .name(name() + ".rxUdpChecksums")
2197007Snate@binkert.org        .desc("Number of rx UDP Checksums done by device")
2206657Snate@binkert.org        .precision(0)
2217002Snate@binkert.org        .prereq(rxBytes)
2227002Snate@binkert.org        ;
2237002Snate@binkert.org
2247002Snate@binkert.org    descDmaReads
2258229Snate@binkert.org        .name(name() + ".descDMAReads")
2268229Snate@binkert.org        .desc("Number of descriptors the device read w/ DMA")
2276657Snate@binkert.org        .precision(0)
2286657Snate@binkert.org        ;
2298229Snate@binkert.org
2308229Snate@binkert.org    descDmaWrites
2318229Snate@binkert.org        .name(name() + ".descDMAWrites")
2328229Snate@binkert.org        .desc("Number of descriptors the device wrote w/ DMA")
2336657Snate@binkert.org        .precision(0)
2346657Snate@binkert.org        ;
2356657Snate@binkert.org
2366657Snate@binkert.org    descDmaRdBytes
2376793SBrad.Beckmann@amd.com        .name(name() + ".descDmaReadBytes")
2386657Snate@binkert.org        .desc("number of descriptor bytes read w/ DMA")
2396657Snate@binkert.org        .precision(0)
2406657Snate@binkert.org        ;
2416657Snate@binkert.org
2426657Snate@binkert.org   descDmaWrBytes
2437002Snate@binkert.org        .name(name() + ".descDmaWriteBytes")
2446657Snate@binkert.org        .desc("number of descriptor bytes write w/ DMA")
2457007Snate@binkert.org        .precision(0)
2467007Snate@binkert.org        ;
2477007Snate@binkert.org
2487007Snate@binkert.org
2497007Snate@binkert.org    txBandwidth
2506657Snate@binkert.org        .name(name() + ".txBandwidth")
2516877Ssteve.reinhardt@amd.com        .desc("Transmit Bandwidth (bits/s)")
2526877Ssteve.reinhardt@amd.com        .precision(0)
2536657Snate@binkert.org        .prereq(txBytes)
2546877Ssteve.reinhardt@amd.com        ;
2556657Snate@binkert.org
2566657Snate@binkert.org    rxBandwidth
2577002Snate@binkert.org        .name(name() + ".rxBandwidth")
2587002Snate@binkert.org        .desc("Receive Bandwidth (bits/s)")
2596657Snate@binkert.org        .precision(0)
2607567SBrad.Beckmann@amd.com        .prereq(rxBytes)
2617567SBrad.Beckmann@amd.com        ;
2627922SBrad.Beckmann@amd.com
2636881SBrad.Beckmann@amd.com    txPacketRate
2647002Snate@binkert.org        .name(name() + ".txPPS")
2657002Snate@binkert.org        .desc("Packet Tranmission Rate (packets/s)")
2666657Snate@binkert.org        .precision(0)
2677002Snate@binkert.org        .prereq(txBytes)
2686902SBrad.Beckmann@amd.com        ;
2696863Sdrh5@cs.wisc.edu
2706863Sdrh5@cs.wisc.edu    rxPacketRate
2717007Snate@binkert.org        .name(name() + ".rxPPS")
2726657Snate@binkert.org        .desc("Packet Reception Rate (packets/s)")
2736657Snate@binkert.org        .precision(0)
2746657Snate@binkert.org        .prereq(rxBytes)
2756657Snate@binkert.org        ;
2766657Snate@binkert.org
2776657Snate@binkert.org    txBandwidth = txBytes * Stats::constant(8) / simSeconds;
2786882SBrad.Beckmann@amd.com    rxBandwidth = rxBytes * Stats::constant(8) / simSeconds;
2796882SBrad.Beckmann@amd.com    txPacketRate = txPackets / simSeconds;
2806882SBrad.Beckmann@amd.com    rxPacketRate = rxPackets / simSeconds;
2816882SBrad.Beckmann@amd.com}
2826657Snate@binkert.org
2836657Snate@binkert.org/**
2846657Snate@binkert.org * This is to read the PCI general configuration registers
2856657Snate@binkert.org */
2867007Snate@binkert.orgvoid
2877839Snilay@cs.wisc.eduNSGigE::ReadConfig(int offset, int size, uint8_t *data)
2887839Snilay@cs.wisc.edu{
2897839Snilay@cs.wisc.edu    if (offset < PCI_DEVICE_SPECIFIC)
2907839Snilay@cs.wisc.edu        PciDev::ReadConfig(offset, size, data);
2917839Snilay@cs.wisc.edu    else
2927839Snilay@cs.wisc.edu        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
2997007Snate@binkert.orgNSGigE::WriteConfig(int offset, int size, uint32_t data)
3007007Snate@binkert.org{
3017007Snate@binkert.org    if (offset < PCI_DEVICE_SPECIFIC)
3027007Snate@binkert.org        PciDev::WriteConfig(offset, size, data);
3037007Snate@binkert.org    else
3047839Snilay@cs.wisc.edu        panic("Device specific PCI config space not implemented!\n");
3057839Snilay@cs.wisc.edu
3067839Snilay@cs.wisc.edu    // Need to catch writes to BARs to update the PIO interface
3077839Snilay@cs.wisc.edu    switch (offset) {
3087839Snilay@cs.wisc.edu        // seems to work fine without all these PCI settings, but i
3097839Snilay@cs.wisc.edu        // 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;
3167007Snate@binkert.org
3177007Snate@binkert.org#if 0
3187002Snate@binkert.org        if (config.data[offset] & PCI_CMD_BME) {
3196657Snate@binkert.org            bmEnabled = true;
3206657Snate@binkert.org        }
3216657Snate@binkert.org        else {
3227055Snate@binkert.org            bmEnabled = false;
3236657Snate@binkert.org        }
3246657Snate@binkert.org
3256657Snate@binkert.org        if (config.data[offset] & PCI_CMD_MSE) {
3266863Sdrh5@cs.wisc.edu            memEnable = true;
3277055Snate@binkert.org        }
3287567SBrad.Beckmann@amd.com        else {
3297567SBrad.Beckmann@amd.com            memEnable = false;
3307567SBrad.Beckmann@amd.com        }
3317567SBrad.Beckmann@amd.com#endif
3327567SBrad.Beckmann@amd.com        break;
3337542SBrad.Beckmann@amd.com
3347542SBrad.Beckmann@amd.com      case PCI0_BASE_ADDR0:
3356657Snate@binkert.org        if (BARAddrs[0] != 0) {
3367007Snate@binkert.org            if (pioInterface)
3376657Snate@binkert.org                pioInterface->addAddrRange(RangeSize(BARAddrs[0], BARSize[0]));
3386657Snate@binkert.org
3396657Snate@binkert.org            BARAddrs[0] &= EV5::PAddrUncachedMask;
3406657Snate@binkert.org        }
3416657Snate@binkert.org        break;
3426657Snate@binkert.org      case PCI0_BASE_ADDR1:
3436657Snate@binkert.org        if (BARAddrs[1] != 0) {
3446657Snate@binkert.org            if (pioInterface)
3457839Snilay@cs.wisc.edu                pioInterface->addAddrRange(RangeSize(BARAddrs[1], BARSize[1]));
3467839Snilay@cs.wisc.edu
3477839Snilay@cs.wisc.edu            BARAddrs[1] &= EV5::PAddrUncachedMask;
3487839Snilay@cs.wisc.edu        }
3497839Snilay@cs.wisc.edu        break;
3507839Snilay@cs.wisc.edu    }
3518086SBrad.Beckmann@amd.com}
3528086SBrad.Beckmann@amd.com
3537839Snilay@cs.wisc.edu/**
3547839Snilay@cs.wisc.edu * This reads the device registers, which are detailed in the NS83820
3557839Snilay@cs.wisc.edu * spec sheet
3567839Snilay@cs.wisc.edu */
3577839Snilay@cs.wisc.eduFault
3587839Snilay@cs.wisc.eduNSGigE::read(MemReqPtr &req, uint8_t *data)
3597839Snilay@cs.wisc.edu{
3607839Snilay@cs.wisc.edu    assert(ioEnable);
3617839Snilay@cs.wisc.edu
3627839Snilay@cs.wisc.edu    //The mask is to give you only the offset into the device register file
3636657Snate@binkert.org    Addr daddr = req->paddr & 0xfff;
3646657Snate@binkert.org    DPRINTF(EthernetPIO, "read  da=%#x pa=%#x va=%#x size=%d\n",
3656657Snate@binkert.org            daddr, req->paddr, req->vaddr, req->size);
3666657Snate@binkert.org
3677839Snilay@cs.wisc.edu
3687839Snilay@cs.wisc.edu    // there are some reserved registers, you can see ns_gige_reg.h and
3697839Snilay@cs.wisc.edu    // the spec sheet for details
3707839Snilay@cs.wisc.edu    if (daddr > LAST && daddr <=  RESERVED) {
3717839Snilay@cs.wisc.edu        panic("Accessing reserved register");
3727839Snilay@cs.wisc.edu    } else if (daddr > RESERVED && daddr <= 0x3FC) {
3737839Snilay@cs.wisc.edu        ReadConfig(daddr & 0xff, req->size, data);
3747839Snilay@cs.wisc.edu        return No_Fault;
3757839Snilay@cs.wisc.edu    } else if (daddr >= MIB_START && daddr <= MIB_END) {
3767839Snilay@cs.wisc.edu        // don't implement all the MIB's.  hopefully the kernel
3777839Snilay@cs.wisc.edu        // doesn't actually DEPEND upon their values
3787839Snilay@cs.wisc.edu        // MIB are just hardware stats keepers
3797839Snilay@cs.wisc.edu        uint32_t &reg = *(uint32_t *) data;
3807839Snilay@cs.wisc.edu        reg = 0;
3817839Snilay@cs.wisc.edu        return No_Fault;
3827839Snilay@cs.wisc.edu    } else if (daddr > 0x3FC)
3836657Snate@binkert.org        panic("Something is messed up!\n");
3846657Snate@binkert.org
3856657Snate@binkert.org    switch (req->size) {
3866657Snate@binkert.org      case sizeof(uint32_t):
3877007Snate@binkert.org        {
3886657Snate@binkert.org            uint32_t &reg = *(uint32_t *)data;
3896657Snate@binkert.org
3906657Snate@binkert.org            switch (daddr) {
3916657Snate@binkert.org              case CR:
3926657Snate@binkert.org                reg = regs.command;
3936657Snate@binkert.org                //these are supposed to be cleared on a read
3946657Snate@binkert.org                reg &= ~(CR_RXD | CR_TXD | CR_TXR | CR_RXR);
3956657Snate@binkert.org                break;
3966657Snate@binkert.org
3976657Snate@binkert.org              case CFG:
3987007Snate@binkert.org                reg = regs.config;
3996657Snate@binkert.org                break;
4006657Snate@binkert.org
4016657Snate@binkert.org              case MEAR:
4026657Snate@binkert.org                reg = regs.mear;
4036657Snate@binkert.org                break;
4046999Snate@binkert.org
4056657Snate@binkert.org              case PTSCR:
4066657Snate@binkert.org                reg = regs.ptscr;
4076657Snate@binkert.org                break;
4086657Snate@binkert.org
4097007Snate@binkert.org              case ISR:
4106657Snate@binkert.org                reg = regs.isr;
4116657Snate@binkert.org                devIntrClear(ISR_ALL);
4126657Snate@binkert.org                break;
4136657Snate@binkert.org
4146657Snate@binkert.org              case IMR:
4157832Snate@binkert.org                reg = regs.imr;
4167002Snate@binkert.org                break;
4177002Snate@binkert.org
4187002Snate@binkert.org              case IER:
4197056Snate@binkert.org                reg = regs.ier;
4206657Snate@binkert.org                break;
4218229Snate@binkert.org
4226657Snate@binkert.org              case IHR:
4236657Snate@binkert.org                reg = regs.ihr;
4247056Snate@binkert.org                break;
4257056Snate@binkert.org
4266657Snate@binkert.org              case TXDP:
4277002Snate@binkert.org                reg = regs.txdp;
4287002Snate@binkert.org                break;
4296657Snate@binkert.org
4306657Snate@binkert.org              case TXDP_HI:
4316657Snate@binkert.org                reg = regs.txdp_hi;
4326657Snate@binkert.org                break;
4336657Snate@binkert.org
4346793SBrad.Beckmann@amd.com              case TXCFG:
4356657Snate@binkert.org                reg = regs.txcfg;
4366657Snate@binkert.org                break;
4376657Snate@binkert.org
4386657Snate@binkert.org              case GPIOR:
4396877Ssteve.reinhardt@amd.com                reg = regs.gpior;
4406877Ssteve.reinhardt@amd.com                break;
4416877Ssteve.reinhardt@amd.com
4426877Ssteve.reinhardt@amd.com              case RXDP:
4436877Ssteve.reinhardt@amd.com                reg = regs.rxdp;
4446877Ssteve.reinhardt@amd.com                break;
4456657Snate@binkert.org
4467542SBrad.Beckmann@amd.com              case RXDP_HI:
4476657Snate@binkert.org                reg = regs.rxdp_hi;
4487007Snate@binkert.org                break;
4496657Snate@binkert.org
4506657Snate@binkert.org              case RXCFG:
4517007Snate@binkert.org                reg = regs.rxcfg;
4526657Snate@binkert.org                break;
4536877Ssteve.reinhardt@amd.com
4546877Ssteve.reinhardt@amd.com              case PQCR:
4556657Snate@binkert.org                reg = regs.pqcr;
4566877Ssteve.reinhardt@amd.com                break;
4576877Ssteve.reinhardt@amd.com
4586877Ssteve.reinhardt@amd.com              case WCSR:
4596877Ssteve.reinhardt@amd.com                reg = regs.wcsr;
4606877Ssteve.reinhardt@amd.com                break;
4616969SBrad.Beckmann@amd.com
4626657Snate@binkert.org              case PCR:
4637567SBrad.Beckmann@amd.com                reg = regs.pcr;
4647567SBrad.Beckmann@amd.com                break;
4657567SBrad.Beckmann@amd.com
4667567SBrad.Beckmann@amd.com                // see the spec sheet for how RFCR and RFDR work
4677567SBrad.Beckmann@amd.com                // basically, you write to RFCR to tell the machine
4687567SBrad.Beckmann@amd.com                // what you want to do next, then you act upon RFDR,
4696657Snate@binkert.org                // and the device will be prepared b/c of what you
4706882SBrad.Beckmann@amd.com                // wrote to RFCR
4716882SBrad.Beckmann@amd.com              case RFCR:
4726882SBrad.Beckmann@amd.com                reg = regs.rfcr;
4736882SBrad.Beckmann@amd.com                break;
4746882SBrad.Beckmann@amd.com
4756882SBrad.Beckmann@amd.com              case RFDR:
4766882SBrad.Beckmann@amd.com                switch (regs.rfcr & RFCR_RFADDR) {
4778189SLisa.Hsu@amd.com                  case 0x000:
4788189SLisa.Hsu@amd.com                    reg = rom.perfectMatch[1];
4796877Ssteve.reinhardt@amd.com                    reg = reg << 8;
4808189SLisa.Hsu@amd.com                    reg += rom.perfectMatch[0];
4818189SLisa.Hsu@amd.com                    break;
4828189SLisa.Hsu@amd.com                  case 0x002:
4838189SLisa.Hsu@amd.com                    reg = rom.perfectMatch[3] << 8;
4846882SBrad.Beckmann@amd.com                    reg += rom.perfectMatch[2];
4856882SBrad.Beckmann@amd.com                    break;
4866882SBrad.Beckmann@amd.com                  case 0x004:
4876882SBrad.Beckmann@amd.com                    reg = rom.perfectMatch[5] << 8;
4886882SBrad.Beckmann@amd.com                    reg += rom.perfectMatch[4];
4896882SBrad.Beckmann@amd.com                    break;
4906882SBrad.Beckmann@amd.com                  default:
4916882SBrad.Beckmann@amd.com                    panic("reading RFDR for something other than PMATCH!\n");
4926882SBrad.Beckmann@amd.com                    // didn't implement other RFDR functionality b/c
4936882SBrad.Beckmann@amd.com                    // driver didn't use it
4948189SLisa.Hsu@amd.com                }
4956882SBrad.Beckmann@amd.com                break;
4966882SBrad.Beckmann@amd.com
4976882SBrad.Beckmann@amd.com              case SRR:
4988189SLisa.Hsu@amd.com                reg = regs.srr;
4998189SLisa.Hsu@amd.com                break;
5008189SLisa.Hsu@amd.com
5018189SLisa.Hsu@amd.com              case MIBC:
5026888SBrad.Beckmann@amd.com                reg = regs.mibc;
5036888SBrad.Beckmann@amd.com                reg &= ~(MIBC_MIBS | MIBC_ACLR);
5046888SBrad.Beckmann@amd.com                break;
5056888SBrad.Beckmann@amd.com
5066888SBrad.Beckmann@amd.com              case VRCR:
5078189SLisa.Hsu@amd.com                reg = regs.vrcr;
5086888SBrad.Beckmann@amd.com                break;
5096888SBrad.Beckmann@amd.com
5106657Snate@binkert.org              case VTCR:
5116888SBrad.Beckmann@amd.com                reg = regs.vtcr;
5126888SBrad.Beckmann@amd.com                break;
5136888SBrad.Beckmann@amd.com
5146888SBrad.Beckmann@amd.com              case VDR:
5156657Snate@binkert.org                reg = regs.vdr;
5166657Snate@binkert.org                break;
5176657Snate@binkert.org
5186657Snate@binkert.org              case CCSR:
5196657Snate@binkert.org                reg = regs.ccsr;
5206657Snate@binkert.org                break;
5216657Snate@binkert.org
5226657Snate@binkert.org              case TBICR:
5236657Snate@binkert.org                reg = regs.tbicr;
5247007Snate@binkert.org                break;
5257007Snate@binkert.org
5266657Snate@binkert.org              case TBISR:
5277007Snate@binkert.org                reg = regs.tbisr;
5287007Snate@binkert.org                break;
5297007Snate@binkert.org
5306657Snate@binkert.org              case TANAR:
5316657Snate@binkert.org                reg = regs.tanar;
5326657Snate@binkert.org                break;
5337007Snate@binkert.org
5347542SBrad.Beckmann@amd.com              case TANLPAR:
5357542SBrad.Beckmann@amd.com                reg = regs.tanlpar;
5367007Snate@binkert.org                break;
5376657Snate@binkert.org
5386657Snate@binkert.org              case TANER:
5396657Snate@binkert.org                reg = regs.taner;
5406657Snate@binkert.org                break;
5416657Snate@binkert.org
5426657Snate@binkert.org              case TESR:
5436657Snate@binkert.org                reg = regs.tesr;
5446657Snate@binkert.org                break;
5456657Snate@binkert.org
5466657Snate@binkert.org              default:
5476657Snate@binkert.org                panic("reading unimplemented register: addr=%#x", daddr);
5486657Snate@binkert.org            }
5496657Snate@binkert.org
5506657Snate@binkert.org            DPRINTF(EthernetPIO, "read from %#x: data=%d data=%#x\n",
5516657Snate@binkert.org                    daddr, reg, reg);
5526657Snate@binkert.org        }
5536657Snate@binkert.org        break;
5546657Snate@binkert.org
5556657Snate@binkert.org      default:
5566657Snate@binkert.org        panic("accessing register with invalid size: addr=%#x, size=%d",
5576657Snate@binkert.org              daddr, req->size);
5586657Snate@binkert.org    }
5596657Snate@binkert.org
5606657Snate@binkert.org    return No_Fault;
5616657Snate@binkert.org}
5626657Snate@binkert.org
5636657Snate@binkert.orgFault
5646657Snate@binkert.orgNSGigE::write(MemReqPtr &req, const uint8_t *data)
5657007Snate@binkert.org{
5666657Snate@binkert.org    assert(ioEnable);
5676657Snate@binkert.org
5686657Snate@binkert.org    Addr daddr = req->paddr & 0xfff;
5696657Snate@binkert.org    DPRINTF(EthernetPIO, "write da=%#x pa=%#x va=%#x size=%d\n",
5707007Snate@binkert.org            daddr, req->paddr, req->vaddr, req->size);
5716657Snate@binkert.org
5727007Snate@binkert.org    if (daddr > LAST && daddr <=  RESERVED) {
5737007Snate@binkert.org        panic("Accessing reserved register");
5746657Snate@binkert.org    } else if (daddr > RESERVED && daddr <= 0x3FC) {
5756657Snate@binkert.org        WriteConfig(daddr & 0xff, req->size, *(uint32_t *)data);
5766657Snate@binkert.org        return No_Fault;
5776657Snate@binkert.org    } else if (daddr > 0x3FC)
5786657Snate@binkert.org        panic("Something is messed up!\n");
5796657Snate@binkert.org
5806657Snate@binkert.org    if (req->size == sizeof(uint32_t)) {
5816657Snate@binkert.org        uint32_t reg = *(uint32_t *)data;
5826657Snate@binkert.org        DPRINTF(EthernetPIO, "write data=%d data=%#x\n", reg, reg);
5836657Snate@binkert.org
5846657Snate@binkert.org        switch (daddr) {
5856657Snate@binkert.org          case CR:
5866657Snate@binkert.org            regs.command = reg;
5876657Snate@binkert.org            if (reg & CR_TXD) {
5886657Snate@binkert.org                txEnable = false;
5897566SBrad.Beckmann@amd.com            } else if (reg & CR_TXE) {
5906657Snate@binkert.org                txEnable = true;
5916657Snate@binkert.org
5926657Snate@binkert.org                // the kernel is enabling the transmit machine
5936657Snate@binkert.org                if (txState == txIdle)
5946657Snate@binkert.org                    txKick();
5956657Snate@binkert.org            }
5966657Snate@binkert.org
5976657Snate@binkert.org            if (reg & CR_RXD) {
5987007Snate@binkert.org                rxEnable = false;
5997007Snate@binkert.org            } else if (reg & CR_RXE) {
6007007Snate@binkert.org                rxEnable = true;
6016657Snate@binkert.org
6026657Snate@binkert.org                if (rxState == rxIdle)
6036657Snate@binkert.org                    rxKick();
6046657Snate@binkert.org            }
6056657Snate@binkert.org
6066657Snate@binkert.org            if (reg & CR_TXR)
6076657Snate@binkert.org                txReset();
6086657Snate@binkert.org
6096657Snate@binkert.org            if (reg & CR_RXR)
6106657Snate@binkert.org                rxReset();
6116657Snate@binkert.org
6126657Snate@binkert.org            if (reg & CR_SWI)
6138187SLisa.Hsu@amd.com                devIntrPost(ISR_SWI);
6146657Snate@binkert.org
6156657Snate@binkert.org            if (reg & CR_RST) {
6166657Snate@binkert.org                txReset();
6176657Snate@binkert.org                rxReset();
6186657Snate@binkert.org
6196657Snate@binkert.org                regsReset();
6206657Snate@binkert.org            }
6216657Snate@binkert.org            break;
6226657Snate@binkert.org
6237454Snate@binkert.org          case CFG:
6246657Snate@binkert.org            if (reg & CFG_LNKSTS ||
6256657Snate@binkert.org                reg & CFG_SPDSTS ||
6266657Snate@binkert.org                reg & CFG_DUPSTS ||
6276657Snate@binkert.org                reg & CFG_RESERVED ||
6287007Snate@binkert.org                reg & CFG_T64ADDR ||
6297056Snate@binkert.org                reg & CFG_PCI64_DET)
6307007Snate@binkert.org                panic("writing to read-only or reserved CFG bits!\n");
6317007Snate@binkert.org
6326657Snate@binkert.org            regs.config |= reg & ~(CFG_LNKSTS | CFG_SPDSTS | CFG_DUPSTS |
6337566SBrad.Beckmann@amd.com                                   CFG_RESERVED | CFG_T64ADDR | CFG_PCI64_DET);
6347566SBrad.Beckmann@amd.com
6357566SBrad.Beckmann@amd.com// all these #if 0's are because i don't THINK the kernel needs to
6367566SBrad.Beckmann@amd.com// have these implemented. if there is a problem relating to one of
6377566SBrad.Beckmann@amd.com// these, you may need to add functionality in.
6387566SBrad.Beckmann@amd.com#if 0
6397566SBrad.Beckmann@amd.com            if (reg & CFG_TBI_EN) ;
6406657Snate@binkert.org            if (reg & CFG_MODE_1000) ;
6417672Snate@binkert.org#endif
6426657Snate@binkert.org
6436657Snate@binkert.org            if (reg & CFG_AUTO_1000)
6446657Snate@binkert.org                panic("CFG_AUTO_1000 not implemented!\n");
6456657Snate@binkert.org
6467672Snate@binkert.org#if 0
6476657Snate@binkert.org            if (reg & CFG_PINT_DUPSTS ||
6487056Snate@binkert.org                reg & CFG_PINT_LNKSTS ||
6496657Snate@binkert.org                reg & CFG_PINT_SPDSTS)
6506657Snate@binkert.org                ;
6517672Snate@binkert.org
6526657Snate@binkert.org            if (reg & CFG_TMRTEST) ;
6536657Snate@binkert.org            if (reg & CFG_MRM_DIS) ;
6546657Snate@binkert.org            if (reg & CFG_MWI_DIS) ;
6556657Snate@binkert.org
6566657Snate@binkert.org            if (reg & CFG_T64ADDR)
6576657Snate@binkert.org                panic("CFG_T64ADDR is read only register!\n");
6586657Snate@binkert.org
6596657Snate@binkert.org            if (reg & CFG_PCI64_DET)
6606657Snate@binkert.org                panic("CFG_PCI64_DET is read only register!\n");
6616657Snate@binkert.org
6626657Snate@binkert.org            if (reg & CFG_DATA64_EN) ;
6637542SBrad.Beckmann@amd.com            if (reg & CFG_M64ADDR) ;
6646657Snate@binkert.org            if (reg & CFG_PHY_RST) ;
6656657Snate@binkert.org            if (reg & CFG_PHY_DIS) ;
6666657Snate@binkert.org#endif
6676657Snate@binkert.org
6686657Snate@binkert.org            if (reg & CFG_EXTSTS_EN)
6696657Snate@binkert.org                extstsEnable = true;
6706657Snate@binkert.org            else
6716657Snate@binkert.org                extstsEnable = false;
6726657Snate@binkert.org
6736657Snate@binkert.org#if 0
6746657Snate@binkert.org              if (reg & CFG_REQALG) ;
6756657Snate@binkert.org              if (reg & CFG_SB) ;
6766657Snate@binkert.org              if (reg & CFG_POW) ;
6776657Snate@binkert.org              if (reg & CFG_EXD) ;
6786657Snate@binkert.org              if (reg & CFG_PESEL) ;
6797007Snate@binkert.org              if (reg & CFG_BROM_DIS) ;
6807007Snate@binkert.org              if (reg & CFG_EXT_125) ;
6817007Snate@binkert.org              if (reg & CFG_BEM) ;
6826657Snate@binkert.org#endif
6836657Snate@binkert.org            break;
6846657Snate@binkert.org
6857007Snate@binkert.org          case MEAR:
6867007Snate@binkert.org            regs.mear = reg;
6877007Snate@binkert.org            // since phy is completely faked, MEAR_MD* don't matter
6886657Snate@binkert.org            // and since the driver never uses MEAR_EE*, they don't
6896657Snate@binkert.org            // matter
6906657Snate@binkert.org#if 0
6917007Snate@binkert.org            if (reg & MEAR_EEDI) ;
6927007Snate@binkert.org            if (reg & MEAR_EEDO) ; // this one is read only
6937007Snate@binkert.org            if (reg & MEAR_EECLK) ;
6946657Snate@binkert.org            if (reg & MEAR_EESEL) ;
6956657Snate@binkert.org            if (reg & MEAR_MDIO) ;
6966657Snate@binkert.org            if (reg & MEAR_MDDIR) ;
6977007Snate@binkert.org            if (reg & MEAR_MDC) ;
6987007Snate@binkert.org#endif
6997007Snate@binkert.org            break;
7006657Snate@binkert.org
7016657Snate@binkert.org          case PTSCR:
7026657Snate@binkert.org            regs.ptscr = reg & ~(PTSCR_RBIST_RDONLY);
7037007Snate@binkert.org            // these control BISTs for various parts of chip - we
7047007Snate@binkert.org            // don't care or do just fake that the BIST is done
7057007Snate@binkert.org            if (reg & PTSCR_RBIST_EN)
7066657Snate@binkert.org                regs.ptscr |= PTSCR_RBIST_DONE;
7076657Snate@binkert.org            if (reg & PTSCR_EEBIST_EN)
7087007Snate@binkert.org                regs.ptscr &= ~PTSCR_EEBIST_EN;
7097007Snate@binkert.org            if (reg & PTSCR_EELOAD_EN)
7107007Snate@binkert.org                regs.ptscr &= ~PTSCR_EELOAD_EN;
7117007Snate@binkert.org            break;
7126657Snate@binkert.org
7136657Snate@binkert.org          case ISR: /* writing to the ISR has no effect */
7146657Snate@binkert.org            panic("ISR is a read only register!\n");
7157007Snate@binkert.org
7167567SBrad.Beckmann@amd.com          case IMR:
7177567SBrad.Beckmann@amd.com            regs.imr = reg;
7187567SBrad.Beckmann@amd.com            devIntrChangeMask();
7197567SBrad.Beckmann@amd.com            break;
7207567SBrad.Beckmann@amd.com
7217567SBrad.Beckmann@amd.com          case IER:
7227567SBrad.Beckmann@amd.com            regs.ier = reg;
7237567SBrad.Beckmann@amd.com            break;
7247567SBrad.Beckmann@amd.com
7257567SBrad.Beckmann@amd.com          case IHR:
7267567SBrad.Beckmann@amd.com            regs.ihr = reg;
7277567SBrad.Beckmann@amd.com            /* not going to implement real interrupt holdoff */
7287567SBrad.Beckmann@amd.com            break;
7298155Snilay@cs.wisc.edu
7308155Snilay@cs.wisc.edu          case TXDP:
7318155Snilay@cs.wisc.edu            regs.txdp = (reg & 0xFFFFFFFC);
7328155Snilay@cs.wisc.edu            assert(txState == txIdle);
7338155Snilay@cs.wisc.edu            CTDD = false;
7348155Snilay@cs.wisc.edu            break;
7358155Snilay@cs.wisc.edu
7368155Snilay@cs.wisc.edu          case TXDP_HI:
7378155Snilay@cs.wisc.edu            regs.txdp_hi = reg;
7388155Snilay@cs.wisc.edu            break;
7398155Snilay@cs.wisc.edu
7407567SBrad.Beckmann@amd.com          case TXCFG:
7418155Snilay@cs.wisc.edu            regs.txcfg = reg;
7428155Snilay@cs.wisc.edu#if 0
7437567SBrad.Beckmann@amd.com            if (reg & TXCFG_CSI) ;
7447567SBrad.Beckmann@amd.com            if (reg & TXCFG_HBI) ;
7457567SBrad.Beckmann@amd.com            if (reg & TXCFG_MLB) ;
7467567SBrad.Beckmann@amd.com            if (reg & TXCFG_ATP) ;
7477922SBrad.Beckmann@amd.com            if (reg & TXCFG_ECRETRY) {
7487922SBrad.Beckmann@amd.com                /*
7497922SBrad.Beckmann@amd.com                 * this could easily be implemented, but considering
7507922SBrad.Beckmann@amd.com                 * the network is just a fake pipe, wouldn't make
7517922SBrad.Beckmann@amd.com                 * sense to do this
7527922SBrad.Beckmann@amd.com                 */
7537922SBrad.Beckmann@amd.com            }
7547922SBrad.Beckmann@amd.com
7558154Snilay@cs.wisc.edu            if (reg & TXCFG_BRST_DIS) ;
7568154Snilay@cs.wisc.edu#endif
7578154Snilay@cs.wisc.edu
7588154Snilay@cs.wisc.edu#if 0
7598154Snilay@cs.wisc.edu            /* we handle our own DMA, ignore the kernel's exhortations */
7608154Snilay@cs.wisc.edu            if (reg & TXCFG_MXDMA) ;
7618154Snilay@cs.wisc.edu#endif
7628154Snilay@cs.wisc.edu
7638154Snilay@cs.wisc.edu            // also, we currently don't care about fill/drain
7648154Snilay@cs.wisc.edu            // thresholds though this may change in the future with
7658154Snilay@cs.wisc.edu            // more realistic networks or a driver which changes it
7668154Snilay@cs.wisc.edu            // according to feedback
7678154Snilay@cs.wisc.edu
7688154Snilay@cs.wisc.edu            break;
7698154Snilay@cs.wisc.edu
7708154Snilay@cs.wisc.edu          case GPIOR:
7718154Snilay@cs.wisc.edu            regs.gpior = reg;
7728154Snilay@cs.wisc.edu            /* these just control general purpose i/o pins, don't matter */
7738154Snilay@cs.wisc.edu            break;
7748154Snilay@cs.wisc.edu
7758154Snilay@cs.wisc.edu          case RXDP:
7767922SBrad.Beckmann@amd.com            regs.rxdp = reg;
7777922SBrad.Beckmann@amd.com            CRDD = false;
7787922SBrad.Beckmann@amd.com            break;
7797922SBrad.Beckmann@amd.com
7807007Snate@binkert.org          case RXDP_HI:
7817007Snate@binkert.org            regs.rxdp_hi = reg;
7826863Sdrh5@cs.wisc.edu            break;
7836863Sdrh5@cs.wisc.edu
7846863Sdrh5@cs.wisc.edu          case RXCFG:
7857007Snate@binkert.org            regs.rxcfg = reg;
7867007Snate@binkert.org#if 0
7877007Snate@binkert.org            if (reg & RXCFG_AEP) ;
7887007Snate@binkert.org            if (reg & RXCFG_ARP) ;
7896863Sdrh5@cs.wisc.edu            if (reg & RXCFG_STRIPCRC) ;
7906863Sdrh5@cs.wisc.edu            if (reg & RXCFG_RX_RD) ;
7916863Sdrh5@cs.wisc.edu            if (reg & RXCFG_ALP) ;
7926863Sdrh5@cs.wisc.edu            if (reg & RXCFG_AIRL) ;
7936863Sdrh5@cs.wisc.edu
7946863Sdrh5@cs.wisc.edu            /* we handle our own DMA, ignore what kernel says about it */
7957007Snate@binkert.org            if (reg & RXCFG_MXDMA) ;
7967007Snate@binkert.org
7977007Snate@binkert.org            //also, we currently don't care about fill/drain thresholds
7987007Snate@binkert.org            //though this may change in the future with more realistic
7997007Snate@binkert.org            //networks or a driver which changes it according to feedback
8006657Snate@binkert.org            if (reg & (RXCFG_DRTH | RXCFG_DRTH0)) ;
8017007Snate@binkert.org#endif
8027007Snate@binkert.org            break;
8037007Snate@binkert.org
8046657Snate@binkert.org          case PQCR:
8056657Snate@binkert.org            /* there is no priority queueing used in the linux 2.6 driver */
8067007Snate@binkert.org            regs.pqcr = reg;
8077007Snate@binkert.org            break;
8087007Snate@binkert.org
8096657Snate@binkert.org          case WCSR:
8106657Snate@binkert.org            /* not going to implement wake on LAN */
8117007Snate@binkert.org            regs.wcsr = reg;
8127007Snate@binkert.org            break;
8137007Snate@binkert.org
8146902SBrad.Beckmann@amd.com          case PCR:
8156902SBrad.Beckmann@amd.com            /* not going to implement pause control */
8166902SBrad.Beckmann@amd.com            regs.pcr = reg;
8176902SBrad.Beckmann@amd.com            break;
8186902SBrad.Beckmann@amd.com
8196902SBrad.Beckmann@amd.com          case RFCR:
8206902SBrad.Beckmann@amd.com            regs.rfcr = reg;
8217025SBrad.Beckmann@amd.com
8226902SBrad.Beckmann@amd.com            rxFilterEnable = (reg & RFCR_RFEN) ? true : false;
8236902SBrad.Beckmann@amd.com            acceptBroadcast = (reg & RFCR_AAB) ? true : false;
8246902SBrad.Beckmann@amd.com            acceptMulticast = (reg & RFCR_AAM) ? true : false;
8256902SBrad.Beckmann@amd.com            acceptUnicast = (reg & RFCR_AAU) ? true : false;
8266902SBrad.Beckmann@amd.com            acceptPerfect = (reg & RFCR_APM) ? true : false;
8277542SBrad.Beckmann@amd.com            acceptArp = (reg & RFCR_AARP) ? true : false;
8287542SBrad.Beckmann@amd.com
8297542SBrad.Beckmann@amd.com#if 0
8306902SBrad.Beckmann@amd.com            if (reg & RFCR_APAT)
8316902SBrad.Beckmann@amd.com                panic("RFCR_APAT not implemented!\n");
8326902SBrad.Beckmann@amd.com#endif
8336902SBrad.Beckmann@amd.com
8346902SBrad.Beckmann@amd.com            if (reg & RFCR_MHEN || reg & RFCR_UHEN)
8356902SBrad.Beckmann@amd.com                panic("hash filtering not implemented!\n");
8366902SBrad.Beckmann@amd.com
8376902SBrad.Beckmann@amd.com            if (reg & RFCR_ULM)
8386902SBrad.Beckmann@amd.com                panic("RFCR_ULM not implemented!\n");
8396902SBrad.Beckmann@amd.com
8406902SBrad.Beckmann@amd.com            break;
8416902SBrad.Beckmann@amd.com
8426902SBrad.Beckmann@amd.com          case RFDR:
8436902SBrad.Beckmann@amd.com            panic("the driver never writes to RFDR, something is wrong!\n");
8446902SBrad.Beckmann@amd.com
8457542SBrad.Beckmann@amd.com          case BRAR:
8466902SBrad.Beckmann@amd.com            panic("the driver never uses BRAR, something is wrong!\n");
8477839Snilay@cs.wisc.edu
8487839Snilay@cs.wisc.edu          case BRDR:
8497839Snilay@cs.wisc.edu            panic("the driver never uses BRDR, something is wrong!\n");
8507839Snilay@cs.wisc.edu
8517839Snilay@cs.wisc.edu          case SRR:
8527839Snilay@cs.wisc.edu            panic("SRR is read only register!\n");
8537839Snilay@cs.wisc.edu
8547839Snilay@cs.wisc.edu          case MIBC:
8557839Snilay@cs.wisc.edu            panic("the driver never uses MIBC, something is wrong!\n");
8567839Snilay@cs.wisc.edu
8577839Snilay@cs.wisc.edu          case VRCR:
8587839Snilay@cs.wisc.edu            regs.vrcr = reg;
8597839Snilay@cs.wisc.edu            break;
8607839Snilay@cs.wisc.edu
8617839Snilay@cs.wisc.edu          case VTCR:
8627839Snilay@cs.wisc.edu            regs.vtcr = reg;
8637839Snilay@cs.wisc.edu            break;
8648086SBrad.Beckmann@amd.com
8658086SBrad.Beckmann@amd.com          case VDR:
8668086SBrad.Beckmann@amd.com            panic("the driver never uses VDR, something is wrong!\n");
8678086SBrad.Beckmann@amd.com            break;
8688086SBrad.Beckmann@amd.com
8698086SBrad.Beckmann@amd.com          case CCSR:
8708086SBrad.Beckmann@amd.com            /* not going to implement clockrun stuff */
8718086SBrad.Beckmann@amd.com            regs.ccsr = reg;
8728086SBrad.Beckmann@amd.com            break;
8737839Snilay@cs.wisc.edu
8747839Snilay@cs.wisc.edu          case TBICR:
8757839Snilay@cs.wisc.edu            regs.tbicr = reg;
8767839Snilay@cs.wisc.edu            if (reg & TBICR_MR_LOOPBACK)
8777839Snilay@cs.wisc.edu                panic("TBICR_MR_LOOPBACK never used, something wrong!\n");
8787839Snilay@cs.wisc.edu
8797839Snilay@cs.wisc.edu            if (reg & TBICR_MR_AN_ENABLE) {
8807839Snilay@cs.wisc.edu                regs.tanlpar = regs.tanar;
8817839Snilay@cs.wisc.edu                regs.tbisr |= (TBISR_MR_AN_COMPLETE | TBISR_MR_LINK_STATUS);
8827839Snilay@cs.wisc.edu            }
8837839Snilay@cs.wisc.edu
8847839Snilay@cs.wisc.edu#if 0
8857839Snilay@cs.wisc.edu            if (reg & TBICR_MR_RESTART_AN) ;
8867839Snilay@cs.wisc.edu#endif
8877839Snilay@cs.wisc.edu
8887839Snilay@cs.wisc.edu            break;
8897839Snilay@cs.wisc.edu
8907839Snilay@cs.wisc.edu          case TBISR:
8917839Snilay@cs.wisc.edu            panic("TBISR is read only register!\n");
8927839Snilay@cs.wisc.edu
8936902SBrad.Beckmann@amd.com          case TANAR:
8946657Snate@binkert.org            regs.tanar = reg;
8956657Snate@binkert.org            if (reg & TANAR_PS2)
8967839Snilay@cs.wisc.edu                panic("this isn't used in driver, something wrong!\n");
8977839Snilay@cs.wisc.edu
8987839Snilay@cs.wisc.edu            if (reg & TANAR_PS1)
8997839Snilay@cs.wisc.edu                panic("this isn't used in driver, something wrong!\n");
9006657Snate@binkert.org            break;
9017839Snilay@cs.wisc.edu
9027839Snilay@cs.wisc.edu          case TANLPAR:
9037839Snilay@cs.wisc.edu            panic("this should only be written to by the fake phy!\n");
9047839Snilay@cs.wisc.edu
9057839Snilay@cs.wisc.edu          case TANER:
9068055Sksewell@umich.edu            panic("TANER is read only register!\n");
9077839Snilay@cs.wisc.edu
9087839Snilay@cs.wisc.edu          case TESR:
9096657Snate@binkert.org            regs.tesr = reg;
9107839Snilay@cs.wisc.edu            break;
9117839Snilay@cs.wisc.edu
9127839Snilay@cs.wisc.edu          default:
9137839Snilay@cs.wisc.edu            panic("invalid register access daddr=%#x", daddr);
9147839Snilay@cs.wisc.edu        }
9157839Snilay@cs.wisc.edu    } else {
9167839Snilay@cs.wisc.edu        panic("Invalid Request Size");
9177839Snilay@cs.wisc.edu    }
9187839Snilay@cs.wisc.edu
9197839Snilay@cs.wisc.edu    return No_Fault;
9207839Snilay@cs.wisc.edu}
9218055Sksewell@umich.edu
9227839Snilay@cs.wisc.eduvoid
9237839Snilay@cs.wisc.eduNSGigE::devIntrPost(uint32_t interrupts)
9247839Snilay@cs.wisc.edu{
9257839Snilay@cs.wisc.edu    if (interrupts & ISR_RESERVE)
9267839Snilay@cs.wisc.edu        panic("Cannot set a reserved interrupt");
9277839Snilay@cs.wisc.edu
9287839Snilay@cs.wisc.edu    if (interrupts & ISR_NOIMPL)
9297839Snilay@cs.wisc.edu        warn("interrupt not implemented %#x\n", interrupts);
9307839Snilay@cs.wisc.edu
9317839Snilay@cs.wisc.edu    interrupts &= ~ISR_NOIMPL;
9327839Snilay@cs.wisc.edu    regs.isr |= interrupts;
9337839Snilay@cs.wisc.edu
9347839Snilay@cs.wisc.edu    DPRINTF(EthernetIntr,
9357839Snilay@cs.wisc.edu            "interrupt written to ISR: intr=%#x isr=%#x imr=%#x\n",
9368055Sksewell@umich.edu            interrupts, regs.isr, regs.imr);
9377839Snilay@cs.wisc.edu
9387839Snilay@cs.wisc.edu    if ((regs.isr & regs.imr)) {
9397839Snilay@cs.wisc.edu        Tick when = curTick;
9407839Snilay@cs.wisc.edu        if (!(regs.isr & regs.imr & ISR_NODELAY))
9417839Snilay@cs.wisc.edu            when += intrDelay;
9427839Snilay@cs.wisc.edu        cpuIntrPost(when);
9437839Snilay@cs.wisc.edu    }
9447839Snilay@cs.wisc.edu}
9457839Snilay@cs.wisc.edu
9467839Snilay@cs.wisc.eduvoid
9476657Snate@binkert.orgNSGigE::devIntrClear(uint32_t interrupts)
9487007Snate@binkert.org{
9497007Snate@binkert.org    if (interrupts & ISR_RESERVE)
9506657Snate@binkert.org        panic("Cannot clear a reserved interrupt");
9518055Sksewell@umich.edu
9526657Snate@binkert.org    interrupts &= ~ISR_NOIMPL;
9536657Snate@binkert.org    regs.isr &= ~interrupts;
9546657Snate@binkert.org
9556657Snate@binkert.org    DPRINTF(EthernetIntr,
9566657Snate@binkert.org            "interrupt cleared from ISR: intr=%x isr=%x imr=%x\n",
9576657Snate@binkert.org            interrupts, regs.isr, regs.imr);
9586657Snate@binkert.org
9596657Snate@binkert.org    if (!(regs.isr & regs.imr))
9606657Snate@binkert.org        cpuIntrClear();
9616999Snate@binkert.org}
9626657Snate@binkert.org
9636657Snate@binkert.orgvoid
9646657Snate@binkert.orgNSGigE::devIntrChangeMask()
9656657Snate@binkert.org{
9666657Snate@binkert.org    DPRINTF(EthernetIntr, "interrupt mask changed: isr=%x imr=%x masked=%x\n",
9676657Snate@binkert.org            regs.isr, regs.imr, regs.isr & regs.imr);
9687832Snate@binkert.org
9697832Snate@binkert.org    if (regs.isr & regs.imr)
9707007Snate@binkert.org        cpuIntrPost(curTick);
9718229Snate@binkert.org    else
9728229Snate@binkert.org        cpuIntrClear();
9738229Snate@binkert.org}
9748229Snate@binkert.org
9756657Snate@binkert.orgvoid
9766657Snate@binkert.orgNSGigE::cpuIntrPost(Tick when)
9776657Snate@binkert.org{
9786657Snate@binkert.org    // If the interrupt you want to post is later than an interrupt
9797055Snate@binkert.org    // already scheduled, just let it post in the coming one and don't
9807055Snate@binkert.org    // schedule another.
9817007Snate@binkert.org    // HOWEVER, must be sure that the scheduled intrTick is in the
9827007Snate@binkert.org    // future (this was formerly the source of a bug)
9836657Snate@binkert.org    /**
9846657Snate@binkert.org     * @todo this warning should be removed and the intrTick code should
9856657Snate@binkert.org     * be fixed.
9866657Snate@binkert.org     */
9876657Snate@binkert.org    assert(when >= curTick);
9886657Snate@binkert.org    assert(intrTick >= curTick || intrTick == 0);
9897007Snate@binkert.org    if (when > intrTick && intrTick != 0) {
9907007Snate@binkert.org        DPRINTF(EthernetIntr, "don't need to schedule event...intrTick=%d\n",
9917007Snate@binkert.org                intrTick);
9927007Snate@binkert.org        return;
9937007Snate@binkert.org    }
9946657Snate@binkert.org
9956657Snate@binkert.org    intrTick = when;
9966657Snate@binkert.org    if (intrTick < curTick) {
9976657Snate@binkert.org        debug_break();
9986657Snate@binkert.org        intrTick = curTick;
9996657Snate@binkert.org    }
10006657Snate@binkert.org
10016657Snate@binkert.org    DPRINTF(EthernetIntr, "going to schedule an interrupt for intrTick=%d\n",
10026657Snate@binkert.org            intrTick);
10036657Snate@binkert.org
10046657Snate@binkert.org    if (intrEvent)
10056657Snate@binkert.org        intrEvent->squash();
10067567SBrad.Beckmann@amd.com    intrEvent = new IntrEvent(this, true);
10077567SBrad.Beckmann@amd.com    intrEvent->schedule(intrTick);
10087567SBrad.Beckmann@amd.com}
10097567SBrad.Beckmann@amd.com
10106657Snate@binkert.orgvoid
10116657Snate@binkert.orgNSGigE::cpuInterrupt()
10126657Snate@binkert.org{
10136657Snate@binkert.org    assert(intrTick == curTick);
10146657Snate@binkert.org
10156657Snate@binkert.org    // Whether or not there's a pending interrupt, we don't care about
10166657Snate@binkert.org    // it anymore
10176657Snate@binkert.org    intrEvent = 0;
10186657Snate@binkert.org    intrTick = 0;
10196657Snate@binkert.org
10207007Snate@binkert.org    // Don't send an interrupt if there's already one
10216657Snate@binkert.org    if (cpuPendingIntr) {
10226657Snate@binkert.org        DPRINTF(EthernetIntr,
10236657Snate@binkert.org                "would send an interrupt now, but there's already pending\n");
10246657Snate@binkert.org    } else {
10256657Snate@binkert.org        // Send interrupt
10266657Snate@binkert.org        cpuPendingIntr = true;
10276657Snate@binkert.org
10286657Snate@binkert.org        DPRINTF(EthernetIntr, "posting interrupt\n");
10296999Snate@binkert.org        intrPost();
10306657Snate@binkert.org    }
10316657Snate@binkert.org}
10326657Snate@binkert.org
10336657Snate@binkert.orgvoid
10346657Snate@binkert.orgNSGigE::cpuIntrClear()
10356657Snate@binkert.org{
10367832Snate@binkert.org    if (!cpuPendingIntr)
10377832Snate@binkert.org        return;
10387805Snilay@cs.wisc.edu
10397832Snate@binkert.org    if (intrEvent) {
10408229Snate@binkert.org        intrEvent->squash();
10418229Snate@binkert.org        intrEvent = 0;
10428229Snate@binkert.org    }
10438229Snate@binkert.org
10446657Snate@binkert.org    intrTick = 0;
10456657Snate@binkert.org
10466657Snate@binkert.org    cpuPendingIntr = false;
10476657Snate@binkert.org
10486657Snate@binkert.org    DPRINTF(EthernetIntr, "clearing interrupt\n");
10496657Snate@binkert.org    intrClear();
10506657Snate@binkert.org}
10516657Snate@binkert.org
10527007Snate@binkert.orgbool
10537007Snate@binkert.orgNSGigE::cpuIntrPending() const
10547839Snilay@cs.wisc.edu{ return cpuPendingIntr; }
10557839Snilay@cs.wisc.edu
10567839Snilay@cs.wisc.eduvoid
10577839Snilay@cs.wisc.eduNSGigE::txReset()
10587839Snilay@cs.wisc.edu{
10597839Snilay@cs.wisc.edu
10607839Snilay@cs.wisc.edu    DPRINTF(Ethernet, "transmit reset\n");
10617839Snilay@cs.wisc.edu
10627839Snilay@cs.wisc.edu    CTDD = false;
10637839Snilay@cs.wisc.edu    txEnable = false;;
10647007Snate@binkert.org    txFragPtr = 0;
10656657Snate@binkert.org    assert(txDescCnt == 0);
10667839Snilay@cs.wisc.edu    txFifo.clear();
10677839Snilay@cs.wisc.edu    txState = txIdle;
10687839Snilay@cs.wisc.edu    assert(txDmaState == dmaIdle);
10697839Snilay@cs.wisc.edu}
10707839Snilay@cs.wisc.edu
10717839Snilay@cs.wisc.eduvoid
10727839Snilay@cs.wisc.eduNSGigE::rxReset()
10737839Snilay@cs.wisc.edu{
10747839Snilay@cs.wisc.edu    DPRINTF(Ethernet, "receive reset\n");
10757839Snilay@cs.wisc.edu
10767839Snilay@cs.wisc.edu    CRDD = false;
10776657Snate@binkert.org    assert(rxPktBytes == 0);
10786657Snate@binkert.org    rxEnable = false;
10797780Snilay@cs.wisc.edu    rxFragPtr = 0;
10807780Snilay@cs.wisc.edu    assert(rxDescCnt == 0);
10817780Snilay@cs.wisc.edu    assert(rxDmaState == dmaIdle);
10827780Snilay@cs.wisc.edu    rxFifo.clear();
10837780Snilay@cs.wisc.edu    rxState = rxIdle;
10847780Snilay@cs.wisc.edu}
10856657Snate@binkert.org
10867007Snate@binkert.orgvoid
10877839Snilay@cs.wisc.eduNSGigE::regsReset()
10887839Snilay@cs.wisc.edu{
10897839Snilay@cs.wisc.edu    memset(&regs, 0, sizeof(regs));
10907839Snilay@cs.wisc.edu    regs.config = CFG_LNKSTS;
10917839Snilay@cs.wisc.edu    regs.mear = MEAR_MDDIR | MEAR_EEDO;
10927839Snilay@cs.wisc.edu    regs.txcfg = 0x120; // set drain threshold to 1024 bytes and
10937839Snilay@cs.wisc.edu                        // fill threshold to 32 bytes
10947839Snilay@cs.wisc.edu    regs.rxcfg = 0x4;   // set drain threshold to 16 bytes
10957839Snilay@cs.wisc.edu    regs.srr = 0x0103;  // set the silicon revision to rev B or 0x103
10966657Snate@binkert.org    regs.mibc = MIBC_FRZ;
10977839Snilay@cs.wisc.edu    regs.vdr = 0x81;    // set the vlan tag type to 802.1q
10986657Snate@binkert.org    regs.tesr = 0xc000; // TBI capable of both full and half duplex
10997780Snilay@cs.wisc.edu
11007780Snilay@cs.wisc.edu    extstsEnable = false;
11017542SBrad.Beckmann@amd.com    acceptBroadcast = false;
11027832Snate@binkert.org    acceptMulticast = false;
11037832Snate@binkert.org    acceptUnicast = false;
11047832Snate@binkert.org    acceptPerfect = false;
11057832Snate@binkert.org    acceptArp = false;
11067832Snate@binkert.org}
11077832Snate@binkert.org
11086657Snate@binkert.orgvoid
11097832Snate@binkert.orgNSGigE::rxDmaReadCopy()
11107839Snilay@cs.wisc.edu{
11117839Snilay@cs.wisc.edu    assert(rxDmaState == dmaReading);
11127839Snilay@cs.wisc.edu
11138086SBrad.Beckmann@amd.com    physmem->dma_read((uint8_t *)rxDmaData, rxDmaAddr, rxDmaLen);
11147839Snilay@cs.wisc.edu    rxDmaState = dmaIdle;
11157839Snilay@cs.wisc.edu
11167839Snilay@cs.wisc.edu    DPRINTF(EthernetDMA, "rx dma read  paddr=%#x len=%d\n",
11177839Snilay@cs.wisc.edu            rxDmaAddr, rxDmaLen);
11188086SBrad.Beckmann@amd.com    DDUMP(EthernetDMA, rxDmaData, rxDmaLen);
11197839Snilay@cs.wisc.edu}
11207839Snilay@cs.wisc.edu
11217839Snilay@cs.wisc.edubool
11227839Snilay@cs.wisc.eduNSGigE::doRxDmaRead()
11236657Snate@binkert.org{
11247832Snate@binkert.org    assert(rxDmaState == dmaIdle || rxDmaState == dmaReadWaiting);
11257832Snate@binkert.org    rxDmaState = dmaReading;
11267832Snate@binkert.org
11277832Snate@binkert.org    if (dmaInterface && !rxDmaFree) {
11287832Snate@binkert.org        if (dmaInterface->busy())
11297832Snate@binkert.org            rxDmaState = dmaReadWaiting;
11306657Snate@binkert.org        else
11317780Snilay@cs.wisc.edu            dmaInterface->doDMA(Read, rxDmaAddr, rxDmaLen, curTick,
11327832Snate@binkert.org                                &rxDmaReadEvent, true);
11337832Snate@binkert.org        return true;
11347832Snate@binkert.org    }
11357832Snate@binkert.org
11367832Snate@binkert.org    if (dmaReadDelay == 0 && dmaReadFactor == 0) {
11377832Snate@binkert.org        rxDmaReadCopy();
11386657Snate@binkert.org        return false;
11396657Snate@binkert.org    }
11406657Snate@binkert.org
11416657Snate@binkert.org    Tick factor = ((rxDmaLen + ULL(63)) >> ULL(6)) * dmaReadFactor;
11426657Snate@binkert.org    Tick start = curTick + dmaReadDelay + factor;
11437007Snate@binkert.org    rxDmaReadEvent.schedule(start);
11447007Snate@binkert.org    return true;
11457007Snate@binkert.org}
11467007Snate@binkert.org
11477839Snilay@cs.wisc.eduvoid
11487839Snilay@cs.wisc.eduNSGigE::rxDmaReadDone()
11497839Snilay@cs.wisc.edu{
11507839Snilay@cs.wisc.edu    assert(rxDmaState == dmaReading);
11517839Snilay@cs.wisc.edu    rxDmaReadCopy();
11527839Snilay@cs.wisc.edu
11537839Snilay@cs.wisc.edu    // If the transmit state machine has a pending DMA, let it go first
11547839Snilay@cs.wisc.edu    if (txDmaState == dmaReadWaiting || txDmaState == dmaWriteWaiting)
11557839Snilay@cs.wisc.edu        txKick();
11567839Snilay@cs.wisc.edu
11577839Snilay@cs.wisc.edu    rxKick();
11587007Snate@binkert.org}
11596657Snate@binkert.org
11606657Snate@binkert.orgvoid
11616657Snate@binkert.orgNSGigE::rxDmaWriteCopy()
11626657Snate@binkert.org{
11636657Snate@binkert.org    assert(rxDmaState == dmaWriting);
11646657Snate@binkert.org
11656657Snate@binkert.org    physmem->dma_write(rxDmaAddr, (uint8_t *)rxDmaData, rxDmaLen);
11666657Snate@binkert.org    rxDmaState = dmaIdle;
11676657Snate@binkert.org
11686657Snate@binkert.org    DPRINTF(EthernetDMA, "rx dma write paddr=%#x len=%d\n",
11696657Snate@binkert.org            rxDmaAddr, rxDmaLen);
11706999Snate@binkert.org    DDUMP(EthernetDMA, rxDmaData, rxDmaLen);
11716657Snate@binkert.org}
11726657Snate@binkert.org
11736657Snate@binkert.orgbool
11746657Snate@binkert.orgNSGigE::doRxDmaWrite()
11756657Snate@binkert.org{
11766657Snate@binkert.org    assert(rxDmaState == dmaIdle || rxDmaState == dmaWriteWaiting);
11776657Snate@binkert.org    rxDmaState = dmaWriting;
11786657Snate@binkert.org
11796657Snate@binkert.org    if (dmaInterface && !rxDmaFree) {
11806657Snate@binkert.org        if (dmaInterface->busy())
11816657Snate@binkert.org            rxDmaState = dmaWriteWaiting;
11826657Snate@binkert.org        else
11836657Snate@binkert.org            dmaInterface->doDMA(WriteInvalidate, rxDmaAddr, rxDmaLen, curTick,
11847007Snate@binkert.org                                &rxDmaWriteEvent, true);
11856657Snate@binkert.org        return true;
11866657Snate@binkert.org    }
11876657Snate@binkert.org
11886657Snate@binkert.org    if (dmaWriteDelay == 0 && dmaWriteFactor == 0) {
11896657Snate@binkert.org        rxDmaWriteCopy();
11906657Snate@binkert.org        return false;
11916657Snate@binkert.org    }
11926657Snate@binkert.org
11936657Snate@binkert.org    Tick factor = ((rxDmaLen + ULL(63)) >> ULL(6)) * dmaWriteFactor;
11946657Snate@binkert.org    Tick start = curTick + dmaWriteDelay + factor;
11956657Snate@binkert.org    rxDmaWriteEvent.schedule(start);
11966657Snate@binkert.org    return true;
11976657Snate@binkert.org}
11986657Snate@binkert.org
11996657Snate@binkert.orgvoid
12006657Snate@binkert.orgNSGigE::rxDmaWriteDone()
12016657Snate@binkert.org{
12026657Snate@binkert.org    assert(rxDmaState == dmaWriting);
12036657Snate@binkert.org    rxDmaWriteCopy();
12046657Snate@binkert.org
12056657Snate@binkert.org    // If the transmit state machine has a pending DMA, let it go first
12067839Snilay@cs.wisc.edu    if (txDmaState == dmaReadWaiting || txDmaState == dmaWriteWaiting)
12077839Snilay@cs.wisc.edu        txKick();
12087839Snilay@cs.wisc.edu
12097839Snilay@cs.wisc.edu    rxKick();
12107839Snilay@cs.wisc.edu}
12117839Snilay@cs.wisc.edu
12127839Snilay@cs.wisc.eduvoid
12137839Snilay@cs.wisc.eduNSGigE::rxKick()
12147839Snilay@cs.wisc.edu{
12157839Snilay@cs.wisc.edu    DPRINTF(EthernetSM, "receive kick rxState=%s (rxBuf.size=%d)\n",
12167839Snilay@cs.wisc.edu            NsRxStateStrings[rxState], rxFifo.size());
12177839Snilay@cs.wisc.edu
12186657Snate@binkert.org    if (rxKickTick > curTick) {
12196657Snate@binkert.org        DPRINTF(EthernetSM, "receive kick exiting, can't run till %d\n",
12206657Snate@binkert.org                rxKickTick);
12216657Snate@binkert.org        return;
12226657Snate@binkert.org    }
12236657Snate@binkert.org
12246657Snate@binkert.org  next:
12256657Snate@binkert.org    switch(rxDmaState) {
12266657Snate@binkert.org      case dmaReadWaiting:
12276657Snate@binkert.org        if (doRxDmaRead())
12286657Snate@binkert.org            goto exit;
12296657Snate@binkert.org        break;
12306657Snate@binkert.org      case dmaWriteWaiting:
12316657Snate@binkert.org        if (doRxDmaWrite())
12326657Snate@binkert.org            goto exit;
12336657Snate@binkert.org        break;
12346657Snate@binkert.org      default:
12356657Snate@binkert.org        break;
12366657Snate@binkert.org    }
12376657Snate@binkert.org
12386657Snate@binkert.org    // see state machine from spec for details
12397805Snilay@cs.wisc.edu    // the way this works is, if you finish work on one state and can
12408159SBrad.Beckmann@amd.com    // go directly to another, you do that through jumping to the
12418159SBrad.Beckmann@amd.com    // label "next".  however, if you have intermediate work, like DMA
12426657Snate@binkert.org    // so that you can't go to the next state yet, you go to exit and
12436657Snate@binkert.org    // exit the loop.  however, when the DMA is done it will trigger
12446657Snate@binkert.org    // an event and come back to this loop.
12456657Snate@binkert.org    switch (rxState) {
12466657Snate@binkert.org      case rxIdle:
12476657Snate@binkert.org        if (!rxEnable) {
12487542SBrad.Beckmann@amd.com            DPRINTF(EthernetSM, "Receive Disabled! Nothing to do.\n");
12497542SBrad.Beckmann@amd.com            goto exit;
12507542SBrad.Beckmann@amd.com        }
12517542SBrad.Beckmann@amd.com
12527542SBrad.Beckmann@amd.com        if (CRDD) {
12537542SBrad.Beckmann@amd.com            rxState = rxDescRefr;
12547542SBrad.Beckmann@amd.com
12557542SBrad.Beckmann@amd.com            rxDmaAddr = regs.rxdp & 0x3fffffff;
12567542SBrad.Beckmann@amd.com            rxDmaData = &rxDescCache + offsetof(ns_desc, link);
12577542SBrad.Beckmann@amd.com            rxDmaLen = sizeof(rxDescCache.link);
12587542SBrad.Beckmann@amd.com            rxDmaFree = dmaDescFree;
12597832Snate@binkert.org
12607542SBrad.Beckmann@amd.com            descDmaReads++;
12617542SBrad.Beckmann@amd.com            descDmaRdBytes += rxDmaLen;
12627542SBrad.Beckmann@amd.com
12638229Snate@binkert.org            if (doRxDmaRead())
12647542SBrad.Beckmann@amd.com                goto exit;
12657542SBrad.Beckmann@amd.com        } else {
12667542SBrad.Beckmann@amd.com            rxState = rxDescRead;
12677542SBrad.Beckmann@amd.com
12687542SBrad.Beckmann@amd.com            rxDmaAddr = regs.rxdp & 0x3fffffff;
12697542SBrad.Beckmann@amd.com            rxDmaData = &rxDescCache;
12707542SBrad.Beckmann@amd.com            rxDmaLen = sizeof(ns_desc);
12717542SBrad.Beckmann@amd.com            rxDmaFree = dmaDescFree;
12727542SBrad.Beckmann@amd.com
12737542SBrad.Beckmann@amd.com            descDmaReads++;
12747542SBrad.Beckmann@amd.com            descDmaRdBytes += rxDmaLen;
12757542SBrad.Beckmann@amd.com
12767542SBrad.Beckmann@amd.com            if (doRxDmaRead())
12777542SBrad.Beckmann@amd.com                goto exit;
12787542SBrad.Beckmann@amd.com        }
12797542SBrad.Beckmann@amd.com        break;
12807542SBrad.Beckmann@amd.com
12817542SBrad.Beckmann@amd.com      case rxDescRefr:
12827542SBrad.Beckmann@amd.com        if (rxDmaState != dmaIdle)
12837542SBrad.Beckmann@amd.com            goto exit;
12847542SBrad.Beckmann@amd.com
12857542SBrad.Beckmann@amd.com        rxState = rxAdvance;
12867542SBrad.Beckmann@amd.com        break;
12877542SBrad.Beckmann@amd.com
12887542SBrad.Beckmann@amd.com     case rxDescRead:
12897542SBrad.Beckmann@amd.com        if (rxDmaState != dmaIdle)
12907542SBrad.Beckmann@amd.com            goto exit;
12917542SBrad.Beckmann@amd.com
12927542SBrad.Beckmann@amd.com        DPRINTF(EthernetDesc,
12937542SBrad.Beckmann@amd.com                "rxDescCache: addr=%08x read descriptor\n",
12947542SBrad.Beckmann@amd.com                regs.rxdp & 0x3fffffff);
12957542SBrad.Beckmann@amd.com        DPRINTF(EthernetDesc,
12967542SBrad.Beckmann@amd.com                "rxDescCache: link=%08x bufptr=%08x cmdsts=%08x extsts=%08x\n",
12977542SBrad.Beckmann@amd.com                rxDescCache.link, rxDescCache.bufptr, rxDescCache.cmdsts,
12987542SBrad.Beckmann@amd.com                rxDescCache.extsts);
12997542SBrad.Beckmann@amd.com
13007542SBrad.Beckmann@amd.com        if (rxDescCache.cmdsts & CMDSTS_OWN) {
13017542SBrad.Beckmann@amd.com            devIntrPost(ISR_RXIDLE);
13027542SBrad.Beckmann@amd.com            rxState = rxIdle;
13037542SBrad.Beckmann@amd.com            goto exit;
13047542SBrad.Beckmann@amd.com        } else {
13057542SBrad.Beckmann@amd.com            rxState = rxFifoBlock;
13067542SBrad.Beckmann@amd.com            rxFragPtr = rxDescCache.bufptr;
13077542SBrad.Beckmann@amd.com            rxDescCnt = rxDescCache.cmdsts & CMDSTS_LEN_MASK;
13087542SBrad.Beckmann@amd.com        }
13097542SBrad.Beckmann@amd.com        break;
13107542SBrad.Beckmann@amd.com
13117542SBrad.Beckmann@amd.com      case rxFifoBlock:
13127542SBrad.Beckmann@amd.com        if (!rxPacket) {
13137542SBrad.Beckmann@amd.com            /**
13147542SBrad.Beckmann@amd.com             * @todo in reality, we should be able to start processing
13157542SBrad.Beckmann@amd.com             * the packet as it arrives, and not have to wait for the
13167542SBrad.Beckmann@amd.com             * full packet ot be in the receive fifo.
13177542SBrad.Beckmann@amd.com             */
13187542SBrad.Beckmann@amd.com            if (rxFifo.empty())
13197542SBrad.Beckmann@amd.com                goto exit;
13207542SBrad.Beckmann@amd.com
13217542SBrad.Beckmann@amd.com            DPRINTF(EthernetSM, "****processing receive of new packet****\n");
13227542SBrad.Beckmann@amd.com
13237542SBrad.Beckmann@amd.com            // If we don't have a packet, grab a new one from the fifo.
13247542SBrad.Beckmann@amd.com            rxPacket = rxFifo.front();
13257542SBrad.Beckmann@amd.com            rxPktBytes = rxPacket->length;
13267542SBrad.Beckmann@amd.com            rxPacketBufPtr = rxPacket->data;
13277542SBrad.Beckmann@amd.com
13287542SBrad.Beckmann@amd.com#if TRACING_ON
13297542SBrad.Beckmann@amd.com            if (DTRACE(Ethernet)) {
13307542SBrad.Beckmann@amd.com                IpPtr ip(rxPacket);
13317542SBrad.Beckmann@amd.com                if (ip) {
13327542SBrad.Beckmann@amd.com                    DPRINTF(Ethernet, "ID is %d\n", ip->id());
13337542SBrad.Beckmann@amd.com                    TcpPtr tcp(ip);
13347542SBrad.Beckmann@amd.com                    if (tcp) {
13357542SBrad.Beckmann@amd.com                        DPRINTF(Ethernet, "Src Port=%d, Dest Port=%d\n",
13367542SBrad.Beckmann@amd.com                                tcp->sport(), tcp->dport());
13377542SBrad.Beckmann@amd.com                    }
13387542SBrad.Beckmann@amd.com                }
13397542SBrad.Beckmann@amd.com            }
13407542SBrad.Beckmann@amd.com#endif
13417542SBrad.Beckmann@amd.com
13427542SBrad.Beckmann@amd.com            // sanity check - i think the driver behaves like this
13437542SBrad.Beckmann@amd.com            assert(rxDescCnt >= rxPktBytes);
13446657Snate@binkert.org            rxFifo.pop();
13456999Snate@binkert.org        }
13466657Snate@binkert.org
13476657Snate@binkert.org
13486657Snate@binkert.org        // dont' need the && rxDescCnt > 0 if driver sanity check
13496657Snate@binkert.org        // above holds
13506657Snate@binkert.org        if (rxPktBytes > 0) {
13516657Snate@binkert.org            rxState = rxFragWrite;
13527542SBrad.Beckmann@amd.com            // don't need min<>(rxPktBytes,rxDescCnt) if above sanity
13537542SBrad.Beckmann@amd.com            // check holds
13546657Snate@binkert.org            rxXferLen = rxPktBytes;
13557832Snate@binkert.org
13567002Snate@binkert.org            rxDmaAddr = rxFragPtr & 0x3fffffff;
13577002Snate@binkert.org            rxDmaData = rxPacketBufPtr;
13588229Snate@binkert.org            rxDmaLen = rxXferLen;
13598229Snate@binkert.org            rxDmaFree = dmaDataFree;
13606657Snate@binkert.org
13616657Snate@binkert.org            if (doRxDmaWrite())
13627007Snate@binkert.org                goto exit;
13637007Snate@binkert.org
13646657Snate@binkert.org        } else {
13656657Snate@binkert.org            rxState = rxDescWrite;
13666657Snate@binkert.org
13676657Snate@binkert.org            //if (rxPktBytes == 0) {  /* packet is done */
13686657Snate@binkert.org            assert(rxPktBytes == 0);
13697542SBrad.Beckmann@amd.com            DPRINTF(EthernetSM, "done with receiving packet\n");
13707542SBrad.Beckmann@amd.com
13717542SBrad.Beckmann@amd.com            rxDescCache.cmdsts |= CMDSTS_OWN;
13726657Snate@binkert.org            rxDescCache.cmdsts &= ~CMDSTS_MORE;
13736657Snate@binkert.org            rxDescCache.cmdsts |= CMDSTS_OK;
13746657Snate@binkert.org            rxDescCache.cmdsts &= 0xffff0000;
13756657Snate@binkert.org            rxDescCache.cmdsts += rxPacket->length;   //i.e. set CMDSTS_SIZE
13766657Snate@binkert.org
13776657Snate@binkert.org#if 0
13786657Snate@binkert.org            /*
13796657Snate@binkert.org             * all the driver uses these are for its own stats keeping
13806657Snate@binkert.org             * which we don't care about, aren't necessary for
13817007Snate@binkert.org             * functionality and doing this would just slow us down.
13826657Snate@binkert.org             * if they end up using this in a later version for
13836657Snate@binkert.org             * functional purposes, just undef
13846657Snate@binkert.org             */
13856657Snate@binkert.org            if (rxFilterEnable) {
13866999Snate@binkert.org                rxDescCache.cmdsts &= ~CMDSTS_DEST_MASK;
13876657Snate@binkert.org                const EthAddr &dst = rxFifoFront()->dst();
13886657Snate@binkert.org                if (dst->unicast())
13896657Snate@binkert.org                    rxDescCache.cmdsts |= CMDSTS_DEST_SELF;
13906657Snate@binkert.org                if (dst->multicast())
13916657Snate@binkert.org                    rxDescCache.cmdsts |= CMDSTS_DEST_MULTI;
13926657Snate@binkert.org                if (dst->broadcast())
13937832Snate@binkert.org                    rxDescCache.cmdsts |= CMDSTS_DEST_MASK;
13947832Snate@binkert.org            }
13956657Snate@binkert.org#endif
13966657Snate@binkert.org
13976657Snate@binkert.org            IpPtr ip(rxPacket);
13986657Snate@binkert.org            if (extstsEnable && ip) {
13996657Snate@binkert.org                rxDescCache.extsts |= EXTSTS_IPPKT;
14006657Snate@binkert.org                rxIpChecksums++;
14016657Snate@binkert.org                if (cksum(ip) != 0) {
14026657Snate@binkert.org                    DPRINTF(EthernetCksum, "Rx IP Checksum Error\n");
14036657Snate@binkert.org                    rxDescCache.extsts |= EXTSTS_IPERR;
14046657Snate@binkert.org                }
14056657Snate@binkert.org                TcpPtr tcp(ip);
14066657Snate@binkert.org                UdpPtr udp(ip);
14076657Snate@binkert.org                if (tcp) {
14086657Snate@binkert.org                    rxDescCache.extsts |= EXTSTS_TCPPKT;
14097007Snate@binkert.org                    rxTcpChecksums++;
14107007Snate@binkert.org                    if (cksum(tcp) != 0) {
14117007Snate@binkert.org                        DPRINTF(EthernetCksum, "Rx TCP Checksum Error\n");
14126657Snate@binkert.org                        rxDescCache.extsts |= EXTSTS_TCPERR;
14136657Snate@binkert.org
14146657Snate@binkert.org                    }
14157007Snate@binkert.org                } else if (udp) {
14167007Snate@binkert.org                    rxDescCache.extsts |= EXTSTS_UDPPKT;
14177007Snate@binkert.org                    rxUdpChecksums++;
14186657Snate@binkert.org                    if (cksum(udp) != 0) {
14196657Snate@binkert.org                        DPRINTF(EthernetCksum, "Rx UDP Checksum Error\n");
14206657Snate@binkert.org                        rxDescCache.extsts |= EXTSTS_UDPERR;
14216657Snate@binkert.org                    }
14226657Snate@binkert.org                }
14236657Snate@binkert.org            }
14246657Snate@binkert.org            rxPacket = 0;
14256657Snate@binkert.org
14266657Snate@binkert.org            /*
14276657Snate@binkert.org             * the driver seems to always receive into desc buffers
14286657Snate@binkert.org             * of size 1514, so you never have a pkt that is split
14297007Snate@binkert.org             * into multiple descriptors on the receive side, so
14307007Snate@binkert.org             * i don't implement that case, hence the assert above.
14316657Snate@binkert.org             */
14326657Snate@binkert.org
14336657Snate@binkert.org            DPRINTF(EthernetDesc,
14346657Snate@binkert.org                    "rxDescCache: addr=%08x writeback cmdsts extsts\n",
14356657Snate@binkert.org                    regs.rxdp & 0x3fffffff);
14367007Snate@binkert.org            DPRINTF(EthernetDesc,
14377007Snate@binkert.org                    "rxDescCache: link=%08x bufptr=%08x cmdsts=%08x extsts=%08x\n",
14387007Snate@binkert.org                    rxDescCache.link, rxDescCache.bufptr, rxDescCache.cmdsts,
14396657Snate@binkert.org                    rxDescCache.extsts);
14406657Snate@binkert.org
14416657Snate@binkert.org            rxDmaAddr = (regs.rxdp + offsetof(ns_desc, cmdsts)) & 0x3fffffff;
14427007Snate@binkert.org            rxDmaData = &(rxDescCache.cmdsts);
14437542SBrad.Beckmann@amd.com            rxDmaLen = sizeof(rxDescCache.cmdsts) + sizeof(rxDescCache.extsts);
14447542SBrad.Beckmann@amd.com            rxDmaFree = dmaDescFree;
14456657Snate@binkert.org
14467542SBrad.Beckmann@amd.com            descDmaWrites++;
14477542SBrad.Beckmann@amd.com            descDmaWrBytes += rxDmaLen;
14487002Snate@binkert.org
14497542SBrad.Beckmann@amd.com            if (doRxDmaWrite())
14507542SBrad.Beckmann@amd.com                goto exit;
14517542SBrad.Beckmann@amd.com        }
14527542SBrad.Beckmann@amd.com        break;
14536657Snate@binkert.org
14547542SBrad.Beckmann@amd.com      case rxFragWrite:
14557542SBrad.Beckmann@amd.com        if (rxDmaState != dmaIdle)
14567542SBrad.Beckmann@amd.com            goto exit;
14577542SBrad.Beckmann@amd.com
14587542SBrad.Beckmann@amd.com        rxPacketBufPtr += rxXferLen;
14597542SBrad.Beckmann@amd.com        rxFragPtr += rxXferLen;
14607542SBrad.Beckmann@amd.com        rxPktBytes -= rxXferLen;
14617542SBrad.Beckmann@amd.com
14626657Snate@binkert.org        rxState = rxFifoBlock;
14636657Snate@binkert.org        break;
14646657Snate@binkert.org
14656657Snate@binkert.org      case rxDescWrite:
14666657Snate@binkert.org        if (rxDmaState != dmaIdle)
14676657Snate@binkert.org            goto exit;
14687007Snate@binkert.org
14696999Snate@binkert.org        assert(rxDescCache.cmdsts & CMDSTS_OWN);
14707007Snate@binkert.org
14717007Snate@binkert.org        assert(rxPacket == 0);
14727007Snate@binkert.org        devIntrPost(ISR_RXOK);
14737007Snate@binkert.org
14747007Snate@binkert.org        if (rxDescCache.cmdsts & CMDSTS_INTR)
14757007Snate@binkert.org            devIntrPost(ISR_RXDESC);
14766657Snate@binkert.org
14776657Snate@binkert.org        if (!rxEnable) {
14786657Snate@binkert.org            DPRINTF(EthernetSM, "Halting the RX state machine\n");
14796657Snate@binkert.org            rxState = rxIdle;
14806657Snate@binkert.org            goto exit;
14816657Snate@binkert.org        } else
14826657Snate@binkert.org            rxState = rxAdvance;
14836657Snate@binkert.org        break;
14846657Snate@binkert.org
14856657Snate@binkert.org      case rxAdvance:
14866657Snate@binkert.org        if (rxDescCache.link == 0) {
14876657Snate@binkert.org            devIntrPost(ISR_RXIDLE);
14886657Snate@binkert.org            rxState = rxIdle;
14896657Snate@binkert.org            CRDD = true;
14906657Snate@binkert.org            goto exit;
14916657Snate@binkert.org        } else {
14926657Snate@binkert.org            rxState = rxDescRead;
14936657Snate@binkert.org            regs.rxdp = rxDescCache.link;
14946657Snate@binkert.org            CRDD = false;
14956657Snate@binkert.org
14966657Snate@binkert.org            rxDmaAddr = regs.rxdp & 0x3fffffff;
14976657Snate@binkert.org            rxDmaData = &rxDescCache;
14986657Snate@binkert.org            rxDmaLen = sizeof(ns_desc);
14996657Snate@binkert.org            rxDmaFree = dmaDescFree;
15006657Snate@binkert.org
15016657Snate@binkert.org            if (doRxDmaRead())
15026657Snate@binkert.org                goto exit;
15036657Snate@binkert.org        }
15046657Snate@binkert.org        break;
15056999Snate@binkert.org
15066657Snate@binkert.org      default:
15076657Snate@binkert.org        panic("Invalid rxState!");
15087007Snate@binkert.org    }
15097007Snate@binkert.org
15106657Snate@binkert.org    DPRINTF(EthernetSM, "entering next rxState=%s\n",
15116657Snate@binkert.org            NsRxStateStrings[rxState]);
15126657Snate@binkert.org
15136657Snate@binkert.org    goto next;
15146657Snate@binkert.org
15156657Snate@binkert.org  exit:
15166657Snate@binkert.org    /**
15176657Snate@binkert.org     * @todo do we want to schedule a future kick?
15186657Snate@binkert.org     */
15196657Snate@binkert.org    DPRINTF(EthernetSM, "rx state machine exited rxState=%s\n",
15206657Snate@binkert.org            NsRxStateStrings[rxState]);
15216657Snate@binkert.org}
15226657Snate@binkert.org
15236657Snate@binkert.orgvoid
15246657Snate@binkert.orgNSGigE::transmit()
15256657Snate@binkert.org{
15266657Snate@binkert.org    if (txFifo.empty()) {
15276657Snate@binkert.org        DPRINTF(Ethernet, "nothing to transmit\n");
15286657Snate@binkert.org        return;
15296657Snate@binkert.org    }
15306657Snate@binkert.org
15316657Snate@binkert.org    DPRINTF(Ethernet, "Attempt Pkt Transmit: txFifo length=%d\n",
15326657Snate@binkert.org            txFifo.size());
15336657Snate@binkert.org    if (interface->sendPacket(txFifo.front())) {
15346657Snate@binkert.org#if TRACING_ON
15356657Snate@binkert.org        if (DTRACE(Ethernet)) {
15366657Snate@binkert.org            IpPtr ip(txFifo.front());
15376657Snate@binkert.org            if (ip) {
15386657Snate@binkert.org                DPRINTF(Ethernet, "ID is %d\n", ip->id());
15396657Snate@binkert.org                TcpPtr tcp(ip);
15406657Snate@binkert.org                if (tcp) {
15416657Snate@binkert.org                    DPRINTF(Ethernet, "Src Port=%d, Dest Port=%d\n",
15426657Snate@binkert.org                            tcp->sport(), tcp->dport());
15436657Snate@binkert.org                }
15446657Snate@binkert.org            }
15456657Snate@binkert.org        }
15466657Snate@binkert.org#endif
15476657Snate@binkert.org
15486657Snate@binkert.org        DDUMP(Ethernet, txFifo.front()->data, txFifo.front()->length);
15496657Snate@binkert.org        txBytes += txFifo.front()->length;
15506657Snate@binkert.org        txPackets++;
15516657Snate@binkert.org
15526657Snate@binkert.org        DPRINTF(Ethernet, "Successful Xmit! now txFifoAvail is %d\n",
15536657Snate@binkert.org                txFifo.avail());
15546657Snate@binkert.org        txFifo.pop();
15556657Snate@binkert.org
15566657Snate@binkert.org        /*
15576657Snate@binkert.org         * normally do a writeback of the descriptor here, and ONLY
15586657Snate@binkert.org         * after that is done, send this interrupt.  but since our
15596657Snate@binkert.org         * stuff never actually fails, just do this interrupt here,
15606657Snate@binkert.org         * otherwise the code has to stray from this nice format.
15616657Snate@binkert.org         * besides, it's functionally the same.
15626657Snate@binkert.org         */
15636657Snate@binkert.org        devIntrPost(ISR_TXOK);
15646657Snate@binkert.org    }
15656657Snate@binkert.org
15666657Snate@binkert.org   if (!txFifo.empty() && !txEvent.scheduled()) {
15676657Snate@binkert.org       DPRINTF(Ethernet, "reschedule transmit\n");
15686657Snate@binkert.org       txEvent.schedule(curTick + 1000);
15696657Snate@binkert.org   }
15706657Snate@binkert.org}
15716657Snate@binkert.org
15726657Snate@binkert.orgvoid
15736657Snate@binkert.orgNSGigE::txDmaReadCopy()
15746657Snate@binkert.org{
15756657Snate@binkert.org    assert(txDmaState == dmaReading);
15766657Snate@binkert.org
15776657Snate@binkert.org    physmem->dma_read((uint8_t *)txDmaData, txDmaAddr, txDmaLen);
15786657Snate@binkert.org    txDmaState = dmaIdle;
15796657Snate@binkert.org
15806657Snate@binkert.org    DPRINTF(EthernetDMA, "tx dma read  paddr=%#x len=%d\n",
15816657Snate@binkert.org            txDmaAddr, txDmaLen);
15826657Snate@binkert.org    DDUMP(EthernetDMA, txDmaData, txDmaLen);
15836657Snate@binkert.org}
15846657Snate@binkert.org
15856657Snate@binkert.orgbool
15866657Snate@binkert.orgNSGigE::doTxDmaRead()
15876657Snate@binkert.org{
15886657Snate@binkert.org    assert(txDmaState == dmaIdle || txDmaState == dmaReadWaiting);
15896657Snate@binkert.org    txDmaState = dmaReading;
15906657Snate@binkert.org
15916657Snate@binkert.org    if (dmaInterface && !txDmaFree) {
15926657Snate@binkert.org        if (dmaInterface->busy())
15936657Snate@binkert.org            txDmaState = dmaReadWaiting;
15946657Snate@binkert.org        else
15956657Snate@binkert.org            dmaInterface->doDMA(Read, txDmaAddr, txDmaLen, curTick,
15966657Snate@binkert.org                                &txDmaReadEvent, true);
15976657Snate@binkert.org        return true;
15987007Snate@binkert.org    }
15996657Snate@binkert.org
16006657Snate@binkert.org    if (dmaReadDelay == 0 && dmaReadFactor == 0.0) {
16016657Snate@binkert.org        txDmaReadCopy();
16026657Snate@binkert.org        return false;
16036657Snate@binkert.org    }
16046657Snate@binkert.org
16056657Snate@binkert.org    Tick factor = ((txDmaLen + ULL(63)) >> ULL(6)) * dmaReadFactor;
16067007Snate@binkert.org    Tick start = curTick + dmaReadDelay + factor;
16076657Snate@binkert.org    txDmaReadEvent.schedule(start);
16086657Snate@binkert.org    return true;
16096657Snate@binkert.org}
16106657Snate@binkert.org
16116657Snate@binkert.orgvoid
16126657Snate@binkert.orgNSGigE::txDmaReadDone()
16136657Snate@binkert.org{
16146657Snate@binkert.org    assert(txDmaState == dmaReading);
16156657Snate@binkert.org    txDmaReadCopy();
16166657Snate@binkert.org
16176657Snate@binkert.org    // If the receive state machine  has a pending DMA, let it go first
16186657Snate@binkert.org    if (rxDmaState == dmaReadWaiting || rxDmaState == dmaWriteWaiting)
16196657Snate@binkert.org        rxKick();
16206657Snate@binkert.org
16216657Snate@binkert.org    txKick();
16227007Snate@binkert.org}
16236657Snate@binkert.org
16246657Snate@binkert.orgvoid
16256657Snate@binkert.orgNSGigE::txDmaWriteCopy()
16266657Snate@binkert.org{
16276657Snate@binkert.org    assert(txDmaState == dmaWriting);
16286657Snate@binkert.org
16296657Snate@binkert.org    physmem->dma_write(txDmaAddr, (uint8_t *)txDmaData, txDmaLen);
16306657Snate@binkert.org    txDmaState = dmaIdle;
16316657Snate@binkert.org
16326657Snate@binkert.org    DPRINTF(EthernetDMA, "tx dma write paddr=%#x len=%d\n",
16336657Snate@binkert.org            txDmaAddr, txDmaLen);
16346657Snate@binkert.org    DDUMP(EthernetDMA, txDmaData, txDmaLen);
16356657Snate@binkert.org}
16366657Snate@binkert.org
16376657Snate@binkert.orgbool
16386657Snate@binkert.orgNSGigE::doTxDmaWrite()
16396657Snate@binkert.org{
16406657Snate@binkert.org    assert(txDmaState == dmaIdle || txDmaState == dmaWriteWaiting);
16416657Snate@binkert.org    txDmaState = dmaWriting;
16426657Snate@binkert.org
16436657Snate@binkert.org    if (dmaInterface && !txDmaFree) {
16446657Snate@binkert.org        if (dmaInterface->busy())
1645            txDmaState = dmaWriteWaiting;
1646        else
1647            dmaInterface->doDMA(WriteInvalidate, txDmaAddr, txDmaLen, curTick,
1648                                &txDmaWriteEvent, true);
1649        return true;
1650    }
1651
1652    if (dmaWriteDelay == 0 && dmaWriteFactor == 0.0) {
1653        txDmaWriteCopy();
1654        return false;
1655    }
1656
1657    Tick factor = ((txDmaLen + ULL(63)) >> ULL(6)) * dmaWriteFactor;
1658    Tick start = curTick + dmaWriteDelay + factor;
1659    txDmaWriteEvent.schedule(start);
1660    return true;
1661}
1662
1663void
1664NSGigE::txDmaWriteDone()
1665{
1666    assert(txDmaState == dmaWriting);
1667    txDmaWriteCopy();
1668
1669    // If the receive state machine  has a pending DMA, let it go first
1670    if (rxDmaState == dmaReadWaiting || rxDmaState == dmaWriteWaiting)
1671        rxKick();
1672
1673    txKick();
1674}
1675
1676void
1677NSGigE::txKick()
1678{
1679    DPRINTF(EthernetSM, "transmit kick txState=%s\n",
1680            NsTxStateStrings[txState]);
1681
1682    if (txKickTick > curTick) {
1683        DPRINTF(EthernetSM, "transmit kick exiting, can't run till %d\n",
1684                txKickTick);
1685
1686        return;
1687    }
1688
1689  next:
1690    switch(txDmaState) {
1691      case dmaReadWaiting:
1692        if (doTxDmaRead())
1693            goto exit;
1694        break;
1695      case dmaWriteWaiting:
1696        if (doTxDmaWrite())
1697            goto exit;
1698        break;
1699      default:
1700        break;
1701    }
1702
1703    switch (txState) {
1704      case txIdle:
1705        if (!txEnable) {
1706            DPRINTF(EthernetSM, "Transmit disabled.  Nothing to do.\n");
1707            goto exit;
1708        }
1709
1710        if (CTDD) {
1711            txState = txDescRefr;
1712
1713            txDmaAddr = regs.txdp & 0x3fffffff;
1714            txDmaData = &txDescCache + offsetof(ns_desc, link);
1715            txDmaLen = sizeof(txDescCache.link);
1716            txDmaFree = dmaDescFree;
1717
1718            descDmaReads++;
1719            descDmaRdBytes += txDmaLen;
1720
1721            if (doTxDmaRead())
1722                goto exit;
1723
1724        } else {
1725            txState = txDescRead;
1726
1727            txDmaAddr = regs.txdp & 0x3fffffff;
1728            txDmaData = &txDescCache;
1729            txDmaLen = sizeof(ns_desc);
1730            txDmaFree = dmaDescFree;
1731
1732            descDmaReads++;
1733            descDmaRdBytes += txDmaLen;
1734
1735            if (doTxDmaRead())
1736                goto exit;
1737        }
1738        break;
1739
1740      case txDescRefr:
1741        if (txDmaState != dmaIdle)
1742            goto exit;
1743
1744        txState = txAdvance;
1745        break;
1746
1747      case txDescRead:
1748        if (txDmaState != dmaIdle)
1749            goto exit;
1750
1751        DPRINTF(EthernetDesc,
1752                "txDescCache: link=%08x bufptr=%08x cmdsts=%08x extsts=%08x\n",
1753                txDescCache.link, txDescCache.bufptr, txDescCache.cmdsts,
1754                txDescCache.extsts);
1755
1756        if (txDescCache.cmdsts & CMDSTS_OWN) {
1757            txState = txFifoBlock;
1758            txFragPtr = txDescCache.bufptr;
1759            txDescCnt = txDescCache.cmdsts & CMDSTS_LEN_MASK;
1760        } else {
1761            devIntrPost(ISR_TXIDLE);
1762            txState = txIdle;
1763            goto exit;
1764        }
1765        break;
1766
1767      case txFifoBlock:
1768        if (!txPacket) {
1769            DPRINTF(EthernetSM, "****starting the tx of a new packet****\n");
1770            txPacket = new PacketData;
1771            txPacket->data = new uint8_t[16384];
1772            txPacketBufPtr = txPacket->data;
1773        }
1774
1775        if (txDescCnt == 0) {
1776            DPRINTF(EthernetSM, "the txDescCnt == 0, done with descriptor\n");
1777            if (txDescCache.cmdsts & CMDSTS_MORE) {
1778                DPRINTF(EthernetSM, "there are more descriptors to come\n");
1779                txState = txDescWrite;
1780
1781                txDescCache.cmdsts &= ~CMDSTS_OWN;
1782
1783                txDmaAddr = regs.txdp + offsetof(ns_desc, cmdsts);
1784                txDmaAddr &= 0x3fffffff;
1785                txDmaData = &(txDescCache.cmdsts);
1786                txDmaLen = sizeof(txDescCache.cmdsts);
1787                txDmaFree = dmaDescFree;
1788
1789                if (doTxDmaWrite())
1790                    goto exit;
1791
1792            } else { /* this packet is totally done */
1793                DPRINTF(EthernetSM, "This packet is done, let's wrap it up\n");
1794                /* deal with the the packet that just finished */
1795                if ((regs.vtcr & VTCR_PPCHK) && extstsEnable) {
1796                    IpPtr ip(txPacket);
1797                    if (txDescCache.extsts & EXTSTS_UDPPKT) {
1798                        UdpPtr udp(ip);
1799                        udp->sum(0);
1800                        udp->sum(cksum(udp));
1801                        txUdpChecksums++;
1802                    } else if (txDescCache.extsts & EXTSTS_TCPPKT) {
1803                        TcpPtr tcp(ip);
1804                        tcp->sum(0);
1805                        tcp->sum(cksum(tcp));
1806                        txTcpChecksums++;
1807                    }
1808                    if (txDescCache.extsts & EXTSTS_IPPKT) {
1809                        ip->sum(0);
1810                        ip->sum(cksum(ip));
1811                        txIpChecksums++;
1812                    }
1813                }
1814
1815                txPacket->length = txPacketBufPtr - txPacket->data;
1816                // this is just because the receive can't handle a
1817                // packet bigger want to make sure
1818                assert(txPacket->length <= 1514);
1819#ifndef NDEBUG
1820                bool success =
1821#endif
1822                    txFifo.push(txPacket);
1823                assert(success);
1824
1825                /*
1826                 * this following section is not tqo spec, but
1827                 * functionally shouldn't be any different.  normally,
1828                 * the chip will wait til the transmit has occurred
1829                 * before writing back the descriptor because it has
1830                 * to wait to see that it was successfully transmitted
1831                 * to decide whether to set CMDSTS_OK or not.
1832                 * however, in the simulator since it is always
1833                 * successfully transmitted, and writing it exactly to
1834                 * spec would complicate the code, we just do it here
1835                 */
1836
1837                txDescCache.cmdsts &= ~CMDSTS_OWN;
1838                txDescCache.cmdsts |= CMDSTS_OK;
1839
1840                DPRINTF(EthernetDesc,
1841                        "txDesc writeback: cmdsts=%08x extsts=%08x\n",
1842                        txDescCache.cmdsts, txDescCache.extsts);
1843
1844                txDmaAddr = regs.txdp + offsetof(ns_desc, cmdsts);
1845                txDmaAddr &= 0x3fffffff;
1846                txDmaData = &(txDescCache.cmdsts);
1847                txDmaLen = sizeof(txDescCache.cmdsts) +
1848                    sizeof(txDescCache.extsts);
1849                txDmaFree = dmaDescFree;
1850
1851                descDmaWrites++;
1852                descDmaWrBytes += txDmaLen;
1853
1854                transmit();
1855                txPacket = 0;
1856
1857                if (!txEnable) {
1858                    DPRINTF(EthernetSM, "halting TX state machine\n");
1859                    txState = txIdle;
1860                    goto exit;
1861                } else
1862                    txState = txAdvance;
1863
1864                if (doTxDmaWrite())
1865                    goto exit;
1866            }
1867        } else {
1868            DPRINTF(EthernetSM, "this descriptor isn't done yet\n");
1869            if (!txFifo.full()) {
1870                txState = txFragRead;
1871
1872                /*
1873                 * The number of bytes transferred is either whatever
1874                 * is left in the descriptor (txDescCnt), or if there
1875                 * is not enough room in the fifo, just whatever room
1876                 * is left in the fifo
1877                 */
1878                txXferLen = min<uint32_t>(txDescCnt, txFifo.avail());
1879
1880                txDmaAddr = txFragPtr & 0x3fffffff;
1881                txDmaData = txPacketBufPtr;
1882                txDmaLen = txXferLen;
1883                txDmaFree = dmaDataFree;
1884
1885                if (doTxDmaRead())
1886                    goto exit;
1887            } else {
1888                txState = txFifoBlock;
1889                transmit();
1890
1891                goto exit;
1892            }
1893
1894        }
1895        break;
1896
1897      case txFragRead:
1898        if (txDmaState != dmaIdle)
1899            goto exit;
1900
1901        txPacketBufPtr += txXferLen;
1902        txFragPtr += txXferLen;
1903        txDescCnt -= txXferLen;
1904        txFifo.reserve(txXferLen);
1905
1906        txState = txFifoBlock;
1907        break;
1908
1909      case txDescWrite:
1910        if (txDmaState != dmaIdle)
1911            goto exit;
1912
1913        if (txDescCache.cmdsts & CMDSTS_INTR)
1914            devIntrPost(ISR_TXDESC);
1915
1916        txState = txAdvance;
1917        break;
1918
1919      case txAdvance:
1920        if (txDescCache.link == 0) {
1921            devIntrPost(ISR_TXIDLE);
1922            txState = txIdle;
1923            goto exit;
1924        } else {
1925            txState = txDescRead;
1926            regs.txdp = txDescCache.link;
1927            CTDD = false;
1928
1929            txDmaAddr = txDescCache.link & 0x3fffffff;
1930            txDmaData = &txDescCache;
1931            txDmaLen = sizeof(ns_desc);
1932            txDmaFree = dmaDescFree;
1933
1934            if (doTxDmaRead())
1935                goto exit;
1936        }
1937        break;
1938
1939      default:
1940        panic("invalid state");
1941    }
1942
1943    DPRINTF(EthernetSM, "entering next txState=%s\n",
1944            NsTxStateStrings[txState]);
1945
1946    goto next;
1947
1948  exit:
1949    /**
1950     * @todo do we want to schedule a future kick?
1951     */
1952    DPRINTF(EthernetSM, "tx state machine exited txState=%s\n",
1953            NsTxStateStrings[txState]);
1954}
1955
1956void
1957NSGigE::transferDone()
1958{
1959    if (txFifo.empty()) {
1960        DPRINTF(Ethernet, "transfer complete: txFifo empty...nothing to do\n");
1961        return;
1962    }
1963
1964    DPRINTF(Ethernet, "transfer complete: data in txFifo...schedule xmit\n");
1965
1966    if (txEvent.scheduled())
1967        txEvent.reschedule(curTick + 1);
1968    else
1969        txEvent.schedule(curTick + 1);
1970}
1971
1972bool
1973NSGigE::rxFilter(const PacketPtr &packet)
1974{
1975    EthPtr eth = packet;
1976    bool drop = true;
1977    string type;
1978
1979    const EthAddr &dst = eth->dst();
1980    if (dst.unicast()) {
1981        // If we're accepting all unicast addresses
1982        if (acceptUnicast)
1983            drop = false;
1984
1985        // If we make a perfect match
1986        if (acceptPerfect && dst == rom.perfectMatch)
1987            drop = false;
1988
1989        if (acceptArp && eth->type() == ETH_TYPE_ARP)
1990            drop = false;
1991
1992    } else if (dst.broadcast()) {
1993        // if we're accepting broadcasts
1994        if (acceptBroadcast)
1995            drop = false;
1996
1997    } else if (dst.multicast()) {
1998        // if we're accepting all multicasts
1999        if (acceptMulticast)
2000            drop = false;
2001
2002    }
2003
2004    if (drop) {
2005        DPRINTF(Ethernet, "rxFilter drop\n");
2006        DDUMP(EthernetData, packet->data, packet->length);
2007    }
2008
2009    return drop;
2010}
2011
2012bool
2013NSGigE::recvPacket(PacketPtr packet)
2014{
2015    rxBytes += packet->length;
2016    rxPackets++;
2017
2018    DPRINTF(Ethernet, "Receiving packet from wire, rxFifoAvail=%d\n",
2019            rxFifo.avail());
2020
2021    if (!rxEnable) {
2022        DPRINTF(Ethernet, "receive disabled...packet dropped\n");
2023        debug_break();
2024        interface->recvDone();
2025        return true;
2026    }
2027
2028    if (rxFilterEnable && rxFilter(packet)) {
2029        DPRINTF(Ethernet, "packet filtered...dropped\n");
2030        interface->recvDone();
2031        return true;
2032    }
2033
2034    if (rxFifo.avail() < packet->length) {
2035        DPRINTF(Ethernet,
2036                "packet will not fit in receive buffer...packet dropped\n");
2037        devIntrPost(ISR_RXORN);
2038        return false;
2039    }
2040
2041    rxFifo.push(packet);
2042    interface->recvDone();
2043
2044    rxKick();
2045    return true;
2046}
2047
2048//=====================================================================
2049//
2050//
2051void
2052NSGigE::serialize(ostream &os)
2053{
2054    // Serialize the PciDev base class
2055    PciDev::serialize(os);
2056
2057    /*
2058     * Finalize any DMA events now.
2059     */
2060    if (rxDmaReadEvent.scheduled())
2061        rxDmaReadCopy();
2062    if (rxDmaWriteEvent.scheduled())
2063        rxDmaWriteCopy();
2064    if (txDmaReadEvent.scheduled())
2065        txDmaReadCopy();
2066    if (txDmaWriteEvent.scheduled())
2067        txDmaWriteCopy();
2068
2069    /*
2070     * Serialize the device registers
2071     */
2072    SERIALIZE_SCALAR(regs.command);
2073    SERIALIZE_SCALAR(regs.config);
2074    SERIALIZE_SCALAR(regs.mear);
2075    SERIALIZE_SCALAR(regs.ptscr);
2076    SERIALIZE_SCALAR(regs.isr);
2077    SERIALIZE_SCALAR(regs.imr);
2078    SERIALIZE_SCALAR(regs.ier);
2079    SERIALIZE_SCALAR(regs.ihr);
2080    SERIALIZE_SCALAR(regs.txdp);
2081    SERIALIZE_SCALAR(regs.txdp_hi);
2082    SERIALIZE_SCALAR(regs.txcfg);
2083    SERIALIZE_SCALAR(regs.gpior);
2084    SERIALIZE_SCALAR(regs.rxdp);
2085    SERIALIZE_SCALAR(regs.rxdp_hi);
2086    SERIALIZE_SCALAR(regs.rxcfg);
2087    SERIALIZE_SCALAR(regs.pqcr);
2088    SERIALIZE_SCALAR(regs.wcsr);
2089    SERIALIZE_SCALAR(regs.pcr);
2090    SERIALIZE_SCALAR(regs.rfcr);
2091    SERIALIZE_SCALAR(regs.rfdr);
2092    SERIALIZE_SCALAR(regs.srr);
2093    SERIALIZE_SCALAR(regs.mibc);
2094    SERIALIZE_SCALAR(regs.vrcr);
2095    SERIALIZE_SCALAR(regs.vtcr);
2096    SERIALIZE_SCALAR(regs.vdr);
2097    SERIALIZE_SCALAR(regs.ccsr);
2098    SERIALIZE_SCALAR(regs.tbicr);
2099    SERIALIZE_SCALAR(regs.tbisr);
2100    SERIALIZE_SCALAR(regs.tanar);
2101    SERIALIZE_SCALAR(regs.tanlpar);
2102    SERIALIZE_SCALAR(regs.taner);
2103    SERIALIZE_SCALAR(regs.tesr);
2104
2105    SERIALIZE_ARRAY(rom.perfectMatch, ETH_ADDR_LEN);
2106
2107    SERIALIZE_SCALAR(ioEnable);
2108
2109    /*
2110     * Serialize the data Fifos
2111     */
2112    rxFifo.serialize("rxFifo", os);
2113    txFifo.serialize("txFifo", os);
2114
2115    /*
2116     * Serialize the various helper variables
2117     */
2118    bool txPacketExists = txPacket;
2119    SERIALIZE_SCALAR(txPacketExists);
2120    if (txPacketExists) {
2121        txPacket->serialize("txPacket", os);
2122        uint32_t txPktBufPtr = (uint32_t) (txPacketBufPtr - txPacket->data);
2123        SERIALIZE_SCALAR(txPktBufPtr);
2124    }
2125
2126    bool rxPacketExists = rxPacket;
2127    SERIALIZE_SCALAR(rxPacketExists);
2128    if (rxPacketExists) {
2129        rxPacket->serialize("rxPacket", os);
2130        uint32_t rxPktBufPtr = (uint32_t) (rxPacketBufPtr - rxPacket->data);
2131        SERIALIZE_SCALAR(rxPktBufPtr);
2132    }
2133
2134    SERIALIZE_SCALAR(txXferLen);
2135    SERIALIZE_SCALAR(rxXferLen);
2136
2137    /*
2138     * Serialize DescCaches
2139     */
2140    SERIALIZE_SCALAR(txDescCache.link);
2141    SERIALIZE_SCALAR(txDescCache.bufptr);
2142    SERIALIZE_SCALAR(txDescCache.cmdsts);
2143    SERIALIZE_SCALAR(txDescCache.extsts);
2144    SERIALIZE_SCALAR(rxDescCache.link);
2145    SERIALIZE_SCALAR(rxDescCache.bufptr);
2146    SERIALIZE_SCALAR(rxDescCache.cmdsts);
2147    SERIALIZE_SCALAR(rxDescCache.extsts);
2148
2149    /*
2150     * Serialize tx state machine
2151     */
2152    int txState = this->txState;
2153    SERIALIZE_SCALAR(txState);
2154    SERIALIZE_SCALAR(txEnable);
2155    SERIALIZE_SCALAR(CTDD);
2156    SERIALIZE_SCALAR(txFragPtr);
2157    SERIALIZE_SCALAR(txDescCnt);
2158    int txDmaState = this->txDmaState;
2159    SERIALIZE_SCALAR(txDmaState);
2160
2161    /*
2162     * Serialize rx state machine
2163     */
2164    int rxState = this->rxState;
2165    SERIALIZE_SCALAR(rxState);
2166    SERIALIZE_SCALAR(rxEnable);
2167    SERIALIZE_SCALAR(CRDD);
2168    SERIALIZE_SCALAR(rxPktBytes);
2169    SERIALIZE_SCALAR(rxDescCnt);
2170    int rxDmaState = this->rxDmaState;
2171    SERIALIZE_SCALAR(rxDmaState);
2172
2173    SERIALIZE_SCALAR(extstsEnable);
2174
2175    /*
2176     * If there's a pending transmit, store the time so we can
2177     * reschedule it later
2178     */
2179    Tick transmitTick = txEvent.scheduled() ? txEvent.when() - curTick : 0;
2180    SERIALIZE_SCALAR(transmitTick);
2181
2182    /*
2183     * receive address filter settings
2184     */
2185    SERIALIZE_SCALAR(rxFilterEnable);
2186    SERIALIZE_SCALAR(acceptBroadcast);
2187    SERIALIZE_SCALAR(acceptMulticast);
2188    SERIALIZE_SCALAR(acceptUnicast);
2189    SERIALIZE_SCALAR(acceptPerfect);
2190    SERIALIZE_SCALAR(acceptArp);
2191
2192    /*
2193     * Keep track of pending interrupt status.
2194     */
2195    SERIALIZE_SCALAR(intrTick);
2196    SERIALIZE_SCALAR(cpuPendingIntr);
2197    Tick intrEventTick = 0;
2198    if (intrEvent)
2199        intrEventTick = intrEvent->when();
2200    SERIALIZE_SCALAR(intrEventTick);
2201
2202}
2203
2204void
2205NSGigE::unserialize(Checkpoint *cp, const std::string &section)
2206{
2207    // Unserialize the PciDev base class
2208    PciDev::unserialize(cp, section);
2209
2210    UNSERIALIZE_SCALAR(regs.command);
2211    UNSERIALIZE_SCALAR(regs.config);
2212    UNSERIALIZE_SCALAR(regs.mear);
2213    UNSERIALIZE_SCALAR(regs.ptscr);
2214    UNSERIALIZE_SCALAR(regs.isr);
2215    UNSERIALIZE_SCALAR(regs.imr);
2216    UNSERIALIZE_SCALAR(regs.ier);
2217    UNSERIALIZE_SCALAR(regs.ihr);
2218    UNSERIALIZE_SCALAR(regs.txdp);
2219    UNSERIALIZE_SCALAR(regs.txdp_hi);
2220    UNSERIALIZE_SCALAR(regs.txcfg);
2221    UNSERIALIZE_SCALAR(regs.gpior);
2222    UNSERIALIZE_SCALAR(regs.rxdp);
2223    UNSERIALIZE_SCALAR(regs.rxdp_hi);
2224    UNSERIALIZE_SCALAR(regs.rxcfg);
2225    UNSERIALIZE_SCALAR(regs.pqcr);
2226    UNSERIALIZE_SCALAR(regs.wcsr);
2227    UNSERIALIZE_SCALAR(regs.pcr);
2228    UNSERIALIZE_SCALAR(regs.rfcr);
2229    UNSERIALIZE_SCALAR(regs.rfdr);
2230    UNSERIALIZE_SCALAR(regs.srr);
2231    UNSERIALIZE_SCALAR(regs.mibc);
2232    UNSERIALIZE_SCALAR(regs.vrcr);
2233    UNSERIALIZE_SCALAR(regs.vtcr);
2234    UNSERIALIZE_SCALAR(regs.vdr);
2235    UNSERIALIZE_SCALAR(regs.ccsr);
2236    UNSERIALIZE_SCALAR(regs.tbicr);
2237    UNSERIALIZE_SCALAR(regs.tbisr);
2238    UNSERIALIZE_SCALAR(regs.tanar);
2239    UNSERIALIZE_SCALAR(regs.tanlpar);
2240    UNSERIALIZE_SCALAR(regs.taner);
2241    UNSERIALIZE_SCALAR(regs.tesr);
2242
2243    UNSERIALIZE_ARRAY(rom.perfectMatch, ETH_ADDR_LEN);
2244
2245    UNSERIALIZE_SCALAR(ioEnable);
2246
2247    /*
2248     * unserialize the data fifos
2249     */
2250    rxFifo.unserialize("rxFifo", cp, section);
2251    txFifo.unserialize("txFifo", cp, section);
2252
2253    /*
2254     * unserialize the various helper variables
2255     */
2256    bool txPacketExists;
2257    UNSERIALIZE_SCALAR(txPacketExists);
2258    if (txPacketExists) {
2259        txPacket = new PacketData;
2260        txPacket->unserialize("txPacket", cp, section);
2261        uint32_t txPktBufPtr;
2262        UNSERIALIZE_SCALAR(txPktBufPtr);
2263        txPacketBufPtr = (uint8_t *) txPacket->data + txPktBufPtr;
2264    } else
2265        txPacket = 0;
2266
2267    bool rxPacketExists;
2268    UNSERIALIZE_SCALAR(rxPacketExists);
2269    rxPacket = 0;
2270    if (rxPacketExists) {
2271        rxPacket = new PacketData;
2272        rxPacket->unserialize("rxPacket", cp, section);
2273        uint32_t rxPktBufPtr;
2274        UNSERIALIZE_SCALAR(rxPktBufPtr);
2275        rxPacketBufPtr = (uint8_t *) rxPacket->data + rxPktBufPtr;
2276    } else
2277        rxPacket = 0;
2278
2279    UNSERIALIZE_SCALAR(txXferLen);
2280    UNSERIALIZE_SCALAR(rxXferLen);
2281
2282    /*
2283     * Unserialize DescCaches
2284     */
2285    UNSERIALIZE_SCALAR(txDescCache.link);
2286    UNSERIALIZE_SCALAR(txDescCache.bufptr);
2287    UNSERIALIZE_SCALAR(txDescCache.cmdsts);
2288    UNSERIALIZE_SCALAR(txDescCache.extsts);
2289    UNSERIALIZE_SCALAR(rxDescCache.link);
2290    UNSERIALIZE_SCALAR(rxDescCache.bufptr);
2291    UNSERIALIZE_SCALAR(rxDescCache.cmdsts);
2292    UNSERIALIZE_SCALAR(rxDescCache.extsts);
2293
2294    /*
2295     * unserialize tx state machine
2296     */
2297    int txState;
2298    UNSERIALIZE_SCALAR(txState);
2299    this->txState = (TxState) txState;
2300    UNSERIALIZE_SCALAR(txEnable);
2301    UNSERIALIZE_SCALAR(CTDD);
2302    UNSERIALIZE_SCALAR(txFragPtr);
2303    UNSERIALIZE_SCALAR(txDescCnt);
2304    int txDmaState;
2305    UNSERIALIZE_SCALAR(txDmaState);
2306    this->txDmaState = (DmaState) txDmaState;
2307
2308    /*
2309     * unserialize rx state machine
2310     */
2311    int rxState;
2312    UNSERIALIZE_SCALAR(rxState);
2313    this->rxState = (RxState) rxState;
2314    UNSERIALIZE_SCALAR(rxEnable);
2315    UNSERIALIZE_SCALAR(CRDD);
2316    UNSERIALIZE_SCALAR(rxPktBytes);
2317    UNSERIALIZE_SCALAR(rxDescCnt);
2318    int rxDmaState;
2319    UNSERIALIZE_SCALAR(rxDmaState);
2320    this->rxDmaState = (DmaState) rxDmaState;
2321
2322    UNSERIALIZE_SCALAR(extstsEnable);
2323
2324     /*
2325     * If there's a pending transmit, reschedule it now
2326     */
2327    Tick transmitTick;
2328    UNSERIALIZE_SCALAR(transmitTick);
2329    if (transmitTick)
2330        txEvent.schedule(curTick + transmitTick);
2331
2332    /*
2333     * unserialize receive address filter settings
2334     */
2335    UNSERIALIZE_SCALAR(rxFilterEnable);
2336    UNSERIALIZE_SCALAR(acceptBroadcast);
2337    UNSERIALIZE_SCALAR(acceptMulticast);
2338    UNSERIALIZE_SCALAR(acceptUnicast);
2339    UNSERIALIZE_SCALAR(acceptPerfect);
2340    UNSERIALIZE_SCALAR(acceptArp);
2341
2342    /*
2343     * Keep track of pending interrupt status.
2344     */
2345    UNSERIALIZE_SCALAR(intrTick);
2346    UNSERIALIZE_SCALAR(cpuPendingIntr);
2347    Tick intrEventTick;
2348    UNSERIALIZE_SCALAR(intrEventTick);
2349    if (intrEventTick) {
2350        intrEvent = new IntrEvent(this, true);
2351        intrEvent->schedule(intrEventTick);
2352    }
2353
2354    /*
2355     * re-add addrRanges to bus bridges
2356     */
2357    if (pioInterface) {
2358        pioInterface->addAddrRange(RangeSize(BARAddrs[0], BARSize[0]));
2359        pioInterface->addAddrRange(RangeSize(BARAddrs[1], BARSize[1]));
2360    }
2361}
2362
2363Tick
2364NSGigE::cacheAccess(MemReqPtr &req)
2365{
2366    DPRINTF(EthernetPIO, "timing access to paddr=%#x (daddr=%#x)\n",
2367            req->paddr, req->paddr - addr);
2368    return curTick + pioLatency;
2369}
2370
2371BEGIN_DECLARE_SIM_OBJECT_PARAMS(NSGigEInt)
2372
2373    SimObjectParam<EtherInt *> peer;
2374    SimObjectParam<NSGigE *> device;
2375
2376END_DECLARE_SIM_OBJECT_PARAMS(NSGigEInt)
2377
2378BEGIN_INIT_SIM_OBJECT_PARAMS(NSGigEInt)
2379
2380    INIT_PARAM_DFLT(peer, "peer interface", NULL),
2381    INIT_PARAM(device, "Ethernet device of this interface")
2382
2383END_INIT_SIM_OBJECT_PARAMS(NSGigEInt)
2384
2385CREATE_SIM_OBJECT(NSGigEInt)
2386{
2387    NSGigEInt *dev_int = new NSGigEInt(getInstanceName(), device);
2388
2389    EtherInt *p = (EtherInt *)peer;
2390    if (p) {
2391        dev_int->setPeer(p);
2392        p->setPeer(dev_int);
2393    }
2394
2395    return dev_int;
2396}
2397
2398REGISTER_SIM_OBJECT("NSGigEInt", NSGigEInt)
2399
2400
2401BEGIN_DECLARE_SIM_OBJECT_PARAMS(NSGigE)
2402
2403    Param<Tick> tx_delay;
2404    Param<Tick> rx_delay;
2405    Param<Tick> intr_delay;
2406    SimObjectParam<MemoryController *> mmu;
2407    SimObjectParam<PhysicalMemory *> physmem;
2408    Param<bool> rx_filter;
2409    Param<string> hardware_address;
2410    SimObjectParam<Bus*> header_bus;
2411    SimObjectParam<Bus*> payload_bus;
2412    SimObjectParam<HierParams *> hier;
2413    Param<Tick> pio_latency;
2414    Param<bool> dma_desc_free;
2415    Param<bool> dma_data_free;
2416    Param<Tick> dma_read_delay;
2417    Param<Tick> dma_write_delay;
2418    Param<Tick> dma_read_factor;
2419    Param<Tick> dma_write_factor;
2420    SimObjectParam<PciConfigAll *> configspace;
2421    SimObjectParam<PciConfigData *> configdata;
2422    SimObjectParam<Platform *> platform;
2423    Param<uint32_t> pci_bus;
2424    Param<uint32_t> pci_dev;
2425    Param<uint32_t> pci_func;
2426    Param<uint32_t> tx_fifo_size;
2427    Param<uint32_t> rx_fifo_size;
2428
2429END_DECLARE_SIM_OBJECT_PARAMS(NSGigE)
2430
2431BEGIN_INIT_SIM_OBJECT_PARAMS(NSGigE)
2432
2433    INIT_PARAM_DFLT(tx_delay, "Transmit Delay", 1000),
2434    INIT_PARAM_DFLT(rx_delay, "Receive Delay", 1000),
2435    INIT_PARAM_DFLT(intr_delay, "Interrupt Delay in microseconds", 0),
2436    INIT_PARAM(mmu, "Memory Controller"),
2437    INIT_PARAM(physmem, "Physical Memory"),
2438    INIT_PARAM_DFLT(rx_filter, "Enable Receive Filter", true),
2439    INIT_PARAM_DFLT(hardware_address, "Ethernet Hardware Address",
2440                    "00:99:00:00:00:01"),
2441    INIT_PARAM_DFLT(header_bus, "The IO Bus to attach to for headers", NULL),
2442    INIT_PARAM_DFLT(payload_bus, "The IO Bus to attach to for payload", NULL),
2443    INIT_PARAM_DFLT(hier, "Hierarchy global variables", &defaultHierParams),
2444    INIT_PARAM_DFLT(pio_latency, "Programmed IO latency in bus cycles", 1),
2445    INIT_PARAM_DFLT(dma_desc_free, "DMA of Descriptors is free", false),
2446    INIT_PARAM_DFLT(dma_data_free, "DMA of Data is free", false),
2447    INIT_PARAM_DFLT(dma_read_delay, "fixed delay for dma reads", 0),
2448    INIT_PARAM_DFLT(dma_write_delay, "fixed delay for dma writes", 0),
2449    INIT_PARAM_DFLT(dma_read_factor, "multiplier for dma reads", 0),
2450    INIT_PARAM_DFLT(dma_write_factor, "multiplier for dma writes", 0),
2451    INIT_PARAM(configspace, "PCI Configspace"),
2452    INIT_PARAM(configdata, "PCI Config data"),
2453    INIT_PARAM(platform, "Platform"),
2454    INIT_PARAM(pci_bus, "PCI bus"),
2455    INIT_PARAM(pci_dev, "PCI device number"),
2456    INIT_PARAM(pci_func, "PCI function code"),
2457    INIT_PARAM_DFLT(tx_fifo_size, "max size in bytes of txFifo", 131072),
2458    INIT_PARAM_DFLT(rx_fifo_size, "max size in bytes of rxFifo", 131072)
2459
2460END_INIT_SIM_OBJECT_PARAMS(NSGigE)
2461
2462
2463CREATE_SIM_OBJECT(NSGigE)
2464{
2465    NSGigE::Params *params = new NSGigE::Params;
2466
2467    params->name = getInstanceName();
2468    params->mmu = mmu;
2469    params->configSpace = configspace;
2470    params->configData = configdata;
2471    params->plat = platform;
2472    params->busNum = pci_bus;
2473    params->deviceNum = pci_dev;
2474    params->functionNum = pci_func;
2475
2476    params->intr_delay = intr_delay;
2477    params->pmem = physmem;
2478    params->tx_delay = tx_delay;
2479    params->rx_delay = rx_delay;
2480    params->hier = hier;
2481    params->header_bus = header_bus;
2482    params->payload_bus = payload_bus;
2483    params->pio_latency = pio_latency;
2484    params->dma_desc_free = dma_desc_free;
2485    params->dma_data_free = dma_data_free;
2486    params->dma_read_delay = dma_read_delay;
2487    params->dma_write_delay = dma_write_delay;
2488    params->dma_read_factor = dma_read_factor;
2489    params->dma_write_factor = dma_write_factor;
2490    params->rx_filter = rx_filter;
2491    params->eaddr = hardware_address;
2492    params->tx_fifo_size = tx_fifo_size;
2493    params->rx_fifo_size = rx_fifo_size;
2494    return new NSGigE(params);
2495}
2496
2497REGISTER_SIM_OBJECT("NSGigE", NSGigE)
2498