ns_gige.cc revision 1036
17322Sgblack@eecs.umich.edu/*
27322Sgblack@eecs.umich.edu * Copyright (c) 2004 The Regents of The University of Michigan
37322Sgblack@eecs.umich.edu * All rights reserved.
47322Sgblack@eecs.umich.edu *
57322Sgblack@eecs.umich.edu * Redistribution and use in source and binary forms, with or without
67322Sgblack@eecs.umich.edu * modification, are permitted provided that the following conditions are
77322Sgblack@eecs.umich.edu * met: redistributions of source code must retain the above copyright
87322Sgblack@eecs.umich.edu * notice, this list of conditions and the following disclaimer;
97322Sgblack@eecs.umich.edu * redistributions in binary form must reproduce the above copyright
107322Sgblack@eecs.umich.edu * notice, this list of conditions and the following disclaimer in the
117322Sgblack@eecs.umich.edu * documentation and/or other materials provided with the distribution;
127322Sgblack@eecs.umich.edu * neither the name of the copyright holders nor the names of its
137322Sgblack@eecs.umich.edu * contributors may be used to endorse or promote products derived from
147322Sgblack@eecs.umich.edu * this software without specific prior written permission.
157322Sgblack@eecs.umich.edu *
167322Sgblack@eecs.umich.edu * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
177322Sgblack@eecs.umich.edu * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
187322Sgblack@eecs.umich.edu * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
197322Sgblack@eecs.umich.edu * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
207322Sgblack@eecs.umich.edu * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
217322Sgblack@eecs.umich.edu * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
227322Sgblack@eecs.umich.edu * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
237322Sgblack@eecs.umich.edu * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
247322Sgblack@eecs.umich.edu * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
257322Sgblack@eecs.umich.edu * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
267322Sgblack@eecs.umich.edu * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
277322Sgblack@eecs.umich.edu */
287322Sgblack@eecs.umich.edu
297322Sgblack@eecs.umich.edu/* @file
307322Sgblack@eecs.umich.edu * Device module for modelling the National Semiconductor
317322Sgblack@eecs.umich.edu * DP83820 ethernet controller.  Does not support priority queueing
327322Sgblack@eecs.umich.edu */
337322Sgblack@eecs.umich.edu#include <cstdio>
347322Sgblack@eecs.umich.edu#include <deque>
357322Sgblack@eecs.umich.edu#include <string>
367322Sgblack@eecs.umich.edu
377322Sgblack@eecs.umich.edu#include "base/inet.hh"
387322Sgblack@eecs.umich.edu#include "cpu/exec_context.hh"
397322Sgblack@eecs.umich.edu#include "cpu/intr_control.hh"
407376Sgblack@eecs.umich.edu#include "dev/dma.hh"
417376Sgblack@eecs.umich.edu#include "dev/etherlink.hh"
427376Sgblack@eecs.umich.edu#include "dev/ns_gige.hh"
437376Sgblack@eecs.umich.edu#include "dev/pciconfigall.hh"
447376Sgblack@eecs.umich.edu#include "dev/tsunami_cchip.hh"
457376Sgblack@eecs.umich.edu#include "mem/bus/bus.hh"
467376Sgblack@eecs.umich.edu#include "mem/bus/dma_interface.hh"
477376Sgblack@eecs.umich.edu#include "mem/bus/pio_interface.hh"
487376Sgblack@eecs.umich.edu#include "mem/bus/pio_interface_impl.hh"
497376Sgblack@eecs.umich.edu#include "mem/functional_mem/memory_control.hh"
507376Sgblack@eecs.umich.edu#include "mem/functional_mem/physical_memory.hh"
517376Sgblack@eecs.umich.edu#include "sim/builder.hh"
527376Sgblack@eecs.umich.edu#include "sim/debug.hh"
537376Sgblack@eecs.umich.edu#include "sim/host.hh"
547376Sgblack@eecs.umich.edu#include "sim/sim_stats.hh"
557376Sgblack@eecs.umich.edu#include "targetarch/vtophys.hh"
567376Sgblack@eecs.umich.edu
577376Sgblack@eecs.umich.educonst char *NsRxStateStrings[] =
587376Sgblack@eecs.umich.edu{
597376Sgblack@eecs.umich.edu    "rxIdle",
607376Sgblack@eecs.umich.edu    "rxDescRefr",
617376Sgblack@eecs.umich.edu    "rxDescRead",
627376Sgblack@eecs.umich.edu    "rxFifoBlock",
637376Sgblack@eecs.umich.edu    "rxFragWrite",
647376Sgblack@eecs.umich.edu    "rxDescWrite",
657376Sgblack@eecs.umich.edu    "rxAdvance"
667376Sgblack@eecs.umich.edu};
677376Sgblack@eecs.umich.edu
687376Sgblack@eecs.umich.educonst char *NsTxStateStrings[] =
697376Sgblack@eecs.umich.edu{
707376Sgblack@eecs.umich.edu    "txIdle",
717376Sgblack@eecs.umich.edu    "txDescRefr",
727376Sgblack@eecs.umich.edu    "txDescRead",
737376Sgblack@eecs.umich.edu    "txFifoBlock",
747376Sgblack@eecs.umich.edu    "txFragRead",
757376Sgblack@eecs.umich.edu    "txDescWrite",
767376Sgblack@eecs.umich.edu    "txAdvance"
777376Sgblack@eecs.umich.edu};
787376Sgblack@eecs.umich.edu
797376Sgblack@eecs.umich.educonst char *NsDmaState[] =
807376Sgblack@eecs.umich.edu{
817376Sgblack@eecs.umich.edu    "dmaIdle",
827376Sgblack@eecs.umich.edu    "dmaReading",
837376Sgblack@eecs.umich.edu    "dmaWriting",
847376Sgblack@eecs.umich.edu    "dmaReadWaiting",
857376Sgblack@eecs.umich.edu    "dmaWriteWaiting"
867376Sgblack@eecs.umich.edu};
877376Sgblack@eecs.umich.edu
887376Sgblack@eecs.umich.eduusing namespace std;
897376Sgblack@eecs.umich.edu
907376Sgblack@eecs.umich.edu// helper function declarations
917376Sgblack@eecs.umich.edu// These functions reverse Endianness so we can evaluate network data
927376Sgblack@eecs.umich.edu// correctly
937376Sgblack@eecs.umich.eduuint16_t reverseEnd16(uint16_t);
947376Sgblack@eecs.umich.eduuint32_t reverseEnd32(uint32_t);
957376Sgblack@eecs.umich.edu
967376Sgblack@eecs.umich.edu///////////////////////////////////////////////////////////////////////
977376Sgblack@eecs.umich.edu//
987376Sgblack@eecs.umich.edu// NSGigE PCI Device
997376Sgblack@eecs.umich.edu//
1007376Sgblack@eecs.umich.eduNSGigE::NSGigE(const std::string &name, IntrControl *i, Tick intr_delay,
1017376Sgblack@eecs.umich.edu               PhysicalMemory *pmem, Tick tx_delay, Tick rx_delay,
1027376Sgblack@eecs.umich.edu               MemoryController *mmu, HierParams *hier, Bus *header_bus,
1037376Sgblack@eecs.umich.edu               Bus *payload_bus, Tick pio_latency, bool dma_desc_free,
1047376Sgblack@eecs.umich.edu               bool dma_data_free, Tick dma_read_delay, Tick dma_write_delay,
1057376Sgblack@eecs.umich.edu               Tick dma_read_factor, Tick dma_write_factor, PciConfigAll *cf,
1067376Sgblack@eecs.umich.edu               PciConfigData *cd, Tsunami *t, uint32_t bus, uint32_t dev,
1077376Sgblack@eecs.umich.edu               uint32_t func, bool rx_filter, const int eaddr[6],
1087376Sgblack@eecs.umich.edu               uint32_t tx_fifo_size, uint32_t rx_fifo_size)
1097376Sgblack@eecs.umich.edu    : PciDev(name, mmu, cf, cd, bus, dev, func), tsunami(t), ioEnable(false),
1107376Sgblack@eecs.umich.edu      maxTxFifoSize(tx_fifo_size), maxRxFifoSize(rx_fifo_size),
1117376Sgblack@eecs.umich.edu      txPacket(0), rxPacket(0), txPacketBufPtr(NULL), rxPacketBufPtr(NULL),
1127376Sgblack@eecs.umich.edu      txXferLen(0), rxXferLen(0), txState(txIdle), txEnable(false),
1137376Sgblack@eecs.umich.edu      CTDD(false), txFifoAvail(tx_fifo_size),
1147376Sgblack@eecs.umich.edu      txFragPtr(0), txDescCnt(0), txDmaState(dmaIdle), rxState(rxIdle),
1157376Sgblack@eecs.umich.edu      rxEnable(false), CRDD(false), rxPktBytes(0), rxFifoCnt(0),
1167376Sgblack@eecs.umich.edu      rxFragPtr(0), rxDescCnt(0), rxDmaState(dmaIdle), extstsEnable(false),
1177376Sgblack@eecs.umich.edu      rxDmaReadEvent(this), rxDmaWriteEvent(this),
1187376Sgblack@eecs.umich.edu      txDmaReadEvent(this), txDmaWriteEvent(this),
1197376Sgblack@eecs.umich.edu      dmaDescFree(dma_desc_free), dmaDataFree(dma_data_free),
1207376Sgblack@eecs.umich.edu      txDelay(tx_delay), rxDelay(rx_delay), rxKickTick(0), txKickTick(0),
1217376Sgblack@eecs.umich.edu      txEvent(this), rxFilterEnable(rx_filter), acceptBroadcast(false),
1227376Sgblack@eecs.umich.edu      acceptMulticast(false), acceptUnicast(false),
1237376Sgblack@eecs.umich.edu      acceptPerfect(false), acceptArp(false),
1247376Sgblack@eecs.umich.edu      physmem(pmem), intctrl(i), intrTick(0), cpuPendingIntr(false),
1257376Sgblack@eecs.umich.edu      intrEvent(0), interface(0)
1267376Sgblack@eecs.umich.edu{
1277376Sgblack@eecs.umich.edu    tsunami->ethernet = this;
1287376Sgblack@eecs.umich.edu
1297376Sgblack@eecs.umich.edu    if (header_bus) {
1307376Sgblack@eecs.umich.edu        pioInterface = newPioInterface(name, hier, header_bus, this,
1317376Sgblack@eecs.umich.edu                                       &NSGigE::cacheAccess);
1327376Sgblack@eecs.umich.edu
1337376Sgblack@eecs.umich.edu        pioLatency = pio_latency * header_bus->clockRatio;
1347376Sgblack@eecs.umich.edu
1357376Sgblack@eecs.umich.edu        if (payload_bus)
1367376Sgblack@eecs.umich.edu            dmaInterface = new DMAInterface<Bus>(name + ".dma",
1377376Sgblack@eecs.umich.edu                                                 header_bus, payload_bus, 1);
1387376Sgblack@eecs.umich.edu        else
1397376Sgblack@eecs.umich.edu            dmaInterface = new DMAInterface<Bus>(name + ".dma",
1407376Sgblack@eecs.umich.edu                                                 header_bus, header_bus, 1);
1417376Sgblack@eecs.umich.edu    } else if (payload_bus) {
1427376Sgblack@eecs.umich.edu        pioInterface = newPioInterface(name, hier, payload_bus, this,
1437376Sgblack@eecs.umich.edu                                       &NSGigE::cacheAccess);
1447376Sgblack@eecs.umich.edu
1457376Sgblack@eecs.umich.edu        pioLatency = pio_latency * payload_bus->clockRatio;
1467376Sgblack@eecs.umich.edu
1477376Sgblack@eecs.umich.edu        dmaInterface = new DMAInterface<Bus>(name + ".dma", payload_bus,
1487376Sgblack@eecs.umich.edu                                         payload_bus, 1);
1497376Sgblack@eecs.umich.edu    }
1507376Sgblack@eecs.umich.edu
1517376Sgblack@eecs.umich.edu
1527376Sgblack@eecs.umich.edu    intrDelay = US2Ticks(intr_delay);
1537376Sgblack@eecs.umich.edu    dmaReadDelay = dma_read_delay;
1547376Sgblack@eecs.umich.edu    dmaWriteDelay = dma_write_delay;
1557376Sgblack@eecs.umich.edu    dmaReadFactor = dma_read_factor;
1567376Sgblack@eecs.umich.edu    dmaWriteFactor = dma_write_factor;
1577376Sgblack@eecs.umich.edu
1587376Sgblack@eecs.umich.edu    regsReset();
1597376Sgblack@eecs.umich.edu    rom.perfectMatch[0] = eaddr[0];
1607376Sgblack@eecs.umich.edu    rom.perfectMatch[1] = eaddr[1];
1617376Sgblack@eecs.umich.edu    rom.perfectMatch[2] = eaddr[2];
1627376Sgblack@eecs.umich.edu    rom.perfectMatch[3] = eaddr[3];
1637376Sgblack@eecs.umich.edu    rom.perfectMatch[4] = eaddr[4];
1647376Sgblack@eecs.umich.edu    rom.perfectMatch[5] = eaddr[5];
1657376Sgblack@eecs.umich.edu}
1667376Sgblack@eecs.umich.edu
1677376Sgblack@eecs.umich.eduNSGigE::~NSGigE()
1687376Sgblack@eecs.umich.edu{}
1697376Sgblack@eecs.umich.edu
1707376Sgblack@eecs.umich.eduvoid
1717376Sgblack@eecs.umich.eduNSGigE::regStats()
1727376Sgblack@eecs.umich.edu{
1737376Sgblack@eecs.umich.edu    txBytes
1747376Sgblack@eecs.umich.edu        .name(name() + ".txBytes")
1757376Sgblack@eecs.umich.edu        .desc("Bytes Transmitted")
1767376Sgblack@eecs.umich.edu        .prereq(txBytes)
1777376Sgblack@eecs.umich.edu        ;
1787376Sgblack@eecs.umich.edu
1797376Sgblack@eecs.umich.edu    rxBytes
1807376Sgblack@eecs.umich.edu        .name(name() + ".rxBytes")
1817376Sgblack@eecs.umich.edu        .desc("Bytes Received")
1827376Sgblack@eecs.umich.edu        .prereq(rxBytes)
1837376Sgblack@eecs.umich.edu        ;
1847376Sgblack@eecs.umich.edu
1857376Sgblack@eecs.umich.edu    txPackets
1867376Sgblack@eecs.umich.edu        .name(name() + ".txPackets")
1877376Sgblack@eecs.umich.edu        .desc("Number of Packets Transmitted")
1887322Sgblack@eecs.umich.edu        .prereq(txBytes)
1897322Sgblack@eecs.umich.edu        ;
1907322Sgblack@eecs.umich.edu
1917322Sgblack@eecs.umich.edu    rxPackets
1927322Sgblack@eecs.umich.edu        .name(name() + ".rxPackets")
1937322Sgblack@eecs.umich.edu        .desc("Number of Packets Received")
1947375Sgblack@eecs.umich.edu        .prereq(rxBytes)
1957322Sgblack@eecs.umich.edu        ;
1967322Sgblack@eecs.umich.edu
1977375Sgblack@eecs.umich.edu    txIPChecksums
1987375Sgblack@eecs.umich.edu        .name(name() + ".txIPChecksums")
1997322Sgblack@eecs.umich.edu        .desc("Number of tx IP Checksums done by device")
2007324Sgblack@eecs.umich.edu        .precision(0)
2017375Sgblack@eecs.umich.edu        .prereq(txBytes)
2027324Sgblack@eecs.umich.edu        ;
2037324Sgblack@eecs.umich.edu
2047375Sgblack@eecs.umich.edu    rxIPChecksums
2057375Sgblack@eecs.umich.edu        .name(name() + ".rxIPChecksums")
2067324Sgblack@eecs.umich.edu        .desc("Number of rx IP Checksums done by device")
2077333Sgblack@eecs.umich.edu        .precision(0)
2087333Sgblack@eecs.umich.edu        .prereq(rxBytes)
2097333Sgblack@eecs.umich.edu        ;
2107333Sgblack@eecs.umich.edu
2117375Sgblack@eecs.umich.edu    txTCPChecksums
2127333Sgblack@eecs.umich.edu        .name(name() + ".txTCPChecksums")
2137333Sgblack@eecs.umich.edu        .desc("Number of tx TCP Checksums done by device")
2147375Sgblack@eecs.umich.edu        .precision(0)
2157375Sgblack@eecs.umich.edu        .prereq(txBytes)
2167333Sgblack@eecs.umich.edu        ;
2177333Sgblack@eecs.umich.edu
2187333Sgblack@eecs.umich.edu    rxTCPChecksums
2197333Sgblack@eecs.umich.edu        .name(name() + ".rxTCPChecksums")
2207333Sgblack@eecs.umich.edu        .desc("Number of rx TCP Checksums done by device")
2217333Sgblack@eecs.umich.edu        .precision(0)
2227375Sgblack@eecs.umich.edu        .prereq(rxBytes)
2237333Sgblack@eecs.umich.edu        ;
2247333Sgblack@eecs.umich.edu
2257375Sgblack@eecs.umich.edu    descDmaReads
2267375Sgblack@eecs.umich.edu        .name(name() + ".descDMAReads")
2277333Sgblack@eecs.umich.edu        .desc("Number of descriptors the device read w/ DMA")
2287333Sgblack@eecs.umich.edu        .precision(0)
2297333Sgblack@eecs.umich.edu        ;
2307333Sgblack@eecs.umich.edu
2317333Sgblack@eecs.umich.edu    descDmaWrites
2327333Sgblack@eecs.umich.edu        .name(name() + ".descDMAWrites")
2337333Sgblack@eecs.umich.edu        .desc("Number of descriptors the device wrote w/ DMA")
2347333Sgblack@eecs.umich.edu        .precision(0)
2357375Sgblack@eecs.umich.edu        ;
2367333Sgblack@eecs.umich.edu
2377333Sgblack@eecs.umich.edu    descDmaRdBytes
2387375Sgblack@eecs.umich.edu        .name(name() + ".descDmaReadBytes")
2397375Sgblack@eecs.umich.edu        .desc("number of descriptor bytes read w/ DMA")
2407333Sgblack@eecs.umich.edu        .precision(0)
2417333Sgblack@eecs.umich.edu        ;
2427333Sgblack@eecs.umich.edu
2437333Sgblack@eecs.umich.edu   descDmaWrBytes
2447333Sgblack@eecs.umich.edu        .name(name() + ".descDmaWriteBytes")
2457375Sgblack@eecs.umich.edu        .desc("number of descriptor bytes write w/ DMA")
2467333Sgblack@eecs.umich.edu        .precision(0)
2477333Sgblack@eecs.umich.edu        ;
2487375Sgblack@eecs.umich.edu
2497375Sgblack@eecs.umich.edu
2507333Sgblack@eecs.umich.edu    txBandwidth
2517333Sgblack@eecs.umich.edu        .name(name() + ".txBandwidth")
2527333Sgblack@eecs.umich.edu        .desc("Transmit Bandwidth (bits/s)")
2537333Sgblack@eecs.umich.edu        .precision(0)
2547333Sgblack@eecs.umich.edu        .prereq(txBytes)
2557333Sgblack@eecs.umich.edu        ;
2567375Sgblack@eecs.umich.edu
2577333Sgblack@eecs.umich.edu    rxBandwidth
2587333Sgblack@eecs.umich.edu        .name(name() + ".rxBandwidth")
2597375Sgblack@eecs.umich.edu        .desc("Receive Bandwidth (bits/s)")
2607375Sgblack@eecs.umich.edu        .precision(0)
2617333Sgblack@eecs.umich.edu        .prereq(rxBytes)
2627333Sgblack@eecs.umich.edu        ;
2637333Sgblack@eecs.umich.edu
2647333Sgblack@eecs.umich.edu    txPacketRate
2657333Sgblack@eecs.umich.edu        .name(name() + ".txPPS")
2667333Sgblack@eecs.umich.edu        .desc("Packet Tranmission Rate (packets/s)")
2677333Sgblack@eecs.umich.edu        .precision(0)
2687333Sgblack@eecs.umich.edu        .prereq(txBytes)
2697375Sgblack@eecs.umich.edu        ;
2707333Sgblack@eecs.umich.edu
2717333Sgblack@eecs.umich.edu    rxPacketRate
2727375Sgblack@eecs.umich.edu        .name(name() + ".rxPPS")
2737375Sgblack@eecs.umich.edu        .desc("Packet Reception Rate (packets/s)")
2747333Sgblack@eecs.umich.edu        .precision(0)
2757333Sgblack@eecs.umich.edu        .prereq(rxBytes)
2767333Sgblack@eecs.umich.edu        ;
2777333Sgblack@eecs.umich.edu
2787333Sgblack@eecs.umich.edu    txBandwidth = txBytes * Stats::constant(8) / simSeconds;
2797375Sgblack@eecs.umich.edu    rxBandwidth = rxBytes * Stats::constant(8) / simSeconds;
2807333Sgblack@eecs.umich.edu    txPacketRate = txPackets / simSeconds;
2817333Sgblack@eecs.umich.edu    rxPacketRate = rxPackets / simSeconds;
2827375Sgblack@eecs.umich.edu}
2837375Sgblack@eecs.umich.edu
2847333Sgblack@eecs.umich.edu/**
2857333Sgblack@eecs.umich.edu * This is to read the PCI general configuration registers
2867333Sgblack@eecs.umich.edu */
2877333Sgblack@eecs.umich.eduvoid
2887333Sgblack@eecs.umich.eduNSGigE::ReadConfig(int offset, int size, uint8_t *data)
2897375Sgblack@eecs.umich.edu{
2907333Sgblack@eecs.umich.edu    if (offset < PCI_DEVICE_SPECIFIC)
2917333Sgblack@eecs.umich.edu        PciDev::ReadConfig(offset, size, data);
2927375Sgblack@eecs.umich.edu    else
2937375Sgblack@eecs.umich.edu        panic("Device specific PCI config space not implemented!\n");
2947333Sgblack@eecs.umich.edu}
2957333Sgblack@eecs.umich.edu
2967333Sgblack@eecs.umich.edu/**
2977333Sgblack@eecs.umich.edu * This is to write to the PCI general configuration registers
2987333Sgblack@eecs.umich.edu */
2997375Sgblack@eecs.umich.eduvoid
3007333Sgblack@eecs.umich.eduNSGigE::WriteConfig(int offset, int size, uint32_t data)
3017333Sgblack@eecs.umich.edu{
3027375Sgblack@eecs.umich.edu    if (offset < PCI_DEVICE_SPECIFIC)
3037375Sgblack@eecs.umich.edu        PciDev::WriteConfig(offset, size, data);
3047333Sgblack@eecs.umich.edu    else
3057333Sgblack@eecs.umich.edu        panic("Device specific PCI config space not implemented!\n");
3067333Sgblack@eecs.umich.edu
3077333Sgblack@eecs.umich.edu    // Need to catch writes to BARs to update the PIO interface
3087333Sgblack@eecs.umich.edu    switch (offset) {
3097375Sgblack@eecs.umich.edu        // seems to work fine without all these PCI settings, but i
3107333Sgblack@eecs.umich.edu        // put in the IO to double check, an assertion will fail if we
3117333Sgblack@eecs.umich.edu        // need to properly implement it
3127375Sgblack@eecs.umich.edu      case PCI_COMMAND:
3137375Sgblack@eecs.umich.edu        if (config.data[offset] & PCI_CMD_IOSE)
3147333Sgblack@eecs.umich.edu            ioEnable = true;
3157333Sgblack@eecs.umich.edu        else
3167333Sgblack@eecs.umich.edu            ioEnable = false;
3177333Sgblack@eecs.umich.edu
3187333Sgblack@eecs.umich.edu#if 0
3197375Sgblack@eecs.umich.edu        if (config.data[offset] & PCI_CMD_BME) {
3207333Sgblack@eecs.umich.edu            bmEnabled = true;
3217333Sgblack@eecs.umich.edu        }
3227375Sgblack@eecs.umich.edu        else {
3237375Sgblack@eecs.umich.edu            bmEnabled = false;
3247333Sgblack@eecs.umich.edu        }
3257333Sgblack@eecs.umich.edu
3267333Sgblack@eecs.umich.edu        if (config.data[offset] & PCI_CMD_MSE) {
3277333Sgblack@eecs.umich.edu            memEnable = true;
3287333Sgblack@eecs.umich.edu        }
3297375Sgblack@eecs.umich.edu        else {
3307333Sgblack@eecs.umich.edu            memEnable = false;
3317333Sgblack@eecs.umich.edu        }
3327375Sgblack@eecs.umich.edu#endif
3337375Sgblack@eecs.umich.edu        break;
3347333Sgblack@eecs.umich.edu
3357333Sgblack@eecs.umich.edu      case PCI0_BASE_ADDR0:
3367333Sgblack@eecs.umich.edu        if (BARAddrs[0] != 0) {
3377333Sgblack@eecs.umich.edu            if (pioInterface)
3387333Sgblack@eecs.umich.edu                pioInterface->addAddrRange(BARAddrs[0],
3397375Sgblack@eecs.umich.edu                                           BARAddrs[0] + BARSize[0] - 1);
3407333Sgblack@eecs.umich.edu
3417333Sgblack@eecs.umich.edu            BARAddrs[0] &= PA_UNCACHED_MASK;
3427375Sgblack@eecs.umich.edu        }
3437375Sgblack@eecs.umich.edu        break;
3447333Sgblack@eecs.umich.edu      case PCI0_BASE_ADDR1:
3457333Sgblack@eecs.umich.edu        if (BARAddrs[1] != 0) {
3467333Sgblack@eecs.umich.edu            if (pioInterface)
3477333Sgblack@eecs.umich.edu                pioInterface->addAddrRange(BARAddrs[1],
3487333Sgblack@eecs.umich.edu                                           BARAddrs[1] + BARSize[1] - 1);
3497375Sgblack@eecs.umich.edu
3507333Sgblack@eecs.umich.edu            BARAddrs[1] &= PA_UNCACHED_MASK;
3517333Sgblack@eecs.umich.edu        }
3527375Sgblack@eecs.umich.edu        break;
3537375Sgblack@eecs.umich.edu    }
3547333Sgblack@eecs.umich.edu}
3557333Sgblack@eecs.umich.edu
3567333Sgblack@eecs.umich.edu/**
3577333Sgblack@eecs.umich.edu * This reads the device registers, which are detailed in the NS83820
3587333Sgblack@eecs.umich.edu * spec sheet
3597333Sgblack@eecs.umich.edu */
3607375Sgblack@eecs.umich.eduFault
3617333Sgblack@eecs.umich.eduNSGigE::read(MemReqPtr &req, uint8_t *data)
3627333Sgblack@eecs.umich.edu{
3637375Sgblack@eecs.umich.edu    assert(ioEnable);
3647375Sgblack@eecs.umich.edu
3657333Sgblack@eecs.umich.edu    //The mask is to give you only the offset into the device register file
3667333Sgblack@eecs.umich.edu    Addr daddr = req->paddr & 0xfff;
3677333Sgblack@eecs.umich.edu    DPRINTF(EthernetPIO, "read  da=%#x pa=%#x va=%#x size=%d\n",
3687333Sgblack@eecs.umich.edu            daddr, req->paddr, req->vaddr, req->size);
3697333Sgblack@eecs.umich.edu
3707333Sgblack@eecs.umich.edu
3717375Sgblack@eecs.umich.edu    // there are some reserved registers, you can see ns_gige_reg.h and
3727333Sgblack@eecs.umich.edu    // the spec sheet for details
3737333Sgblack@eecs.umich.edu    if (daddr > LAST && daddr <=  RESERVED) {
3747375Sgblack@eecs.umich.edu        panic("Accessing reserved register");
3757375Sgblack@eecs.umich.edu    } else if (daddr > RESERVED && daddr <= 0x3FC) {
3767333Sgblack@eecs.umich.edu        ReadConfig(daddr & 0xff, req->size, data);
3777381Sgblack@eecs.umich.edu        return No_Fault;
3787381Sgblack@eecs.umich.edu    } else if (daddr >= MIB_START && daddr <= MIB_END) {
3797381Sgblack@eecs.umich.edu        // don't implement all the MIB's.  hopefully the kernel
3807381Sgblack@eecs.umich.edu        // doesn't actually DEPEND upon their values
3817381Sgblack@eecs.umich.edu        // MIB are just hardware stats keepers
3827381Sgblack@eecs.umich.edu        uint32_t &reg = *(uint32_t *) data;
3837381Sgblack@eecs.umich.edu        reg = 0;
3847364Sgblack@eecs.umich.edu        return No_Fault;
3857364Sgblack@eecs.umich.edu    } else if (daddr > 0x3FC)
3867382Sgblack@eecs.umich.edu        panic("Something is messed up!\n");
3877378Sgblack@eecs.umich.edu
3887381Sgblack@eecs.umich.edu    switch (req->size) {
3897386Sgblack@eecs.umich.edu      case sizeof(uint32_t):
3907381Sgblack@eecs.umich.edu        {
3917378Sgblack@eecs.umich.edu            uint32_t &reg = *(uint32_t *)data;
3927364Sgblack@eecs.umich.edu
3937364Sgblack@eecs.umich.edu            switch (daddr) {
3947364Sgblack@eecs.umich.edu              case CR:
3957364Sgblack@eecs.umich.edu                reg = regs.command;
3967375Sgblack@eecs.umich.edu                //these are supposed to be cleared on a read
3977364Sgblack@eecs.umich.edu                reg &= ~(CR_RXD | CR_TXD | CR_TXR | CR_RXR);
3987364Sgblack@eecs.umich.edu                break;
3997375Sgblack@eecs.umich.edu
4007375Sgblack@eecs.umich.edu              case CFG:
4017364Sgblack@eecs.umich.edu                reg = regs.config;
4027364Sgblack@eecs.umich.edu                break;
4037364Sgblack@eecs.umich.edu
4047364Sgblack@eecs.umich.edu              case MEAR:
4057364Sgblack@eecs.umich.edu                reg = regs.mear;
4067364Sgblack@eecs.umich.edu                break;
4077382Sgblack@eecs.umich.edu
4087378Sgblack@eecs.umich.edu              case PTSCR:
4097381Sgblack@eecs.umich.edu                reg = regs.ptscr;
4107386Sgblack@eecs.umich.edu                break;
4117381Sgblack@eecs.umich.edu
4127378Sgblack@eecs.umich.edu              case ISR:
4137364Sgblack@eecs.umich.edu                reg = regs.isr;
4147364Sgblack@eecs.umich.edu                devIntrClear(ISR_ALL);
4157364Sgblack@eecs.umich.edu                break;
4167364Sgblack@eecs.umich.edu
4177364Sgblack@eecs.umich.edu              case IMR:
4187364Sgblack@eecs.umich.edu                reg = regs.imr;
4197364Sgblack@eecs.umich.edu                break;
4207375Sgblack@eecs.umich.edu
4217364Sgblack@eecs.umich.edu              case IER:
4227364Sgblack@eecs.umich.edu                reg = regs.ier;
4237375Sgblack@eecs.umich.edu                break;
4247375Sgblack@eecs.umich.edu
4257364Sgblack@eecs.umich.edu              case IHR:
4267365Sgblack@eecs.umich.edu                reg = regs.ihr;
4277365Sgblack@eecs.umich.edu                break;
4287365Sgblack@eecs.umich.edu
4297365Sgblack@eecs.umich.edu              case TXDP:
4307375Sgblack@eecs.umich.edu                reg = regs.txdp;
4317365Sgblack@eecs.umich.edu                break;
4327365Sgblack@eecs.umich.edu
4337375Sgblack@eecs.umich.edu              case TXDP_HI:
4347375Sgblack@eecs.umich.edu                reg = regs.txdp_hi;
4357365Sgblack@eecs.umich.edu                break;
4367365Sgblack@eecs.umich.edu
4377365Sgblack@eecs.umich.edu              case TXCFG:
4387365Sgblack@eecs.umich.edu                reg = regs.txcfg;
4397365Sgblack@eecs.umich.edu                break;
4407365Sgblack@eecs.umich.edu
4417365Sgblack@eecs.umich.edu              case GPIOR:
4427365Sgblack@eecs.umich.edu                reg = regs.gpior;
4437365Sgblack@eecs.umich.edu                break;
4447375Sgblack@eecs.umich.edu
4457365Sgblack@eecs.umich.edu              case RXDP:
4467365Sgblack@eecs.umich.edu                reg = regs.rxdp;
4477375Sgblack@eecs.umich.edu                break;
4487375Sgblack@eecs.umich.edu
4497365Sgblack@eecs.umich.edu              case RXDP_HI:
4507366Sgblack@eecs.umich.edu                reg = regs.rxdp_hi;
4517366Sgblack@eecs.umich.edu                break;
4527366Sgblack@eecs.umich.edu
4537366Sgblack@eecs.umich.edu              case RXCFG:
4547375Sgblack@eecs.umich.edu                reg = regs.rxcfg;
4557366Sgblack@eecs.umich.edu                break;
4567366Sgblack@eecs.umich.edu
4577375Sgblack@eecs.umich.edu              case PQCR:
4587375Sgblack@eecs.umich.edu                reg = regs.pqcr;
4597366Sgblack@eecs.umich.edu                break;
4607366Sgblack@eecs.umich.edu
4617366Sgblack@eecs.umich.edu              case WCSR:
4627366Sgblack@eecs.umich.edu                reg = regs.wcsr;
4637366Sgblack@eecs.umich.edu                break;
4647366Sgblack@eecs.umich.edu
4657366Sgblack@eecs.umich.edu              case PCR:
4667366Sgblack@eecs.umich.edu                reg = regs.pcr;
4677366Sgblack@eecs.umich.edu                break;
4687375Sgblack@eecs.umich.edu
4697366Sgblack@eecs.umich.edu                // see the spec sheet for how RFCR and RFDR work
4707366Sgblack@eecs.umich.edu                // basically, you write to RFCR to tell the machine
4717375Sgblack@eecs.umich.edu                // what you want to do next, then you act upon RFDR,
4727375Sgblack@eecs.umich.edu                // and the device will be prepared b/c of what you
4737366Sgblack@eecs.umich.edu                // wrote to RFCR
4747367Sgblack@eecs.umich.edu              case RFCR:
4757367Sgblack@eecs.umich.edu                reg = regs.rfcr;
4767382Sgblack@eecs.umich.edu                break;
4777378Sgblack@eecs.umich.edu
4787381Sgblack@eecs.umich.edu              case RFDR:
4797385Sgblack@eecs.umich.edu                switch (regs.rfcr & RFCR_RFADDR) {
4807381Sgblack@eecs.umich.edu                  case 0x000:
4817378Sgblack@eecs.umich.edu                    reg = rom.perfectMatch[1];
4827367Sgblack@eecs.umich.edu                    reg = reg << 8;
4837375Sgblack@eecs.umich.edu                    reg += rom.perfectMatch[0];
4847367Sgblack@eecs.umich.edu                    break;
4857367Sgblack@eecs.umich.edu                  case 0x002:
4867375Sgblack@eecs.umich.edu                    reg = rom.perfectMatch[3] << 8;
4877375Sgblack@eecs.umich.edu                    reg += rom.perfectMatch[2];
4887367Sgblack@eecs.umich.edu                    break;
4897367Sgblack@eecs.umich.edu                  case 0x004:
4907367Sgblack@eecs.umich.edu                    reg = rom.perfectMatch[5] << 8;
4917367Sgblack@eecs.umich.edu                    reg += rom.perfectMatch[4];
4927367Sgblack@eecs.umich.edu                    break;
4937367Sgblack@eecs.umich.edu                  default:
4947385Sgblack@eecs.umich.edu                    panic("reading RFDR for something other than PMATCH!\n");
4957385Sgblack@eecs.umich.edu                    // didn't implement other RFDR functionality b/c
4967382Sgblack@eecs.umich.edu                    // driver didn't use it
4977378Sgblack@eecs.umich.edu                }
4987381Sgblack@eecs.umich.edu                break;
4997385Sgblack@eecs.umich.edu
5007385Sgblack@eecs.umich.edu              case SRR:
5017381Sgblack@eecs.umich.edu                reg = regs.srr;
5027378Sgblack@eecs.umich.edu                break;
5037367Sgblack@eecs.umich.edu
5047367Sgblack@eecs.umich.edu              case MIBC:
5057367Sgblack@eecs.umich.edu                reg = regs.mibc;
5067375Sgblack@eecs.umich.edu                reg &= ~(MIBC_MIBS | MIBC_ACLR);
5077367Sgblack@eecs.umich.edu                break;
5087367Sgblack@eecs.umich.edu
5097375Sgblack@eecs.umich.edu              case VRCR:
5107375Sgblack@eecs.umich.edu                reg = regs.vrcr;
5117367Sgblack@eecs.umich.edu                break;
5127368Sgblack@eecs.umich.edu
5137368Sgblack@eecs.umich.edu              case VTCR:
5147382Sgblack@eecs.umich.edu                reg = regs.vtcr;
5157378Sgblack@eecs.umich.edu                break;
5167381Sgblack@eecs.umich.edu
5177385Sgblack@eecs.umich.edu              case VDR:
5187381Sgblack@eecs.umich.edu                reg = regs.vdr;
5197378Sgblack@eecs.umich.edu                break;
5207368Sgblack@eecs.umich.edu
5217375Sgblack@eecs.umich.edu              case CCSR:
5227368Sgblack@eecs.umich.edu                reg = regs.ccsr;
5237368Sgblack@eecs.umich.edu                break;
5247375Sgblack@eecs.umich.edu
5257375Sgblack@eecs.umich.edu              case TBICR:
5267368Sgblack@eecs.umich.edu                reg = regs.tbicr;
5277368Sgblack@eecs.umich.edu                break;
5287368Sgblack@eecs.umich.edu
5297368Sgblack@eecs.umich.edu              case TBISR:
5307368Sgblack@eecs.umich.edu                reg = regs.tbisr;
5317368Sgblack@eecs.umich.edu                break;
5327382Sgblack@eecs.umich.edu
5337378Sgblack@eecs.umich.edu              case TANAR:
5347381Sgblack@eecs.umich.edu                reg = regs.tanar;
5357385Sgblack@eecs.umich.edu                break;
5367381Sgblack@eecs.umich.edu
5377378Sgblack@eecs.umich.edu              case TANLPAR:
5387368Sgblack@eecs.umich.edu                reg = regs.tanlpar;
5397368Sgblack@eecs.umich.edu                break;
5407368Sgblack@eecs.umich.edu
5417375Sgblack@eecs.umich.edu              case TANER:
5427368Sgblack@eecs.umich.edu                reg = regs.taner;
5437368Sgblack@eecs.umich.edu                break;
5447375Sgblack@eecs.umich.edu
5457375Sgblack@eecs.umich.edu              case TESR:
5467368Sgblack@eecs.umich.edu                reg = regs.tesr;
5477369Sgblack@eecs.umich.edu                break;
5487369Sgblack@eecs.umich.edu
5497382Sgblack@eecs.umich.edu              default:
5507378Sgblack@eecs.umich.edu                panic("reading unimplemented register: addr=%#x", daddr);
5517381Sgblack@eecs.umich.edu            }
5527385Sgblack@eecs.umich.edu
5537381Sgblack@eecs.umich.edu            DPRINTF(EthernetPIO, "read from %#x: data=%d data=%#x\n",
5547378Sgblack@eecs.umich.edu                    daddr, reg, reg);
5557369Sgblack@eecs.umich.edu        }
5567375Sgblack@eecs.umich.edu        break;
5577369Sgblack@eecs.umich.edu
5587369Sgblack@eecs.umich.edu      default:
5597375Sgblack@eecs.umich.edu        panic("accessing register with invalid size: addr=%#x, size=%d",
5607375Sgblack@eecs.umich.edu              daddr, req->size);
5617369Sgblack@eecs.umich.edu    }
5627369Sgblack@eecs.umich.edu
5637369Sgblack@eecs.umich.edu    return No_Fault;
5647369Sgblack@eecs.umich.edu}
5657369Sgblack@eecs.umich.edu
5667369Sgblack@eecs.umich.eduFault
5677382Sgblack@eecs.umich.eduNSGigE::write(MemReqPtr &req, const uint8_t *data)
5687378Sgblack@eecs.umich.edu{
5697381Sgblack@eecs.umich.edu    assert(ioEnable);
5707385Sgblack@eecs.umich.edu
5717381Sgblack@eecs.umich.edu    Addr daddr = req->paddr & 0xfff;
5727378Sgblack@eecs.umich.edu    DPRINTF(EthernetPIO, "write da=%#x pa=%#x va=%#x size=%d\n",
5737369Sgblack@eecs.umich.edu            daddr, req->paddr, req->vaddr, req->size);
5747369Sgblack@eecs.umich.edu
5757369Sgblack@eecs.umich.edu    if (daddr > LAST && daddr <=  RESERVED) {
5767375Sgblack@eecs.umich.edu        panic("Accessing reserved register");
5777369Sgblack@eecs.umich.edu    } else if (daddr > RESERVED && daddr <= 0x3FC) {
5787369Sgblack@eecs.umich.edu        WriteConfig(daddr & 0xff, req->size, *(uint32_t *)data);
5797375Sgblack@eecs.umich.edu        return No_Fault;
5807375Sgblack@eecs.umich.edu    } else if (daddr > 0x3FC)
5817369Sgblack@eecs.umich.edu        panic("Something is messed up!\n");
5827369Sgblack@eecs.umich.edu
5837369Sgblack@eecs.umich.edu    if (req->size == sizeof(uint32_t)) {
5847382Sgblack@eecs.umich.edu        uint32_t reg = *(uint32_t *)data;
5857378Sgblack@eecs.umich.edu        DPRINTF(EthernetPIO, "write data=%d data=%#x\n", reg, reg);
5867381Sgblack@eecs.umich.edu
5877369Sgblack@eecs.umich.edu        switch (daddr) {
5887381Sgblack@eecs.umich.edu          case CR:
5897378Sgblack@eecs.umich.edu            regs.command = reg;
5907369Sgblack@eecs.umich.edu            if (reg & CR_TXD) {
5917369Sgblack@eecs.umich.edu                txEnable = false;
5927369Sgblack@eecs.umich.edu            } else if (reg & CR_TXE) {
5937369Sgblack@eecs.umich.edu                txEnable = true;
5947375Sgblack@eecs.umich.edu
5957369Sgblack@eecs.umich.edu                // the kernel is enabling the transmit machine
5967369Sgblack@eecs.umich.edu                if (txState == txIdle)
5977375Sgblack@eecs.umich.edu                    txKick();
5987375Sgblack@eecs.umich.edu            }
5997369Sgblack@eecs.umich.edu
6007369Sgblack@eecs.umich.edu            if (reg & CR_RXD) {
6017369Sgblack@eecs.umich.edu                rxEnable = false;
6027369Sgblack@eecs.umich.edu            } else if (reg & CR_RXE) {
6037369Sgblack@eecs.umich.edu                rxEnable = true;
6047382Sgblack@eecs.umich.edu
6057378Sgblack@eecs.umich.edu                if (rxState == rxIdle)
6067381Sgblack@eecs.umich.edu                    rxKick();
6077369Sgblack@eecs.umich.edu            }
6087381Sgblack@eecs.umich.edu
6097378Sgblack@eecs.umich.edu            if (reg & CR_TXR)
6107369Sgblack@eecs.umich.edu                txReset();
6117369Sgblack@eecs.umich.edu
6127369Sgblack@eecs.umich.edu            if (reg & CR_RXR)
6137369Sgblack@eecs.umich.edu                rxReset();
6147369Sgblack@eecs.umich.edu
6157369Sgblack@eecs.umich.edu            if (reg & CR_SWI)
6167375Sgblack@eecs.umich.edu                devIntrPost(ISR_SWI);
6177369Sgblack@eecs.umich.edu
6187369Sgblack@eecs.umich.edu            if (reg & CR_RST) {
6197375Sgblack@eecs.umich.edu                txReset();
6207375Sgblack@eecs.umich.edu                rxReset();
6217369Sgblack@eecs.umich.edu
6227381Sgblack@eecs.umich.edu                regsReset();
6237381Sgblack@eecs.umich.edu            }
6247381Sgblack@eecs.umich.edu            break;
6257381Sgblack@eecs.umich.edu
6267381Sgblack@eecs.umich.edu          case CFG:
6277381Sgblack@eecs.umich.edu            if (reg & CFG_LNKSTS ||
6287381Sgblack@eecs.umich.edu                reg & CFG_SPDSTS ||
6297370Sgblack@eecs.umich.edu                reg & CFG_DUPSTS ||
6307370Sgblack@eecs.umich.edu                reg & CFG_RESERVED ||
6317382Sgblack@eecs.umich.edu                reg & CFG_T64ADDR ||
6327378Sgblack@eecs.umich.edu                reg & CFG_PCI64_DET)
6337381Sgblack@eecs.umich.edu                panic("writing to read-only or reserved CFG bits!\n");
6347385Sgblack@eecs.umich.edu
6357370Sgblack@eecs.umich.edu            regs.config |= reg & ~(CFG_LNKSTS | CFG_SPDSTS | CFG_DUPSTS |
6367370Sgblack@eecs.umich.edu                                   CFG_RESERVED | CFG_T64ADDR | CFG_PCI64_DET);
6377370Sgblack@eecs.umich.edu
6387382Sgblack@eecs.umich.edu// all these #if 0's are because i don't THINK the kernel needs to
6397385Sgblack@eecs.umich.edu// have these implemented. if there is a problem relating to one of
6407381Sgblack@eecs.umich.edu// these, you may need to add functionality in.
6417378Sgblack@eecs.umich.edu#if 0
6427370Sgblack@eecs.umich.edu            if (reg & CFG_TBI_EN) ;
6437375Sgblack@eecs.umich.edu            if (reg & CFG_MODE_1000) ;
6447370Sgblack@eecs.umich.edu#endif
6457370Sgblack@eecs.umich.edu
6467375Sgblack@eecs.umich.edu            if (reg & CFG_AUTO_1000)
6477375Sgblack@eecs.umich.edu                panic("CFG_AUTO_1000 not implemented!\n");
6487370Sgblack@eecs.umich.edu
6497370Sgblack@eecs.umich.edu#if 0
6507370Sgblack@eecs.umich.edu            if (reg & CFG_PINT_DUPSTS ||
6517370Sgblack@eecs.umich.edu                reg & CFG_PINT_LNKSTS ||
6527370Sgblack@eecs.umich.edu                reg & CFG_PINT_SPDSTS)
6537370Sgblack@eecs.umich.edu                ;
6547370Sgblack@eecs.umich.edu
6557382Sgblack@eecs.umich.edu            if (reg & CFG_TMRTEST) ;
6567378Sgblack@eecs.umich.edu            if (reg & CFG_MRM_DIS) ;
6577381Sgblack@eecs.umich.edu            if (reg & CFG_MWI_DIS) ;
6587385Sgblack@eecs.umich.edu
6597370Sgblack@eecs.umich.edu            if (reg & CFG_T64ADDR)
6607370Sgblack@eecs.umich.edu                panic("CFG_T64ADDR is read only register!\n");
6617370Sgblack@eecs.umich.edu
6627370Sgblack@eecs.umich.edu            if (reg & CFG_PCI64_DET)
6637382Sgblack@eecs.umich.edu                panic("CFG_PCI64_DET is read only register!\n");
6647385Sgblack@eecs.umich.edu
6657381Sgblack@eecs.umich.edu            if (reg & CFG_DATA64_EN) ;
6667378Sgblack@eecs.umich.edu            if (reg & CFG_M64ADDR) ;
6677370Sgblack@eecs.umich.edu            if (reg & CFG_PHY_RST) ;
6687370Sgblack@eecs.umich.edu            if (reg & CFG_PHY_DIS) ;
6697370Sgblack@eecs.umich.edu#endif
6707375Sgblack@eecs.umich.edu
6717370Sgblack@eecs.umich.edu            if (reg & CFG_EXTSTS_EN)
6727370Sgblack@eecs.umich.edu                extstsEnable = true;
6737375Sgblack@eecs.umich.edu            else
6747375Sgblack@eecs.umich.edu                extstsEnable = false;
6757370Sgblack@eecs.umich.edu
6767370Sgblack@eecs.umich.edu#if 0
6777370Sgblack@eecs.umich.edu              if (reg & CFG_REQALG) ;
6787382Sgblack@eecs.umich.edu              if (reg & CFG_SB) ;
6797378Sgblack@eecs.umich.edu              if (reg & CFG_POW) ;
6807381Sgblack@eecs.umich.edu              if (reg & CFG_EXD) ;
6817385Sgblack@eecs.umich.edu              if (reg & CFG_PESEL) ;
6827370Sgblack@eecs.umich.edu              if (reg & CFG_BROM_DIS) ;
6837370Sgblack@eecs.umich.edu              if (reg & CFG_EXT_125) ;
6847370Sgblack@eecs.umich.edu              if (reg & CFG_BEM) ;
6857382Sgblack@eecs.umich.edu#endif
6867386Sgblack@eecs.umich.edu            break;
6877381Sgblack@eecs.umich.edu
6887378Sgblack@eecs.umich.edu          case MEAR:
6897370Sgblack@eecs.umich.edu            regs.mear = reg;
6907375Sgblack@eecs.umich.edu            // since phy is completely faked, MEAR_MD* don't matter
6917370Sgblack@eecs.umich.edu            // and since the driver never uses MEAR_EE*, they don't
6927370Sgblack@eecs.umich.edu            // matter
6937375Sgblack@eecs.umich.edu#if 0
6947375Sgblack@eecs.umich.edu            if (reg & MEAR_EEDI) ;
6957370Sgblack@eecs.umich.edu            if (reg & MEAR_EEDO) ; // this one is read only
6967370Sgblack@eecs.umich.edu            if (reg & MEAR_EECLK) ;
6977370Sgblack@eecs.umich.edu            if (reg & MEAR_EESEL) ;
6987370Sgblack@eecs.umich.edu            if (reg & MEAR_MDIO) ;
6997370Sgblack@eecs.umich.edu            if (reg & MEAR_MDDIR) ;
7007370Sgblack@eecs.umich.edu            if (reg & MEAR_MDC) ;
7017370Sgblack@eecs.umich.edu#endif
7027382Sgblack@eecs.umich.edu            break;
7037378Sgblack@eecs.umich.edu
7047381Sgblack@eecs.umich.edu          case PTSCR:
7057385Sgblack@eecs.umich.edu            regs.ptscr = reg & ~(PTSCR_RBIST_RDONLY);
7067370Sgblack@eecs.umich.edu            // these control BISTs for various parts of chip - we
7077370Sgblack@eecs.umich.edu            // don't care or do just fake that the BIST is done
7087370Sgblack@eecs.umich.edu            if (reg & PTSCR_RBIST_EN)
7097370Sgblack@eecs.umich.edu                regs.ptscr |= PTSCR_RBIST_DONE;
7107386Sgblack@eecs.umich.edu            if (reg & PTSCR_EEBIST_EN)
7117382Sgblack@eecs.umich.edu                regs.ptscr &= ~PTSCR_EEBIST_EN;
7127381Sgblack@eecs.umich.edu            if (reg & PTSCR_EELOAD_EN)
7137378Sgblack@eecs.umich.edu                regs.ptscr &= ~PTSCR_EELOAD_EN;
7147370Sgblack@eecs.umich.edu            break;
7157370Sgblack@eecs.umich.edu
7167370Sgblack@eecs.umich.edu          case ISR: /* writing to the ISR has no effect */
7177375Sgblack@eecs.umich.edu            panic("ISR is a read only register!\n");
7187370Sgblack@eecs.umich.edu
7197370Sgblack@eecs.umich.edu          case IMR:
7207375Sgblack@eecs.umich.edu            regs.imr = reg;
7217375Sgblack@eecs.umich.edu            devIntrChangeMask();
7227370Sgblack@eecs.umich.edu            break;
7237371Sgblack@eecs.umich.edu
7247371Sgblack@eecs.umich.edu          case IER:
7257382Sgblack@eecs.umich.edu            regs.ier = reg;
7267378Sgblack@eecs.umich.edu            break;
7277381Sgblack@eecs.umich.edu
7287385Sgblack@eecs.umich.edu          case IHR:
7297371Sgblack@eecs.umich.edu            regs.ihr = reg;
7307371Sgblack@eecs.umich.edu            /* not going to implement real interrupt holdoff */
7317371Sgblack@eecs.umich.edu            break;
7327382Sgblack@eecs.umich.edu
7337386Sgblack@eecs.umich.edu          case TXDP:
7347381Sgblack@eecs.umich.edu            regs.txdp = (reg & 0xFFFFFFFC);
7357378Sgblack@eecs.umich.edu            assert(txState == txIdle);
7367371Sgblack@eecs.umich.edu            CTDD = false;
7377375Sgblack@eecs.umich.edu            break;
7387371Sgblack@eecs.umich.edu
7397371Sgblack@eecs.umich.edu          case TXDP_HI:
7407375Sgblack@eecs.umich.edu            regs.txdp_hi = reg;
7417375Sgblack@eecs.umich.edu            break;
7427371Sgblack@eecs.umich.edu
7437371Sgblack@eecs.umich.edu          case TXCFG:
7447371Sgblack@eecs.umich.edu            regs.txcfg = reg;
7457371Sgblack@eecs.umich.edu#if 0
7467371Sgblack@eecs.umich.edu            if (reg & TXCFG_CSI) ;
7477371Sgblack@eecs.umich.edu            if (reg & TXCFG_HBI) ;
7487371Sgblack@eecs.umich.edu            if (reg & TXCFG_MLB) ;
7497382Sgblack@eecs.umich.edu            if (reg & TXCFG_ATP) ;
7507378Sgblack@eecs.umich.edu            if (reg & TXCFG_ECRETRY) {
7517381Sgblack@eecs.umich.edu                /*
7527385Sgblack@eecs.umich.edu                 * this could easily be implemented, but considering
7537371Sgblack@eecs.umich.edu                 * the network is just a fake pipe, wouldn't make
7547371Sgblack@eecs.umich.edu                 * sense to do this
7557371Sgblack@eecs.umich.edu                 */
7567371Sgblack@eecs.umich.edu            }
7577382Sgblack@eecs.umich.edu
7587386Sgblack@eecs.umich.edu            if (reg & TXCFG_BRST_DIS) ;
7597381Sgblack@eecs.umich.edu#endif
7607378Sgblack@eecs.umich.edu
7617371Sgblack@eecs.umich.edu#if 0
7627371Sgblack@eecs.umich.edu            /* we handle our own DMA, ignore the kernel's exhortations */
7637371Sgblack@eecs.umich.edu            if (reg & TXCFG_MXDMA) ;
7647375Sgblack@eecs.umich.edu#endif
7657371Sgblack@eecs.umich.edu
7667371Sgblack@eecs.umich.edu            // also, we currently don't care about fill/drain
7677375Sgblack@eecs.umich.edu            // thresholds though this may change in the future with
7687375Sgblack@eecs.umich.edu            // more realistic networks or a driver which changes it
7697371Sgblack@eecs.umich.edu            // according to feedback
7707371Sgblack@eecs.umich.edu
7717371Sgblack@eecs.umich.edu            break;
7727382Sgblack@eecs.umich.edu
7737378Sgblack@eecs.umich.edu          case GPIOR:
7747381Sgblack@eecs.umich.edu            regs.gpior = reg;
7757385Sgblack@eecs.umich.edu            /* these just control general purpose i/o pins, don't matter */
7767371Sgblack@eecs.umich.edu            break;
7777371Sgblack@eecs.umich.edu
7787371Sgblack@eecs.umich.edu          case RXDP:
7797382Sgblack@eecs.umich.edu            regs.rxdp = reg;
7807386Sgblack@eecs.umich.edu            CRDD = false;
7817381Sgblack@eecs.umich.edu            break;
7827378Sgblack@eecs.umich.edu
7837371Sgblack@eecs.umich.edu          case RXDP_HI:
7847375Sgblack@eecs.umich.edu            regs.rxdp_hi = reg;
7857371Sgblack@eecs.umich.edu            break;
7867371Sgblack@eecs.umich.edu
7877375Sgblack@eecs.umich.edu          case RXCFG:
7887375Sgblack@eecs.umich.edu            regs.rxcfg = reg;
7897371Sgblack@eecs.umich.edu#if 0
7907371Sgblack@eecs.umich.edu            if (reg & RXCFG_AEP) ;
7917371Sgblack@eecs.umich.edu            if (reg & RXCFG_ARP) ;
7927371Sgblack@eecs.umich.edu            if (reg & RXCFG_STRIPCRC) ;
7937371Sgblack@eecs.umich.edu            if (reg & RXCFG_RX_RD) ;
7947371Sgblack@eecs.umich.edu            if (reg & RXCFG_ALP) ;
7957371Sgblack@eecs.umich.edu            if (reg & RXCFG_AIRL) ;
7967382Sgblack@eecs.umich.edu
7977378Sgblack@eecs.umich.edu            /* we handle our own DMA, ignore what kernel says about it */
7987381Sgblack@eecs.umich.edu            if (reg & RXCFG_MXDMA) ;
7997385Sgblack@eecs.umich.edu
8007371Sgblack@eecs.umich.edu            //also, we currently don't care about fill/drain thresholds
8017371Sgblack@eecs.umich.edu            //though this may change in the future with more realistic
8027371Sgblack@eecs.umich.edu            //networks or a driver which changes it according to feedback
8037371Sgblack@eecs.umich.edu            if (reg & (RXCFG_DRTH | RXCFG_DRTH0)) ;
8047382Sgblack@eecs.umich.edu#endif
8057386Sgblack@eecs.umich.edu            break;
8067381Sgblack@eecs.umich.edu
8077378Sgblack@eecs.umich.edu          case PQCR:
8087371Sgblack@eecs.umich.edu            /* there is no priority queueing used in the linux 2.6 driver */
8097371Sgblack@eecs.umich.edu            regs.pqcr = reg;
8107371Sgblack@eecs.umich.edu            break;
8117375Sgblack@eecs.umich.edu
8127371Sgblack@eecs.umich.edu          case WCSR:
8137371Sgblack@eecs.umich.edu            /* not going to implement wake on LAN */
8147375Sgblack@eecs.umich.edu            regs.wcsr = reg;
8157375Sgblack@eecs.umich.edu            break;
8167371Sgblack@eecs.umich.edu
8177371Sgblack@eecs.umich.edu          case PCR:
8187371Sgblack@eecs.umich.edu            /* not going to implement pause control */
8197382Sgblack@eecs.umich.edu            regs.pcr = reg;
8207378Sgblack@eecs.umich.edu            break;
8217381Sgblack@eecs.umich.edu
8227385Sgblack@eecs.umich.edu          case RFCR:
8237371Sgblack@eecs.umich.edu            regs.rfcr = reg;
8247371Sgblack@eecs.umich.edu
8257371Sgblack@eecs.umich.edu            rxFilterEnable = (reg & RFCR_RFEN) ? true : false;
8267371Sgblack@eecs.umich.edu            acceptBroadcast = (reg & RFCR_AAB) ? true : false;
8277381Sgblack@eecs.umich.edu            acceptMulticast = (reg & RFCR_AAM) ? true : false;
8287378Sgblack@eecs.umich.edu            acceptUnicast = (reg & RFCR_AAU) ? true : false;
8297371Sgblack@eecs.umich.edu            acceptPerfect = (reg & RFCR_APM) ? true : false;
8307375Sgblack@eecs.umich.edu            acceptArp = (reg & RFCR_AARP) ? true : false;
8317371Sgblack@eecs.umich.edu
8327371Sgblack@eecs.umich.edu#if 0
8337375Sgblack@eecs.umich.edu            if (reg & RFCR_APAT)
8347375Sgblack@eecs.umich.edu                panic("RFCR_APAT not implemented!\n");
8357371Sgblack@eecs.umich.edu#endif
8367371Sgblack@eecs.umich.edu
8377371Sgblack@eecs.umich.edu            if (reg & RFCR_MHEN || reg & RFCR_UHEN)
8387371Sgblack@eecs.umich.edu                panic("hash filtering not implemented!\n");
8397371Sgblack@eecs.umich.edu
8407371Sgblack@eecs.umich.edu            if (reg & RFCR_ULM)
8417371Sgblack@eecs.umich.edu                panic("RFCR_ULM not implemented!\n");
8427382Sgblack@eecs.umich.edu
8437378Sgblack@eecs.umich.edu            break;
8447381Sgblack@eecs.umich.edu
8457385Sgblack@eecs.umich.edu          case RFDR:
8467371Sgblack@eecs.umich.edu            panic("the driver never writes to RFDR, something is wrong!\n");
8477371Sgblack@eecs.umich.edu
8487371Sgblack@eecs.umich.edu          case BRAR:
8497371Sgblack@eecs.umich.edu            panic("the driver never uses BRAR, something is wrong!\n");
8507371Sgblack@eecs.umich.edu
8517381Sgblack@eecs.umich.edu          case BRDR:
8527378Sgblack@eecs.umich.edu            panic("the driver never uses BRDR, something is wrong!\n");
8537371Sgblack@eecs.umich.edu
8547371Sgblack@eecs.umich.edu          case SRR:
8557371Sgblack@eecs.umich.edu            panic("SRR is read only register!\n");
8567375Sgblack@eecs.umich.edu
8577371Sgblack@eecs.umich.edu          case MIBC:
8587371Sgblack@eecs.umich.edu            panic("the driver never uses MIBC, something is wrong!\n");
8597375Sgblack@eecs.umich.edu
8607375Sgblack@eecs.umich.edu          case VRCR:
8617371Sgblack@eecs.umich.edu            regs.vrcr = reg;
8627381Sgblack@eecs.umich.edu            break;
8637381Sgblack@eecs.umich.edu
8647381Sgblack@eecs.umich.edu          case VTCR:
8657381Sgblack@eecs.umich.edu            regs.vtcr = reg;
8667381Sgblack@eecs.umich.edu            break;
8677381Sgblack@eecs.umich.edu
8687381Sgblack@eecs.umich.edu          case VDR:
8697373Sgblack@eecs.umich.edu            panic("the driver never uses VDR, something is wrong!\n");
8707373Sgblack@eecs.umich.edu            break;
8717378Sgblack@eecs.umich.edu
8727381Sgblack@eecs.umich.edu          case CCSR:
8737373Sgblack@eecs.umich.edu            /* not going to implement clockrun stuff */
8747381Sgblack@eecs.umich.edu            regs.ccsr = reg;
8757378Sgblack@eecs.umich.edu            break;
8767373Sgblack@eecs.umich.edu
8777375Sgblack@eecs.umich.edu          case TBICR:
8787373Sgblack@eecs.umich.edu            regs.tbicr = reg;
8797373Sgblack@eecs.umich.edu            if (reg & TBICR_MR_LOOPBACK)
8807375Sgblack@eecs.umich.edu                panic("TBICR_MR_LOOPBACK never used, something wrong!\n");
8817375Sgblack@eecs.umich.edu
8827373Sgblack@eecs.umich.edu            if (reg & TBICR_MR_AN_ENABLE) {
8837373Sgblack@eecs.umich.edu                regs.tanlpar = regs.tanar;
8847373Sgblack@eecs.umich.edu                regs.tbisr |= (TBISR_MR_AN_COMPLETE | TBISR_MR_LINK_STATUS);
8857373Sgblack@eecs.umich.edu            }
8867378Sgblack@eecs.umich.edu
8877381Sgblack@eecs.umich.edu#if 0
8887373Sgblack@eecs.umich.edu            if (reg & TBICR_MR_RESTART_AN) ;
8897381Sgblack@eecs.umich.edu#endif
8907378Sgblack@eecs.umich.edu
8917373Sgblack@eecs.umich.edu            break;
8927373Sgblack@eecs.umich.edu
8937373Sgblack@eecs.umich.edu          case TBISR:
8947375Sgblack@eecs.umich.edu            panic("TBISR is read only register!\n");
8957373Sgblack@eecs.umich.edu
8967373Sgblack@eecs.umich.edu          case TANAR:
8977375Sgblack@eecs.umich.edu            regs.tanar = reg;
8987375Sgblack@eecs.umich.edu            if (reg & TANAR_PS2)
8997373Sgblack@eecs.umich.edu                panic("this isn't used in driver, something wrong!\n");
9007373Sgblack@eecs.umich.edu
9017373Sgblack@eecs.umich.edu            if (reg & TANAR_PS1)
9027378Sgblack@eecs.umich.edu                panic("this isn't used in driver, something wrong!\n");
9037381Sgblack@eecs.umich.edu            break;
9047373Sgblack@eecs.umich.edu
9057381Sgblack@eecs.umich.edu          case TANLPAR:
9067378Sgblack@eecs.umich.edu            panic("this should only be written to by the fake phy!\n");
9077373Sgblack@eecs.umich.edu
9087375Sgblack@eecs.umich.edu          case TANER:
9097373Sgblack@eecs.umich.edu            panic("TANER is read only register!\n");
9107373Sgblack@eecs.umich.edu
9117375Sgblack@eecs.umich.edu          case TESR:
9127375Sgblack@eecs.umich.edu            regs.tesr = reg;
9137373Sgblack@eecs.umich.edu            break;
9147373Sgblack@eecs.umich.edu
9157373Sgblack@eecs.umich.edu          default:
9167373Sgblack@eecs.umich.edu            panic("invalid register access daddr=%#x", daddr);
9177378Sgblack@eecs.umich.edu        }
9187381Sgblack@eecs.umich.edu    } else {
9197373Sgblack@eecs.umich.edu        panic("Invalid Request Size");
9207381Sgblack@eecs.umich.edu    }
9217378Sgblack@eecs.umich.edu
9227373Sgblack@eecs.umich.edu    return No_Fault;
9237373Sgblack@eecs.umich.edu}
9247373Sgblack@eecs.umich.edu
9257375Sgblack@eecs.umich.eduvoid
9267373Sgblack@eecs.umich.eduNSGigE::devIntrPost(uint32_t interrupts)
9277373Sgblack@eecs.umich.edu{
9287375Sgblack@eecs.umich.edu    bool delay = false;
9297375Sgblack@eecs.umich.edu
9307373Sgblack@eecs.umich.edu    if (interrupts & ISR_RESERVE)
9317373Sgblack@eecs.umich.edu        panic("Cannot set a reserved interrupt");
9327380Sgblack@eecs.umich.edu
9337382Sgblack@eecs.umich.edu    if (interrupts & ISR_TXRCMP)
9347380Sgblack@eecs.umich.edu        regs.isr |= ISR_TXRCMP;
9357381Sgblack@eecs.umich.edu
9367388Sgblack@eecs.umich.edu    if (interrupts & ISR_RXRCMP)
9377381Sgblack@eecs.umich.edu        regs.isr |= ISR_RXRCMP;
9387380Sgblack@eecs.umich.edu
9397380Sgblack@eecs.umich.edu//ISR_DPERR  not implemented
9407380Sgblack@eecs.umich.edu//ISR_SSERR not implemented
9417380Sgblack@eecs.umich.edu//ISR_RMABT not implemented
9427380Sgblack@eecs.umich.edu//ISR_RXSOVR not implemented
9437380Sgblack@eecs.umich.edu//ISR_HIBINT not implemented
9447380Sgblack@eecs.umich.edu//ISR_PHY not implemented
9457380Sgblack@eecs.umich.edu//ISR_PME not implemented
9467380Sgblack@eecs.umich.edu
9477380Sgblack@eecs.umich.edu    if (interrupts & ISR_SWI)
9487380Sgblack@eecs.umich.edu        regs.isr |= ISR_SWI;
9497380Sgblack@eecs.umich.edu
9507382Sgblack@eecs.umich.edu//ISR_MIB not implemented
9517380Sgblack@eecs.umich.edu//ISR_TXURN not implemented
9527381Sgblack@eecs.umich.edu
9537388Sgblack@eecs.umich.edu    if (interrupts & ISR_TXIDLE)
9547381Sgblack@eecs.umich.edu        regs.isr |= ISR_TXIDLE;
9557380Sgblack@eecs.umich.edu
9567380Sgblack@eecs.umich.edu    if (interrupts & ISR_TXERR)
9577380Sgblack@eecs.umich.edu        regs.isr |= ISR_TXERR;
9587380Sgblack@eecs.umich.edu
9597380Sgblack@eecs.umich.edu    if (interrupts & ISR_TXDESC)
9607380Sgblack@eecs.umich.edu        regs.isr |= ISR_TXDESC;
9617380Sgblack@eecs.umich.edu
9627380Sgblack@eecs.umich.edu    if (interrupts & ISR_TXOK) {
9637380Sgblack@eecs.umich.edu        regs.isr |= ISR_TXOK;
9647380Sgblack@eecs.umich.edu        delay = true;
9657380Sgblack@eecs.umich.edu    }
9667382Sgblack@eecs.umich.edu
9677380Sgblack@eecs.umich.edu    if (interrupts & ISR_RXORN)
9687381Sgblack@eecs.umich.edu        regs.isr |= ISR_RXORN;
9697388Sgblack@eecs.umich.edu
9707381Sgblack@eecs.umich.edu    if (interrupts & ISR_RXIDLE)
9717380Sgblack@eecs.umich.edu        regs.isr |= ISR_RXIDLE;
9727380Sgblack@eecs.umich.edu
9737380Sgblack@eecs.umich.edu//ISR_RXEARLY not implemented
9747380Sgblack@eecs.umich.edu
9757380Sgblack@eecs.umich.edu    if (interrupts & ISR_RXERR)
9767380Sgblack@eecs.umich.edu        regs.isr |= ISR_RXERR;
9777380Sgblack@eecs.umich.edu
9787380Sgblack@eecs.umich.edu    if (interrupts & ISR_RXDESC)
9797380Sgblack@eecs.umich.edu        regs.isr |= ISR_RXDESC;
9807380Sgblack@eecs.umich.edu
9817380Sgblack@eecs.umich.edu    if (interrupts & ISR_RXOK) {
9827380Sgblack@eecs.umich.edu        delay = true;
9837382Sgblack@eecs.umich.edu        regs.isr |= ISR_RXOK;
9847380Sgblack@eecs.umich.edu    }
9857381Sgblack@eecs.umich.edu
9867388Sgblack@eecs.umich.edu    if ((regs.isr & regs.imr)) {
9877381Sgblack@eecs.umich.edu        Tick when = curTick;
9887380Sgblack@eecs.umich.edu        if (delay)
9897380Sgblack@eecs.umich.edu            when += intrDelay;
9907380Sgblack@eecs.umich.edu        cpuIntrPost(when);
9917380Sgblack@eecs.umich.edu    }
9927380Sgblack@eecs.umich.edu
9937380Sgblack@eecs.umich.edu    DPRINTF(EthernetIntr,
9947380Sgblack@eecs.umich.edu            "interrupt written to ISR: intr=%#x isr=%#x imr=%#x\n",
9957380Sgblack@eecs.umich.edu            interrupts, regs.isr, regs.imr);
9967380Sgblack@eecs.umich.edu}
9977380Sgblack@eecs.umich.edu
9987373Sgblack@eecs.umich.eduvoid
9997382Sgblack@eecs.umich.eduNSGigE::devIntrClear(uint32_t interrupts)
10007378Sgblack@eecs.umich.edu{
10017380Sgblack@eecs.umich.edu    if (interrupts & ISR_RESERVE)
10027381Sgblack@eecs.umich.edu        panic("Cannot clear a reserved interrupt");
10037387Sgblack@eecs.umich.edu
10047381Sgblack@eecs.umich.edu    if (interrupts & ISR_TXRCMP)
10057378Sgblack@eecs.umich.edu        regs.isr &= ~ISR_TXRCMP;
10067373Sgblack@eecs.umich.edu
10077375Sgblack@eecs.umich.edu    if (interrupts & ISR_RXRCMP)
10087373Sgblack@eecs.umich.edu        regs.isr &= ~ISR_RXRCMP;
10097373Sgblack@eecs.umich.edu
10107375Sgblack@eecs.umich.edu//ISR_DPERR  not implemented
10117375Sgblack@eecs.umich.edu//ISR_SSERR not implemented
10127373Sgblack@eecs.umich.edu//ISR_RMABT not implemented
10137373Sgblack@eecs.umich.edu//ISR_RXSOVR not implemented
10147373Sgblack@eecs.umich.edu//ISR_HIBINT not implemented
10157373Sgblack@eecs.umich.edu//ISR_PHY not implemented
10167373Sgblack@eecs.umich.edu//ISR_PME not implemented
10177382Sgblack@eecs.umich.edu
10187378Sgblack@eecs.umich.edu    if (interrupts & ISR_SWI)
10197380Sgblack@eecs.umich.edu        regs.isr &= ~ISR_SWI;
10207381Sgblack@eecs.umich.edu
10217387Sgblack@eecs.umich.edu//ISR_MIB not implemented
10227381Sgblack@eecs.umich.edu//ISR_TXURN not implemented
10237378Sgblack@eecs.umich.edu
10247373Sgblack@eecs.umich.edu    if (interrupts & ISR_TXIDLE)
10257373Sgblack@eecs.umich.edu        regs.isr &= ~ISR_TXIDLE;
10267375Sgblack@eecs.umich.edu
10277373Sgblack@eecs.umich.edu    if (interrupts & ISR_TXERR)
10287373Sgblack@eecs.umich.edu        regs.isr &= ~ISR_TXERR;
10297375Sgblack@eecs.umich.edu
10307375Sgblack@eecs.umich.edu    if (interrupts & ISR_TXDESC)
10317373Sgblack@eecs.umich.edu        regs.isr &= ~ISR_TXDESC;
10327373Sgblack@eecs.umich.edu
10337373Sgblack@eecs.umich.edu    if (interrupts & ISR_TXOK)
10347382Sgblack@eecs.umich.edu        regs.isr &= ~ISR_TXOK;
10357378Sgblack@eecs.umich.edu
10367380Sgblack@eecs.umich.edu    if (interrupts & ISR_RXORN)
10377381Sgblack@eecs.umich.edu        regs.isr &= ~ISR_RXORN;
10387387Sgblack@eecs.umich.edu
10397381Sgblack@eecs.umich.edu    if (interrupts & ISR_RXIDLE)
10407378Sgblack@eecs.umich.edu        regs.isr &= ~ISR_RXIDLE;
10417373Sgblack@eecs.umich.edu
10427375Sgblack@eecs.umich.edu//ISR_RXEARLY not implemented
10437373Sgblack@eecs.umich.edu
10447373Sgblack@eecs.umich.edu    if (interrupts & ISR_RXERR)
10457375Sgblack@eecs.umich.edu        regs.isr &= ~ISR_RXERR;
10467375Sgblack@eecs.umich.edu
10477373Sgblack@eecs.umich.edu    if (interrupts & ISR_RXDESC)
10487373Sgblack@eecs.umich.edu        regs.isr &= ~ISR_RXDESC;
10497373Sgblack@eecs.umich.edu
10507373Sgblack@eecs.umich.edu    if (interrupts & ISR_RXOK)
10517373Sgblack@eecs.umich.edu        regs.isr &= ~ISR_RXOK;
10527382Sgblack@eecs.umich.edu
10537378Sgblack@eecs.umich.edu    DPRINTF(EthernetIntr,
10547380Sgblack@eecs.umich.edu            "interrupt cleared from ISR: intr=%x isr=%x imr=%x\n",
10557381Sgblack@eecs.umich.edu            interrupts, regs.isr, regs.imr);
10567387Sgblack@eecs.umich.edu
10577381Sgblack@eecs.umich.edu    if (!(regs.isr & regs.imr))
10587378Sgblack@eecs.umich.edu        cpuIntrClear();
10597373Sgblack@eecs.umich.edu}
10607373Sgblack@eecs.umich.edu
10617375Sgblack@eecs.umich.eduvoid
10627373Sgblack@eecs.umich.eduNSGigE::devIntrChangeMask()
10637373Sgblack@eecs.umich.edu{
10647375Sgblack@eecs.umich.edu    DPRINTF(EthernetIntr, "interrupt mask changed: isr=%x imr=%x masked=%x\n",
10657375Sgblack@eecs.umich.edu            regs.isr, regs.imr, regs.isr & regs.imr);
10667373Sgblack@eecs.umich.edu
10677374Sgblack@eecs.umich.edu    if (regs.isr & regs.imr)
10687374Sgblack@eecs.umich.edu        cpuIntrPost(curTick);
10697374Sgblack@eecs.umich.edu    else
10707382Sgblack@eecs.umich.edu        cpuIntrClear();
10717378Sgblack@eecs.umich.edu}
10727381Sgblack@eecs.umich.edu
10737374Sgblack@eecs.umich.eduvoid
10747381Sgblack@eecs.umich.eduNSGigE::cpuIntrPost(Tick when)
10757378Sgblack@eecs.umich.edu{
10767374Sgblack@eecs.umich.edu    // If the interrupt you want to post is later than an interrupt
10777374Sgblack@eecs.umich.edu    // already scheduled, just let it post in the coming one and don't
10787374Sgblack@eecs.umich.edu    // schedule another.
10797375Sgblack@eecs.umich.edu    // HOWEVER, must be sure that the scheduled intrTick is in the
10807374Sgblack@eecs.umich.edu    // future (this was formerly the source of a bug)
10817374Sgblack@eecs.umich.edu    /**
10827375Sgblack@eecs.umich.edu     * @todo this warning should be removed and the intrTick code should
10837375Sgblack@eecs.umich.edu     * be fixed.
10847374Sgblack@eecs.umich.edu     */
10857374Sgblack@eecs.umich.edu    if (intrTick < curTick && intrTick != 0) {
10867374Sgblack@eecs.umich.edu        warn("intrTick < curTick !!!  intrTick=%d curTick=%d\n",
10877374Sgblack@eecs.umich.edu             intrTick, curTick);
10887374Sgblack@eecs.umich.edu        intrTick = 0;
10897382Sgblack@eecs.umich.edu    }
10907378Sgblack@eecs.umich.edu    assert((intrTick >= curTick) || (intrTick == 0));
10917381Sgblack@eecs.umich.edu    if (when > intrTick && intrTick != 0)
10927386Sgblack@eecs.umich.edu        return;
10937381Sgblack@eecs.umich.edu
10947378Sgblack@eecs.umich.edu    intrTick = when;
10957374Sgblack@eecs.umich.edu
10967375Sgblack@eecs.umich.edu    if (intrEvent) {
10977374Sgblack@eecs.umich.edu        intrEvent->squash();
10987374Sgblack@eecs.umich.edu        intrEvent = 0;
10997375Sgblack@eecs.umich.edu    }
11007375Sgblack@eecs.umich.edu
11017374Sgblack@eecs.umich.edu    if (when < curTick) {
11027377Sgblack@eecs.umich.edu        cpuInterrupt();
11037377Sgblack@eecs.umich.edu    } else {
11047389Sgblack@eecs.umich.edu        DPRINTF(EthernetIntr,
11057377Sgblack@eecs.umich.edu                "going to schedule an interrupt for intrTick=%d\n",
11067377Sgblack@eecs.umich.edu                intrTick);
11077377Sgblack@eecs.umich.edu        intrEvent = new IntrEvent(this, true);
11087377Sgblack@eecs.umich.edu        intrEvent->schedule(intrTick);
11097377Sgblack@eecs.umich.edu    }
11107377Sgblack@eecs.umich.edu}
11117377Sgblack@eecs.umich.edu
11127377Sgblack@eecs.umich.eduvoid
11137389Sgblack@eecs.umich.eduNSGigE::cpuInterrupt()
11147389Sgblack@eecs.umich.edu{
11157389Sgblack@eecs.umich.edu    // Don't send an interrupt if there's already one
11167389Sgblack@eecs.umich.edu    if (cpuPendingIntr) {
11177389Sgblack@eecs.umich.edu        DPRINTF(EthernetIntr,
11187389Sgblack@eecs.umich.edu                "would send an interrupt now, but there's already pending\n");
11197389Sgblack@eecs.umich.edu        intrTick = 0;
11207389Sgblack@eecs.umich.edu        return;
11217389Sgblack@eecs.umich.edu    }
11227389Sgblack@eecs.umich.edu    // Don't send an interrupt if it's supposed to be delayed
11237389Sgblack@eecs.umich.edu    if (intrTick > curTick) {
11247389Sgblack@eecs.umich.edu        DPRINTF(EthernetIntr,
11257389Sgblack@eecs.umich.edu                "an interrupt is scheduled for %d, wait til then\n",
11267389Sgblack@eecs.umich.edu                intrTick);
11277377Sgblack@eecs.umich.edu        return;
11287377Sgblack@eecs.umich.edu    }
11297377Sgblack@eecs.umich.edu
11307377Sgblack@eecs.umich.edu    // Whether or not there's a pending interrupt, we don't care about
11317377Sgblack@eecs.umich.edu    // it anymore
11327377Sgblack@eecs.umich.edu    intrEvent = 0;
11337377Sgblack@eecs.umich.edu    intrTick = 0;
11347377Sgblack@eecs.umich.edu
11357377Sgblack@eecs.umich.edu    // Send interrupt
11367377Sgblack@eecs.umich.edu    cpuPendingIntr = true;
11377377Sgblack@eecs.umich.edu    /** @todo rework the intctrl to be tsunami ok */
11387377Sgblack@eecs.umich.edu    //intctrl->post(TheISA::INTLEVEL_IRQ1, TheISA::INTINDEX_ETHERNET);
11397377Sgblack@eecs.umich.edu    DPRINTF(EthernetIntr, "Posting interrupts to cchip!\n");
11407377Sgblack@eecs.umich.edu    tsunami->cchip->postDRIR(configData->config.hdr.pci0.interruptLine);
11417377Sgblack@eecs.umich.edu}
11427382Sgblack@eecs.umich.edu
11437377Sgblack@eecs.umich.eduvoid
11447377Sgblack@eecs.umich.eduNSGigE::cpuIntrClear()
11457377Sgblack@eecs.umich.edu{
11467377Sgblack@eecs.umich.edu    if (!cpuPendingIntr)
11477377Sgblack@eecs.umich.edu        return;
11487377Sgblack@eecs.umich.edu
11497377Sgblack@eecs.umich.edu    cpuPendingIntr = false;
11507377Sgblack@eecs.umich.edu    /** @todo rework the intctrl to be tsunami ok */
11517389Sgblack@eecs.umich.edu    //intctrl->clear(TheISA::INTLEVEL_IRQ1, TheISA::INTINDEX_ETHERNET);
11527389Sgblack@eecs.umich.edu    DPRINTF(EthernetIntr, "clearing all interrupts from cchip\n");
11537389Sgblack@eecs.umich.edu    tsunami->cchip->clearDRIR(configData->config.hdr.pci0.interruptLine);
11547389Sgblack@eecs.umich.edu}
11557389Sgblack@eecs.umich.edu
11567389Sgblack@eecs.umich.edubool
11577389Sgblack@eecs.umich.eduNSGigE::cpuIntrPending() const
11587377Sgblack@eecs.umich.edu{ return cpuPendingIntr; }
11597377Sgblack@eecs.umich.edu
11607377Sgblack@eecs.umich.eduvoid
11617377Sgblack@eecs.umich.eduNSGigE::txReset()
11627377Sgblack@eecs.umich.edu{
11637377Sgblack@eecs.umich.edu
11647377Sgblack@eecs.umich.edu    DPRINTF(Ethernet, "transmit reset\n");
11657377Sgblack@eecs.umich.edu
11667377Sgblack@eecs.umich.edu    CTDD = false;
11677377Sgblack@eecs.umich.edu    txFifoAvail = maxTxFifoSize;
11687377Sgblack@eecs.umich.edu    txEnable = false;;
11697377Sgblack@eecs.umich.edu    txFragPtr = 0;
11707389Sgblack@eecs.umich.edu    assert(txDescCnt == 0);
11717377Sgblack@eecs.umich.edu    txFifo.clear();
11727389Sgblack@eecs.umich.edu    txState = txIdle;
11737389Sgblack@eecs.umich.edu    assert(txDmaState == dmaIdle);
11747377Sgblack@eecs.umich.edu}
11757377Sgblack@eecs.umich.edu
11767377Sgblack@eecs.umich.eduvoid
11777377Sgblack@eecs.umich.eduNSGigE::rxReset()
11787377Sgblack@eecs.umich.edu{
11797377Sgblack@eecs.umich.edu    DPRINTF(Ethernet, "receive reset\n");
11807377Sgblack@eecs.umich.edu
11817389Sgblack@eecs.umich.edu    CRDD = false;
11827389Sgblack@eecs.umich.edu    assert(rxPktBytes == 0);
11837389Sgblack@eecs.umich.edu    rxFifoCnt = 0;
11847389Sgblack@eecs.umich.edu    rxEnable = false;
11857389Sgblack@eecs.umich.edu    rxFragPtr = 0;
11867389Sgblack@eecs.umich.edu    assert(rxDescCnt == 0);
11877389Sgblack@eecs.umich.edu    assert(rxDmaState == dmaIdle);
11887389Sgblack@eecs.umich.edu    rxFifo.clear();
11897389Sgblack@eecs.umich.edu    rxState = rxIdle;
11907389Sgblack@eecs.umich.edu}
11917389Sgblack@eecs.umich.edu
11927377Sgblack@eecs.umich.eduvoid
11937377Sgblack@eecs.umich.eduNSGigE::regsReset()
11947377Sgblack@eecs.umich.edu{
11957377Sgblack@eecs.umich.edu    memset(&regs, 0, sizeof(regs));
11967377Sgblack@eecs.umich.edu    regs.config = 0x80000000;
11977377Sgblack@eecs.umich.edu    regs.mear = 0x12;
11987377Sgblack@eecs.umich.edu    regs.isr = 0x00608000;
11997377Sgblack@eecs.umich.edu    regs.txcfg = 0x120;
12007377Sgblack@eecs.umich.edu    regs.rxcfg = 0x4;
12017377Sgblack@eecs.umich.edu    regs.srr = 0x0103;
12027377Sgblack@eecs.umich.edu    regs.mibc = 0x2;
12037377Sgblack@eecs.umich.edu    regs.vdr = 0x81;
12047377Sgblack@eecs.umich.edu    regs.tesr = 0xc000;
12057389Sgblack@eecs.umich.edu
12067389Sgblack@eecs.umich.edu    extstsEnable = false;
12077377Sgblack@eecs.umich.edu    acceptBroadcast = false;
12087382Sgblack@eecs.umich.edu    acceptMulticast = false;
12097377Sgblack@eecs.umich.edu    acceptUnicast = false;
12107377Sgblack@eecs.umich.edu    acceptPerfect = false;
12117377Sgblack@eecs.umich.edu    acceptArp = false;
12127377Sgblack@eecs.umich.edu}
12137377Sgblack@eecs.umich.edu
12147377Sgblack@eecs.umich.eduvoid
12157377Sgblack@eecs.umich.eduNSGigE::rxDmaReadCopy()
12167377Sgblack@eecs.umich.edu{
12177389Sgblack@eecs.umich.edu    assert(rxDmaState == dmaReading);
12187389Sgblack@eecs.umich.edu
12197389Sgblack@eecs.umich.edu    physmem->dma_read((uint8_t *)rxDmaData, rxDmaAddr, rxDmaLen);
12207389Sgblack@eecs.umich.edu    rxDmaState = dmaIdle;
12217389Sgblack@eecs.umich.edu
12227377Sgblack@eecs.umich.edu    DPRINTF(EthernetDMA, "rx dma read  paddr=%#x len=%d\n",
12237377Sgblack@eecs.umich.edu            rxDmaAddr, rxDmaLen);
12247377Sgblack@eecs.umich.edu    DDUMP(EthernetDMA, rxDmaData, rxDmaLen);
12257377Sgblack@eecs.umich.edu}
12267377Sgblack@eecs.umich.edu
12277377Sgblack@eecs.umich.edubool
12287377Sgblack@eecs.umich.eduNSGigE::doRxDmaRead()
12297377Sgblack@eecs.umich.edu{
12307377Sgblack@eecs.umich.edu    assert(rxDmaState == dmaIdle || rxDmaState == dmaReadWaiting);
12317377Sgblack@eecs.umich.edu    rxDmaState = dmaReading;
12327389Sgblack@eecs.umich.edu
12337389Sgblack@eecs.umich.edu    if (dmaInterface && !rxDmaFree) {
12347389Sgblack@eecs.umich.edu        if (dmaInterface->busy())
12357389Sgblack@eecs.umich.edu            rxDmaState = dmaReadWaiting;
12367389Sgblack@eecs.umich.edu        else
12377389Sgblack@eecs.umich.edu            dmaInterface->doDMA(Read, rxDmaAddr, rxDmaLen, curTick,
12387389Sgblack@eecs.umich.edu                                &rxDmaReadEvent, true);
12397389Sgblack@eecs.umich.edu        return true;
12407389Sgblack@eecs.umich.edu    }
12417389Sgblack@eecs.umich.edu
12427389Sgblack@eecs.umich.edu    if (dmaReadDelay == 0 && dmaReadFactor == 0) {
12437389Sgblack@eecs.umich.edu        rxDmaReadCopy();
12447389Sgblack@eecs.umich.edu        return false;
12457389Sgblack@eecs.umich.edu    }
12467389Sgblack@eecs.umich.edu
12477389Sgblack@eecs.umich.edu    Tick factor = ((rxDmaLen + ULL(63)) >> ULL(6)) * dmaReadFactor;
12487389Sgblack@eecs.umich.edu    Tick start = curTick + dmaReadDelay + factor;
12497389Sgblack@eecs.umich.edu    rxDmaReadEvent.schedule(start);
12507389Sgblack@eecs.umich.edu    return true;
12517389Sgblack@eecs.umich.edu}
12527389Sgblack@eecs.umich.edu
12537389Sgblack@eecs.umich.eduvoid
12547389Sgblack@eecs.umich.eduNSGigE::rxDmaReadDone()
12557389Sgblack@eecs.umich.edu{
12567389Sgblack@eecs.umich.edu    assert(rxDmaState == dmaReading);
12577389Sgblack@eecs.umich.edu    rxDmaReadCopy();
12587389Sgblack@eecs.umich.edu
12597389Sgblack@eecs.umich.edu    // If the transmit state machine has a pending DMA, let it go first
12607389Sgblack@eecs.umich.edu    if (txDmaState == dmaReadWaiting || txDmaState == dmaWriteWaiting)
12617389Sgblack@eecs.umich.edu        txKick();
12627389Sgblack@eecs.umich.edu
12637389Sgblack@eecs.umich.edu    rxKick();
12647389Sgblack@eecs.umich.edu}
12657389Sgblack@eecs.umich.edu
12667389Sgblack@eecs.umich.eduvoid
12677389Sgblack@eecs.umich.eduNSGigE::rxDmaWriteCopy()
12687389Sgblack@eecs.umich.edu{
12697389Sgblack@eecs.umich.edu    assert(rxDmaState == dmaWriting);
12707389Sgblack@eecs.umich.edu
12717389Sgblack@eecs.umich.edu    physmem->dma_write(rxDmaAddr, (uint8_t *)rxDmaData, rxDmaLen);
12727389Sgblack@eecs.umich.edu    rxDmaState = dmaIdle;
12737389Sgblack@eecs.umich.edu
12747389Sgblack@eecs.umich.edu    DPRINTF(EthernetDMA, "rx dma write paddr=%#x len=%d\n",
12757389Sgblack@eecs.umich.edu            rxDmaAddr, rxDmaLen);
12767389Sgblack@eecs.umich.edu    DDUMP(EthernetDMA, rxDmaData, rxDmaLen);
12777389Sgblack@eecs.umich.edu}
12787389Sgblack@eecs.umich.edu
12797389Sgblack@eecs.umich.edubool
12807389Sgblack@eecs.umich.eduNSGigE::doRxDmaWrite()
12817389Sgblack@eecs.umich.edu{
12827389Sgblack@eecs.umich.edu    assert(rxDmaState == dmaIdle || rxDmaState == dmaWriteWaiting);
12837389Sgblack@eecs.umich.edu    rxDmaState = dmaWriting;
12847389Sgblack@eecs.umich.edu
12857389Sgblack@eecs.umich.edu    if (dmaInterface && !rxDmaFree) {
12867389Sgblack@eecs.umich.edu        if (dmaInterface->busy())
12877389Sgblack@eecs.umich.edu            rxDmaState = dmaWriteWaiting;
12887389Sgblack@eecs.umich.edu        else
12897389Sgblack@eecs.umich.edu            dmaInterface->doDMA(WriteInvalidate, rxDmaAddr, rxDmaLen, curTick,
12907389Sgblack@eecs.umich.edu                                &rxDmaWriteEvent, true);
12917389Sgblack@eecs.umich.edu        return true;
12927389Sgblack@eecs.umich.edu    }
12937389Sgblack@eecs.umich.edu
12947389Sgblack@eecs.umich.edu    if (dmaWriteDelay == 0 && dmaWriteFactor == 0) {
12957389Sgblack@eecs.umich.edu        rxDmaWriteCopy();
12967389Sgblack@eecs.umich.edu        return false;
12977389Sgblack@eecs.umich.edu    }
12987389Sgblack@eecs.umich.edu
12997389Sgblack@eecs.umich.edu    Tick factor = ((rxDmaLen + ULL(63)) >> ULL(6)) * dmaWriteFactor;
13007389Sgblack@eecs.umich.edu    Tick start = curTick + dmaWriteDelay + factor;
13017389Sgblack@eecs.umich.edu    rxDmaWriteEvent.schedule(start);
13027389Sgblack@eecs.umich.edu    return true;
13037389Sgblack@eecs.umich.edu}
13047389Sgblack@eecs.umich.edu
13057389Sgblack@eecs.umich.eduvoid
13067389Sgblack@eecs.umich.eduNSGigE::rxDmaWriteDone()
13077389Sgblack@eecs.umich.edu{
13087389Sgblack@eecs.umich.edu    assert(rxDmaState == dmaWriting);
13097389Sgblack@eecs.umich.edu    rxDmaWriteCopy();
13107389Sgblack@eecs.umich.edu
13117389Sgblack@eecs.umich.edu    // If the transmit state machine has a pending DMA, let it go first
13127389Sgblack@eecs.umich.edu    if (txDmaState == dmaReadWaiting || txDmaState == dmaWriteWaiting)
13137389Sgblack@eecs.umich.edu        txKick();
13147389Sgblack@eecs.umich.edu
13157389Sgblack@eecs.umich.edu    rxKick();
13167389Sgblack@eecs.umich.edu}
13177389Sgblack@eecs.umich.edu
13187389Sgblack@eecs.umich.eduvoid
13197389Sgblack@eecs.umich.eduNSGigE::rxKick()
13207389Sgblack@eecs.umich.edu{
13217389Sgblack@eecs.umich.edu    DPRINTF(EthernetSM, "receive kick rxState=%s (rxBuf.size=%d)\n",
13227389Sgblack@eecs.umich.edu            NsRxStateStrings[rxState], rxFifo.size());
13237389Sgblack@eecs.umich.edu
13247389Sgblack@eecs.umich.edu    if (rxKickTick > curTick) {
13257322Sgblack@eecs.umich.edu        DPRINTF(EthernetSM, "receive kick exiting, can't run till %d\n",
13267379Sgblack@eecs.umich.edu                rxKickTick);
13277379Sgblack@eecs.umich.edu        return;
13287379Sgblack@eecs.umich.edu    }
13297379Sgblack@eecs.umich.edu
13307379Sgblack@eecs.umich.edu  next:
13317379Sgblack@eecs.umich.edu    switch(rxDmaState) {
13327379Sgblack@eecs.umich.edu      case dmaReadWaiting:
13337379Sgblack@eecs.umich.edu        if (doRxDmaRead())
13347382Sgblack@eecs.umich.edu            goto exit;
13357379Sgblack@eecs.umich.edu        break;
13367381Sgblack@eecs.umich.edu      case dmaWriteWaiting:
13377379Sgblack@eecs.umich.edu        if (doRxDmaWrite())
13387381Sgblack@eecs.umich.edu            goto exit;
13397379Sgblack@eecs.umich.edu        break;
13407379Sgblack@eecs.umich.edu      default:
13417379Sgblack@eecs.umich.edu        break;
13427379Sgblack@eecs.umich.edu    }
13437379Sgblack@eecs.umich.edu
13447379Sgblack@eecs.umich.edu    // see state machine from spec for details
13457379Sgblack@eecs.umich.edu    // the way this works is, if you finish work on one state and can
13467379Sgblack@eecs.umich.edu    // go directly to another, you do that through jumping to the
13477379Sgblack@eecs.umich.edu    // label "next".  however, if you have intermediate work, like DMA
13487379Sgblack@eecs.umich.edu    // so that you can't go to the next state yet, you go to exit and
13497379Sgblack@eecs.umich.edu    // exit the loop.  however, when the DMA is done it will trigger
13507379Sgblack@eecs.umich.edu    // an event and come back to this loop.
13517382Sgblack@eecs.umich.edu    switch (rxState) {
13527379Sgblack@eecs.umich.edu      case rxIdle:
13537381Sgblack@eecs.umich.edu        if (!rxEnable) {
13547379Sgblack@eecs.umich.edu            DPRINTF(EthernetSM, "Receive Disabled! Nothing to do.\n");
13557381Sgblack@eecs.umich.edu            goto exit;
13567379Sgblack@eecs.umich.edu        }
13577379Sgblack@eecs.umich.edu
13587379Sgblack@eecs.umich.edu        if (CRDD) {
13597379Sgblack@eecs.umich.edu            rxState = rxDescRefr;
13607379Sgblack@eecs.umich.edu
13617379Sgblack@eecs.umich.edu            rxDmaAddr = regs.rxdp & 0x3fffffff;
13627379Sgblack@eecs.umich.edu            rxDmaData = &rxDescCache + offsetof(ns_desc, link);
13637379Sgblack@eecs.umich.edu            rxDmaLen = sizeof(rxDescCache.link);
13647379Sgblack@eecs.umich.edu            rxDmaFree = dmaDescFree;
13657379Sgblack@eecs.umich.edu
13667379Sgblack@eecs.umich.edu            descDmaReads++;
13677379Sgblack@eecs.umich.edu            descDmaRdBytes += rxDmaLen;
13687382Sgblack@eecs.umich.edu
13697379Sgblack@eecs.umich.edu            if (doRxDmaRead())
13707381Sgblack@eecs.umich.edu                goto exit;
13717379Sgblack@eecs.umich.edu        } else {
13727381Sgblack@eecs.umich.edu            rxState = rxDescRead;
13737379Sgblack@eecs.umich.edu
13747379Sgblack@eecs.umich.edu            rxDmaAddr = regs.rxdp & 0x3fffffff;
13757379Sgblack@eecs.umich.edu            rxDmaData = &rxDescCache;
13767379Sgblack@eecs.umich.edu            rxDmaLen = sizeof(ns_desc);
13777379Sgblack@eecs.umich.edu            rxDmaFree = dmaDescFree;
13787379Sgblack@eecs.umich.edu
13797379Sgblack@eecs.umich.edu            descDmaReads++;
13807379Sgblack@eecs.umich.edu            descDmaRdBytes += rxDmaLen;
13817379Sgblack@eecs.umich.edu
13827379Sgblack@eecs.umich.edu            if (doRxDmaRead())
13837379Sgblack@eecs.umich.edu                goto exit;
13847379Sgblack@eecs.umich.edu        }
13857382Sgblack@eecs.umich.edu        break;
13867379Sgblack@eecs.umich.edu
13877381Sgblack@eecs.umich.edu      case rxDescRefr:
13887379Sgblack@eecs.umich.edu        if (rxDmaState != dmaIdle)
13897381Sgblack@eecs.umich.edu            goto exit;
13907379Sgblack@eecs.umich.edu
13917379Sgblack@eecs.umich.edu        rxState = rxAdvance;
13927379Sgblack@eecs.umich.edu        break;
13937379Sgblack@eecs.umich.edu
13947379Sgblack@eecs.umich.edu     case rxDescRead:
13957379Sgblack@eecs.umich.edu        if (rxDmaState != dmaIdle)
13967379Sgblack@eecs.umich.edu            goto exit;
13977379Sgblack@eecs.umich.edu
13987379Sgblack@eecs.umich.edu        DPRINTF(EthernetDesc,
13997379Sgblack@eecs.umich.edu                "rxDescCache: addr=%08x read descriptor\n",
14007379Sgblack@eecs.umich.edu                regs.rxdp & 0x3fffffff);
14017379Sgblack@eecs.umich.edu        DPRINTF(EthernetDesc,
14027379Sgblack@eecs.umich.edu                "rxDescCache: link=%08x bufptr=%08x cmdsts=%08x extsts=%08x\n",
14037381Sgblack@eecs.umich.edu                rxDescCache.link, rxDescCache.bufptr, rxDescCache.cmdsts,
14047386Sgblack@eecs.umich.edu                rxDescCache.extsts);
14057381Sgblack@eecs.umich.edu
14067379Sgblack@eecs.umich.edu        if (rxDescCache.cmdsts & CMDSTS_OWN) {
14077379Sgblack@eecs.umich.edu            devIntrPost(ISR_RXIDLE);
14087379Sgblack@eecs.umich.edu            rxState = rxIdle;
14097379Sgblack@eecs.umich.edu            goto exit;
14107379Sgblack@eecs.umich.edu        } else {
14117379Sgblack@eecs.umich.edu            rxState = rxFifoBlock;
14127379Sgblack@eecs.umich.edu            rxFragPtr = rxDescCache.bufptr;
14137379Sgblack@eecs.umich.edu            rxDescCnt = rxDescCache.cmdsts & CMDSTS_LEN_MASK;
14147379Sgblack@eecs.umich.edu        }
14157379Sgblack@eecs.umich.edu        break;
14167379Sgblack@eecs.umich.edu
14177379Sgblack@eecs.umich.edu      case rxFifoBlock:
14187379Sgblack@eecs.umich.edu        if (!rxPacket) {
14197381Sgblack@eecs.umich.edu            /**
14207386Sgblack@eecs.umich.edu             * @todo in reality, we should be able to start processing
14217381Sgblack@eecs.umich.edu             * the packet as it arrives, and not have to wait for the
14227379Sgblack@eecs.umich.edu             * full packet ot be in the receive fifo.
14237379Sgblack@eecs.umich.edu             */
14247379Sgblack@eecs.umich.edu            if (rxFifo.empty())
14257379Sgblack@eecs.umich.edu                goto exit;
14267379Sgblack@eecs.umich.edu
14277379Sgblack@eecs.umich.edu            DPRINTF(EthernetSM, "****processing receive of new packet****\n");
14287379Sgblack@eecs.umich.edu
14297379Sgblack@eecs.umich.edu            // If we don't have a packet, grab a new one from the fifo.
14307379Sgblack@eecs.umich.edu            rxPacket = rxFifo.front();
14317379Sgblack@eecs.umich.edu            rxPktBytes = rxPacket->length;
14327379Sgblack@eecs.umich.edu            rxPacketBufPtr = rxPacket->data;
14337379Sgblack@eecs.umich.edu
14347379Sgblack@eecs.umich.edu#if TRACING_ON
14357381Sgblack@eecs.umich.edu            if (DTRACE(Ethernet)) {
14367386Sgblack@eecs.umich.edu                if (rxPacket->isIpPkt()) {
14377381Sgblack@eecs.umich.edu                    ip_header *ip = rxPacket->getIpHdr();
14387379Sgblack@eecs.umich.edu                    DPRINTF(Ethernet, "ID is %d\n", reverseEnd16(ip->ID));
14397379Sgblack@eecs.umich.edu                    if (rxPacket->isTcpPkt()) {
14407379Sgblack@eecs.umich.edu                        tcp_header *tcp = rxPacket->getTcpHdr(ip);
14417379Sgblack@eecs.umich.edu                        DPRINTF(Ethernet, "Src Port=%d, Dest Port=%d\n",
14427379Sgblack@eecs.umich.edu                                reverseEnd16(tcp->src_port_num),
14437379Sgblack@eecs.umich.edu                                reverseEnd16(tcp->dest_port_num));
14447379Sgblack@eecs.umich.edu                    }
14457379Sgblack@eecs.umich.edu                }
14467379Sgblack@eecs.umich.edu            }
14477379Sgblack@eecs.umich.edu#endif
14487379Sgblack@eecs.umich.edu
14497379Sgblack@eecs.umich.edu            // sanity check - i think the driver behaves like this
14507379Sgblack@eecs.umich.edu            assert(rxDescCnt >= rxPktBytes);
14517381Sgblack@eecs.umich.edu
14527386Sgblack@eecs.umich.edu            // Must clear the value before popping to decrement the
14537381Sgblack@eecs.umich.edu            // reference count
14547379Sgblack@eecs.umich.edu            rxFifo.front() = NULL;
14557379Sgblack@eecs.umich.edu            rxFifo.pop_front();
14567379Sgblack@eecs.umich.edu            rxFifoCnt -= rxPacket->length;
14577379Sgblack@eecs.umich.edu        }
14587379Sgblack@eecs.umich.edu
14597379Sgblack@eecs.umich.edu
14607379Sgblack@eecs.umich.edu        // dont' need the && rxDescCnt > 0 if driver sanity check
14617379Sgblack@eecs.umich.edu        // above holds
14627379Sgblack@eecs.umich.edu        if (rxPktBytes > 0) {
14637379Sgblack@eecs.umich.edu            rxState = rxFragWrite;
14647379Sgblack@eecs.umich.edu            // don't need min<>(rxPktBytes,rxDescCnt) if above sanity
14657379Sgblack@eecs.umich.edu            // check holds
14667382Sgblack@eecs.umich.edu            rxXferLen = rxPktBytes;
14677379Sgblack@eecs.umich.edu
14687381Sgblack@eecs.umich.edu            rxDmaAddr = rxFragPtr & 0x3fffffff;
14697379Sgblack@eecs.umich.edu            rxDmaData = rxPacketBufPtr;
14707381Sgblack@eecs.umich.edu            rxDmaLen = rxXferLen;
14717379Sgblack@eecs.umich.edu            rxDmaFree = dmaDataFree;
14727379Sgblack@eecs.umich.edu
14737379Sgblack@eecs.umich.edu            if (doRxDmaWrite())
14747379Sgblack@eecs.umich.edu                goto exit;
14757379Sgblack@eecs.umich.edu
14767379Sgblack@eecs.umich.edu        } else {
14777379Sgblack@eecs.umich.edu            rxState = rxDescWrite;
14787379Sgblack@eecs.umich.edu
14797379Sgblack@eecs.umich.edu            //if (rxPktBytes == 0) {  /* packet is done */
14807379Sgblack@eecs.umich.edu            assert(rxPktBytes == 0);
14817379Sgblack@eecs.umich.edu            DPRINTF(EthernetSM, "done with receiving packet\n");
14827379Sgblack@eecs.umich.edu
14837379Sgblack@eecs.umich.edu            rxDescCache.cmdsts |= CMDSTS_OWN;
14847382Sgblack@eecs.umich.edu            rxDescCache.cmdsts &= ~CMDSTS_MORE;
14857379Sgblack@eecs.umich.edu            rxDescCache.cmdsts |= CMDSTS_OK;
14867381Sgblack@eecs.umich.edu            rxDescCache.cmdsts &= 0xffff0000;
14877379Sgblack@eecs.umich.edu            rxDescCache.cmdsts += rxPacket->length;   //i.e. set CMDSTS_SIZE
14887381Sgblack@eecs.umich.edu
14897379Sgblack@eecs.umich.edu#if 0
14907379Sgblack@eecs.umich.edu            /*
14917379Sgblack@eecs.umich.edu             * all the driver uses these are for its own stats keeping
14927379Sgblack@eecs.umich.edu             * which we don't care about, aren't necessary for
14937379Sgblack@eecs.umich.edu             * functionality and doing this would just slow us down.
14947379Sgblack@eecs.umich.edu             * if they end up using this in a later version for
14957379Sgblack@eecs.umich.edu             * functional purposes, just undef
14967379Sgblack@eecs.umich.edu             */
14977379Sgblack@eecs.umich.edu            if (rxFilterEnable) {
14987379Sgblack@eecs.umich.edu                rxDescCache.cmdsts &= ~CMDSTS_DEST_MASK;
14997379Sgblack@eecs.umich.edu                if (rxFifo.front()->IsUnicast())
15007379Sgblack@eecs.umich.edu                    rxDescCache.cmdsts |= CMDSTS_DEST_SELF;
15017379Sgblack@eecs.umich.edu                if (rxFifo.front()->IsMulticast())
15027382Sgblack@eecs.umich.edu                    rxDescCache.cmdsts |= CMDSTS_DEST_MULTI;
15037379Sgblack@eecs.umich.edu                if (rxFifo.front()->IsBroadcast())
15047381Sgblack@eecs.umich.edu                    rxDescCache.cmdsts |= CMDSTS_DEST_MASK;
15057379Sgblack@eecs.umich.edu            }
15067381Sgblack@eecs.umich.edu#endif
15077379Sgblack@eecs.umich.edu
15087379Sgblack@eecs.umich.edu            if (rxPacket->isIpPkt() && extstsEnable) {
15097379Sgblack@eecs.umich.edu                rxDescCache.extsts |= EXTSTS_IPPKT;
15107379Sgblack@eecs.umich.edu                rxIPChecksums++;
15117379Sgblack@eecs.umich.edu                if (!ipChecksum(rxPacket, false)) {
15127379Sgblack@eecs.umich.edu                    DPRINTF(EthernetCksum, "Rx IP Checksum Error\n");
15137379Sgblack@eecs.umich.edu                    rxDescCache.extsts |= EXTSTS_IPERR;
15147379Sgblack@eecs.umich.edu                }
15157379Sgblack@eecs.umich.edu                if (rxPacket->isTcpPkt()) {
15167379Sgblack@eecs.umich.edu                    rxDescCache.extsts |= EXTSTS_TCPPKT;
15177379Sgblack@eecs.umich.edu                    rxTCPChecksums++;
15187379Sgblack@eecs.umich.edu                    if (!tcpChecksum(rxPacket, false)) {
15197379Sgblack@eecs.umich.edu                        DPRINTF(EthernetCksum, "Rx TCP Checksum Error\n");
15207382Sgblack@eecs.umich.edu                        rxDescCache.extsts |= EXTSTS_TCPERR;
15217379Sgblack@eecs.umich.edu
15227381Sgblack@eecs.umich.edu                    }
15237379Sgblack@eecs.umich.edu                } else if (rxPacket->isUdpPkt()) {
15247381Sgblack@eecs.umich.edu                    rxDescCache.extsts |= EXTSTS_UDPPKT;
15257379Sgblack@eecs.umich.edu                    if (!udpChecksum(rxPacket, false)) {
15267379Sgblack@eecs.umich.edu                        DPRINTF(EthernetCksum, "Rx UDP Checksum Error\n");
15277379Sgblack@eecs.umich.edu                        rxDescCache.extsts |= EXTSTS_UDPERR;
15287379Sgblack@eecs.umich.edu                    }
15297379Sgblack@eecs.umich.edu                }
15307379Sgblack@eecs.umich.edu            }
15317379Sgblack@eecs.umich.edu            rxPacket = 0;
15327379Sgblack@eecs.umich.edu
15337379Sgblack@eecs.umich.edu            /*
15347379Sgblack@eecs.umich.edu             * the driver seems to always receive into desc buffers
15357379Sgblack@eecs.umich.edu             * of size 1514, so you never have a pkt that is split
15367379Sgblack@eecs.umich.edu             * into multiple descriptors on the receive side, so
15377379Sgblack@eecs.umich.edu             * i don't implement that case, hence the assert above.
15387379Sgblack@eecs.umich.edu             */
15397381Sgblack@eecs.umich.edu
15407386Sgblack@eecs.umich.edu            DPRINTF(EthernetDesc,
15417381Sgblack@eecs.umich.edu                    "rxDescCache: addr=%08x writeback cmdsts extsts\n",
15427379Sgblack@eecs.umich.edu                    regs.rxdp & 0x3fffffff);
15437379Sgblack@eecs.umich.edu            DPRINTF(EthernetDesc,
15447379Sgblack@eecs.umich.edu                    "rxDescCache: link=%08x bufptr=%08x cmdsts=%08x extsts=%08x\n",
15457379Sgblack@eecs.umich.edu                    rxDescCache.link, rxDescCache.bufptr, rxDescCache.cmdsts,
15467379Sgblack@eecs.umich.edu                    rxDescCache.extsts);
15477379Sgblack@eecs.umich.edu
15487379Sgblack@eecs.umich.edu            rxDmaAddr = (regs.rxdp + offsetof(ns_desc, cmdsts)) & 0x3fffffff;
15497379Sgblack@eecs.umich.edu            rxDmaData = &(rxDescCache.cmdsts);
15507379Sgblack@eecs.umich.edu            rxDmaLen = sizeof(rxDescCache.cmdsts) + sizeof(rxDescCache.extsts);
15517379Sgblack@eecs.umich.edu            rxDmaFree = dmaDescFree;
15527379Sgblack@eecs.umich.edu
15537379Sgblack@eecs.umich.edu            descDmaWrites++;
15547379Sgblack@eecs.umich.edu            descDmaWrBytes += rxDmaLen;
15557379Sgblack@eecs.umich.edu
15567381Sgblack@eecs.umich.edu            if (doRxDmaWrite())
15577386Sgblack@eecs.umich.edu                goto exit;
15587381Sgblack@eecs.umich.edu        }
15597379Sgblack@eecs.umich.edu        break;
15607379Sgblack@eecs.umich.edu
15617379Sgblack@eecs.umich.edu      case rxFragWrite:
15627379Sgblack@eecs.umich.edu        if (rxDmaState != dmaIdle)
15637379Sgblack@eecs.umich.edu            goto exit;
15647379Sgblack@eecs.umich.edu
15657379Sgblack@eecs.umich.edu        rxPacketBufPtr += rxXferLen;
15667379Sgblack@eecs.umich.edu        rxFragPtr += rxXferLen;
15677379Sgblack@eecs.umich.edu        rxPktBytes -= rxXferLen;
15687379Sgblack@eecs.umich.edu
15697379Sgblack@eecs.umich.edu        rxState = rxFifoBlock;
15707379Sgblack@eecs.umich.edu        break;
15717379Sgblack@eecs.umich.edu
15727379Sgblack@eecs.umich.edu      case rxDescWrite:
15737381Sgblack@eecs.umich.edu        if (rxDmaState != dmaIdle)
15747386Sgblack@eecs.umich.edu            goto exit;
15757381Sgblack@eecs.umich.edu
15767379Sgblack@eecs.umich.edu        assert(rxDescCache.cmdsts & CMDSTS_OWN);
15777379Sgblack@eecs.umich.edu
15787379Sgblack@eecs.umich.edu        assert(rxPacket == 0);
15797379Sgblack@eecs.umich.edu        devIntrPost(ISR_RXOK);
15807379Sgblack@eecs.umich.edu
15817379Sgblack@eecs.umich.edu        if (rxDescCache.cmdsts & CMDSTS_INTR)
15827379Sgblack@eecs.umich.edu            devIntrPost(ISR_RXDESC);
15837379Sgblack@eecs.umich.edu
15847379Sgblack@eecs.umich.edu        if (!rxEnable) {
15857379Sgblack@eecs.umich.edu            DPRINTF(EthernetSM, "Halting the RX state machine\n");
15867379Sgblack@eecs.umich.edu            rxState = rxIdle;
15877379Sgblack@eecs.umich.edu            goto exit;
15887379Sgblack@eecs.umich.edu        } else
15897379Sgblack@eecs.umich.edu            rxState = rxAdvance;
15907381Sgblack@eecs.umich.edu        break;
15917386Sgblack@eecs.umich.edu
15927381Sgblack@eecs.umich.edu      case rxAdvance:
15937379Sgblack@eecs.umich.edu        if (rxDescCache.link == 0) {
15947379Sgblack@eecs.umich.edu            devIntrPost(ISR_RXIDLE);
15957379Sgblack@eecs.umich.edu            rxState = rxIdle;
15967379Sgblack@eecs.umich.edu            CRDD = true;
15977379Sgblack@eecs.umich.edu            goto exit;
15987379Sgblack@eecs.umich.edu        } else {
15997379Sgblack@eecs.umich.edu            rxState = rxDescRead;
16007379Sgblack@eecs.umich.edu            regs.rxdp = rxDescCache.link;
16017379Sgblack@eecs.umich.edu            CRDD = false;
16027379Sgblack@eecs.umich.edu
16037379Sgblack@eecs.umich.edu            rxDmaAddr = regs.rxdp & 0x3fffffff;
16047379Sgblack@eecs.umich.edu            rxDmaData = &rxDescCache;
1605            rxDmaLen = sizeof(ns_desc);
1606            rxDmaFree = dmaDescFree;
1607
1608            if (doRxDmaRead())
1609                goto exit;
1610        }
1611        break;
1612
1613      default:
1614        panic("Invalid rxState!");
1615    }
1616
1617    DPRINTF(EthernetSM, "entering next rxState=%s\n",
1618            NsRxStateStrings[rxState]);
1619
1620    goto next;
1621
1622  exit:
1623    /**
1624     * @todo do we want to schedule a future kick?
1625     */
1626    DPRINTF(EthernetSM, "rx state machine exited rxState=%s\n",
1627            NsRxStateStrings[rxState]);
1628}
1629
1630void
1631NSGigE::transmit()
1632{
1633    if (txFifo.empty()) {
1634        DPRINTF(Ethernet, "nothing to transmit\n");
1635        return;
1636    }
1637
1638    DPRINTF(Ethernet, "Attempt Pkt Transmit: txFifo length=%d\n",
1639            maxTxFifoSize - txFifoAvail);
1640    if (interface->sendPacket(txFifo.front())) {
1641#if TRACING_ON
1642        if (DTRACE(Ethernet)) {
1643            if (txFifo.front()->isIpPkt()) {
1644                ip_header *ip = txFifo.front()->getIpHdr();
1645                DPRINTF(Ethernet, "ID is %d\n", reverseEnd16(ip->ID));
1646                if (txFifo.front()->isTcpPkt()) {
1647                    tcp_header *tcp = txFifo.front()->getTcpHdr(ip);
1648                    DPRINTF(Ethernet, "Src Port=%d, Dest Port=%d\n",
1649                            reverseEnd16(tcp->src_port_num),
1650                            reverseEnd16(tcp->dest_port_num));
1651                }
1652            }
1653        }
1654#endif
1655
1656        DDUMP(Ethernet, txFifo.front()->data, txFifo.front()->length);
1657        txBytes += txFifo.front()->length;
1658        txPackets++;
1659
1660        txFifoAvail += txFifo.front()->length;
1661
1662        DPRINTF(Ethernet, "Successful Xmit! now txFifoAvail is %d\n",
1663                txFifoAvail);
1664        txFifo.front() = NULL;
1665        txFifo.pop_front();
1666
1667        /*
1668         * normally do a writeback of the descriptor here, and ONLY
1669         * after that is done, send this interrupt.  but since our
1670         * stuff never actually fails, just do this interrupt here,
1671         * otherwise the code has to stray from this nice format.
1672         * besides, it's functionally the same.
1673         */
1674        devIntrPost(ISR_TXOK);
1675    } else {
1676        DPRINTF(Ethernet,
1677                "May need to rethink always sending the descriptors back?\n");
1678    }
1679
1680   if (!txFifo.empty() && !txEvent.scheduled()) {
1681       DPRINTF(Ethernet, "reschedule transmit\n");
1682       txEvent.schedule(curTick + 1000);
1683   }
1684}
1685
1686void
1687NSGigE::txDmaReadCopy()
1688{
1689    assert(txDmaState == dmaReading);
1690
1691    physmem->dma_read((uint8_t *)txDmaData, txDmaAddr, txDmaLen);
1692    txDmaState = dmaIdle;
1693
1694    DPRINTF(EthernetDMA, "tx dma read  paddr=%#x len=%d\n",
1695            txDmaAddr, txDmaLen);
1696    DDUMP(EthernetDMA, txDmaData, txDmaLen);
1697}
1698
1699bool
1700NSGigE::doTxDmaRead()
1701{
1702    assert(txDmaState == dmaIdle || txDmaState == dmaReadWaiting);
1703    txDmaState = dmaReading;
1704
1705    if (dmaInterface && !txDmaFree) {
1706        if (dmaInterface->busy())
1707            txDmaState = dmaReadWaiting;
1708        else
1709            dmaInterface->doDMA(Read, txDmaAddr, txDmaLen, curTick,
1710                                &txDmaReadEvent, true);
1711        return true;
1712    }
1713
1714    if (dmaReadDelay == 0 && dmaReadFactor == 0.0) {
1715        txDmaReadCopy();
1716        return false;
1717    }
1718
1719    Tick factor = ((txDmaLen + ULL(63)) >> ULL(6)) * dmaReadFactor;
1720    Tick start = curTick + dmaReadDelay + factor;
1721    txDmaReadEvent.schedule(start);
1722    return true;
1723}
1724
1725void
1726NSGigE::txDmaReadDone()
1727{
1728    assert(txDmaState == dmaReading);
1729    txDmaReadCopy();
1730
1731    // If the receive state machine  has a pending DMA, let it go first
1732    if (rxDmaState == dmaReadWaiting || rxDmaState == dmaWriteWaiting)
1733        rxKick();
1734
1735    txKick();
1736}
1737
1738void
1739NSGigE::txDmaWriteCopy()
1740{
1741    assert(txDmaState == dmaWriting);
1742
1743    physmem->dma_write(txDmaAddr, (uint8_t *)txDmaData, txDmaLen);
1744    txDmaState = dmaIdle;
1745
1746    DPRINTF(EthernetDMA, "tx dma write paddr=%#x len=%d\n",
1747            txDmaAddr, txDmaLen);
1748    DDUMP(EthernetDMA, txDmaData, txDmaLen);
1749}
1750
1751bool
1752NSGigE::doTxDmaWrite()
1753{
1754    assert(txDmaState == dmaIdle || txDmaState == dmaWriteWaiting);
1755    txDmaState = dmaWriting;
1756
1757    if (dmaInterface && !txDmaFree) {
1758        if (dmaInterface->busy())
1759            txDmaState = dmaWriteWaiting;
1760        else
1761            dmaInterface->doDMA(WriteInvalidate, txDmaAddr, txDmaLen, curTick,
1762                                &txDmaWriteEvent, true);
1763        return true;
1764    }
1765
1766    if (dmaWriteDelay == 0 && dmaWriteFactor == 0.0) {
1767        txDmaWriteCopy();
1768        return false;
1769    }
1770
1771    Tick factor = ((txDmaLen + ULL(63)) >> ULL(6)) * dmaWriteFactor;
1772    Tick start = curTick + dmaWriteDelay + factor;
1773    txDmaWriteEvent.schedule(start);
1774    return true;
1775}
1776
1777void
1778NSGigE::txDmaWriteDone()
1779{
1780    assert(txDmaState == dmaWriting);
1781    txDmaWriteCopy();
1782
1783    // If the receive state machine  has a pending DMA, let it go first
1784    if (rxDmaState == dmaReadWaiting || rxDmaState == dmaWriteWaiting)
1785        rxKick();
1786
1787    txKick();
1788}
1789
1790void
1791NSGigE::txKick()
1792{
1793    DPRINTF(EthernetSM, "transmit kick txState=%s\n",
1794            NsTxStateStrings[txState]);
1795
1796    if (txKickTick > curTick) {
1797        DPRINTF(EthernetSM, "transmit kick exiting, can't run till %d\n",
1798                txKickTick);
1799
1800        return;
1801    }
1802
1803  next:
1804    switch(txDmaState) {
1805      case dmaReadWaiting:
1806        if (doTxDmaRead())
1807            goto exit;
1808        break;
1809      case dmaWriteWaiting:
1810        if (doTxDmaWrite())
1811            goto exit;
1812        break;
1813      default:
1814        break;
1815    }
1816
1817    switch (txState) {
1818      case txIdle:
1819        if (!txEnable) {
1820            DPRINTF(EthernetSM, "Transmit disabled.  Nothing to do.\n");
1821            goto exit;
1822        }
1823
1824        if (CTDD) {
1825            txState = txDescRefr;
1826
1827            txDmaAddr = regs.txdp & 0x3fffffff;
1828            txDmaData = &txDescCache + offsetof(ns_desc, link);
1829            txDmaLen = sizeof(txDescCache.link);
1830            txDmaFree = dmaDescFree;
1831
1832            descDmaReads++;
1833            descDmaRdBytes += txDmaLen;
1834
1835            if (doTxDmaRead())
1836                goto exit;
1837
1838        } else {
1839            txState = txDescRead;
1840
1841            txDmaAddr = regs.txdp & 0x3fffffff;
1842            txDmaData = &txDescCache;
1843            txDmaLen = sizeof(ns_desc);
1844            txDmaFree = dmaDescFree;
1845
1846            descDmaReads++;
1847            descDmaRdBytes += txDmaLen;
1848
1849            if (doTxDmaRead())
1850                goto exit;
1851        }
1852        break;
1853
1854      case txDescRefr:
1855        if (txDmaState != dmaIdle)
1856            goto exit;
1857
1858        txState = txAdvance;
1859        break;
1860
1861      case txDescRead:
1862        if (txDmaState != dmaIdle)
1863            goto exit;
1864
1865        DPRINTF(EthernetDesc,
1866                "txDescCache: link=%08x bufptr=%08x cmdsts=%08x extsts=%08x\n",
1867                txDescCache.link, txDescCache.bufptr, txDescCache.cmdsts,
1868                txDescCache.extsts);
1869
1870        if (txDescCache.cmdsts & CMDSTS_OWN) {
1871            txState = txFifoBlock;
1872            txFragPtr = txDescCache.bufptr;
1873            txDescCnt = txDescCache.cmdsts & CMDSTS_LEN_MASK;
1874        } else {
1875            devIntrPost(ISR_TXIDLE);
1876            txState = txIdle;
1877            goto exit;
1878        }
1879        break;
1880
1881      case txFifoBlock:
1882        if (!txPacket) {
1883            DPRINTF(EthernetSM, "****starting the tx of a new packet****\n");
1884            txPacket = new EtherPacket;
1885            txPacket->data = new uint8_t[16384];
1886            txPacketBufPtr = txPacket->data;
1887        }
1888
1889        if (txDescCnt == 0) {
1890            DPRINTF(EthernetSM, "the txDescCnt == 0, done with descriptor\n");
1891            if (txDescCache.cmdsts & CMDSTS_MORE) {
1892                DPRINTF(EthernetSM, "there are more descriptors to come\n");
1893                txState = txDescWrite;
1894
1895                txDescCache.cmdsts &= ~CMDSTS_OWN;
1896
1897                txDmaAddr = regs.txdp + offsetof(ns_desc, cmdsts);
1898                txDmaAddr &= 0x3fffffff;
1899                txDmaData = &(txDescCache.cmdsts);
1900                txDmaLen = sizeof(txDescCache.cmdsts);
1901                txDmaFree = dmaDescFree;
1902
1903                if (doTxDmaWrite())
1904                    goto exit;
1905
1906            } else { /* this packet is totally done */
1907                DPRINTF(EthernetSM, "This packet is done, let's wrap it up\n");
1908                /* deal with the the packet that just finished */
1909                if ((regs.vtcr & VTCR_PPCHK) && extstsEnable) {
1910                    if (txDescCache.extsts & EXTSTS_UDPPKT) {
1911                        udpChecksum(txPacket, true);
1912                    } else if (txDescCache.extsts & EXTSTS_TCPPKT) {
1913                        tcpChecksum(txPacket, true);
1914                        txTCPChecksums++;
1915                    }
1916                    if (txDescCache.extsts & EXTSTS_IPPKT) {
1917                        ipChecksum(txPacket, true);
1918                        txIPChecksums++;
1919                    }
1920                }
1921
1922                txPacket->length = txPacketBufPtr - txPacket->data;
1923                // this is just because the receive can't handle a
1924                // packet bigger want to make sure
1925                assert(txPacket->length <= 1514);
1926                txFifo.push_back(txPacket);
1927
1928                /*
1929                 * this following section is not tqo spec, but
1930                 * functionally shouldn't be any different.  normally,
1931                 * the chip will wait til the transmit has occurred
1932                 * before writing back the descriptor because it has
1933                 * to wait to see that it was successfully transmitted
1934                 * to decide whether to set CMDSTS_OK or not.
1935                 * however, in the simulator since it is always
1936                 * successfully transmitted, and writing it exactly to
1937                 * spec would complicate the code, we just do it here
1938                 */
1939
1940                txDescCache.cmdsts &= ~CMDSTS_OWN;
1941                txDescCache.cmdsts |= CMDSTS_OK;
1942
1943                DPRINTF(EthernetDesc,
1944                        "txDesc writeback: cmdsts=%08x extsts=%08x\n",
1945                        txDescCache.cmdsts, txDescCache.extsts);
1946
1947                txDmaAddr = regs.txdp + offsetof(ns_desc, cmdsts);
1948                txDmaAddr &= 0x3fffffff;
1949                txDmaData = &(txDescCache.cmdsts);
1950                txDmaLen = sizeof(txDescCache.cmdsts) +
1951                    sizeof(txDescCache.extsts);
1952                txDmaFree = dmaDescFree;
1953
1954                descDmaWrites++;
1955                descDmaWrBytes += txDmaLen;
1956
1957                transmit();
1958                txPacket = 0;
1959
1960                if (!txEnable) {
1961                    DPRINTF(EthernetSM, "halting TX state machine\n");
1962                    txState = txIdle;
1963                    goto exit;
1964                } else
1965                    txState = txAdvance;
1966
1967                if (doTxDmaWrite())
1968                    goto exit;
1969            }
1970        } else {
1971            DPRINTF(EthernetSM, "this descriptor isn't done yet\n");
1972            if (txFifoAvail) {
1973                txState = txFragRead;
1974
1975                /*
1976                 * The number of bytes transferred is either whatever
1977                 * is left in the descriptor (txDescCnt), or if there
1978                 * is not enough room in the fifo, just whatever room
1979                 * is left in the fifo
1980                 */
1981                txXferLen = min<uint32_t>(txDescCnt, txFifoAvail);
1982
1983                txDmaAddr = txFragPtr & 0x3fffffff;
1984                txDmaData = txPacketBufPtr;
1985                txDmaLen = txXferLen;
1986                txDmaFree = dmaDataFree;
1987
1988                if (doTxDmaRead())
1989                    goto exit;
1990            } else {
1991                txState = txFifoBlock;
1992                transmit();
1993
1994                goto exit;
1995            }
1996
1997        }
1998        break;
1999
2000      case txFragRead:
2001        if (txDmaState != dmaIdle)
2002            goto exit;
2003
2004        txPacketBufPtr += txXferLen;
2005        txFragPtr += txXferLen;
2006        txDescCnt -= txXferLen;
2007        txFifoAvail -= txXferLen;
2008
2009        txState = txFifoBlock;
2010        break;
2011
2012      case txDescWrite:
2013        if (txDmaState != dmaIdle)
2014            goto exit;
2015
2016        if (txDescCache.cmdsts & CMDSTS_INTR)
2017            devIntrPost(ISR_TXDESC);
2018
2019        txState = txAdvance;
2020        break;
2021
2022      case txAdvance:
2023        if (txDescCache.link == 0) {
2024            devIntrPost(ISR_TXIDLE);
2025            txState = txIdle;
2026            goto exit;
2027        } else {
2028            txState = txDescRead;
2029            regs.txdp = txDescCache.link;
2030            CTDD = false;
2031
2032            txDmaAddr = txDescCache.link & 0x3fffffff;
2033            txDmaData = &txDescCache;
2034            txDmaLen = sizeof(ns_desc);
2035            txDmaFree = dmaDescFree;
2036
2037            if (doTxDmaRead())
2038                goto exit;
2039        }
2040        break;
2041
2042      default:
2043        panic("invalid state");
2044    }
2045
2046    DPRINTF(EthernetSM, "entering next txState=%s\n",
2047            NsTxStateStrings[txState]);
2048
2049    goto next;
2050
2051  exit:
2052    /**
2053     * @todo do we want to schedule a future kick?
2054     */
2055    DPRINTF(EthernetSM, "tx state machine exited txState=%s\n",
2056            NsTxStateStrings[txState]);
2057}
2058
2059void
2060NSGigE::transferDone()
2061{
2062    if (txFifo.empty()) {
2063        DPRINTF(Ethernet, "transfer complete: txFifo empty...nothing to do\n");
2064        return;
2065    }
2066
2067    DPRINTF(Ethernet, "transfer complete: data in txFifo...schedule xmit\n");
2068
2069    if (txEvent.scheduled())
2070        txEvent.reschedule(curTick + 1);
2071    else
2072        txEvent.schedule(curTick + 1);
2073}
2074
2075bool
2076NSGigE::rxFilter(PacketPtr packet)
2077{
2078    bool drop = true;
2079    string type;
2080
2081    if (packet->IsUnicast()) {
2082        type = "unicast";
2083
2084        // If we're accepting all unicast addresses
2085        if (acceptUnicast)
2086            drop = false;
2087
2088        // If we make a perfect match
2089        if (acceptPerfect &&
2090            memcmp(rom.perfectMatch, packet->data, EADDR_LEN) == 0)
2091            drop = false;
2092
2093        eth_header *eth = (eth_header *) packet->data;
2094        if ((acceptArp) && (eth->type == 0x608))
2095            drop = false;
2096
2097    } else if (packet->IsBroadcast()) {
2098        type = "broadcast";
2099
2100        // if we're accepting broadcasts
2101        if (acceptBroadcast)
2102            drop = false;
2103
2104    } else if (packet->IsMulticast()) {
2105        type = "multicast";
2106
2107        // if we're accepting all multicasts
2108        if (acceptMulticast)
2109            drop = false;
2110
2111    } else {
2112        type = "unknown";
2113
2114        // oh well, punt on this one
2115    }
2116
2117    if (drop) {
2118        DPRINTF(Ethernet, "rxFilter drop\n");
2119        DDUMP(EthernetData, packet->data, packet->length);
2120    }
2121
2122    return drop;
2123}
2124
2125bool
2126NSGigE::recvPacket(PacketPtr packet)
2127{
2128    rxBytes += packet->length;
2129    rxPackets++;
2130
2131    DPRINTF(Ethernet, "Receiving packet from wire, rxFifoAvail=%d\n",
2132            maxRxFifoSize - rxFifoCnt);
2133
2134    if (!rxEnable) {
2135        DPRINTF(Ethernet, "receive disabled...packet dropped\n");
2136        debug_break();
2137        interface->recvDone();
2138        return true;
2139    }
2140
2141    if (rxFilterEnable && rxFilter(packet)) {
2142        DPRINTF(Ethernet, "packet filtered...dropped\n");
2143        interface->recvDone();
2144        return true;
2145    }
2146
2147    if ((rxFifoCnt + packet->length) >= maxRxFifoSize) {
2148        DPRINTF(Ethernet,
2149                "packet will not fit in receive buffer...packet dropped\n");
2150        devIntrPost(ISR_RXORN);
2151        return false;
2152    }
2153
2154    rxFifo.push_back(packet);
2155    rxFifoCnt += packet->length;
2156    interface->recvDone();
2157
2158    rxKick();
2159    return true;
2160}
2161
2162/**
2163 * does a udp checksum.  if gen is true, then it generates it and puts
2164 * it in the right place else, it just checks what it calculates
2165 * against the value in the header in packet
2166 */
2167bool
2168NSGigE::udpChecksum(PacketPtr packet, bool gen)
2169{
2170    ip_header *ip = packet->getIpHdr();
2171    udp_header *hdr = packet->getUdpHdr(ip);
2172
2173    pseudo_header *pseudo = new pseudo_header;
2174
2175    pseudo->src_ip_addr = ip->src_ip_addr;
2176    pseudo->dest_ip_addr = ip->dest_ip_addr;
2177    pseudo->protocol = ip->protocol;
2178    pseudo->len = hdr->len;
2179
2180    uint16_t cksum = checksumCalc((uint16_t *) pseudo, (uint16_t *) hdr,
2181                                  (uint32_t) hdr->len);
2182
2183    delete pseudo;
2184    if (gen)
2185        hdr->chksum = cksum;
2186    else
2187        if (cksum != 0)
2188            return false;
2189
2190    return true;
2191}
2192
2193bool
2194NSGigE::tcpChecksum(PacketPtr packet, bool gen)
2195{
2196    ip_header *ip = packet->getIpHdr();
2197    tcp_header *hdr = packet->getTcpHdr(ip);
2198
2199    uint16_t cksum;
2200    pseudo_header *pseudo = new pseudo_header;
2201    if (!gen) {
2202        pseudo->src_ip_addr = ip->src_ip_addr;
2203        pseudo->dest_ip_addr = ip->dest_ip_addr;
2204        pseudo->protocol = reverseEnd16(ip->protocol);
2205        pseudo->len = reverseEnd16(reverseEnd16(ip->dgram_len) -
2206                                   (ip->vers_len & 0xf)*4);
2207
2208        cksum = checksumCalc((uint16_t *) pseudo, (uint16_t *) hdr,
2209                             (uint32_t) reverseEnd16(pseudo->len));
2210    } else {
2211        pseudo->src_ip_addr = 0;
2212        pseudo->dest_ip_addr = 0;
2213        pseudo->protocol = hdr->chksum;
2214        pseudo->len = 0;
2215        hdr->chksum = 0;
2216        cksum = checksumCalc((uint16_t *) pseudo, (uint16_t *) hdr,
2217                             (uint32_t) (reverseEnd16(ip->dgram_len) -
2218                                         (ip->vers_len & 0xf)*4));
2219    }
2220
2221    delete pseudo;
2222    if (gen)
2223        hdr->chksum = cksum;
2224    else
2225        if (cksum != 0)
2226            return false;
2227
2228    return true;
2229}
2230
2231bool
2232NSGigE::ipChecksum(PacketPtr packet, bool gen)
2233{
2234    ip_header *hdr = packet->getIpHdr();
2235
2236    uint16_t cksum = checksumCalc(NULL, (uint16_t *) hdr,
2237                                  (hdr->vers_len & 0xf)*4);
2238
2239    if (gen) {
2240        DPRINTF(EthernetCksum, "generated checksum: %#x\n", cksum);
2241        hdr->hdr_chksum = cksum;
2242    }
2243    else
2244        if (cksum != 0)
2245            return false;
2246
2247    return true;
2248}
2249
2250uint16_t
2251NSGigE::checksumCalc(uint16_t *pseudo, uint16_t *buf, uint32_t len)
2252{
2253    uint32_t sum = 0;
2254
2255    uint16_t last_pad = 0;
2256    if (len & 1) {
2257        last_pad = buf[len/2] & 0xff;
2258        len--;
2259        sum += last_pad;
2260    }
2261
2262    if (pseudo) {
2263        sum = pseudo[0] + pseudo[1] + pseudo[2] +
2264            pseudo[3] + pseudo[4] + pseudo[5];
2265    }
2266
2267    for (int i=0; i < (len/2); ++i) {
2268        sum += buf[i];
2269    }
2270
2271    while (sum >> 16)
2272        sum = (sum >> 16) + (sum & 0xffff);
2273
2274    return ~sum;
2275}
2276
2277//=====================================================================
2278//
2279//
2280void
2281NSGigE::serialize(ostream &os)
2282{
2283    // Serialize the PciDev base class
2284    PciDev::serialize(os);
2285
2286    /*
2287     * Finalize any DMA events now.
2288     */
2289    if (rxDmaReadEvent.scheduled())
2290        rxDmaReadCopy();
2291    if (rxDmaWriteEvent.scheduled())
2292        rxDmaWriteCopy();
2293    if (txDmaReadEvent.scheduled())
2294        txDmaReadCopy();
2295    if (txDmaWriteEvent.scheduled())
2296        txDmaWriteCopy();
2297
2298    /*
2299     * Serialize the device registers
2300     */
2301    SERIALIZE_SCALAR(regs.command);
2302    SERIALIZE_SCALAR(regs.config);
2303    SERIALIZE_SCALAR(regs.mear);
2304    SERIALIZE_SCALAR(regs.ptscr);
2305    SERIALIZE_SCALAR(regs.isr);
2306    SERIALIZE_SCALAR(regs.imr);
2307    SERIALIZE_SCALAR(regs.ier);
2308    SERIALIZE_SCALAR(regs.ihr);
2309    SERIALIZE_SCALAR(regs.txdp);
2310    SERIALIZE_SCALAR(regs.txdp_hi);
2311    SERIALIZE_SCALAR(regs.txcfg);
2312    SERIALIZE_SCALAR(regs.gpior);
2313    SERIALIZE_SCALAR(regs.rxdp);
2314    SERIALIZE_SCALAR(regs.rxdp_hi);
2315    SERIALIZE_SCALAR(regs.rxcfg);
2316    SERIALIZE_SCALAR(regs.pqcr);
2317    SERIALIZE_SCALAR(regs.wcsr);
2318    SERIALIZE_SCALAR(regs.pcr);
2319    SERIALIZE_SCALAR(regs.rfcr);
2320    SERIALIZE_SCALAR(regs.rfdr);
2321    SERIALIZE_SCALAR(regs.srr);
2322    SERIALIZE_SCALAR(regs.mibc);
2323    SERIALIZE_SCALAR(regs.vrcr);
2324    SERIALIZE_SCALAR(regs.vtcr);
2325    SERIALIZE_SCALAR(regs.vdr);
2326    SERIALIZE_SCALAR(regs.ccsr);
2327    SERIALIZE_SCALAR(regs.tbicr);
2328    SERIALIZE_SCALAR(regs.tbisr);
2329    SERIALIZE_SCALAR(regs.tanar);
2330    SERIALIZE_SCALAR(regs.tanlpar);
2331    SERIALIZE_SCALAR(regs.taner);
2332    SERIALIZE_SCALAR(regs.tesr);
2333
2334    SERIALIZE_ARRAY(rom.perfectMatch, EADDR_LEN);
2335
2336    SERIALIZE_SCALAR(ioEnable);
2337
2338    /*
2339     * Serialize the data Fifos
2340     */
2341    int txNumPkts = txFifo.size();
2342    SERIALIZE_SCALAR(txNumPkts);
2343    int i = 0;
2344    pktiter_t end = txFifo.end();
2345    for (pktiter_t p = txFifo.begin(); p != end; ++p) {
2346        nameOut(os, csprintf("%s.txFifo%d", name(), i++));
2347        (*p)->serialize(os);
2348    }
2349
2350    int rxNumPkts = rxFifo.size();
2351    SERIALIZE_SCALAR(rxNumPkts);
2352    i = 0;
2353    end = rxFifo.end();
2354    for (pktiter_t p = rxFifo.begin(); p != end; ++p) {
2355        nameOut(os, csprintf("%s.rxFifo%d", name(), i++));
2356        (*p)->serialize(os);
2357    }
2358
2359    /*
2360     * Serialize the various helper variables
2361     */
2362    bool txPacketExists = txPacket;
2363    SERIALIZE_SCALAR(txPacketExists);
2364    if (txPacketExists) {
2365        nameOut(os, csprintf("%s.txPacket", name()));
2366        txPacket->serialize(os);
2367        uint32_t txPktBufPtr = (uint32_t) (txPacketBufPtr - txPacket->data);
2368        SERIALIZE_SCALAR(txPktBufPtr);
2369    }
2370
2371    bool rxPacketExists = rxPacket;
2372    SERIALIZE_SCALAR(rxPacketExists);
2373    if (rxPacketExists) {
2374        nameOut(os, csprintf("%s.rxPacket", name()));
2375        rxPacket->serialize(os);
2376        uint32_t rxPktBufPtr = (uint32_t) (rxPacketBufPtr - rxPacket->data);
2377        SERIALIZE_SCALAR(rxPktBufPtr);
2378    }
2379
2380    SERIALIZE_SCALAR(txXferLen);
2381    SERIALIZE_SCALAR(rxXferLen);
2382
2383    /*
2384     * Serialize DescCaches
2385     */
2386    SERIALIZE_SCALAR(txDescCache.link);
2387    SERIALIZE_SCALAR(txDescCache.bufptr);
2388    SERIALIZE_SCALAR(txDescCache.cmdsts);
2389    SERIALIZE_SCALAR(txDescCache.extsts);
2390    SERIALIZE_SCALAR(rxDescCache.link);
2391    SERIALIZE_SCALAR(rxDescCache.bufptr);
2392    SERIALIZE_SCALAR(rxDescCache.cmdsts);
2393    SERIALIZE_SCALAR(rxDescCache.extsts);
2394
2395    /*
2396     * Serialize tx state machine
2397     */
2398    int txState = this->txState;
2399    SERIALIZE_SCALAR(txState);
2400    SERIALIZE_SCALAR(txEnable);
2401    SERIALIZE_SCALAR(CTDD);
2402    SERIALIZE_SCALAR(txFifoAvail);
2403    SERIALIZE_SCALAR(txFragPtr);
2404    SERIALIZE_SCALAR(txDescCnt);
2405    int txDmaState = this->txDmaState;
2406    SERIALIZE_SCALAR(txDmaState);
2407
2408    /*
2409     * Serialize rx state machine
2410     */
2411    int rxState = this->rxState;
2412    SERIALIZE_SCALAR(rxState);
2413    SERIALIZE_SCALAR(rxEnable);
2414    SERIALIZE_SCALAR(CRDD);
2415    SERIALIZE_SCALAR(rxPktBytes);
2416    SERIALIZE_SCALAR(rxFifoCnt);
2417    SERIALIZE_SCALAR(rxDescCnt);
2418    int rxDmaState = this->rxDmaState;
2419    SERIALIZE_SCALAR(rxDmaState);
2420
2421    SERIALIZE_SCALAR(extstsEnable);
2422
2423    /*
2424     * If there's a pending transmit, store the time so we can
2425     * reschedule it later
2426     */
2427    Tick transmitTick = txEvent.scheduled() ? txEvent.when() - curTick : 0;
2428    SERIALIZE_SCALAR(transmitTick);
2429
2430    /*
2431     * receive address filter settings
2432     */
2433    SERIALIZE_SCALAR(rxFilterEnable);
2434    SERIALIZE_SCALAR(acceptBroadcast);
2435    SERIALIZE_SCALAR(acceptMulticast);
2436    SERIALIZE_SCALAR(acceptUnicast);
2437    SERIALIZE_SCALAR(acceptPerfect);
2438    SERIALIZE_SCALAR(acceptArp);
2439
2440    /*
2441     * Keep track of pending interrupt status.
2442     */
2443    SERIALIZE_SCALAR(intrTick);
2444    SERIALIZE_SCALAR(cpuPendingIntr);
2445    Tick intrEventTick = 0;
2446    if (intrEvent)
2447        intrEventTick = intrEvent->when();
2448    SERIALIZE_SCALAR(intrEventTick);
2449
2450}
2451
2452void
2453NSGigE::unserialize(Checkpoint *cp, const std::string &section)
2454{
2455    // Unserialize the PciDev base class
2456    PciDev::unserialize(cp, section);
2457
2458    UNSERIALIZE_SCALAR(regs.command);
2459    UNSERIALIZE_SCALAR(regs.config);
2460    UNSERIALIZE_SCALAR(regs.mear);
2461    UNSERIALIZE_SCALAR(regs.ptscr);
2462    UNSERIALIZE_SCALAR(regs.isr);
2463    UNSERIALIZE_SCALAR(regs.imr);
2464    UNSERIALIZE_SCALAR(regs.ier);
2465    UNSERIALIZE_SCALAR(regs.ihr);
2466    UNSERIALIZE_SCALAR(regs.txdp);
2467    UNSERIALIZE_SCALAR(regs.txdp_hi);
2468    UNSERIALIZE_SCALAR(regs.txcfg);
2469    UNSERIALIZE_SCALAR(regs.gpior);
2470    UNSERIALIZE_SCALAR(regs.rxdp);
2471    UNSERIALIZE_SCALAR(regs.rxdp_hi);
2472    UNSERIALIZE_SCALAR(regs.rxcfg);
2473    UNSERIALIZE_SCALAR(regs.pqcr);
2474    UNSERIALIZE_SCALAR(regs.wcsr);
2475    UNSERIALIZE_SCALAR(regs.pcr);
2476    UNSERIALIZE_SCALAR(regs.rfcr);
2477    UNSERIALIZE_SCALAR(regs.rfdr);
2478    UNSERIALIZE_SCALAR(regs.srr);
2479    UNSERIALIZE_SCALAR(regs.mibc);
2480    UNSERIALIZE_SCALAR(regs.vrcr);
2481    UNSERIALIZE_SCALAR(regs.vtcr);
2482    UNSERIALIZE_SCALAR(regs.vdr);
2483    UNSERIALIZE_SCALAR(regs.ccsr);
2484    UNSERIALIZE_SCALAR(regs.tbicr);
2485    UNSERIALIZE_SCALAR(regs.tbisr);
2486    UNSERIALIZE_SCALAR(regs.tanar);
2487    UNSERIALIZE_SCALAR(regs.tanlpar);
2488    UNSERIALIZE_SCALAR(regs.taner);
2489    UNSERIALIZE_SCALAR(regs.tesr);
2490
2491    UNSERIALIZE_ARRAY(rom.perfectMatch, EADDR_LEN);
2492
2493    UNSERIALIZE_SCALAR(ioEnable);
2494
2495    /*
2496     * unserialize the data fifos
2497     */
2498    int txNumPkts;
2499    UNSERIALIZE_SCALAR(txNumPkts);
2500    int i;
2501    for (i = 0; i < txNumPkts; ++i) {
2502        PacketPtr p = new EtherPacket;
2503        p->unserialize(cp, csprintf("%s.rxFifo%d", section, i));
2504        txFifo.push_back(p);
2505    }
2506
2507    int rxNumPkts;
2508    UNSERIALIZE_SCALAR(rxNumPkts);
2509    for (i = 0; i < rxNumPkts; ++i) {
2510        PacketPtr p = new EtherPacket;
2511        p->unserialize(cp, csprintf("%s.rxFifo%d", section, i));
2512        rxFifo.push_back(p);
2513    }
2514
2515    /*
2516     * unserialize the various helper variables
2517     */
2518    bool txPacketExists;
2519    UNSERIALIZE_SCALAR(txPacketExists);
2520    if (txPacketExists) {
2521        txPacket = new EtherPacket;
2522        txPacket->unserialize(cp, csprintf("%s.txPacket", section));
2523        uint32_t txPktBufPtr;
2524        UNSERIALIZE_SCALAR(txPktBufPtr);
2525        txPacketBufPtr = (uint8_t *) txPacket->data + txPktBufPtr;
2526    } else
2527        txPacket = 0;
2528
2529    bool rxPacketExists;
2530    UNSERIALIZE_SCALAR(rxPacketExists);
2531    rxPacket = 0;
2532    if (rxPacketExists) {
2533        rxPacket = new EtherPacket;
2534        rxPacket->unserialize(cp, csprintf("%s.rxPacket", section));
2535        uint32_t rxPktBufPtr;
2536        UNSERIALIZE_SCALAR(rxPktBufPtr);
2537        rxPacketBufPtr = (uint8_t *) rxPacket->data + rxPktBufPtr;
2538    } else
2539        rxPacket = 0;
2540
2541    UNSERIALIZE_SCALAR(txXferLen);
2542    UNSERIALIZE_SCALAR(rxXferLen);
2543
2544    /*
2545     * Unserialize DescCaches
2546     */
2547    UNSERIALIZE_SCALAR(txDescCache.link);
2548    UNSERIALIZE_SCALAR(txDescCache.bufptr);
2549    UNSERIALIZE_SCALAR(txDescCache.cmdsts);
2550    UNSERIALIZE_SCALAR(txDescCache.extsts);
2551    UNSERIALIZE_SCALAR(rxDescCache.link);
2552    UNSERIALIZE_SCALAR(rxDescCache.bufptr);
2553    UNSERIALIZE_SCALAR(rxDescCache.cmdsts);
2554    UNSERIALIZE_SCALAR(rxDescCache.extsts);
2555
2556    /*
2557     * unserialize tx state machine
2558     */
2559    int txState;
2560    UNSERIALIZE_SCALAR(txState);
2561    this->txState = (TxState) txState;
2562    UNSERIALIZE_SCALAR(txEnable);
2563    UNSERIALIZE_SCALAR(CTDD);
2564    UNSERIALIZE_SCALAR(txFifoAvail);
2565    UNSERIALIZE_SCALAR(txFragPtr);
2566    UNSERIALIZE_SCALAR(txDescCnt);
2567    int txDmaState;
2568    UNSERIALIZE_SCALAR(txDmaState);
2569    this->txDmaState = (DmaState) txDmaState;
2570
2571    /*
2572     * unserialize rx state machine
2573     */
2574    int rxState;
2575    UNSERIALIZE_SCALAR(rxState);
2576    this->rxState = (RxState) rxState;
2577    UNSERIALIZE_SCALAR(rxEnable);
2578    UNSERIALIZE_SCALAR(CRDD);
2579    UNSERIALIZE_SCALAR(rxPktBytes);
2580    UNSERIALIZE_SCALAR(rxFifoCnt);
2581    UNSERIALIZE_SCALAR(rxDescCnt);
2582    int rxDmaState;
2583    UNSERIALIZE_SCALAR(rxDmaState);
2584    this->rxDmaState = (DmaState) rxDmaState;
2585
2586    UNSERIALIZE_SCALAR(extstsEnable);
2587
2588     /*
2589     * If there's a pending transmit, reschedule it now
2590     */
2591    Tick transmitTick;
2592    UNSERIALIZE_SCALAR(transmitTick);
2593    if (transmitTick)
2594        txEvent.schedule(curTick + transmitTick);
2595
2596    /*
2597     * unserialize receive address filter settings
2598     */
2599    UNSERIALIZE_SCALAR(rxFilterEnable);
2600    UNSERIALIZE_SCALAR(acceptBroadcast);
2601    UNSERIALIZE_SCALAR(acceptMulticast);
2602    UNSERIALIZE_SCALAR(acceptUnicast);
2603    UNSERIALIZE_SCALAR(acceptPerfect);
2604    UNSERIALIZE_SCALAR(acceptArp);
2605
2606    /*
2607     * Keep track of pending interrupt status.
2608     */
2609    UNSERIALIZE_SCALAR(intrTick);
2610    UNSERIALIZE_SCALAR(cpuPendingIntr);
2611    Tick intrEventTick;
2612    UNSERIALIZE_SCALAR(intrEventTick);
2613    if (intrEventTick) {
2614        intrEvent = new IntrEvent(this, true);
2615        intrEvent->schedule(intrEventTick);
2616    }
2617
2618    /*
2619     * re-add addrRanges to bus bridges
2620     */
2621    if (pioInterface) {
2622        pioInterface->addAddrRange(BARAddrs[0], BARAddrs[0] + BARSize[0] - 1);
2623        pioInterface->addAddrRange(BARAddrs[1], BARAddrs[1] + BARSize[1] - 1);
2624    }
2625}
2626
2627Tick
2628NSGigE::cacheAccess(MemReqPtr &req)
2629{
2630    DPRINTF(EthernetPIO, "timing access to paddr=%#x (daddr=%#x)\n",
2631            req->paddr, req->paddr - addr);
2632    return curTick + pioLatency;
2633}
2634//=====================================================================
2635
2636
2637//********** helper functions******************************************
2638
2639uint16_t reverseEnd16(uint16_t num)
2640{
2641    uint16_t reverse = (num & 0xff)<<8;
2642    reverse += ((num & 0xff00) >> 8);
2643    return reverse;
2644}
2645
2646uint32_t reverseEnd32(uint32_t num)
2647{
2648    uint32_t reverse = (reverseEnd16(num & 0xffff)) << 16;
2649    reverse += reverseEnd16((uint16_t) ((num & 0xffff0000) >> 8));
2650    return reverse;
2651}
2652
2653
2654
2655//=====================================================================
2656
2657BEGIN_DECLARE_SIM_OBJECT_PARAMS(NSGigEInt)
2658
2659    SimObjectParam<EtherInt *> peer;
2660    SimObjectParam<NSGigE *> device;
2661
2662END_DECLARE_SIM_OBJECT_PARAMS(NSGigEInt)
2663
2664BEGIN_INIT_SIM_OBJECT_PARAMS(NSGigEInt)
2665
2666    INIT_PARAM_DFLT(peer, "peer interface", NULL),
2667    INIT_PARAM(device, "Ethernet device of this interface")
2668
2669END_INIT_SIM_OBJECT_PARAMS(NSGigEInt)
2670
2671CREATE_SIM_OBJECT(NSGigEInt)
2672{
2673    NSGigEInt *dev_int = new NSGigEInt(getInstanceName(), device);
2674
2675    EtherInt *p = (EtherInt *)peer;
2676    if (p) {
2677        dev_int->setPeer(p);
2678        p->setPeer(dev_int);
2679    }
2680
2681    return dev_int;
2682}
2683
2684REGISTER_SIM_OBJECT("NSGigEInt", NSGigEInt)
2685
2686
2687BEGIN_DECLARE_SIM_OBJECT_PARAMS(NSGigE)
2688
2689    Param<Tick> tx_delay;
2690    Param<Tick> rx_delay;
2691    SimObjectParam<IntrControl *> intr_ctrl;
2692    Param<Tick> intr_delay;
2693    SimObjectParam<MemoryController *> mmu;
2694    SimObjectParam<PhysicalMemory *> physmem;
2695    Param<bool> rx_filter;
2696    Param<string> hardware_address;
2697    SimObjectParam<Bus*> header_bus;
2698    SimObjectParam<Bus*> payload_bus;
2699    SimObjectParam<HierParams *> hier;
2700    Param<Tick> pio_latency;
2701    Param<bool> dma_desc_free;
2702    Param<bool> dma_data_free;
2703    Param<Tick> dma_read_delay;
2704    Param<Tick> dma_write_delay;
2705    Param<Tick> dma_read_factor;
2706    Param<Tick> dma_write_factor;
2707    SimObjectParam<PciConfigAll *> configspace;
2708    SimObjectParam<PciConfigData *> configdata;
2709    SimObjectParam<Tsunami *> tsunami;
2710    Param<uint32_t> pci_bus;
2711    Param<uint32_t> pci_dev;
2712    Param<uint32_t> pci_func;
2713    Param<uint32_t> tx_fifo_size;
2714    Param<uint32_t> rx_fifo_size;
2715
2716END_DECLARE_SIM_OBJECT_PARAMS(NSGigE)
2717
2718BEGIN_INIT_SIM_OBJECT_PARAMS(NSGigE)
2719
2720    INIT_PARAM_DFLT(tx_delay, "Transmit Delay", 1000),
2721    INIT_PARAM_DFLT(rx_delay, "Receive Delay", 1000),
2722    INIT_PARAM(intr_ctrl, "Interrupt Controller"),
2723    INIT_PARAM_DFLT(intr_delay, "Interrupt Delay in microseconds", 0),
2724    INIT_PARAM(mmu, "Memory Controller"),
2725    INIT_PARAM(physmem, "Physical Memory"),
2726    INIT_PARAM_DFLT(rx_filter, "Enable Receive Filter", true),
2727    INIT_PARAM_DFLT(hardware_address, "Ethernet Hardware Address",
2728                    "00:99:00:00:00:01"),
2729    INIT_PARAM_DFLT(header_bus, "The IO Bus to attach to for headers", NULL),
2730    INIT_PARAM_DFLT(payload_bus, "The IO Bus to attach to for payload", NULL),
2731    INIT_PARAM_DFLT(hier, "Hierarchy global variables", &defaultHierParams),
2732    INIT_PARAM_DFLT(pio_latency, "Programmed IO latency in bus cycles", 1),
2733    INIT_PARAM_DFLT(dma_desc_free, "DMA of Descriptors is free", false),
2734    INIT_PARAM_DFLT(dma_data_free, "DMA of Data is free", false),
2735    INIT_PARAM_DFLT(dma_read_delay, "fixed delay for dma reads", 0),
2736    INIT_PARAM_DFLT(dma_write_delay, "fixed delay for dma writes", 0),
2737    INIT_PARAM_DFLT(dma_read_factor, "multiplier for dma reads", 0),
2738    INIT_PARAM_DFLT(dma_write_factor, "multiplier for dma writes", 0),
2739    INIT_PARAM(configspace, "PCI Configspace"),
2740    INIT_PARAM(configdata, "PCI Config data"),
2741    INIT_PARAM(tsunami, "Tsunami"),
2742    INIT_PARAM(pci_bus, "PCI bus"),
2743    INIT_PARAM(pci_dev, "PCI device number"),
2744    INIT_PARAM(pci_func, "PCI function code"),
2745    INIT_PARAM_DFLT(tx_fifo_size, "max size in bytes of txFifo", 131072),
2746    INIT_PARAM_DFLT(rx_fifo_size, "max size in bytes of rxFifo", 131072)
2747
2748END_INIT_SIM_OBJECT_PARAMS(NSGigE)
2749
2750
2751CREATE_SIM_OBJECT(NSGigE)
2752{
2753    int eaddr[6];
2754    sscanf(((string)hardware_address).c_str(), "%x:%x:%x:%x:%x:%x",
2755           &eaddr[0], &eaddr[1], &eaddr[2], &eaddr[3], &eaddr[4], &eaddr[5]);
2756
2757    return new NSGigE(getInstanceName(), intr_ctrl, intr_delay,
2758                      physmem, tx_delay, rx_delay, mmu, hier, header_bus,
2759                      payload_bus, pio_latency, dma_desc_free, dma_data_free,
2760                      dma_read_delay, dma_write_delay, dma_read_factor,
2761                      dma_write_factor, configspace, configdata,
2762                      tsunami, pci_bus, pci_dev, pci_func, rx_filter, eaddr,
2763                      tx_fifo_size, rx_fifo_size);
2764}
2765
2766REGISTER_SIM_OBJECT("NSGigE", NSGigE)
2767