ns_gige.cc revision 1224
16657Snate@binkert.org/*
26657Snate@binkert.org * Copyright (c) 2004 The Regents of The University of Michigan
36657Snate@binkert.org * All rights reserved.
46657Snate@binkert.org *
56657Snate@binkert.org * Redistribution and use in source and binary forms, with or without
66657Snate@binkert.org * modification, are permitted provided that the following conditions are
76657Snate@binkert.org * met: redistributions of source code must retain the above copyright
86657Snate@binkert.org * notice, this list of conditions and the following disclaimer;
96657Snate@binkert.org * redistributions in binary form must reproduce the above copyright
106657Snate@binkert.org * notice, this list of conditions and the following disclaimer in the
116657Snate@binkert.org * documentation and/or other materials provided with the distribution;
126657Snate@binkert.org * neither the name of the copyright holders nor the names of its
136657Snate@binkert.org * contributors may be used to endorse or promote products derived from
146657Snate@binkert.org * this software without specific prior written permission.
156657Snate@binkert.org *
166657Snate@binkert.org * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
176657Snate@binkert.org * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
186657Snate@binkert.org * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
196657Snate@binkert.org * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
206657Snate@binkert.org * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
216657Snate@binkert.org * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
226657Snate@binkert.org * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
236657Snate@binkert.org * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
246657Snate@binkert.org * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
256657Snate@binkert.org * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
266657Snate@binkert.org * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
276657Snate@binkert.org */
286999Snate@binkert.org
296657Snate@binkert.org/* @file
306657Snate@binkert.org * Device module for modelling the National Semiconductor
316657Snate@binkert.org * DP83820 ethernet controller.  Does not support priority queueing
326657Snate@binkert.org */
338189SLisa.Hsu@amd.com#include <cstdio>
346657Snate@binkert.org#include <deque>
356882SBrad.Beckmann@amd.com#include <string>
369364Snilay@cs.wisc.edu
377055Snate@binkert.org#include "base/inet.hh"
386882SBrad.Beckmann@amd.com#include "cpu/exec_context.hh"
396882SBrad.Beckmann@amd.com#include "cpu/intr_control.hh"
408191SLisa.Hsu@amd.com#include "dev/dma.hh"
416882SBrad.Beckmann@amd.com#include "dev/etherlink.hh"
426882SBrad.Beckmann@amd.com#include "dev/ns_gige.hh"
439102SNuwan.Jayasena@amd.com#include "dev/pciconfigall.hh"
449366Snilay@cs.wisc.edu#include "mem/bus/bus.hh"
459366Snilay@cs.wisc.edu#include "mem/bus/dma_interface.hh"
466882SBrad.Beckmann@amd.com#include "mem/bus/pio_interface.hh"
476882SBrad.Beckmann@amd.com#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"
516657Snate@binkert.org#include "sim/debug.hh"
526657Snate@binkert.org#include "sim/host.hh"
539366Snilay@cs.wisc.edu#include "sim/stats.hh"
547839Snilay@cs.wisc.edu#include "targetarch/vtophys.hh"
556657Snate@binkert.org
566882SBrad.Beckmann@amd.comconst char *NsRxStateStrings[] =
576882SBrad.Beckmann@amd.com{
586882SBrad.Beckmann@amd.com    "rxIdle",
596882SBrad.Beckmann@amd.com    "rxDescRefr",
606882SBrad.Beckmann@amd.com    "rxDescRead",
616882SBrad.Beckmann@amd.com    "rxFifoBlock",
626657Snate@binkert.org    "rxFragWrite",
639366Snilay@cs.wisc.edu    "rxDescWrite",
649366Snilay@cs.wisc.edu    "rxAdvance"
656657Snate@binkert.org};
666657Snate@binkert.org
676657Snate@binkert.orgconst char *NsTxStateStrings[] =
686657Snate@binkert.org{
699104Shestness@cs.utexas.edu    "txIdle",
706657Snate@binkert.org    "txDescRefr",
716657Snate@binkert.org    "txDescRead",
726657Snate@binkert.org    "txFifoBlock",
736657Snate@binkert.org    "txFragRead",
747839Snilay@cs.wisc.edu    "txDescWrite",
757839Snilay@cs.wisc.edu    "txAdvance"
769366Snilay@cs.wisc.edu};
776657Snate@binkert.org
786657Snate@binkert.orgconst char *NsDmaState[] =
796657Snate@binkert.org{
806657Snate@binkert.org    "dmaIdle",
816657Snate@binkert.org    "dmaReading",
826657Snate@binkert.org    "dmaWriting",
836657Snate@binkert.org    "dmaReadWaiting",
846657Snate@binkert.org    "dmaWriteWaiting"
856657Snate@binkert.org};
866657Snate@binkert.org
876657Snate@binkert.orgusing namespace std;
886657Snate@binkert.orgusing namespace Net;
896657Snate@binkert.org
906657Snate@binkert.org///////////////////////////////////////////////////////////////////////
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),
966779SBrad.Beckmann@amd.com      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),
1069104Shestness@cs.utexas.edu      txDelay(p->tx_delay), rxDelay(p->rx_delay),
1079104Shestness@cs.utexas.edu      rxKickTick(0), txKickTick(0),
1089104Shestness@cs.utexas.edu      txEvent(this), rxFilterEnable(p->rx_filter), acceptBroadcast(false),
1099104Shestness@cs.utexas.edu      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) {
1156657Snate@binkert.org        pioInterface = newPioInterface(name(), p->hier,
1166657Snate@binkert.org                                       p->header_bus, this,
1176657Snate@binkert.org                                       &NSGigE::cacheAccess);
1186657Snate@binkert.org
1196657Snate@binkert.org        pioLatency = p->pio_latency * p->header_bus->clockRatio;
1206657Snate@binkert.org
1216657Snate@binkert.org        if (p->payload_bus)
1226657Snate@binkert.org            dmaInterface = new DMAInterface<Bus>(name() + ".dma",
1236657Snate@binkert.org                                                 p->header_bus,
1246657Snate@binkert.org                                                 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) {
1307839Snilay@cs.wisc.edu        pioInterface = newPioInterface(name(), p->hier,
1317839Snilay@cs.wisc.edu                                       p->payload_bus, this,
1327839Snilay@cs.wisc.edu                                       &NSGigE::cacheAccess);
1337839Snilay@cs.wisc.edu
1347839Snilay@cs.wisc.edu        pioLatency = p->pio_latency * p->payload_bus->clockRatio;
1357839Snilay@cs.wisc.edu
1367839Snilay@cs.wisc.edu        dmaInterface = new DMAInterface<Bus>(name() + ".dma",
1377839Snilay@cs.wisc.edu                                             p->payload_bus,
1387839Snilay@cs.wisc.edu                                             p->payload_bus, 1);
1397839Snilay@cs.wisc.edu    }
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")
1616657Snate@binkert.org        .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)
1686657Snate@binkert.org        ;
1696657Snate@binkert.org
1709219Spower.jg@gmail.com    txPackets
1716877Ssteve.reinhardt@amd.com        .name(name() + ".txPackets")
1726657Snate@binkert.org        .desc("Number of Packets Transmitted")
1739219Spower.jg@gmail.com        .prereq(txBytes)
1746657Snate@binkert.org        ;
1759219Spower.jg@gmail.com
1766657Snate@binkert.org    rxPackets
1776657Snate@binkert.org        .name(name() + ".rxPackets")
1787542SBrad.Beckmann@amd.com        .desc("Number of Packets Received")
1797542SBrad.Beckmann@amd.com        .prereq(rxBytes)
1806657Snate@binkert.org        ;
1816877Ssteve.reinhardt@amd.com
1826999Snate@binkert.org    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")
1926877Ssteve.reinhardt@amd.com        .precision(0)
1939338SAndreas.Sandberg@arm.com        .prereq(rxBytes)
1946877Ssteve.reinhardt@amd.com        ;
1956877Ssteve.reinhardt@amd.com
1966877Ssteve.reinhardt@amd.com    txTcpChecksums
1976877Ssteve.reinhardt@amd.com        .name(name() + ".txTcpChecksums")
1986877Ssteve.reinhardt@amd.com        .desc("Number of tx TCP Checksums done by device")
1996877Ssteve.reinhardt@amd.com        .precision(0)
2006882SBrad.Beckmann@amd.com        .prereq(txBytes)
2016882SBrad.Beckmann@amd.com        ;
2026882SBrad.Beckmann@amd.com
2036882SBrad.Beckmann@amd.com    rxTcpChecksums
2046882SBrad.Beckmann@amd.com        .name(name() + ".rxTcpChecksums")
2056882SBrad.Beckmann@amd.com        .desc("Number of rx TCP Checksums done by device")
2066882SBrad.Beckmann@amd.com        .precision(0)
2076877Ssteve.reinhardt@amd.com        .prereq(rxBytes)
2086877Ssteve.reinhardt@amd.com        ;
2096877Ssteve.reinhardt@amd.com
2106877Ssteve.reinhardt@amd.com    txUdpChecksums
2116657Snate@binkert.org        .name(name() + ".txUdpChecksums")
2126657Snate@binkert.org        .desc("Number of tx UDP Checksums done by device")
2136999Snate@binkert.org        .precision(0)
2146657Snate@binkert.org        .prereq(txBytes)
2156657Snate@binkert.org        ;
2166657Snate@binkert.org
2176657Snate@binkert.org    rxUdpChecksums
2186657Snate@binkert.org        .name(name() + ".rxUdpChecksums")
2196657Snate@binkert.org        .desc("Number of rx UDP Checksums done by device")
2207007Snate@binkert.org        .precision(0)
2216657Snate@binkert.org        .prereq(rxBytes)
2226657Snate@binkert.org        ;
2236657Snate@binkert.org
2246657Snate@binkert.org    descDmaReads
2256657Snate@binkert.org        .name(name() + ".descDMAReads")
2267007Snate@binkert.org        .desc("Number of descriptors the device read w/ DMA")
2277007Snate@binkert.org        .precision(0)
2286657Snate@binkert.org        ;
2297002Snate@binkert.org
2307002Snate@binkert.org    descDmaWrites
2317002Snate@binkert.org        .name(name() + ".descDMAWrites")
2327002Snate@binkert.org        .desc("Number of descriptors the device wrote w/ DMA")
2338229Snate@binkert.org        .precision(0)
2348229Snate@binkert.org        ;
2356657Snate@binkert.org
2366657Snate@binkert.org    descDmaRdBytes
2378229Snate@binkert.org        .name(name() + ".descDmaReadBytes")
2388229Snate@binkert.org        .desc("number of descriptor bytes read w/ DMA")
2398229Snate@binkert.org        .precision(0)
2408229Snate@binkert.org        ;
2416657Snate@binkert.org
2426657Snate@binkert.org   descDmaWrBytes
2436657Snate@binkert.org        .name(name() + ".descDmaWriteBytes")
2446657Snate@binkert.org        .desc("number of descriptor bytes write w/ DMA")
2456793SBrad.Beckmann@amd.com        .precision(0)
2466657Snate@binkert.org        ;
2476657Snate@binkert.org
2486657Snate@binkert.org
2496657Snate@binkert.org    txBandwidth
2506657Snate@binkert.org        .name(name() + ".txBandwidth")
2517002Snate@binkert.org        .desc("Transmit Bandwidth (bits/s)")
2526657Snate@binkert.org        .precision(0)
2537007Snate@binkert.org        .prereq(txBytes)
2547007Snate@binkert.org        ;
2559271Snilay@cs.wisc.edu
2566877Ssteve.reinhardt@amd.com    rxBandwidth
2576877Ssteve.reinhardt@amd.com        .name(name() + ".rxBandwidth")
2586657Snate@binkert.org        .desc("Receive Bandwidth (bits/s)")
2596877Ssteve.reinhardt@amd.com        .precision(0)
2606657Snate@binkert.org        .prereq(rxBytes)
2616657Snate@binkert.org        ;
2627002Snate@binkert.org
2637002Snate@binkert.org    txPacketRate
2647567SBrad.Beckmann@amd.com        .name(name() + ".txPPS")
2657567SBrad.Beckmann@amd.com        .desc("Packet Tranmission Rate (packets/s)")
2667922SBrad.Beckmann@amd.com        .precision(0)
2676881SBrad.Beckmann@amd.com        .prereq(txBytes)
2687002Snate@binkert.org        ;
2696657Snate@binkert.org
2707002Snate@binkert.org    rxPacketRate
2716902SBrad.Beckmann@amd.com        .name(name() + ".rxPPS")
2726863Sdrh5@cs.wisc.edu        .desc("Packet Reception Rate (packets/s)")
2736863Sdrh5@cs.wisc.edu        .precision(0)
2748683Snilay@cs.wisc.edu        .prereq(rxBytes)
2758683Snilay@cs.wisc.edu        ;
2767007Snate@binkert.org
2779302Snilay@cs.wisc.edu    txBandwidth = txBytes * Stats::constant(8) / simSeconds;
2789302Snilay@cs.wisc.edu    rxBandwidth = rxBytes * Stats::constant(8) / simSeconds;
2799302Snilay@cs.wisc.edu    txPacketRate = txPackets / simSeconds;
2806657Snate@binkert.org    rxPacketRate = rxPackets / simSeconds;
2816657Snate@binkert.org}
2826657Snate@binkert.org
2836657Snate@binkert.org/**
2846657Snate@binkert.org * This is to read the PCI general configuration registers
2856657Snate@binkert.org */
2866882SBrad.Beckmann@amd.comvoid
2876882SBrad.Beckmann@amd.comNSGigE::ReadConfig(int offset, int size, uint8_t *data)
2886882SBrad.Beckmann@amd.com{
2896882SBrad.Beckmann@amd.com    if (offset < PCI_DEVICE_SPECIFIC)
2906657Snate@binkert.org        PciDev::ReadConfig(offset, size, data);
2916657Snate@binkert.org    else
2927007Snate@binkert.org        panic("Device specific PCI config space not implemented!\n");
2937839Snilay@cs.wisc.edu}
2947839Snilay@cs.wisc.edu
2957839Snilay@cs.wisc.edu/**
2967839Snilay@cs.wisc.edu * This is to write to the PCI general configuration registers
2977839Snilay@cs.wisc.edu */
2987839Snilay@cs.wisc.eduvoid
2997839Snilay@cs.wisc.eduNSGigE::WriteConfig(int offset, int size, uint32_t data)
3007839Snilay@cs.wisc.edu{
3017839Snilay@cs.wisc.edu    if (offset < PCI_DEVICE_SPECIFIC)
3027839Snilay@cs.wisc.edu        PciDev::WriteConfig(offset, size, data);
3037839Snilay@cs.wisc.edu    else
3047839Snilay@cs.wisc.edu        panic("Device specific PCI config space not implemented!\n");
3057007Snate@binkert.org
3067007Snate@binkert.org    // Need to catch writes to BARs to update the PIO interface
3077007Snate@binkert.org    switch (offset) {
3087007Snate@binkert.org        // seems to work fine without all these PCI settings, but i
3097007Snate@binkert.org        // put in the IO to double check, an assertion will fail if we
3107839Snilay@cs.wisc.edu        // need to properly implement it
3117839Snilay@cs.wisc.edu      case PCI_COMMAND:
3127839Snilay@cs.wisc.edu        if (config.data[offset] & PCI_CMD_IOSE)
3137839Snilay@cs.wisc.edu            ioEnable = true;
3147839Snilay@cs.wisc.edu        else
3157839Snilay@cs.wisc.edu            ioEnable = false;
3167839Snilay@cs.wisc.edu
3177839Snilay@cs.wisc.edu#if 0
3187839Snilay@cs.wisc.edu        if (config.data[offset] & PCI_CMD_BME) {
3197839Snilay@cs.wisc.edu            bmEnabled = true;
3207839Snilay@cs.wisc.edu        }
3217839Snilay@cs.wisc.edu        else {
3227007Snate@binkert.org            bmEnabled = false;
3237007Snate@binkert.org        }
3247542SBrad.Beckmann@amd.com
3257542SBrad.Beckmann@amd.com        if (config.data[offset] & PCI_CMD_MSE) {
3266657Snate@binkert.org            memEnable = true;
3277007Snate@binkert.org        }
3286657Snate@binkert.org        else {
3296657Snate@binkert.org            memEnable = false;
3306657Snate@binkert.org        }
3316657Snate@binkert.org#endif
3326657Snate@binkert.org        break;
3336657Snate@binkert.org
3346657Snate@binkert.org      case PCI0_BASE_ADDR0:
3356657Snate@binkert.org        if (BARAddrs[0] != 0) {
3367839Snilay@cs.wisc.edu            if (pioInterface)
3377839Snilay@cs.wisc.edu                pioInterface->addAddrRange(RangeSize(BARAddrs[0], BARSize[0]));
3387839Snilay@cs.wisc.edu
3397839Snilay@cs.wisc.edu            BARAddrs[0] &= EV5::PAddrUncachedMask;
3407839Snilay@cs.wisc.edu        }
3417839Snilay@cs.wisc.edu        break;
3427839Snilay@cs.wisc.edu      case PCI0_BASE_ADDR1:
3437839Snilay@cs.wisc.edu        if (BARAddrs[1] != 0) {
3447839Snilay@cs.wisc.edu            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    }
3517839Snilay@cs.wisc.edu}
3526657Snate@binkert.org
3536657Snate@binkert.org/**
3546657Snate@binkert.org * This reads the device registers, which are detailed in the NS83820
3556657Snate@binkert.org * 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
3637839Snilay@cs.wisc.edu    Addr daddr = req->paddr & 0xfff;
3647839Snilay@cs.wisc.edu    DPRINTF(EthernetPIO, "read  da=%#x pa=%#x va=%#x size=%d\n",
3657839Snilay@cs.wisc.edu            daddr, req->paddr, req->vaddr, req->size);
3667839Snilay@cs.wisc.edu
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");
3726657Snate@binkert.org    } else if (daddr > RESERVED && daddr <= 0x3FC) {
3736657Snate@binkert.org        ReadConfig(daddr & 0xff, req->size, data);
3746657Snate@binkert.org        return No_Fault;
3756657Snate@binkert.org    } else if (daddr >= MIB_START && daddr <= MIB_END) {
3767007Snate@binkert.org        // don't implement all the MIB's.  hopefully the kernel
3776657Snate@binkert.org        // doesn't actually DEPEND upon their values
3786657Snate@binkert.org        // MIB are just hardware stats keepers
3799273Snilay@cs.wisc.edu        uint32_t &reg = *(uint32_t *) data;
3806657Snate@binkert.org        reg = 0;
3816657Snate@binkert.org        return No_Fault;
3826657Snate@binkert.org    } 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
3909219Spower.jg@gmail.com            switch (daddr) {
3916657Snate@binkert.org              case CR:
3926657Snate@binkert.org                reg = regs.command;
3936999Snate@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;
4048946Sandreas.hansson@arm.com
4058946Sandreas.hansson@arm.com              case PTSCR:
4068946Sandreas.hansson@arm.com                reg = regs.ptscr;
4077832Snate@binkert.org                break;
4087002Snate@binkert.org
4097002Snate@binkert.org              case ISR:
4107002Snate@binkert.org                reg = regs.isr;
4118641Snate@binkert.org                devIntrClear(ISR_ALL);
4127056Snate@binkert.org                break;
4138232Snate@binkert.org
4148232Snate@binkert.org              case IMR:
4156657Snate@binkert.org                reg = regs.imr;
4168229Snate@binkert.org                break;
4176657Snate@binkert.org
4186657Snate@binkert.org              case IER:
4197056Snate@binkert.org                reg = regs.ier;
4206657Snate@binkert.org                break;
4219219Spower.jg@gmail.com
4229219Spower.jg@gmail.com              case IHR:
4239219Spower.jg@gmail.com                reg = regs.ihr;
4249219Spower.jg@gmail.com                break;
4259219Spower.jg@gmail.com
4267002Snate@binkert.org              case TXDP:
4277002Snate@binkert.org                reg = regs.txdp;
4286657Snate@binkert.org                break;
4296657Snate@binkert.org
4306657Snate@binkert.org              case TXDP_HI:
4316657Snate@binkert.org                reg = regs.txdp_hi;
4326657Snate@binkert.org                break;
4336793SBrad.Beckmann@amd.com
4346657Snate@binkert.org              case TXCFG:
4356657Snate@binkert.org                reg = regs.txcfg;
4366657Snate@binkert.org                break;
4376657Snate@binkert.org
4386877Ssteve.reinhardt@amd.com              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;
4446657Snate@binkert.org                break;
4457542SBrad.Beckmann@amd.com
4466657Snate@binkert.org              case RXDP_HI:
4477007Snate@binkert.org                reg = regs.rxdp_hi;
4486657Snate@binkert.org                break;
4496657Snate@binkert.org
4507007Snate@binkert.org              case RXCFG:
4516657Snate@binkert.org                reg = regs.rxcfg;
4526877Ssteve.reinhardt@amd.com                break;
4536877Ssteve.reinhardt@amd.com
4546657Snate@binkert.org              case PQCR:
4558532SLisa.Hsu@amd.com                reg = regs.pqcr;
4566657Snate@binkert.org                break;
4577567SBrad.Beckmann@amd.com
4587567SBrad.Beckmann@amd.com              case WCSR:
4597567SBrad.Beckmann@amd.com                reg = regs.wcsr;
4607567SBrad.Beckmann@amd.com                break;
4617567SBrad.Beckmann@amd.com
4627567SBrad.Beckmann@amd.com              case PCR:
4636657Snate@binkert.org                reg = regs.pcr;
4646882SBrad.Beckmann@amd.com                break;
4656882SBrad.Beckmann@amd.com
4666882SBrad.Beckmann@amd.com                // see the spec sheet for how RFCR and RFDR work
4676882SBrad.Beckmann@amd.com                // basically, you write to RFCR to tell the machine
4686882SBrad.Beckmann@amd.com                // what you want to do next, then you act upon RFDR,
4696882SBrad.Beckmann@amd.com                // and the device will be prepared b/c of what you
4706882SBrad.Beckmann@amd.com                // wrote to RFCR
4718189SLisa.Hsu@amd.com              case RFCR:
4728189SLisa.Hsu@amd.com                reg = regs.rfcr;
4736877Ssteve.reinhardt@amd.com                break;
4748189SLisa.Hsu@amd.com
4758189SLisa.Hsu@amd.com              case RFDR:
4768189SLisa.Hsu@amd.com                switch (regs.rfcr & RFCR_RFADDR) {
4778189SLisa.Hsu@amd.com                  case 0x000:
4786882SBrad.Beckmann@amd.com                    reg = rom.perfectMatch[1];
4796882SBrad.Beckmann@amd.com                    reg = reg << 8;
4806882SBrad.Beckmann@amd.com                    reg += rom.perfectMatch[0];
4816882SBrad.Beckmann@amd.com                    break;
4826882SBrad.Beckmann@amd.com                  case 0x002:
4836882SBrad.Beckmann@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;
4888189SLisa.Hsu@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");
4928189SLisa.Hsu@amd.com                    // didn't implement other RFDR functionality b/c
4938189SLisa.Hsu@amd.com                    // driver didn't use it
4948189SLisa.Hsu@amd.com                }
4958189SLisa.Hsu@amd.com                break;
4968938SLisa.Hsu@amd.com
4978938SLisa.Hsu@amd.com              case SRR:
4988938SLisa.Hsu@amd.com                reg = regs.srr;
4998938SLisa.Hsu@amd.com                break;
5008938SLisa.Hsu@amd.com
5018938SLisa.Hsu@amd.com              case MIBC:
5028938SLisa.Hsu@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:
5076888SBrad.Beckmann@amd.com                reg = regs.vrcr;
5088189SLisa.Hsu@amd.com                break;
5096888SBrad.Beckmann@amd.com
5106888SBrad.Beckmann@amd.com              case VTCR:
5116657Snate@binkert.org                reg = regs.vtcr;
5126888SBrad.Beckmann@amd.com                break;
5136888SBrad.Beckmann@amd.com
5146888SBrad.Beckmann@amd.com              case VDR:
5156888SBrad.Beckmann@amd.com                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;
5246657Snate@binkert.org                break;
5257007Snate@binkert.org
5267007Snate@binkert.org              case TBISR:
5276657Snate@binkert.org                reg = regs.tbisr;
5287007Snate@binkert.org                break;
5297007Snate@binkert.org
5307007Snate@binkert.org              case TANAR:
5316657Snate@binkert.org                reg = regs.tanar;
5326657Snate@binkert.org                break;
5336657Snate@binkert.org
5347007Snate@binkert.org              case TANLPAR:
5357542SBrad.Beckmann@amd.com                reg = regs.tanlpar;
5367542SBrad.Beckmann@amd.com                break;
5377007Snate@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:
5569273Snilay@cs.wisc.edu        panic("accessing register with invalid size: addr=%#x, size=%d",
5576657Snate@binkert.org              daddr, req->size);
5586657Snate@binkert.org    }
5596657Snate@binkert.org
5609364Snilay@cs.wisc.edu    return No_Fault;
5617007Snate@binkert.org}
5626657Snate@binkert.org
5636657Snate@binkert.orgFault
5646657Snate@binkert.orgNSGigE::write(MemReqPtr &req, const uint8_t *data)
5656657Snate@binkert.org{
5667007Snate@binkert.org    assert(ioEnable);
5676657Snate@binkert.org
5687007Snate@binkert.org    Addr daddr = req->paddr & 0xfff;
5697007Snate@binkert.org    DPRINTF(EthernetPIO, "write da=%#x pa=%#x va=%#x size=%d\n",
5706657Snate@binkert.org            daddr, req->paddr, req->vaddr, req->size);
5716657Snate@binkert.org
5726657Snate@binkert.org    if (daddr > LAST && daddr <=  RESERVED) {
5736657Snate@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) {
5857566SBrad.Beckmann@amd.com          case CR:
5866657Snate@binkert.org            regs.command = reg;
5876657Snate@binkert.org            if (reg & CR_TXD) {
5886657Snate@binkert.org                txEnable = false;
5896657Snate@binkert.org            } else if (reg & CR_TXE) {
5906657Snate@binkert.org                txEnable = true;
5918308Stushar@csail.mit.edu
5926657Snate@binkert.org                // the kernel is enabling the transmit machine
5936657Snate@binkert.org                if (txState == txIdle)
5946657Snate@binkert.org                    txKick();
5957007Snate@binkert.org            }
5967007Snate@binkert.org
5978308Stushar@csail.mit.edu            if (reg & CR_RXD) {
5986657Snate@binkert.org                rxEnable = false;
5996657Snate@binkert.org            } else if (reg & CR_RXE) {
6006657Snate@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)
6108187SLisa.Hsu@amd.com                rxReset();
6116657Snate@binkert.org
6126657Snate@binkert.org            if (reg & CR_SWI)
6136657Snate@binkert.org                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();
6207454Snate@binkert.org            }
6216657Snate@binkert.org            break;
6226657Snate@binkert.org
6236657Snate@binkert.org          case CFG:
6246657Snate@binkert.org            if (reg & CFG_LNKSTS ||
6257007Snate@binkert.org                reg & CFG_SPDSTS ||
6267056Snate@binkert.org                reg & CFG_DUPSTS ||
6277007Snate@binkert.org                reg & CFG_RESERVED ||
6287007Snate@binkert.org                reg & CFG_T64ADDR ||
6296657Snate@binkert.org                reg & CFG_PCI64_DET)
6307566SBrad.Beckmann@amd.com                panic("writing to read-only or reserved CFG bits!\n");
6317566SBrad.Beckmann@amd.com
6327566SBrad.Beckmann@amd.com            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
6369366Snilay@cs.wisc.edu// have these implemented. if there is a problem relating to one of
6379366Snilay@cs.wisc.edu// these, you may need to add functionality in.
6389366Snilay@cs.wisc.edu#if 0
6399366Snilay@cs.wisc.edu            if (reg & CFG_TBI_EN) ;
6407566SBrad.Beckmann@amd.com            if (reg & CFG_MODE_1000) ;
6416657Snate@binkert.org#endif
6427672Snate@binkert.org
6436657Snate@binkert.org            if (reg & CFG_AUTO_1000)
6446657Snate@binkert.org                panic("CFG_AUTO_1000 not implemented!\n");
6456657Snate@binkert.org
6466657Snate@binkert.org#if 0
6477672Snate@binkert.org            if (reg & CFG_PINT_DUPSTS ||
6486657Snate@binkert.org                reg & CFG_PINT_LNKSTS ||
6497056Snate@binkert.org                reg & CFG_PINT_SPDSTS)
6506657Snate@binkert.org                ;
6516657Snate@binkert.org
6527672Snate@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) ;
6636657Snate@binkert.org            if (reg & CFG_M64ADDR) ;
6647542SBrad.Beckmann@amd.com            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) ;
6798683Snilay@cs.wisc.edu              if (reg & CFG_BROM_DIS) ;
6808683Snilay@cs.wisc.edu              if (reg & CFG_EXT_125) ;
6818683Snilay@cs.wisc.edu              if (reg & CFG_BEM) ;
6828683Snilay@cs.wisc.edu#endif
6838683Snilay@cs.wisc.edu            break;
6848683Snilay@cs.wisc.edu
6856657Snate@binkert.org          case MEAR:
6867007Snate@binkert.org            regs.mear = reg;
6877007Snate@binkert.org            // since phy is completely faked, MEAR_MD* don't matter
6887007Snate@binkert.org            // and since the driver never uses MEAR_EE*, they don't
6896657Snate@binkert.org            // matter
6906657Snate@binkert.org#if 0
6916657Snate@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) ;
6947007Snate@binkert.org            if (reg & MEAR_EESEL) ;
6956657Snate@binkert.org            if (reg & MEAR_MDIO) ;
6966657Snate@binkert.org            if (reg & MEAR_MDDIR) ;
6976657Snate@binkert.org            if (reg & MEAR_MDC) ;
6988683Snilay@cs.wisc.edu#endif
6998683Snilay@cs.wisc.edu            break;
7008683Snilay@cs.wisc.edu
7018683Snilay@cs.wisc.edu          case PTSCR:
7028683Snilay@cs.wisc.edu            regs.ptscr = reg & ~(PTSCR_RBIST_RDONLY);
7038683Snilay@cs.wisc.edu            // 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)
7067007Snate@binkert.org                regs.ptscr |= PTSCR_RBIST_DONE;
7076657Snate@binkert.org            if (reg & PTSCR_EEBIST_EN)
7086657Snate@binkert.org                regs.ptscr &= ~PTSCR_EEBIST_EN;
7096657Snate@binkert.org            if (reg & PTSCR_EELOAD_EN)
7107007Snate@binkert.org                regs.ptscr &= ~PTSCR_EELOAD_EN;
7117007Snate@binkert.org            break;
7127007Snate@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");
7156657Snate@binkert.org
7167007Snate@binkert.org          case IMR:
7177007Snate@binkert.org            regs.imr = reg;
7187007Snate@binkert.org            devIntrChangeMask();
7196657Snate@binkert.org            break;
7206657Snate@binkert.org
7217007Snate@binkert.org          case IER:
7227007Snate@binkert.org            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;
7297567SBrad.Beckmann@amd.com
7307567SBrad.Beckmann@amd.com          case TXDP:
7317567SBrad.Beckmann@amd.com            regs.txdp = (reg & 0xFFFFFFFC);
7327567SBrad.Beckmann@amd.com            assert(txState == txIdle);
7337567SBrad.Beckmann@amd.com            CTDD = false;
7347567SBrad.Beckmann@amd.com            break;
7357567SBrad.Beckmann@amd.com
7368155Snilay@cs.wisc.edu          case TXDP_HI:
7378155Snilay@cs.wisc.edu            regs.txdp_hi = reg;
7388155Snilay@cs.wisc.edu            break;
7398155Snilay@cs.wisc.edu
7408155Snilay@cs.wisc.edu          case TXCFG:
7418155Snilay@cs.wisc.edu            regs.txcfg = reg;
7428155Snilay@cs.wisc.edu#if 0
7438155Snilay@cs.wisc.edu            if (reg & TXCFG_CSI) ;
7448155Snilay@cs.wisc.edu            if (reg & TXCFG_HBI) ;
7458155Snilay@cs.wisc.edu            if (reg & TXCFG_MLB) ;
7468155Snilay@cs.wisc.edu            if (reg & TXCFG_ATP) ;
7477567SBrad.Beckmann@amd.com            if (reg & TXCFG_ECRETRY) {
7488155Snilay@cs.wisc.edu                /*
7498155Snilay@cs.wisc.edu                 * this could easily be implemented, but considering
7507567SBrad.Beckmann@amd.com                 * the network is just a fake pipe, wouldn't make
7517567SBrad.Beckmann@amd.com                 * sense to do this
7527567SBrad.Beckmann@amd.com                 */
7537567SBrad.Beckmann@amd.com            }
7547922SBrad.Beckmann@amd.com
7557922SBrad.Beckmann@amd.com            if (reg & TXCFG_BRST_DIS) ;
7567922SBrad.Beckmann@amd.com#endif
7577922SBrad.Beckmann@amd.com
7587922SBrad.Beckmann@amd.com#if 0
7597922SBrad.Beckmann@amd.com            /* we handle our own DMA, ignore the kernel's exhortations */
7607922SBrad.Beckmann@amd.com            if (reg & TXCFG_MXDMA) ;
7617922SBrad.Beckmann@amd.com#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:
7768154Snilay@cs.wisc.edu            regs.rxdp = reg;
7778154Snilay@cs.wisc.edu            CRDD = false;
7788154Snilay@cs.wisc.edu            break;
7798154Snilay@cs.wisc.edu
7808154Snilay@cs.wisc.edu          case RXDP_HI:
7818154Snilay@cs.wisc.edu            regs.rxdp_hi = reg;
7828154Snilay@cs.wisc.edu            break;
7837922SBrad.Beckmann@amd.com
7847922SBrad.Beckmann@amd.com          case RXCFG:
7857922SBrad.Beckmann@amd.com            regs.rxcfg = reg;
7867922SBrad.Beckmann@amd.com#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) ;
7927007Snate@binkert.org            if (reg & RXCFG_AIRL) ;
7937007Snate@binkert.org
7947007Snate@binkert.org            /* we handle our own DMA, ignore what kernel says about it */
7957007Snate@binkert.org            if (reg & RXCFG_MXDMA) ;
7966863Sdrh5@cs.wisc.edu
7976863Sdrh5@cs.wisc.edu            //also, we currently don't care about fill/drain thresholds
7986863Sdrh5@cs.wisc.edu            //though this may change in the future with more realistic
7996863Sdrh5@cs.wisc.edu            //networks or a driver which changes it according to feedback
8006863Sdrh5@cs.wisc.edu            if (reg & (RXCFG_DRTH | RXCFG_DRTH0)) ;
8016863Sdrh5@cs.wisc.edu#endif
8027007Snate@binkert.org            break;
8037007Snate@binkert.org
8047007Snate@binkert.org          case PQCR:
8057007Snate@binkert.org            /* there is no priority queueing used in the linux 2.6 driver */
8067007Snate@binkert.org            regs.pqcr = reg;
8076657Snate@binkert.org            break;
8087007Snate@binkert.org
8097007Snate@binkert.org          case WCSR:
8107007Snate@binkert.org            /* not going to implement wake on LAN */
8116902SBrad.Beckmann@amd.com            regs.wcsr = reg;
8126902SBrad.Beckmann@amd.com            break;
8136902SBrad.Beckmann@amd.com
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;
8187025SBrad.Beckmann@amd.com
8196902SBrad.Beckmann@amd.com          case RFCR:
8206902SBrad.Beckmann@amd.com            regs.rfcr = reg;
8216902SBrad.Beckmann@amd.com
8226902SBrad.Beckmann@amd.com            rxFilterEnable = (reg & RFCR_RFEN) ? true : false;
8236902SBrad.Beckmann@amd.com            acceptBroadcast = (reg & RFCR_AAB) ? true : false;
8247542SBrad.Beckmann@amd.com            acceptMulticast = (reg & RFCR_AAM) ? true : false;
8257542SBrad.Beckmann@amd.com            acceptUnicast = (reg & RFCR_AAU) ? true : false;
8267542SBrad.Beckmann@amd.com            acceptPerfect = (reg & RFCR_APM) ? true : false;
8276902SBrad.Beckmann@amd.com            acceptArp = (reg & RFCR_AARP) ? true : false;
8286902SBrad.Beckmann@amd.com
8296902SBrad.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
8427542SBrad.Beckmann@amd.com          case RFDR:
8436902SBrad.Beckmann@amd.com            panic("the driver never writes to RFDR, something is wrong!\n");
8447839Snilay@cs.wisc.edu
8457839Snilay@cs.wisc.edu          case BRAR:
8467839Snilay@cs.wisc.edu            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;
8647839Snilay@cs.wisc.edu
8657839Snilay@cs.wisc.edu          case VDR:
8667839Snilay@cs.wisc.edu            panic("the driver never uses VDR, something is wrong!\n");
8677839Snilay@cs.wisc.edu            break;
8687839Snilay@cs.wisc.edu
8697839Snilay@cs.wisc.edu          case CCSR:
8707839Snilay@cs.wisc.edu            /* not going to implement clockrun stuff */
8717839Snilay@cs.wisc.edu            regs.ccsr = reg;
8727839Snilay@cs.wisc.edu            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;
8816902SBrad.Beckmann@amd.com                regs.tbisr |= (TBISR_MR_AN_COMPLETE | TBISR_MR_LINK_STATUS);
8828683Snilay@cs.wisc.edu            }
8838683Snilay@cs.wisc.edu
8848683Snilay@cs.wisc.edu#if 0
8858683Snilay@cs.wisc.edu            if (reg & TBICR_MR_RESTART_AN) ;
8868683Snilay@cs.wisc.edu#endif
8878683Snilay@cs.wisc.edu
8888683Snilay@cs.wisc.edu            break;
8898683Snilay@cs.wisc.edu
8908683Snilay@cs.wisc.edu          case TBISR:
8918683Snilay@cs.wisc.edu            panic("TBISR is read only register!\n");
8928683Snilay@cs.wisc.edu
8938683Snilay@cs.wisc.edu          case TANAR:
8948683Snilay@cs.wisc.edu            regs.tanar = reg;
8958683Snilay@cs.wisc.edu            if (reg & TANAR_PS2)
8968683Snilay@cs.wisc.edu                panic("this isn't used in driver, something wrong!\n");
8978683Snilay@cs.wisc.edu
8988683Snilay@cs.wisc.edu            if (reg & TANAR_PS1)
8996657Snate@binkert.org                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
9056657Snate@binkert.org          case TANER:
9067839Snilay@cs.wisc.edu            panic("TANER is read only register!\n");
9077839Snilay@cs.wisc.edu
9087839Snilay@cs.wisc.edu          case TESR:
9097839Snilay@cs.wisc.edu            regs.tesr = reg;
9107839Snilay@cs.wisc.edu            break;
9118055Sksewell@umich.edu
9127839Snilay@cs.wisc.edu          default:
9137839Snilay@cs.wisc.edu            panic("invalid register access daddr=%#x", daddr);
9146657Snate@binkert.org        }
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}
9217839Snilay@cs.wisc.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)
9268055Sksewell@umich.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",
9367839Snilay@cs.wisc.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))
9418055Sksewell@umich.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
9477839Snilay@cs.wisc.eduNSGigE::devIntrClear(uint32_t interrupts)
9487839Snilay@cs.wisc.edu{
9497839Snilay@cs.wisc.edu    if (interrupts & ISR_RESERVE)
9507839Snilay@cs.wisc.edu        panic("Cannot clear a reserved interrupt");
9517839Snilay@cs.wisc.edu
9526657Snate@binkert.org    interrupts &= ~ISR_NOIMPL;
9537007Snate@binkert.org    regs.isr &= ~interrupts;
9547007Snate@binkert.org
9556657Snate@binkert.org    DPRINTF(EthernetIntr,
9568055Sksewell@umich.edu            "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();
9618478Snilay@cs.wisc.edu}
9628478Snilay@cs.wisc.edu
9638478Snilay@cs.wisc.eduvoid
9649302Snilay@cs.wisc.eduNSGigE::devIntrChangeMask()
9659302Snilay@cs.wisc.edu{
9669302Snilay@cs.wisc.edu    DPRINTF(EthernetIntr, "interrupt mask changed: isr=%x imr=%x masked=%x\n",
9679302Snilay@cs.wisc.edu            regs.isr, regs.imr, regs.isr & regs.imr);
9689302Snilay@cs.wisc.edu
9699302Snilay@cs.wisc.edu    if (regs.isr & regs.imr)
9709302Snilay@cs.wisc.edu        cpuIntrPost(curTick);
9719302Snilay@cs.wisc.edu    else
9729302Snilay@cs.wisc.edu        cpuIntrClear();
9739302Snilay@cs.wisc.edu}
9749302Snilay@cs.wisc.edu
9759302Snilay@cs.wisc.eduvoid
9769302Snilay@cs.wisc.eduNSGigE::cpuIntrPost(Tick when)
9779302Snilay@cs.wisc.edu{
9789302Snilay@cs.wisc.edu    // If the interrupt you want to post is later than an interrupt
9799302Snilay@cs.wisc.edu    // already scheduled, just let it post in the coming one and don't
9809302Snilay@cs.wisc.edu    // schedule another.
9819302Snilay@cs.wisc.edu    // HOWEVER, must be sure that the scheduled intrTick is in the
9829302Snilay@cs.wisc.edu    // future (this was formerly the source of a bug)
9839302Snilay@cs.wisc.edu    /**
9849302Snilay@cs.wisc.edu     * @todo this warning should be removed and the intrTick code should
9859302Snilay@cs.wisc.edu     * be fixed.
9869302Snilay@cs.wisc.edu     */
9879302Snilay@cs.wisc.edu    assert(when >= curTick);
9889302Snilay@cs.wisc.edu    assert(intrTick >= curTick || intrTick == 0);
9899302Snilay@cs.wisc.edu    if (when > intrTick && intrTick != 0) {
9909302Snilay@cs.wisc.edu        DPRINTF(EthernetIntr, "don't need to schedule event...intrTick=%d\n",
9919302Snilay@cs.wisc.edu                intrTick);
9929302Snilay@cs.wisc.edu        return;
9939302Snilay@cs.wisc.edu    }
9949302Snilay@cs.wisc.edu
9959302Snilay@cs.wisc.edu    intrTick = when;
9969302Snilay@cs.wisc.edu    if (intrTick < curTick) {
9976657Snate@binkert.org        debug_break();
9986657Snate@binkert.org        intrTick = curTick;
9999219Spower.jg@gmail.com    }
10006657Snate@binkert.org
10016657Snate@binkert.org    DPRINTF(EthernetIntr, "going to schedule an interrupt for intrTick=%d\n",
10026999Snate@binkert.org            intrTick);
10036657Snate@binkert.org
10046657Snate@binkert.org    if (intrEvent)
10059104Shestness@cs.utexas.edu        intrEvent->squash();
10069104Shestness@cs.utexas.edu    intrEvent = new IntrEvent(this, true);
10079104Shestness@cs.utexas.edu    intrEvent->schedule(intrTick);
10089104Shestness@cs.utexas.edu}
10096657Snate@binkert.org
10106657Snate@binkert.orgvoid
10116657Snate@binkert.orgNSGigE::cpuInterrupt()
10126657Snate@binkert.org{
10138946Sandreas.hansson@arm.com    assert(intrTick == curTick);
10148946Sandreas.hansson@arm.com
10158946Sandreas.hansson@arm.com    // Whether or not there's a pending interrupt, we don't care about
10167832Snate@binkert.org    // it anymore
10177832Snate@binkert.org    intrEvent = 0;
10187007Snate@binkert.org    intrTick = 0;
10198232Snate@binkert.org
10208229Snate@binkert.org    // Don't send an interrupt if there's already one
10218229Snate@binkert.org    if (cpuPendingIntr) {
10228229Snate@binkert.org        DPRINTF(EthernetIntr,
10239104Shestness@cs.utexas.edu                "would send an interrupt now, but there's already pending\n");
10249104Shestness@cs.utexas.edu    } else {
10259104Shestness@cs.utexas.edu        // Send interrupt
10269104Shestness@cs.utexas.edu        cpuPendingIntr = true;
10279104Shestness@cs.utexas.edu
10289104Shestness@cs.utexas.edu        DPRINTF(EthernetIntr, "posting interrupt\n");
10298229Snate@binkert.org        intrPost();
10306657Snate@binkert.org    }
10316657Snate@binkert.org}
10329219Spower.jg@gmail.com
10339219Spower.jg@gmail.comvoid
10349219Spower.jg@gmail.comNSGigE::cpuIntrClear()
10359219Spower.jg@gmail.com{
10369219Spower.jg@gmail.com    if (!cpuPendingIntr)
10379219Spower.jg@gmail.com        return;
10389219Spower.jg@gmail.com
10396657Snate@binkert.org    if (intrEvent) {
10407055Snate@binkert.org        intrEvent->squash();
10417055Snate@binkert.org        intrEvent = 0;
10427007Snate@binkert.org    }
10437007Snate@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();
10507007Snate@binkert.org}
10517007Snate@binkert.org
10527007Snate@binkert.orgbool
10537007Snate@binkert.orgNSGigE::cpuIntrPending() const
10549230Snilay@cs.wisc.edu{ return cpuPendingIntr; }
10556657Snate@binkert.org
10566657Snate@binkert.orgvoid
10576657Snate@binkert.orgNSGigE::txReset()
10586657Snate@binkert.org{
10596657Snate@binkert.org
10606657Snate@binkert.org    DPRINTF(Ethernet, "transmit reset\n");
10616657Snate@binkert.org
10626657Snate@binkert.org    CTDD = false;
10636657Snate@binkert.org    txEnable = false;;
10646657Snate@binkert.org    txFragPtr = 0;
10656657Snate@binkert.org    assert(txDescCnt == 0);
10666657Snate@binkert.org    txFifo.clear();
10677567SBrad.Beckmann@amd.com    txState = txIdle;
10687567SBrad.Beckmann@amd.com    assert(txDmaState == dmaIdle);
10697567SBrad.Beckmann@amd.com}
10707567SBrad.Beckmann@amd.com
10716657Snate@binkert.orgvoid
10726657Snate@binkert.orgNSGigE::rxReset()
10736657Snate@binkert.org{
10746657Snate@binkert.org    DPRINTF(Ethernet, "receive reset\n");
10756657Snate@binkert.org
10766657Snate@binkert.org    CRDD = false;
10776657Snate@binkert.org    assert(rxPktBytes == 0);
10786657Snate@binkert.org    rxEnable = false;
10796657Snate@binkert.org    rxFragPtr = 0;
10806657Snate@binkert.org    assert(rxDescCnt == 0);
10816657Snate@binkert.org    assert(rxDmaState == dmaIdle);
10826657Snate@binkert.org    rxFifo.clear();
10836657Snate@binkert.org    rxState = rxIdle;
10846657Snate@binkert.org}
10856657Snate@binkert.org
10866657Snate@binkert.orgvoid
10876657Snate@binkert.orgNSGigE::regsReset()
10886657Snate@binkert.org{
10896999Snate@binkert.org    memset(&regs, 0, sizeof(regs));
10906657Snate@binkert.org    regs.config = CFG_LNKSTS;
10916657Snate@binkert.org    regs.mear = MEAR_MDDIR | MEAR_EEDO;
10926657Snate@binkert.org    regs.txcfg = 0x120; // set drain threshold to 1024 bytes and
10936657Snate@binkert.org                        // fill threshold to 32 bytes
10946657Snate@binkert.org    regs.rxcfg = 0x4;   // set drain threshold to 16 bytes
10956657Snate@binkert.org    regs.srr = 0x0103;  // set the silicon revision to rev B or 0x103
10967832Snate@binkert.org    regs.mibc = MIBC_FRZ;
10977832Snate@binkert.org    regs.vdr = 0x81;    // set the vlan tag type to 802.1q
10987805Snilay@cs.wisc.edu    regs.tesr = 0xc000; // TBI capable of both full and half duplex
10997832Snate@binkert.org
11008232Snate@binkert.org    extstsEnable = false;
11018232Snate@binkert.org    acceptBroadcast = false;
11028229Snate@binkert.org    acceptMulticast = false;
11038229Snate@binkert.org    acceptUnicast = false;
11048229Snate@binkert.org    acceptPerfect = false;
11058229Snate@binkert.org    acceptArp = false;
11066657Snate@binkert.org}
11076657Snate@binkert.org
11086657Snate@binkert.orgvoid
11096657Snate@binkert.orgNSGigE::rxDmaReadCopy()
11106657Snate@binkert.org{
11116657Snate@binkert.org    assert(rxDmaState == dmaReading);
11126657Snate@binkert.org
11136657Snate@binkert.org    physmem->dma_read((uint8_t *)rxDmaData, rxDmaAddr, rxDmaLen);
11147007Snate@binkert.org    rxDmaState = dmaIdle;
11157007Snate@binkert.org
11167839Snilay@cs.wisc.edu    DPRINTF(EthernetDMA, "rx dma read  paddr=%#x len=%d\n",
11177839Snilay@cs.wisc.edu            rxDmaAddr, rxDmaLen);
11187839Snilay@cs.wisc.edu    DDUMP(EthernetDMA, rxDmaData, rxDmaLen);
11197839Snilay@cs.wisc.edu}
11207839Snilay@cs.wisc.edu
11217839Snilay@cs.wisc.edubool
11227839Snilay@cs.wisc.eduNSGigE::doRxDmaRead()
11237839Snilay@cs.wisc.edu{
11247839Snilay@cs.wisc.edu    assert(rxDmaState == dmaIdle || rxDmaState == dmaReadWaiting);
11257839Snilay@cs.wisc.edu    rxDmaState = dmaReading;
11267007Snate@binkert.org
11276657Snate@binkert.org    if (dmaInterface && !rxDmaFree) {
11287839Snilay@cs.wisc.edu        if (dmaInterface->busy())
11297839Snilay@cs.wisc.edu            rxDmaState = dmaReadWaiting;
11308337Snilay@cs.wisc.edu        else
11317839Snilay@cs.wisc.edu            dmaInterface->doDMA(Read, rxDmaAddr, rxDmaLen, curTick,
11328337Snilay@cs.wisc.edu                                &rxDmaReadEvent, true);
11337839Snilay@cs.wisc.edu        return true;
11348337Snilay@cs.wisc.edu    }
11357839Snilay@cs.wisc.edu
11368337Snilay@cs.wisc.edu    if (dmaReadDelay == 0 && dmaReadFactor == 0) {
11377839Snilay@cs.wisc.edu        rxDmaReadCopy();
11387839Snilay@cs.wisc.edu        return false;
11396657Snate@binkert.org    }
11406657Snate@binkert.org
11417780Snilay@cs.wisc.edu    Tick factor = ((rxDmaLen + ULL(63)) >> ULL(6)) * dmaReadFactor;
11429171Snilay@cs.wisc.edu    Tick start = curTick + dmaReadDelay + factor;
11439171Snilay@cs.wisc.edu    rxDmaReadEvent.schedule(start);
11446657Snate@binkert.org    return true;
11457007Snate@binkert.org}
11467839Snilay@cs.wisc.edu
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)
11556657Snate@binkert.org        txKick();
11567839Snilay@cs.wisc.edu
11576657Snate@binkert.org    rxKick();
11587780Snilay@cs.wisc.edu}
11597780Snilay@cs.wisc.edu
11607542SBrad.Beckmann@amd.comvoid
11618266Sksewell@umich.eduNSGigE::rxDmaWriteCopy()
11628266Sksewell@umich.edu{
11638266Sksewell@umich.edu    assert(rxDmaState == dmaWriting);
11648266Sksewell@umich.edu
11658266Sksewell@umich.edu    physmem->dma_write(rxDmaAddr, (uint8_t *)rxDmaData, rxDmaLen);
11668266Sksewell@umich.edu    rxDmaState = dmaIdle;
11676657Snate@binkert.org
11687832Snate@binkert.org    DPRINTF(EthernetDMA, "rx dma write paddr=%#x len=%d\n",
11697839Snilay@cs.wisc.edu            rxDmaAddr, rxDmaLen);
11707839Snilay@cs.wisc.edu    DDUMP(EthernetDMA, rxDmaData, rxDmaLen);
11718337Snilay@cs.wisc.edu}
11728341Snilay@cs.wisc.edu
11737839Snilay@cs.wisc.edubool
11748337Snilay@cs.wisc.eduNSGigE::doRxDmaWrite()
11758341Snilay@cs.wisc.edu{
11767839Snilay@cs.wisc.edu    assert(rxDmaState == dmaIdle || rxDmaState == dmaWriteWaiting);
11778337Snilay@cs.wisc.edu    rxDmaState = dmaWriting;
11788341Snilay@cs.wisc.edu
11797839Snilay@cs.wisc.edu    if (dmaInterface && !rxDmaFree) {
11808337Snilay@cs.wisc.edu        if (dmaInterface->busy())
11818341Snilay@cs.wisc.edu            rxDmaState = dmaWriteWaiting;
11827839Snilay@cs.wisc.edu        else
11837839Snilay@cs.wisc.edu            dmaInterface->doDMA(WriteInvalidate, rxDmaAddr, rxDmaLen, curTick,
11846657Snate@binkert.org                                &rxDmaWriteEvent, true);
11858266Sksewell@umich.edu        return true;
11868266Sksewell@umich.edu    }
11878266Sksewell@umich.edu
11888266Sksewell@umich.edu    if (dmaWriteDelay == 0 && dmaWriteFactor == 0) {
11898266Sksewell@umich.edu        rxDmaWriteCopy();
11908266Sksewell@umich.edu        return false;
11916657Snate@binkert.org    }
11927780Snilay@cs.wisc.edu
11938266Sksewell@umich.edu    Tick factor = ((rxDmaLen + ULL(63)) >> ULL(6)) * dmaWriteFactor;
11948266Sksewell@umich.edu    Tick start = curTick + dmaWriteDelay + factor;
11958266Sksewell@umich.edu    rxDmaWriteEvent.schedule(start);
11968266Sksewell@umich.edu    return true;
11978266Sksewell@umich.edu}
11988266Sksewell@umich.edu
11996657Snate@binkert.orgvoid
12006657Snate@binkert.orgNSGigE::rxDmaWriteDone()
12016657Snate@binkert.org{
12026657Snate@binkert.org    assert(rxDmaState == dmaWriting);
12036657Snate@binkert.org    rxDmaWriteCopy();
12047007Snate@binkert.org
12057007Snate@binkert.org    // If the transmit state machine has a pending DMA, let it go first
12067007Snate@binkert.org    if (txDmaState == dmaReadWaiting || txDmaState == dmaWriteWaiting)
12077007Snate@binkert.org        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
12187839Snilay@cs.wisc.edu    if (rxKickTick > curTick) {
12197007Snate@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:
12316999Snate@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
12389104Shestness@cs.utexas.edu    // see state machine from spec for details
12396657Snate@binkert.org    // the way this works is, if you finish work on one state and can
12406657Snate@binkert.org    // go directly to another, you do that through jumping to the
12416657Snate@binkert.org    // 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) {
12467007Snate@binkert.org      case rxIdle:
12476657Snate@binkert.org        if (!rxEnable) {
12486657Snate@binkert.org            DPRINTF(EthernetSM, "Receive Disabled! Nothing to do.\n");
12496657Snate@binkert.org            goto exit;
12506657Snate@binkert.org        }
12519105SBrad.Beckmann@amd.com
12529105SBrad.Beckmann@amd.com        if (CRDD) {
12539105SBrad.Beckmann@amd.com            rxState = rxDescRefr;
12549105SBrad.Beckmann@amd.com
12559105SBrad.Beckmann@amd.com            rxDmaAddr = regs.rxdp & 0x3fffffff;
12569105SBrad.Beckmann@amd.com            rxDmaData = &rxDescCache + offsetof(ns_desc, link);
12579105SBrad.Beckmann@amd.com            rxDmaLen = sizeof(rxDescCache.link);
12589105SBrad.Beckmann@amd.com            rxDmaFree = dmaDescFree;
12596657Snate@binkert.org
12606657Snate@binkert.org            descDmaReads++;
12616657Snate@binkert.org            descDmaRdBytes += rxDmaLen;
12626657Snate@binkert.org
12636657Snate@binkert.org            if (doRxDmaRead())
12646657Snate@binkert.org                goto exit;
12656657Snate@binkert.org        } else {
12669104Shestness@cs.utexas.edu            rxState = rxDescRead;
12679104Shestness@cs.utexas.edu
12689104Shestness@cs.utexas.edu            rxDmaAddr = regs.rxdp & 0x3fffffff;
12699104Shestness@cs.utexas.edu            rxDmaData = &rxDescCache;
12706657Snate@binkert.org            rxDmaLen = sizeof(ns_desc);
12716657Snate@binkert.org            rxDmaFree = dmaDescFree;
12726657Snate@binkert.org
12736657Snate@binkert.org            descDmaReads++;
12746657Snate@binkert.org            descDmaRdBytes += rxDmaLen;
12756657Snate@binkert.org
12766657Snate@binkert.org            if (doRxDmaRead())
12776657Snate@binkert.org                goto exit;
12786657Snate@binkert.org        }
12796657Snate@binkert.org        break;
12807839Snilay@cs.wisc.edu
12817839Snilay@cs.wisc.edu      case rxDescRefr:
12827839Snilay@cs.wisc.edu        if (rxDmaState != dmaIdle)
12837839Snilay@cs.wisc.edu            goto exit;
12847839Snilay@cs.wisc.edu
12857839Snilay@cs.wisc.edu        rxState = rxAdvance;
12867839Snilay@cs.wisc.edu        break;
12877839Snilay@cs.wisc.edu
12887839Snilay@cs.wisc.edu     case rxDescRead:
12897839Snilay@cs.wisc.edu        if (rxDmaState != dmaIdle)
12907839Snilay@cs.wisc.edu            goto exit;
12917839Snilay@cs.wisc.edu
12926657Snate@binkert.org        DPRINTF(EthernetDesc,
12936657Snate@binkert.org                "rxDescCache: addr=%08x read descriptor\n",
12946657Snate@binkert.org                regs.rxdp & 0x3fffffff);
12956657Snate@binkert.org        DPRINTF(EthernetDesc,
12966657Snate@binkert.org                "rxDescCache: link=%08x bufptr=%08x cmdsts=%08x extsts=%08x\n",
12976657Snate@binkert.org                rxDescCache.link, rxDescCache.bufptr, rxDescCache.cmdsts,
12986657Snate@binkert.org                rxDescCache.extsts);
12996657Snate@binkert.org
13006657Snate@binkert.org        if (rxDescCache.cmdsts & CMDSTS_OWN) {
13016657Snate@binkert.org            devIntrPost(ISR_RXIDLE);
13026657Snate@binkert.org            rxState = rxIdle;
13036657Snate@binkert.org            goto exit;
13046657Snate@binkert.org        } else {
13056657Snate@binkert.org            rxState = rxFifoBlock;
13066657Snate@binkert.org            rxFragPtr = rxDescCache.bufptr;
13076657Snate@binkert.org            rxDescCnt = rxDescCache.cmdsts & CMDSTS_LEN_MASK;
13086657Snate@binkert.org        }
13096657Snate@binkert.org        break;
13106657Snate@binkert.org
13116657Snate@binkert.org      case rxFifoBlock:
13126657Snate@binkert.org        if (!rxPacket) {
13137805Snilay@cs.wisc.edu            /**
13148159SBrad.Beckmann@amd.com             * @todo in reality, we should be able to start processing
13159171Snilay@cs.wisc.edu             * the packet as it arrives, and not have to wait for the
13166657Snate@binkert.org             * full packet ot be in the receive fifo.
13176657Snate@binkert.org             */
13186657Snate@binkert.org            if (rxFifo.empty())
13196657Snate@binkert.org                goto exit;
13206657Snate@binkert.org
13216657Snate@binkert.org            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());
13337832Snate@binkert.org                    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());
13378229Snate@binkert.org                    }
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);
13447542SBrad.Beckmann@amd.com            rxFifo.pop();
13457542SBrad.Beckmann@amd.com        }
13467542SBrad.Beckmann@amd.com
13477542SBrad.Beckmann@amd.com
13487542SBrad.Beckmann@amd.com        // dont' need the && rxDescCnt > 0 if driver sanity check
13497542SBrad.Beckmann@amd.com        // above holds
13507542SBrad.Beckmann@amd.com        if (rxPktBytes > 0) {
13517542SBrad.Beckmann@amd.com            rxState = rxFragWrite;
13527542SBrad.Beckmann@amd.com            // don't need min<>(rxPktBytes,rxDescCnt) if above sanity
13537542SBrad.Beckmann@amd.com            // check holds
13547542SBrad.Beckmann@amd.com            rxXferLen = rxPktBytes;
13557542SBrad.Beckmann@amd.com
13567542SBrad.Beckmann@amd.com            rxDmaAddr = rxFragPtr & 0x3fffffff;
13577542SBrad.Beckmann@amd.com            rxDmaData = rxPacketBufPtr;
13587542SBrad.Beckmann@amd.com            rxDmaLen = rxXferLen;
13597542SBrad.Beckmann@amd.com            rxDmaFree = dmaDataFree;
13607542SBrad.Beckmann@amd.com
13617542SBrad.Beckmann@amd.com            if (doRxDmaWrite())
13627542SBrad.Beckmann@amd.com                goto exit;
13637542SBrad.Beckmann@amd.com
13647542SBrad.Beckmann@amd.com        } else {
13657542SBrad.Beckmann@amd.com            rxState = rxDescWrite;
13667542SBrad.Beckmann@amd.com
13677542SBrad.Beckmann@amd.com            //if (rxPktBytes == 0) {  /* packet is done */
13687542SBrad.Beckmann@amd.com            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;
13727542SBrad.Beckmann@amd.com            rxDescCache.cmdsts &= ~CMDSTS_MORE;
13737542SBrad.Beckmann@amd.com            rxDescCache.cmdsts |= CMDSTS_OK;
13747542SBrad.Beckmann@amd.com            rxDescCache.cmdsts &= 0xffff0000;
13757542SBrad.Beckmann@amd.com            rxDescCache.cmdsts += rxPacket->length;   //i.e. set CMDSTS_SIZE
13767542SBrad.Beckmann@amd.com
13777542SBrad.Beckmann@amd.com#if 0
13787542SBrad.Beckmann@amd.com            /*
13797542SBrad.Beckmann@amd.com             * all the driver uses these are for its own stats keeping
13807542SBrad.Beckmann@amd.com             * which we don't care about, aren't necessary for
13817542SBrad.Beckmann@amd.com             * functionality and doing this would just slow us down.
13827542SBrad.Beckmann@amd.com             * if they end up using this in a later version for
13837542SBrad.Beckmann@amd.com             * functional purposes, just undef
13847542SBrad.Beckmann@amd.com             */
13857542SBrad.Beckmann@amd.com            if (rxFilterEnable) {
13867542SBrad.Beckmann@amd.com                rxDescCache.cmdsts &= ~CMDSTS_DEST_MASK;
13877542SBrad.Beckmann@amd.com                const EthAddr &dst = rxFifoFront()->dst();
13887542SBrad.Beckmann@amd.com                if (dst->unicast())
13897542SBrad.Beckmann@amd.com                    rxDescCache.cmdsts |= CMDSTS_DEST_SELF;
13907542SBrad.Beckmann@amd.com                if (dst->multicast())
13917542SBrad.Beckmann@amd.com                    rxDescCache.cmdsts |= CMDSTS_DEST_MULTI;
13927542SBrad.Beckmann@amd.com                if (dst->broadcast())
13937542SBrad.Beckmann@amd.com                    rxDescCache.cmdsts |= CMDSTS_DEST_MASK;
13947542SBrad.Beckmann@amd.com            }
13957542SBrad.Beckmann@amd.com#endif
13967542SBrad.Beckmann@amd.com
13977542SBrad.Beckmann@amd.com            IpPtr ip(rxPacket);
13987542SBrad.Beckmann@amd.com            if (extstsEnable && ip) {
13997542SBrad.Beckmann@amd.com                rxDescCache.extsts |= EXTSTS_IPPKT;
14007542SBrad.Beckmann@amd.com                rxIpChecksums++;
14017542SBrad.Beckmann@amd.com                if (cksum(ip) != 0) {
14027542SBrad.Beckmann@amd.com                    DPRINTF(EthernetCksum, "Rx IP Checksum Error\n");
14037542SBrad.Beckmann@amd.com                    rxDescCache.extsts |= EXTSTS_IPERR;
14047542SBrad.Beckmann@amd.com                }
14057542SBrad.Beckmann@amd.com                TcpPtr tcp(ip);
14067542SBrad.Beckmann@amd.com                UdpPtr udp(ip);
14077542SBrad.Beckmann@amd.com                if (tcp) {
14087542SBrad.Beckmann@amd.com                    rxDescCache.extsts |= EXTSTS_TCPPKT;
14097542SBrad.Beckmann@amd.com                    rxTcpChecksums++;
14107542SBrad.Beckmann@amd.com                    if (cksum(tcp) != 0) {
14117542SBrad.Beckmann@amd.com                        DPRINTF(EthernetCksum, "Rx TCP Checksum Error\n");
14127542SBrad.Beckmann@amd.com                        rxDescCache.extsts |= EXTSTS_TCPERR;
14137542SBrad.Beckmann@amd.com
14147542SBrad.Beckmann@amd.com                    }
14157542SBrad.Beckmann@amd.com                } else if (udp) {
14167542SBrad.Beckmann@amd.com                    rxDescCache.extsts |= EXTSTS_UDPPKT;
14177542SBrad.Beckmann@amd.com                    rxUdpChecksums++;
14186657Snate@binkert.org                    if (cksum(udp) != 0) {
14196999Snate@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
14267542SBrad.Beckmann@amd.com            /*
14277542SBrad.Beckmann@amd.com             * the driver seems to always receive into desc buffers
14286657Snate@binkert.org             * of size 1514, so you never have a pkt that is split
14297832Snate@binkert.org             * into multiple descriptors on the receive side, so
14307002Snate@binkert.org             * i don't implement that case, hence the assert above.
14317002Snate@binkert.org             */
14328229Snate@binkert.org
14338229Snate@binkert.org            DPRINTF(EthernetDesc,
14348608Snilay@cs.wisc.edu                    "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",
14386657Snate@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;
14426657Snate@binkert.org            rxDmaData = &(rxDescCache.cmdsts);
14437542SBrad.Beckmann@amd.com            rxDmaLen = sizeof(rxDescCache.cmdsts) + sizeof(rxDescCache.extsts);
14447542SBrad.Beckmann@amd.com            rxDmaFree = dmaDescFree;
14457542SBrad.Beckmann@amd.com
14466657Snate@binkert.org            descDmaWrites++;
14476657Snate@binkert.org            descDmaWrBytes += rxDmaLen;
14486657Snate@binkert.org
14496657Snate@binkert.org            if (doRxDmaWrite())
14506657Snate@binkert.org                goto exit;
14516657Snate@binkert.org        }
14526657Snate@binkert.org        break;
14536657Snate@binkert.org
14546657Snate@binkert.org      case rxFragWrite:
14557007Snate@binkert.org        if (rxDmaState != dmaIdle)
14566657Snate@binkert.org            goto exit;
14576657Snate@binkert.org
14586657Snate@binkert.org        rxPacketBufPtr += rxXferLen;
14596657Snate@binkert.org        rxFragPtr += rxXferLen;
14606999Snate@binkert.org        rxPktBytes -= rxXferLen;
14616657Snate@binkert.org
14626657Snate@binkert.org        rxState = rxFifoBlock;
14636657Snate@binkert.org        break;
14646657Snate@binkert.org
14656657Snate@binkert.org      case rxDescWrite:
14666657Snate@binkert.org        if (rxDmaState != dmaIdle)
14677832Snate@binkert.org            goto exit;
14687832Snate@binkert.org
14696657Snate@binkert.org        assert(rxDescCache.cmdsts & CMDSTS_OWN);
14706657Snate@binkert.org
14716657Snate@binkert.org        assert(rxPacket == 0);
14726657Snate@binkert.org        devIntrPost(ISR_RXOK);
14736657Snate@binkert.org
14746657Snate@binkert.org        if (rxDescCache.cmdsts & CMDSTS_INTR)
14756657Snate@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;
14837007Snate@binkert.org        break;
14847007Snate@binkert.org
14857007Snate@binkert.org      case rxAdvance:
14866657Snate@binkert.org        if (rxDescCache.link == 0) {
14876657Snate@binkert.org            devIntrPost(ISR_RXIDLE);
14886657Snate@binkert.org            rxState = rxIdle;
14897007Snate@binkert.org            CRDD = true;
14907007Snate@binkert.org            goto exit;
14917007Snate@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;
15037007Snate@binkert.org        }
15047007Snate@binkert.org        break;
15056657Snate@binkert.org
15066657Snate@binkert.org      default:
15076657Snate@binkert.org        panic("Invalid rxState!");
15086657Snate@binkert.org    }
15096657Snate@binkert.org
15107007Snate@binkert.org    DPRINTF(EthernetSM, "entering next rxState=%s\n",
15117007Snate@binkert.org            NsRxStateStrings[rxState]);
15127007Snate@binkert.org
15136657Snate@binkert.org    goto next;
15146657Snate@binkert.org
15156657Snate@binkert.org  exit:
15167007Snate@binkert.org    /**
15177542SBrad.Beckmann@amd.com     * @todo do we want to schedule a future kick?
15187542SBrad.Beckmann@amd.com     */
15196657Snate@binkert.org    DPRINTF(EthernetSM, "rx state machine exited rxState=%s\n",
15207542SBrad.Beckmann@amd.com            NsRxStateStrings[rxState]);
15217542SBrad.Beckmann@amd.com}
15227002Snate@binkert.org
15237542SBrad.Beckmann@amd.comvoid
15247542SBrad.Beckmann@amd.comNSGigE::transmit()
15257542SBrad.Beckmann@amd.com{
15267542SBrad.Beckmann@amd.com    if (txFifo.empty()) {
15276657Snate@binkert.org        DPRINTF(Ethernet, "nothing to transmit\n");
15287542SBrad.Beckmann@amd.com        return;
15297542SBrad.Beckmann@amd.com    }
15307542SBrad.Beckmann@amd.com
15317542SBrad.Beckmann@amd.com    DPRINTF(Ethernet, "Attempt Pkt Transmit: txFifo length=%d\n",
15327542SBrad.Beckmann@amd.com            txFifo.size());
15337542SBrad.Beckmann@amd.com    if (interface->sendPacket(txFifo.front())) {
15347542SBrad.Beckmann@amd.com#if TRACING_ON
15357542SBrad.Beckmann@amd.com        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",
15427007Snate@binkert.org                            tcp->sport(), tcp->dport());
15436999Snate@binkert.org                }
15447007Snate@binkert.org            }
15457007Snate@binkert.org        }
15467007Snate@binkert.org#endif
15477007Snate@binkert.org
15487007Snate@binkert.org        DDUMP(Ethernet, txFifo.front()->data, txFifo.front()->length);
15497007Snate@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;
15796999Snate@binkert.org
15806657Snate@binkert.org    DPRINTF(EthernetDMA, "tx dma read  paddr=%#x len=%d\n",
15816657Snate@binkert.org            txDmaAddr, txDmaLen);
15827007Snate@binkert.org    DDUMP(EthernetDMA, txDmaData, txDmaLen);
15837007Snate@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;
15986657Snate@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;
16066657Snate@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();
16226657Snate@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())
16456657Snate@binkert.org            txDmaState = dmaWriteWaiting;
16466657Snate@binkert.org        else
16476657Snate@binkert.org            dmaInterface->doDMA(WriteInvalidate, txDmaAddr, txDmaLen, curTick,
16486657Snate@binkert.org                                &txDmaWriteEvent, true);
16496657Snate@binkert.org        return true;
16506657Snate@binkert.org    }
16516657Snate@binkert.org
16526657Snate@binkert.org    if (dmaWriteDelay == 0 && dmaWriteFactor == 0.0) {
16536657Snate@binkert.org        txDmaWriteCopy();
16546657Snate@binkert.org        return false;
16556657Snate@binkert.org    }
16566657Snate@binkert.org
16576657Snate@binkert.org    Tick factor = ((txDmaLen + ULL(63)) >> ULL(6)) * dmaWriteFactor;
16586657Snate@binkert.org    Tick start = curTick + dmaWriteDelay + factor;
16596657Snate@binkert.org    txDmaWriteEvent.schedule(start);
16606657Snate@binkert.org    return true;
16616657Snate@binkert.org}
16626657Snate@binkert.org
16636657Snate@binkert.orgvoid
16646657Snate@binkert.orgNSGigE::txDmaWriteDone()
16656657Snate@binkert.org{
16666657Snate@binkert.org    assert(txDmaState == dmaWriting);
16676657Snate@binkert.org    txDmaWriteCopy();
16686657Snate@binkert.org
16696657Snate@binkert.org    // If the receive state machine  has a pending DMA, let it go first
16706657Snate@binkert.org    if (rxDmaState == dmaReadWaiting || rxDmaState == dmaWriteWaiting)
16716657Snate@binkert.org        rxKick();
16727007Snate@binkert.org
16736657Snate@binkert.org    txKick();
16746657Snate@binkert.org}
16756657Snate@binkert.org
16766657Snate@binkert.orgvoid
16776657Snate@binkert.orgNSGigE::txKick()
16786657Snate@binkert.org{
16796657Snate@binkert.org    DPRINTF(EthernetSM, "transmit kick txState=%s\n",
16807007Snate@binkert.org            NsTxStateStrings[txState]);
16816657Snate@binkert.org
16826657Snate@binkert.org    if (txKickTick > curTick) {
16836657Snate@binkert.org        DPRINTF(EthernetSM, "transmit kick exiting, can't run till %d\n",
16846657Snate@binkert.org                txKickTick);
16856657Snate@binkert.org
16866657Snate@binkert.org        return;
16876657Snate@binkert.org    }
16886657Snate@binkert.org
16896657Snate@binkert.org  next:
16906657Snate@binkert.org    switch(txDmaState) {
16916657Snate@binkert.org      case dmaReadWaiting:
16926657Snate@binkert.org        if (doTxDmaRead())
16936657Snate@binkert.org            goto exit;
16946657Snate@binkert.org        break;
16956657Snate@binkert.org      case dmaWriteWaiting:
16967007Snate@binkert.org        if (doTxDmaWrite())
16976657Snate@binkert.org            goto exit;
16986657Snate@binkert.org        break;
16996657Snate@binkert.org      default:
17006657Snate@binkert.org        break;
17016657Snate@binkert.org    }
17026657Snate@binkert.org
17036657Snate@binkert.org    switch (txState) {
17046657Snate@binkert.org      case txIdle:
17056657Snate@binkert.org        if (!txEnable) {
17066657Snate@binkert.org            DPRINTF(EthernetSM, "Transmit disabled.  Nothing to do.\n");
17076657Snate@binkert.org            goto exit;
17086657Snate@binkert.org        }
17096657Snate@binkert.org
17106657Snate@binkert.org        if (CTDD) {
17116657Snate@binkert.org            txState = txDescRefr;
17126657Snate@binkert.org
17136657Snate@binkert.org            txDmaAddr = regs.txdp & 0x3fffffff;
17146657Snate@binkert.org            txDmaData = &txDescCache + offsetof(ns_desc, link);
17156657Snate@binkert.org            txDmaLen = sizeof(txDescCache.link);
17166657Snate@binkert.org            txDmaFree = dmaDescFree;
17176657Snate@binkert.org
17186657Snate@binkert.org            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(rxFragPtr);
2170    SERIALIZE_SCALAR(rxDescCnt);
2171    int rxDmaState = this->rxDmaState;
2172    SERIALIZE_SCALAR(rxDmaState);
2173
2174    SERIALIZE_SCALAR(extstsEnable);
2175
2176    /*
2177     * If there's a pending transmit, store the time so we can
2178     * reschedule it later
2179     */
2180    Tick transmitTick = txEvent.scheduled() ? txEvent.when() - curTick : 0;
2181    SERIALIZE_SCALAR(transmitTick);
2182
2183    /*
2184     * receive address filter settings
2185     */
2186    SERIALIZE_SCALAR(rxFilterEnable);
2187    SERIALIZE_SCALAR(acceptBroadcast);
2188    SERIALIZE_SCALAR(acceptMulticast);
2189    SERIALIZE_SCALAR(acceptUnicast);
2190    SERIALIZE_SCALAR(acceptPerfect);
2191    SERIALIZE_SCALAR(acceptArp);
2192
2193    /*
2194     * Keep track of pending interrupt status.
2195     */
2196    SERIALIZE_SCALAR(intrTick);
2197    SERIALIZE_SCALAR(cpuPendingIntr);
2198    Tick intrEventTick = 0;
2199    if (intrEvent)
2200        intrEventTick = intrEvent->when();
2201    SERIALIZE_SCALAR(intrEventTick);
2202
2203}
2204
2205void
2206NSGigE::unserialize(Checkpoint *cp, const std::string &section)
2207{
2208    // Unserialize the PciDev base class
2209    PciDev::unserialize(cp, section);
2210
2211    UNSERIALIZE_SCALAR(regs.command);
2212    UNSERIALIZE_SCALAR(regs.config);
2213    UNSERIALIZE_SCALAR(regs.mear);
2214    UNSERIALIZE_SCALAR(regs.ptscr);
2215    UNSERIALIZE_SCALAR(regs.isr);
2216    UNSERIALIZE_SCALAR(regs.imr);
2217    UNSERIALIZE_SCALAR(regs.ier);
2218    UNSERIALIZE_SCALAR(regs.ihr);
2219    UNSERIALIZE_SCALAR(regs.txdp);
2220    UNSERIALIZE_SCALAR(regs.txdp_hi);
2221    UNSERIALIZE_SCALAR(regs.txcfg);
2222    UNSERIALIZE_SCALAR(regs.gpior);
2223    UNSERIALIZE_SCALAR(regs.rxdp);
2224    UNSERIALIZE_SCALAR(regs.rxdp_hi);
2225    UNSERIALIZE_SCALAR(regs.rxcfg);
2226    UNSERIALIZE_SCALAR(regs.pqcr);
2227    UNSERIALIZE_SCALAR(regs.wcsr);
2228    UNSERIALIZE_SCALAR(regs.pcr);
2229    UNSERIALIZE_SCALAR(regs.rfcr);
2230    UNSERIALIZE_SCALAR(regs.rfdr);
2231    UNSERIALIZE_SCALAR(regs.srr);
2232    UNSERIALIZE_SCALAR(regs.mibc);
2233    UNSERIALIZE_SCALAR(regs.vrcr);
2234    UNSERIALIZE_SCALAR(regs.vtcr);
2235    UNSERIALIZE_SCALAR(regs.vdr);
2236    UNSERIALIZE_SCALAR(regs.ccsr);
2237    UNSERIALIZE_SCALAR(regs.tbicr);
2238    UNSERIALIZE_SCALAR(regs.tbisr);
2239    UNSERIALIZE_SCALAR(regs.tanar);
2240    UNSERIALIZE_SCALAR(regs.tanlpar);
2241    UNSERIALIZE_SCALAR(regs.taner);
2242    UNSERIALIZE_SCALAR(regs.tesr);
2243
2244    UNSERIALIZE_ARRAY(rom.perfectMatch, ETH_ADDR_LEN);
2245
2246    UNSERIALIZE_SCALAR(ioEnable);
2247
2248    /*
2249     * unserialize the data fifos
2250     */
2251    rxFifo.unserialize("rxFifo", cp, section);
2252    txFifo.unserialize("txFifo", cp, section);
2253
2254    /*
2255     * unserialize the various helper variables
2256     */
2257    bool txPacketExists;
2258    UNSERIALIZE_SCALAR(txPacketExists);
2259    if (txPacketExists) {
2260        txPacket = new PacketData;
2261        txPacket->unserialize("txPacket", cp, section);
2262        uint32_t txPktBufPtr;
2263        UNSERIALIZE_SCALAR(txPktBufPtr);
2264        txPacketBufPtr = (uint8_t *) txPacket->data + txPktBufPtr;
2265    } else
2266        txPacket = 0;
2267
2268    bool rxPacketExists;
2269    UNSERIALIZE_SCALAR(rxPacketExists);
2270    rxPacket = 0;
2271    if (rxPacketExists) {
2272        rxPacket = new PacketData;
2273        rxPacket->unserialize("rxPacket", cp, section);
2274        uint32_t rxPktBufPtr;
2275        UNSERIALIZE_SCALAR(rxPktBufPtr);
2276        rxPacketBufPtr = (uint8_t *) rxPacket->data + rxPktBufPtr;
2277    } else
2278        rxPacket = 0;
2279
2280    UNSERIALIZE_SCALAR(txXferLen);
2281    UNSERIALIZE_SCALAR(rxXferLen);
2282
2283    /*
2284     * Unserialize DescCaches
2285     */
2286    UNSERIALIZE_SCALAR(txDescCache.link);
2287    UNSERIALIZE_SCALAR(txDescCache.bufptr);
2288    UNSERIALIZE_SCALAR(txDescCache.cmdsts);
2289    UNSERIALIZE_SCALAR(txDescCache.extsts);
2290    UNSERIALIZE_SCALAR(rxDescCache.link);
2291    UNSERIALIZE_SCALAR(rxDescCache.bufptr);
2292    UNSERIALIZE_SCALAR(rxDescCache.cmdsts);
2293    UNSERIALIZE_SCALAR(rxDescCache.extsts);
2294
2295    /*
2296     * unserialize tx state machine
2297     */
2298    int txState;
2299    UNSERIALIZE_SCALAR(txState);
2300    this->txState = (TxState) txState;
2301    UNSERIALIZE_SCALAR(txEnable);
2302    UNSERIALIZE_SCALAR(CTDD);
2303    UNSERIALIZE_SCALAR(txFragPtr);
2304    UNSERIALIZE_SCALAR(txDescCnt);
2305    int txDmaState;
2306    UNSERIALIZE_SCALAR(txDmaState);
2307    this->txDmaState = (DmaState) txDmaState;
2308
2309    /*
2310     * unserialize rx state machine
2311     */
2312    int rxState;
2313    UNSERIALIZE_SCALAR(rxState);
2314    this->rxState = (RxState) rxState;
2315    UNSERIALIZE_SCALAR(rxEnable);
2316    UNSERIALIZE_SCALAR(CRDD);
2317    UNSERIALIZE_SCALAR(rxPktBytes);
2318    UNSERIALIZE_SCALAR(rxFragPtr);
2319    UNSERIALIZE_SCALAR(rxDescCnt);
2320    int rxDmaState;
2321    UNSERIALIZE_SCALAR(rxDmaState);
2322    this->rxDmaState = (DmaState) rxDmaState;
2323
2324    UNSERIALIZE_SCALAR(extstsEnable);
2325
2326     /*
2327     * If there's a pending transmit, reschedule it now
2328     */
2329    Tick transmitTick;
2330    UNSERIALIZE_SCALAR(transmitTick);
2331    if (transmitTick)
2332        txEvent.schedule(curTick + transmitTick);
2333
2334    /*
2335     * unserialize receive address filter settings
2336     */
2337    UNSERIALIZE_SCALAR(rxFilterEnable);
2338    UNSERIALIZE_SCALAR(acceptBroadcast);
2339    UNSERIALIZE_SCALAR(acceptMulticast);
2340    UNSERIALIZE_SCALAR(acceptUnicast);
2341    UNSERIALIZE_SCALAR(acceptPerfect);
2342    UNSERIALIZE_SCALAR(acceptArp);
2343
2344    /*
2345     * Keep track of pending interrupt status.
2346     */
2347    UNSERIALIZE_SCALAR(intrTick);
2348    UNSERIALIZE_SCALAR(cpuPendingIntr);
2349    Tick intrEventTick;
2350    UNSERIALIZE_SCALAR(intrEventTick);
2351    if (intrEventTick) {
2352        intrEvent = new IntrEvent(this, true);
2353        intrEvent->schedule(intrEventTick);
2354    }
2355
2356    /*
2357     * re-add addrRanges to bus bridges
2358     */
2359    if (pioInterface) {
2360        pioInterface->addAddrRange(RangeSize(BARAddrs[0], BARSize[0]));
2361        pioInterface->addAddrRange(RangeSize(BARAddrs[1], BARSize[1]));
2362    }
2363}
2364
2365Tick
2366NSGigE::cacheAccess(MemReqPtr &req)
2367{
2368    DPRINTF(EthernetPIO, "timing access to paddr=%#x (daddr=%#x)\n",
2369            req->paddr, req->paddr - addr);
2370    return curTick + pioLatency;
2371}
2372
2373BEGIN_DECLARE_SIM_OBJECT_PARAMS(NSGigEInt)
2374
2375    SimObjectParam<EtherInt *> peer;
2376    SimObjectParam<NSGigE *> device;
2377
2378END_DECLARE_SIM_OBJECT_PARAMS(NSGigEInt)
2379
2380BEGIN_INIT_SIM_OBJECT_PARAMS(NSGigEInt)
2381
2382    INIT_PARAM_DFLT(peer, "peer interface", NULL),
2383    INIT_PARAM(device, "Ethernet device of this interface")
2384
2385END_INIT_SIM_OBJECT_PARAMS(NSGigEInt)
2386
2387CREATE_SIM_OBJECT(NSGigEInt)
2388{
2389    NSGigEInt *dev_int = new NSGigEInt(getInstanceName(), device);
2390
2391    EtherInt *p = (EtherInt *)peer;
2392    if (p) {
2393        dev_int->setPeer(p);
2394        p->setPeer(dev_int);
2395    }
2396
2397    return dev_int;
2398}
2399
2400REGISTER_SIM_OBJECT("NSGigEInt", NSGigEInt)
2401
2402
2403BEGIN_DECLARE_SIM_OBJECT_PARAMS(NSGigE)
2404
2405    Param<Tick> tx_delay;
2406    Param<Tick> rx_delay;
2407    Param<Tick> intr_delay;
2408    SimObjectParam<MemoryController *> mmu;
2409    SimObjectParam<PhysicalMemory *> physmem;
2410    Param<bool> rx_filter;
2411    Param<string> hardware_address;
2412    SimObjectParam<Bus*> header_bus;
2413    SimObjectParam<Bus*> payload_bus;
2414    SimObjectParam<HierParams *> hier;
2415    Param<Tick> pio_latency;
2416    Param<bool> dma_desc_free;
2417    Param<bool> dma_data_free;
2418    Param<Tick> dma_read_delay;
2419    Param<Tick> dma_write_delay;
2420    Param<Tick> dma_read_factor;
2421    Param<Tick> dma_write_factor;
2422    SimObjectParam<PciConfigAll *> configspace;
2423    SimObjectParam<PciConfigData *> configdata;
2424    SimObjectParam<Platform *> platform;
2425    Param<uint32_t> pci_bus;
2426    Param<uint32_t> pci_dev;
2427    Param<uint32_t> pci_func;
2428    Param<uint32_t> tx_fifo_size;
2429    Param<uint32_t> rx_fifo_size;
2430
2431END_DECLARE_SIM_OBJECT_PARAMS(NSGigE)
2432
2433BEGIN_INIT_SIM_OBJECT_PARAMS(NSGigE)
2434
2435    INIT_PARAM_DFLT(tx_delay, "Transmit Delay", 1000),
2436    INIT_PARAM_DFLT(rx_delay, "Receive Delay", 1000),
2437    INIT_PARAM_DFLT(intr_delay, "Interrupt Delay in microseconds", 0),
2438    INIT_PARAM(mmu, "Memory Controller"),
2439    INIT_PARAM(physmem, "Physical Memory"),
2440    INIT_PARAM_DFLT(rx_filter, "Enable Receive Filter", true),
2441    INIT_PARAM_DFLT(hardware_address, "Ethernet Hardware Address",
2442                    "00:99:00:00:00:01"),
2443    INIT_PARAM_DFLT(header_bus, "The IO Bus to attach to for headers", NULL),
2444    INIT_PARAM_DFLT(payload_bus, "The IO Bus to attach to for payload", NULL),
2445    INIT_PARAM_DFLT(hier, "Hierarchy global variables", &defaultHierParams),
2446    INIT_PARAM_DFLT(pio_latency, "Programmed IO latency in bus cycles", 1),
2447    INIT_PARAM_DFLT(dma_desc_free, "DMA of Descriptors is free", false),
2448    INIT_PARAM_DFLT(dma_data_free, "DMA of Data is free", false),
2449    INIT_PARAM_DFLT(dma_read_delay, "fixed delay for dma reads", 0),
2450    INIT_PARAM_DFLT(dma_write_delay, "fixed delay for dma writes", 0),
2451    INIT_PARAM_DFLT(dma_read_factor, "multiplier for dma reads", 0),
2452    INIT_PARAM_DFLT(dma_write_factor, "multiplier for dma writes", 0),
2453    INIT_PARAM(configspace, "PCI Configspace"),
2454    INIT_PARAM(configdata, "PCI Config data"),
2455    INIT_PARAM(platform, "Platform"),
2456    INIT_PARAM(pci_bus, "PCI bus"),
2457    INIT_PARAM(pci_dev, "PCI device number"),
2458    INIT_PARAM(pci_func, "PCI function code"),
2459    INIT_PARAM_DFLT(tx_fifo_size, "max size in bytes of txFifo", 131072),
2460    INIT_PARAM_DFLT(rx_fifo_size, "max size in bytes of rxFifo", 131072)
2461
2462END_INIT_SIM_OBJECT_PARAMS(NSGigE)
2463
2464
2465CREATE_SIM_OBJECT(NSGigE)
2466{
2467    NSGigE::Params *params = new NSGigE::Params;
2468
2469    params->name = getInstanceName();
2470    params->mmu = mmu;
2471    params->configSpace = configspace;
2472    params->configData = configdata;
2473    params->plat = platform;
2474    params->busNum = pci_bus;
2475    params->deviceNum = pci_dev;
2476    params->functionNum = pci_func;
2477
2478    params->intr_delay = intr_delay;
2479    params->pmem = physmem;
2480    params->tx_delay = tx_delay;
2481    params->rx_delay = rx_delay;
2482    params->hier = hier;
2483    params->header_bus = header_bus;
2484    params->payload_bus = payload_bus;
2485    params->pio_latency = pio_latency;
2486    params->dma_desc_free = dma_desc_free;
2487    params->dma_data_free = dma_data_free;
2488    params->dma_read_delay = dma_read_delay;
2489    params->dma_write_delay = dma_write_delay;
2490    params->dma_read_factor = dma_read_factor;
2491    params->dma_write_factor = dma_write_factor;
2492    params->rx_filter = rx_filter;
2493    params->eaddr = hardware_address;
2494    params->tx_fifo_size = tx_fifo_size;
2495    params->rx_fifo_size = rx_fifo_size;
2496    return new NSGigE(params);
2497}
2498
2499REGISTER_SIM_OBJECT("NSGigE", NSGigE)
2500