ns_gige.cc revision 944
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/ns_gige.hh"
427376Sgblack@eecs.umich.edu#include "dev/etherlink.hh"
437376Sgblack@eecs.umich.edu#include "mem/bus/bus.hh"
447376Sgblack@eecs.umich.edu#include "mem/bus/dma_interface.hh"
457376Sgblack@eecs.umich.edu#include "mem/bus/pio_interface.hh"
467376Sgblack@eecs.umich.edu#include "mem/bus/pio_interface_impl.hh"
477376Sgblack@eecs.umich.edu#include "mem/functional_mem/memory_control.hh"
487376Sgblack@eecs.umich.edu#include "mem/functional_mem/physical_memory.hh"
497376Sgblack@eecs.umich.edu#include "sim/builder.hh"
507376Sgblack@eecs.umich.edu#include "sim/host.hh"
517376Sgblack@eecs.umich.edu#include "sim/sim_stats.hh"
527376Sgblack@eecs.umich.edu#include "targetarch/vtophys.hh"
537376Sgblack@eecs.umich.edu#include "dev/pciconfigall.hh"
547376Sgblack@eecs.umich.edu#include "dev/tsunami_cchip.hh"
557376Sgblack@eecs.umich.edu
567376Sgblack@eecs.umich.educonst char *NsRxStateStrings[] =
577376Sgblack@eecs.umich.edu{
587376Sgblack@eecs.umich.edu    "rxIdle",
597376Sgblack@eecs.umich.edu    "rxDescRefr",
607376Sgblack@eecs.umich.edu    "rxDescRead",
617376Sgblack@eecs.umich.edu    "rxFifoBlock",
627376Sgblack@eecs.umich.edu    "rxFragWrite",
637376Sgblack@eecs.umich.edu    "rxDescWrite",
647376Sgblack@eecs.umich.edu    "rxAdvance"
657376Sgblack@eecs.umich.edu};
667376Sgblack@eecs.umich.edu
677376Sgblack@eecs.umich.educonst char *NsTxStateStrings[] =
687376Sgblack@eecs.umich.edu{
697376Sgblack@eecs.umich.edu    "txIdle",
707376Sgblack@eecs.umich.edu    "txDescRefr",
717376Sgblack@eecs.umich.edu    "txDescRead",
727376Sgblack@eecs.umich.edu    "txFifoBlock",
737376Sgblack@eecs.umich.edu    "txFragRead",
747376Sgblack@eecs.umich.edu    "txDescWrite",
757376Sgblack@eecs.umich.edu    "txAdvance"
767376Sgblack@eecs.umich.edu};
777376Sgblack@eecs.umich.edu
787376Sgblack@eecs.umich.educonst char *NsDmaState[] =
797376Sgblack@eecs.umich.edu{
807376Sgblack@eecs.umich.edu    "dmaIdle",
817376Sgblack@eecs.umich.edu    "dmaReading",
827376Sgblack@eecs.umich.edu    "dmaWriting",
837376Sgblack@eecs.umich.edu    "dmaReadWaiting",
847376Sgblack@eecs.umich.edu    "dmaWriteWaiting"
857376Sgblack@eecs.umich.edu};
867376Sgblack@eecs.umich.edu
877376Sgblack@eecs.umich.eduusing namespace std;
887376Sgblack@eecs.umich.edu
897376Sgblack@eecs.umich.edu//helper function declarations
907376Sgblack@eecs.umich.edu//These functions reverse Endianness so we can evaluate network data correctly
917376Sgblack@eecs.umich.eduuint16_t reverseEnd16(uint16_t);
927376Sgblack@eecs.umich.eduuint32_t reverseEnd32(uint32_t);
937376Sgblack@eecs.umich.edu
947376Sgblack@eecs.umich.edu///////////////////////////////////////////////////////////////////////
957376Sgblack@eecs.umich.edu//
967376Sgblack@eecs.umich.edu// NSGigE PCI Device
977376Sgblack@eecs.umich.edu//
987376Sgblack@eecs.umich.eduNSGigE::NSGigE(const std::string &name, IntrControl *i, Tick intr_delay,
997376Sgblack@eecs.umich.edu             PhysicalMemory *pmem, Tick tx_delay, Tick rx_delay,
1007376Sgblack@eecs.umich.edu             MemoryController *mmu, HierParams *hier, Bus *header_bus,
1017376Sgblack@eecs.umich.edu             Bus *payload_bus, Tick pio_latency, bool dma_desc_free,
1027376Sgblack@eecs.umich.edu             bool dma_data_free, Tick dma_read_delay, Tick dma_write_delay,
1037376Sgblack@eecs.umich.edu             Tick dma_read_factor, Tick dma_write_factor, PciConfigAll *cf,
1047376Sgblack@eecs.umich.edu             PciConfigData *cd, Tsunami *t, uint32_t bus, uint32_t dev,
1057376Sgblack@eecs.umich.edu             uint32_t func, bool rx_filter, const int eaddr[6])
1067376Sgblack@eecs.umich.edu    : PciDev(name, mmu, cf, cd, bus, dev, func), tsunami(t), ioEnable(false),
1077376Sgblack@eecs.umich.edu      txPacket(0), rxPacket(0), txPacketBufPtr(NULL), rxPacketBufPtr(NULL),
1087376Sgblack@eecs.umich.edu      txXferLen(0), rxXferLen(0), txState(txIdle), CTDD(false),
1097376Sgblack@eecs.umich.edu      txFifoAvail(MAX_TX_FIFO_SIZE), txHalt(false),
1107376Sgblack@eecs.umich.edu      txFragPtr(0), txDescCnt(0), txDmaState(dmaIdle), rxState(rxIdle),
1117376Sgblack@eecs.umich.edu      CRDD(false), rxPktBytes(0), rxFifoCnt(0), rxHalt(false),
1127376Sgblack@eecs.umich.edu      rxFragPtr(0), rxDescCnt(0), rxDmaState(dmaIdle), extstsEnable(false),
1137376Sgblack@eecs.umich.edu      rxDmaReadEvent(this), rxDmaWriteEvent(this),
1147376Sgblack@eecs.umich.edu      txDmaReadEvent(this), txDmaWriteEvent(this),
1157376Sgblack@eecs.umich.edu      dmaDescFree(dma_desc_free), dmaDataFree(dma_data_free),
1167376Sgblack@eecs.umich.edu      txDelay(tx_delay), rxDelay(rx_delay), rxKickTick(0), txKickTick(0),
1177376Sgblack@eecs.umich.edu      txEvent(this), rxFilterEnable(rx_filter), acceptBroadcast(false),
1187376Sgblack@eecs.umich.edu      acceptMulticast(false), acceptUnicast(false),
1197376Sgblack@eecs.umich.edu      acceptPerfect(false), acceptArp(false),
1207376Sgblack@eecs.umich.edu      physmem(pmem), intctrl(i), intrTick(0), cpuPendingIntr(false),
1217376Sgblack@eecs.umich.edu      intrEvent(0), interface(0), pioLatency(pio_latency)
1227376Sgblack@eecs.umich.edu{
1237376Sgblack@eecs.umich.edu    tsunami->ethernet = this;
1247376Sgblack@eecs.umich.edu
1257376Sgblack@eecs.umich.edu    if (header_bus) {
1267376Sgblack@eecs.umich.edu        pioInterface = newPioInterface(name, hier, header_bus, this,
1277376Sgblack@eecs.umich.edu                                       &NSGigE::cacheAccess);
1287376Sgblack@eecs.umich.edu
1297376Sgblack@eecs.umich.edu        if (payload_bus)
1307376Sgblack@eecs.umich.edu            dmaInterface = new DMAInterface<Bus>(name + ".dma",
1317376Sgblack@eecs.umich.edu                                                 header_bus, payload_bus, 1);
1327376Sgblack@eecs.umich.edu        else
1337376Sgblack@eecs.umich.edu            dmaInterface = new DMAInterface<Bus>(name + ".dma",
1347376Sgblack@eecs.umich.edu                                                 header_bus, header_bus, 1);
1357376Sgblack@eecs.umich.edu    } else if (payload_bus) {
1367376Sgblack@eecs.umich.edu        pioInterface = newPioInterface(name, hier, payload_bus, this,
1377376Sgblack@eecs.umich.edu                                       &NSGigE::cacheAccess);
1387376Sgblack@eecs.umich.edu
1397376Sgblack@eecs.umich.edu        dmaInterface = new DMAInterface<Bus>(name + ".dma", payload_bus,
1407376Sgblack@eecs.umich.edu                                         payload_bus, 1);
1417376Sgblack@eecs.umich.edu
1427376Sgblack@eecs.umich.edu    }
1437376Sgblack@eecs.umich.edu
1447376Sgblack@eecs.umich.edu
1457376Sgblack@eecs.umich.edu    intrDelay = US2Ticks(intr_delay);
1467376Sgblack@eecs.umich.edu    dmaReadDelay = dma_read_delay;
1477376Sgblack@eecs.umich.edu    dmaWriteDelay = dma_write_delay;
1487376Sgblack@eecs.umich.edu    dmaReadFactor = dma_read_factor;
1497376Sgblack@eecs.umich.edu    dmaWriteFactor = dma_write_factor;
1507376Sgblack@eecs.umich.edu
1517376Sgblack@eecs.umich.edu    regsReset();
1527376Sgblack@eecs.umich.edu    rom.perfectMatch[0] = eaddr[0];
1537376Sgblack@eecs.umich.edu    rom.perfectMatch[1] = eaddr[1];
1547376Sgblack@eecs.umich.edu    rom.perfectMatch[2] = eaddr[2];
1557376Sgblack@eecs.umich.edu    rom.perfectMatch[3] = eaddr[3];
1567376Sgblack@eecs.umich.edu    rom.perfectMatch[4] = eaddr[4];
1577376Sgblack@eecs.umich.edu    rom.perfectMatch[5] = eaddr[5];
1587376Sgblack@eecs.umich.edu}
1597376Sgblack@eecs.umich.edu
1607376Sgblack@eecs.umich.eduNSGigE::~NSGigE()
1617376Sgblack@eecs.umich.edu{}
1627376Sgblack@eecs.umich.edu
1637376Sgblack@eecs.umich.eduvoid
1647376Sgblack@eecs.umich.eduNSGigE::regStats()
1657376Sgblack@eecs.umich.edu{
1667376Sgblack@eecs.umich.edu    txBytes
1677376Sgblack@eecs.umich.edu        .name(name() + ".txBytes")
1687376Sgblack@eecs.umich.edu        .desc("Bytes Transmitted")
1697376Sgblack@eecs.umich.edu        .prereq(txBytes)
1707376Sgblack@eecs.umich.edu        ;
1717376Sgblack@eecs.umich.edu
1727376Sgblack@eecs.umich.edu    rxBytes
1737376Sgblack@eecs.umich.edu        .name(name() + ".rxBytes")
1747376Sgblack@eecs.umich.edu        .desc("Bytes Received")
1757376Sgblack@eecs.umich.edu        .prereq(rxBytes)
1767376Sgblack@eecs.umich.edu        ;
1777376Sgblack@eecs.umich.edu
1787376Sgblack@eecs.umich.edu    txPackets
1797376Sgblack@eecs.umich.edu        .name(name() + ".txPackets")
1807376Sgblack@eecs.umich.edu        .desc("Number of Packets Transmitted")
1817376Sgblack@eecs.umich.edu        .prereq(txBytes)
1827376Sgblack@eecs.umich.edu        ;
1837376Sgblack@eecs.umich.edu
1847376Sgblack@eecs.umich.edu    rxPackets
1857376Sgblack@eecs.umich.edu        .name(name() + ".rxPackets")
1867376Sgblack@eecs.umich.edu        .desc("Number of Packets Received")
1877376Sgblack@eecs.umich.edu        .prereq(rxBytes)
1887322Sgblack@eecs.umich.edu        ;
1897322Sgblack@eecs.umich.edu
1907322Sgblack@eecs.umich.edu    txBandwidth
1917322Sgblack@eecs.umich.edu        .name(name() + ".txBandwidth")
1927322Sgblack@eecs.umich.edu        .desc("Transmit Bandwidth (bits/s)")
1937322Sgblack@eecs.umich.edu        .precision(0)
1947396Sgblack@eecs.umich.edu        .prereq(txBytes)
1957640Sgblack@eecs.umich.edu        ;
1967640Sgblack@eecs.umich.edu
1977322Sgblack@eecs.umich.edu    rxBandwidth
1987396Sgblack@eecs.umich.edu        .name(name() + ".rxBandwidth")
1997396Sgblack@eecs.umich.edu        .desc("Receive Bandwidth (bits/s)")
2007322Sgblack@eecs.umich.edu        .precision(0)
2017324Sgblack@eecs.umich.edu        .prereq(rxBytes)
2027643Sgblack@eecs.umich.edu        ;
2037643Sgblack@eecs.umich.edu
2047643Sgblack@eecs.umich.edu    txPacketRate
2057643Sgblack@eecs.umich.edu        .name(name() + ".txPPS")
2067643Sgblack@eecs.umich.edu        .desc("Packet Tranmission Rate (packets/s)")
2077643Sgblack@eecs.umich.edu        .precision(0)
2087643Sgblack@eecs.umich.edu        .prereq(txBytes)
2097643Sgblack@eecs.umich.edu        ;
2107643Sgblack@eecs.umich.edu
2117643Sgblack@eecs.umich.edu    rxPacketRate
2127643Sgblack@eecs.umich.edu        .name(name() + ".rxPPS")
2137396Sgblack@eecs.umich.edu        .desc("Packet Reception Rate (packets/s)")
2147640Sgblack@eecs.umich.edu        .precision(0)
2157640Sgblack@eecs.umich.edu        .prereq(rxBytes)
2167324Sgblack@eecs.umich.edu        ;
2177396Sgblack@eecs.umich.edu
2187396Sgblack@eecs.umich.edu    txBandwidth = txBytes * Stats::constant(8) / simSeconds;
2197324Sgblack@eecs.umich.edu    rxBandwidth = rxBytes * Stats::constant(8) / simSeconds;
2207333Sgblack@eecs.umich.edu    txPacketRate = txPackets / simSeconds;
2217643Sgblack@eecs.umich.edu    rxPacketRate = rxPackets / simSeconds;
2227643Sgblack@eecs.umich.edu}
2237643Sgblack@eecs.umich.edu
2247643Sgblack@eecs.umich.edu/**
2257643Sgblack@eecs.umich.edu * This is to read the PCI general configuration registers
2267643Sgblack@eecs.umich.edu */
2277643Sgblack@eecs.umich.eduvoid
2287643Sgblack@eecs.umich.eduNSGigE::ReadConfig(int offset, int size, uint8_t *data)
2297643Sgblack@eecs.umich.edu{
2307643Sgblack@eecs.umich.edu    if (offset < PCI_DEVICE_SPECIFIC)
2317643Sgblack@eecs.umich.edu        PciDev::ReadConfig(offset, size, data);
2327396Sgblack@eecs.umich.edu    else
2337392Sgblack@eecs.umich.edu        panic("Device specific PCI config space not implemented!\n");
2347392Sgblack@eecs.umich.edu}
2357396Sgblack@eecs.umich.edu
2367396Sgblack@eecs.umich.edu/**
2377392Sgblack@eecs.umich.edu * This is to write to the PCI general configuration registers
2387392Sgblack@eecs.umich.edu */
2397643Sgblack@eecs.umich.eduvoid
2407643Sgblack@eecs.umich.eduNSGigE::WriteConfig(int offset, int size, uint32_t data)
2417643Sgblack@eecs.umich.edu{
2427643Sgblack@eecs.umich.edu    if (offset < PCI_DEVICE_SPECIFIC)
2437643Sgblack@eecs.umich.edu        PciDev::WriteConfig(offset, size, data);
2447643Sgblack@eecs.umich.edu    else
2457643Sgblack@eecs.umich.edu        panic("Device specific PCI config space not implemented!\n");
2467643Sgblack@eecs.umich.edu
2477643Sgblack@eecs.umich.edu    // Need to catch writes to BARs to update the PIO interface
2487643Sgblack@eecs.umich.edu    switch (offset) {
2497643Sgblack@eecs.umich.edu        //seems to work fine without all these PCI settings, but i put in the IO
2507640Sgblack@eecs.umich.edu        //to double check, an assertion will fail if we need to properly
2517333Sgblack@eecs.umich.edu        // implement it
2527333Sgblack@eecs.umich.edu      case PCI_COMMAND:
2537396Sgblack@eecs.umich.edu        if (config.data[offset] & PCI_CMD_IOSE)
2547333Sgblack@eecs.umich.edu            ioEnable = true;
2557333Sgblack@eecs.umich.edu        else
2567396Sgblack@eecs.umich.edu            ioEnable = false;
2577396Sgblack@eecs.umich.edu
2587333Sgblack@eecs.umich.edu#if 0
2597333Sgblack@eecs.umich.edu        if (config.data[offset] & PCI_CMD_BME) {
2607640Sgblack@eecs.umich.edu            bmEnabled = true;
2617333Sgblack@eecs.umich.edu        }
2627333Sgblack@eecs.umich.edu        else {
2637333Sgblack@eecs.umich.edu            bmEnabled = false;
2647396Sgblack@eecs.umich.edu        }
2657333Sgblack@eecs.umich.edu
2667333Sgblack@eecs.umich.edu        if (config.data[offset] & PCI_CMD_MSE) {
2677396Sgblack@eecs.umich.edu            memEnable = true;
2687396Sgblack@eecs.umich.edu        }
2697333Sgblack@eecs.umich.edu        else {
2707333Sgblack@eecs.umich.edu            memEnable = false;
2717640Sgblack@eecs.umich.edu        }
2727333Sgblack@eecs.umich.edu#endif
2737333Sgblack@eecs.umich.edu        break;
2747333Sgblack@eecs.umich.edu
2757333Sgblack@eecs.umich.edu      case PCI0_BASE_ADDR0:
2767333Sgblack@eecs.umich.edu        if (BARAddrs[0] != 0) {
2777396Sgblack@eecs.umich.edu
2787333Sgblack@eecs.umich.edu            if (pioInterface)
2797333Sgblack@eecs.umich.edu                pioInterface->addAddrRange(BARAddrs[0], BARAddrs[0] + BARSize[0] - 1);
2807396Sgblack@eecs.umich.edu
2817396Sgblack@eecs.umich.edu            BARAddrs[0] &= PA_UNCACHED_MASK;
2827333Sgblack@eecs.umich.edu
2837333Sgblack@eecs.umich.edu        }
2847640Sgblack@eecs.umich.edu        break;
2857333Sgblack@eecs.umich.edu      case PCI0_BASE_ADDR1:
2867333Sgblack@eecs.umich.edu        if (BARAddrs[1] != 0) {
2877396Sgblack@eecs.umich.edu
2887333Sgblack@eecs.umich.edu            if (pioInterface)
2897333Sgblack@eecs.umich.edu                pioInterface->addAddrRange(BARAddrs[1], BARAddrs[1] + BARSize[1] - 1);
2907396Sgblack@eecs.umich.edu
2917396Sgblack@eecs.umich.edu            BARAddrs[1] &= PA_UNCACHED_MASK;
2927333Sgblack@eecs.umich.edu
2937333Sgblack@eecs.umich.edu        }
2947640Sgblack@eecs.umich.edu        break;
2957333Sgblack@eecs.umich.edu    }
2967333Sgblack@eecs.umich.edu}
2977333Sgblack@eecs.umich.edu
2987396Sgblack@eecs.umich.edu/**
2997333Sgblack@eecs.umich.edu * This reads the device registers, which are detailed in the NS83820
3007333Sgblack@eecs.umich.edu * spec sheet
3017396Sgblack@eecs.umich.edu */
3027396Sgblack@eecs.umich.eduFault
3037333Sgblack@eecs.umich.eduNSGigE::read(MemReqPtr &req, uint8_t *data)
3047333Sgblack@eecs.umich.edu{
3057640Sgblack@eecs.umich.edu    assert(ioEnable);
3067333Sgblack@eecs.umich.edu
3077333Sgblack@eecs.umich.edu    //The mask is to give you only the offset into the device register file
3087333Sgblack@eecs.umich.edu    Addr daddr = req->paddr & 0xfff;
3097333Sgblack@eecs.umich.edu    DPRINTF(EthernetPIO, "read  da=%#x pa=%#x va=%#x size=%d\n",
3107333Sgblack@eecs.umich.edu            daddr, req->paddr, req->vaddr, req->size);
3117396Sgblack@eecs.umich.edu
3127333Sgblack@eecs.umich.edu
3137333Sgblack@eecs.umich.edu    //there are some reserved registers, you can see ns_gige_reg.h and
3147396Sgblack@eecs.umich.edu    //the spec sheet for details
3157396Sgblack@eecs.umich.edu    if (daddr > LAST && daddr <=  RESERVED) {
3167333Sgblack@eecs.umich.edu        panic("Accessing reserved register");
3177333Sgblack@eecs.umich.edu    } else if (daddr > RESERVED && daddr <= 0x3FC) {
3187640Sgblack@eecs.umich.edu        ReadConfig(daddr & 0xff, req->size, data);
3197639Sgblack@eecs.umich.edu        return No_Fault;
3207333Sgblack@eecs.umich.edu    } else if (daddr >= MIB_START && daddr <= MIB_END) {
3217396Sgblack@eecs.umich.edu        // don't implement all the MIB's.  hopefully the kernel
3227333Sgblack@eecs.umich.edu        // doesn't actually DEPEND upon their values
3237333Sgblack@eecs.umich.edu        // MIB are just hardware stats keepers
3247396Sgblack@eecs.umich.edu        uint32_t &reg = *(uint32_t *) data;
3257396Sgblack@eecs.umich.edu        reg = 0;
3267333Sgblack@eecs.umich.edu        return No_Fault;
3277333Sgblack@eecs.umich.edu    } else if (daddr > 0x3FC)
3287640Sgblack@eecs.umich.edu        panic("Something is messed up!\n");
3297639Sgblack@eecs.umich.edu
3307333Sgblack@eecs.umich.edu    switch (req->size) {
3317396Sgblack@eecs.umich.edu      case sizeof(uint32_t):
3327333Sgblack@eecs.umich.edu        {
3337333Sgblack@eecs.umich.edu            uint32_t &reg = *(uint32_t *)data;
3347396Sgblack@eecs.umich.edu
3357396Sgblack@eecs.umich.edu            switch (daddr) {
3367333Sgblack@eecs.umich.edu              case CR:
3377333Sgblack@eecs.umich.edu                reg = regs.command;
3387640Sgblack@eecs.umich.edu                //these are supposed to be cleared on a read
3397333Sgblack@eecs.umich.edu                reg &= ~(CR_RXD | CR_TXD | CR_TXR | CR_RXR);
3407333Sgblack@eecs.umich.edu                break;
3417396Sgblack@eecs.umich.edu
3427333Sgblack@eecs.umich.edu              case CFG:
3437333Sgblack@eecs.umich.edu                reg = regs.config;
3447396Sgblack@eecs.umich.edu                break;
3457396Sgblack@eecs.umich.edu
3467333Sgblack@eecs.umich.edu              case MEAR:
3477333Sgblack@eecs.umich.edu                reg = regs.mear;
3487640Sgblack@eecs.umich.edu                break;
3497639Sgblack@eecs.umich.edu
3507639Sgblack@eecs.umich.edu              case PTSCR:
3517333Sgblack@eecs.umich.edu                reg = regs.ptscr;
3527396Sgblack@eecs.umich.edu                break;
3537333Sgblack@eecs.umich.edu
3547333Sgblack@eecs.umich.edu              case ISR:
3557396Sgblack@eecs.umich.edu                reg = regs.isr;
3567396Sgblack@eecs.umich.edu                devIntrClear(ISR_ALL);
3577333Sgblack@eecs.umich.edu                break;
3587333Sgblack@eecs.umich.edu
3597640Sgblack@eecs.umich.edu              case IMR:
3607639Sgblack@eecs.umich.edu                reg = regs.imr;
3617639Sgblack@eecs.umich.edu                break;
3627333Sgblack@eecs.umich.edu
3637396Sgblack@eecs.umich.edu              case IER:
3647333Sgblack@eecs.umich.edu                reg = regs.ier;
3657333Sgblack@eecs.umich.edu                break;
3667396Sgblack@eecs.umich.edu
3677396Sgblack@eecs.umich.edu              case IHR:
3687333Sgblack@eecs.umich.edu                reg = regs.ihr;
3697333Sgblack@eecs.umich.edu                break;
3707640Sgblack@eecs.umich.edu
3717639Sgblack@eecs.umich.edu              case TXDP:
3727639Sgblack@eecs.umich.edu                reg = regs.txdp;
3737333Sgblack@eecs.umich.edu                break;
3747396Sgblack@eecs.umich.edu
3757333Sgblack@eecs.umich.edu              case TXDP_HI:
3767333Sgblack@eecs.umich.edu                reg = regs.txdp_hi;
3777396Sgblack@eecs.umich.edu                break;
3787396Sgblack@eecs.umich.edu
3797333Sgblack@eecs.umich.edu              case TXCFG:
3807333Sgblack@eecs.umich.edu                reg = regs.txcfg;
3817640Sgblack@eecs.umich.edu                break;
3827639Sgblack@eecs.umich.edu
3837639Sgblack@eecs.umich.edu              case GPIOR:
3847333Sgblack@eecs.umich.edu                reg = regs.gpior;
3857396Sgblack@eecs.umich.edu                break;
3867333Sgblack@eecs.umich.edu
3877333Sgblack@eecs.umich.edu              case RXDP:
3887396Sgblack@eecs.umich.edu                reg = regs.rxdp;
3897396Sgblack@eecs.umich.edu                break;
3907333Sgblack@eecs.umich.edu
3917333Sgblack@eecs.umich.edu              case RXDP_HI:
3927640Sgblack@eecs.umich.edu                reg = regs.rxdp_hi;
3937333Sgblack@eecs.umich.edu                break;
3947333Sgblack@eecs.umich.edu
3957396Sgblack@eecs.umich.edu              case RXCFG:
3967333Sgblack@eecs.umich.edu                reg = regs.rxcfg;
3977333Sgblack@eecs.umich.edu                break;
3987396Sgblack@eecs.umich.edu
3997396Sgblack@eecs.umich.edu              case PQCR:
4007333Sgblack@eecs.umich.edu                reg = regs.pqcr;
4017333Sgblack@eecs.umich.edu                break;
4027640Sgblack@eecs.umich.edu
4037333Sgblack@eecs.umich.edu              case WCSR:
4047333Sgblack@eecs.umich.edu                reg = regs.wcsr;
4057333Sgblack@eecs.umich.edu                break;
4067396Sgblack@eecs.umich.edu
4077333Sgblack@eecs.umich.edu              case PCR:
4087333Sgblack@eecs.umich.edu                reg = regs.pcr;
4097396Sgblack@eecs.umich.edu                break;
4107396Sgblack@eecs.umich.edu
4117333Sgblack@eecs.umich.edu                //see the spec sheet for how RFCR and RFDR work
4127333Sgblack@eecs.umich.edu                //basically, you write to RFCR to tell the machine what you want to do next
4137640Sgblack@eecs.umich.edu                //then you act upon RFDR, and the device will be prepared b/c
4147333Sgblack@eecs.umich.edu                //of what you wrote to RFCR
4157333Sgblack@eecs.umich.edu              case RFCR:
4167333Sgblack@eecs.umich.edu                reg = regs.rfcr;
4177396Sgblack@eecs.umich.edu                break;
4187333Sgblack@eecs.umich.edu
4197333Sgblack@eecs.umich.edu              case RFDR:
4207396Sgblack@eecs.umich.edu                switch (regs.rfcr & RFCR_RFADDR) {
4217396Sgblack@eecs.umich.edu                  case 0x000:
4227333Sgblack@eecs.umich.edu                    reg = rom.perfectMatch[1];
4237381Sgblack@eecs.umich.edu                    reg = reg << 8;
4247381Sgblack@eecs.umich.edu                    reg += rom.perfectMatch[0];
4257381Sgblack@eecs.umich.edu                    break;
4267381Sgblack@eecs.umich.edu                  case 0x002:
4277381Sgblack@eecs.umich.edu                    reg = rom.perfectMatch[3] << 8;
4287381Sgblack@eecs.umich.edu                    reg += rom.perfectMatch[2];
4297381Sgblack@eecs.umich.edu                    break;
4307364Sgblack@eecs.umich.edu                  case 0x004:
4317640Sgblack@eecs.umich.edu                    reg = rom.perfectMatch[5] << 8;
4327643Sgblack@eecs.umich.edu                    reg += rom.perfectMatch[4];
4337396Sgblack@eecs.umich.edu                    break;
4347643Sgblack@eecs.umich.edu                  default:
4357364Sgblack@eecs.umich.edu                    panic("reading from RFDR for something for other than PMATCH!\n");
4367396Sgblack@eecs.umich.edu                    //didn't implement other RFDR functionality b/c driver didn't use
4377639Sgblack@eecs.umich.edu                }
4387396Sgblack@eecs.umich.edu                break;
4397640Sgblack@eecs.umich.edu
4407643Sgblack@eecs.umich.edu              case SRR:
4417396Sgblack@eecs.umich.edu                reg = regs.srr;
4427643Sgblack@eecs.umich.edu                break;
4437396Sgblack@eecs.umich.edu
4447396Sgblack@eecs.umich.edu              case MIBC:
4457396Sgblack@eecs.umich.edu                reg = regs.mibc;
4467396Sgblack@eecs.umich.edu                reg &= ~(MIBC_MIBS | MIBC_ACLR);
4477396Sgblack@eecs.umich.edu                break;
4487396Sgblack@eecs.umich.edu
4497639Sgblack@eecs.umich.edu              case VRCR:
4507396Sgblack@eecs.umich.edu                reg = regs.vrcr;
4517396Sgblack@eecs.umich.edu                break;
4527396Sgblack@eecs.umich.edu
4537396Sgblack@eecs.umich.edu              case VTCR:
4547396Sgblack@eecs.umich.edu                reg = regs.vtcr;
4557364Sgblack@eecs.umich.edu                break;
4567396Sgblack@eecs.umich.edu
4577396Sgblack@eecs.umich.edu              case VDR:
4587365Sgblack@eecs.umich.edu                reg = regs.vdr;
4597396Sgblack@eecs.umich.edu                break;
4607396Sgblack@eecs.umich.edu
4617396Sgblack@eecs.umich.edu              case CCSR:
4627396Sgblack@eecs.umich.edu                reg = regs.ccsr;
4637396Sgblack@eecs.umich.edu                break;
4647396Sgblack@eecs.umich.edu
4657396Sgblack@eecs.umich.edu              case TBICR:
4667396Sgblack@eecs.umich.edu                reg = regs.tbicr;
4677365Sgblack@eecs.umich.edu                break;
4687396Sgblack@eecs.umich.edu
4697396Sgblack@eecs.umich.edu              case TBISR:
4707366Sgblack@eecs.umich.edu                reg = regs.tbisr;
4717396Sgblack@eecs.umich.edu                break;
4727396Sgblack@eecs.umich.edu
4737396Sgblack@eecs.umich.edu              case TANAR:
4747396Sgblack@eecs.umich.edu                reg = regs.tanar;
4757366Sgblack@eecs.umich.edu                break;
4767396Sgblack@eecs.umich.edu
4777396Sgblack@eecs.umich.edu              case TANLPAR:
4787396Sgblack@eecs.umich.edu                reg = regs.tanlpar;
4797396Sgblack@eecs.umich.edu                break;
4807367Sgblack@eecs.umich.edu
4817396Sgblack@eecs.umich.edu              case TANER:
4827396Sgblack@eecs.umich.edu                reg = regs.taner;
4837396Sgblack@eecs.umich.edu                break;
4847396Sgblack@eecs.umich.edu
4857367Sgblack@eecs.umich.edu              case TESR:
4867396Sgblack@eecs.umich.edu                reg = regs.tesr;
4877396Sgblack@eecs.umich.edu                break;
4887396Sgblack@eecs.umich.edu
4897396Sgblack@eecs.umich.edu              default:
4907396Sgblack@eecs.umich.edu                panic("reading unimplemented register: addr = %#x", daddr);
4917396Sgblack@eecs.umich.edu            }
4927396Sgblack@eecs.umich.edu
4937396Sgblack@eecs.umich.edu            DPRINTF(EthernetPIO, "read from %#x: data=%d data=%#x\n",
4947368Sgblack@eecs.umich.edu                    daddr, reg, reg);
4957396Sgblack@eecs.umich.edu        }
4967396Sgblack@eecs.umich.edu        break;
4977368Sgblack@eecs.umich.edu
4987396Sgblack@eecs.umich.edu      default:
4997396Sgblack@eecs.umich.edu        panic("accessing register with invalid size: addr=%#x, size=%d",
5007396Sgblack@eecs.umich.edu              daddr, req->size);
5017396Sgblack@eecs.umich.edu    }
5027369Sgblack@eecs.umich.edu
5037396Sgblack@eecs.umich.edu    return No_Fault;
5047369Sgblack@eecs.umich.edu}
5057396Sgblack@eecs.umich.edu
5067396Sgblack@eecs.umich.eduFault
5077396Sgblack@eecs.umich.eduNSGigE::write(MemReqPtr &req, const uint8_t *data)
5087396Sgblack@eecs.umich.edu{
5097369Sgblack@eecs.umich.edu    assert(ioEnable);
5107396Sgblack@eecs.umich.edu
5117396Sgblack@eecs.umich.edu    Addr daddr = req->paddr & 0xfff;
5127396Sgblack@eecs.umich.edu    DPRINTF(EthernetPIO, "write da=%#x pa=%#x va=%#x size=%d\n",
5137396Sgblack@eecs.umich.edu            daddr, req->paddr, req->vaddr, req->size);
5147396Sgblack@eecs.umich.edu
5157396Sgblack@eecs.umich.edu    if (daddr > LAST && daddr <=  RESERVED) {
5167369Sgblack@eecs.umich.edu        panic("Accessing reserved register");
5177396Sgblack@eecs.umich.edu    } else if (daddr > RESERVED && daddr <= 0x3FC) {
5187396Sgblack@eecs.umich.edu        WriteConfig(daddr & 0xff, req->size, *(uint32_t *)data);
5197396Sgblack@eecs.umich.edu        return No_Fault;
5207396Sgblack@eecs.umich.edu    } else if (daddr > 0x3FC)
5217396Sgblack@eecs.umich.edu        panic("Something is messed up!\n");
5227396Sgblack@eecs.umich.edu
5237396Sgblack@eecs.umich.edu    if (req->size == sizeof(uint32_t)) {
5247396Sgblack@eecs.umich.edu        uint32_t reg = *(uint32_t *)data;
5257396Sgblack@eecs.umich.edu        DPRINTF(EthernetPIO, "write data=%d data=%#x\n", reg, reg);
5267396Sgblack@eecs.umich.edu
5277396Sgblack@eecs.umich.edu        switch (daddr) {
5287396Sgblack@eecs.umich.edu          case CR:
5297381Sgblack@eecs.umich.edu            regs.command = reg;
5307381Sgblack@eecs.umich.edu            if ((reg & (CR_TXE | CR_TXD)) == (CR_TXE | CR_TXD)) {
5317381Sgblack@eecs.umich.edu                txHalt = true;
5327381Sgblack@eecs.umich.edu            } else if (reg & CR_TXE) {
5337381Sgblack@eecs.umich.edu                //the kernel is enabling the transmit machine
5347381Sgblack@eecs.umich.edu                if (txState == txIdle)
5357381Sgblack@eecs.umich.edu                    txKick();
5367370Sgblack@eecs.umich.edu            } else if (reg & CR_TXD) {
5377640Sgblack@eecs.umich.edu                txHalt = true;
5387643Sgblack@eecs.umich.edu            }
5397396Sgblack@eecs.umich.edu
5407639Sgblack@eecs.umich.edu            if ((reg & (CR_RXE | CR_RXD)) == (CR_RXE | CR_RXD)) {
5417639Sgblack@eecs.umich.edu                rxHalt = true;
5427639Sgblack@eecs.umich.edu            } else if (reg & CR_RXE) {
5437643Sgblack@eecs.umich.edu                if (rxState == rxIdle) {
5447370Sgblack@eecs.umich.edu                    rxKick();
5457396Sgblack@eecs.umich.edu                }
5467370Sgblack@eecs.umich.edu            } else if (reg & CR_RXD) {
5477370Sgblack@eecs.umich.edu                rxHalt = true;
5487396Sgblack@eecs.umich.edu            }
5497396Sgblack@eecs.umich.edu
5507370Sgblack@eecs.umich.edu            if (reg & CR_TXR)
5517370Sgblack@eecs.umich.edu                txReset();
5527640Sgblack@eecs.umich.edu
5537643Sgblack@eecs.umich.edu            if (reg & CR_RXR)
5547396Sgblack@eecs.umich.edu                rxReset();
5557396Sgblack@eecs.umich.edu
5567639Sgblack@eecs.umich.edu            if (reg & CR_SWI)
5577396Sgblack@eecs.umich.edu                devIntrPost(ISR_SWI);
5587639Sgblack@eecs.umich.edu
5597639Sgblack@eecs.umich.edu            if (reg & CR_RST) {
5607643Sgblack@eecs.umich.edu                txReset();
5617396Sgblack@eecs.umich.edu                rxReset();
5627396Sgblack@eecs.umich.edu
5637370Sgblack@eecs.umich.edu                regsReset();
5647396Sgblack@eecs.umich.edu            }
5657370Sgblack@eecs.umich.edu            break;
5667370Sgblack@eecs.umich.edu
5677396Sgblack@eecs.umich.edu          case CFG:
5687396Sgblack@eecs.umich.edu            if (reg & CFG_LNKSTS || reg & CFG_SPDSTS || reg & CFG_DUPSTS
5697370Sgblack@eecs.umich.edu                || reg & CFG_RESERVED || reg & CFG_T64ADDR
5707370Sgblack@eecs.umich.edu                || reg & CFG_PCI64_DET)
5717640Sgblack@eecs.umich.edu                panic("writing to read-only or reserved CFG bits!\n");
5727643Sgblack@eecs.umich.edu
5737396Sgblack@eecs.umich.edu            regs.config |= reg & ~(CFG_LNKSTS | CFG_SPDSTS | CFG_DUPSTS | CFG_RESERVED |
5747639Sgblack@eecs.umich.edu                                  CFG_T64ADDR | CFG_PCI64_DET);
5757639Sgblack@eecs.umich.edu
5767639Sgblack@eecs.umich.edu// all these #if 0's are because i don't THINK the kernel needs to have these implemented
5777643Sgblack@eecs.umich.edu// if there is a problem relating to one of these, you may need to add functionality in
5787370Sgblack@eecs.umich.edu#if 0
5797396Sgblack@eecs.umich.edu              if (reg & CFG_TBI_EN) ;
5807370Sgblack@eecs.umich.edu              if (reg & CFG_MODE_1000) ;
5817370Sgblack@eecs.umich.edu#endif
5827396Sgblack@eecs.umich.edu
5837396Sgblack@eecs.umich.edu            if (reg & CFG_AUTO_1000)
5847370Sgblack@eecs.umich.edu                panic("CFG_AUTO_1000 not implemented!\n");
5857370Sgblack@eecs.umich.edu
5867640Sgblack@eecs.umich.edu#if 0
5877643Sgblack@eecs.umich.edu            if (reg & CFG_PINT_DUPSTS || reg & CFG_PINT_LNKSTS || reg & CFG_PINT_SPDSTS) ;
5887396Sgblack@eecs.umich.edu            if (reg & CFG_TMRTEST) ;
5897396Sgblack@eecs.umich.edu            if (reg & CFG_MRM_DIS) ;
5907639Sgblack@eecs.umich.edu            if (reg & CFG_MWI_DIS) ;
5917396Sgblack@eecs.umich.edu
5927639Sgblack@eecs.umich.edu            if (reg & CFG_T64ADDR)
5937639Sgblack@eecs.umich.edu                panic("CFG_T64ADDR is read only register!\n");
5947643Sgblack@eecs.umich.edu
5957396Sgblack@eecs.umich.edu            if (reg & CFG_PCI64_DET)
5967396Sgblack@eecs.umich.edu                panic("CFG_PCI64_DET is read only register!\n");
5977370Sgblack@eecs.umich.edu
5987396Sgblack@eecs.umich.edu            if (reg & CFG_DATA64_EN) ;
5997370Sgblack@eecs.umich.edu            if (reg & CFG_M64ADDR) ;
6007370Sgblack@eecs.umich.edu            if (reg & CFG_PHY_RST) ;
6017396Sgblack@eecs.umich.edu            if (reg & CFG_PHY_DIS) ;
6027396Sgblack@eecs.umich.edu#endif
6037370Sgblack@eecs.umich.edu
6047371Sgblack@eecs.umich.edu            if (reg & CFG_EXTSTS_EN)
6057640Sgblack@eecs.umich.edu                extstsEnable = true;
6067643Sgblack@eecs.umich.edu            else
6077396Sgblack@eecs.umich.edu                extstsEnable = false;
6087639Sgblack@eecs.umich.edu
6097639Sgblack@eecs.umich.edu#if 0
6107639Sgblack@eecs.umich.edu              if (reg & CFG_REQALG) ;
6117643Sgblack@eecs.umich.edu              if (reg & CFG_SB) ;
6127371Sgblack@eecs.umich.edu              if (reg & CFG_POW) ;
6137396Sgblack@eecs.umich.edu              if (reg & CFG_EXD) ;
6147371Sgblack@eecs.umich.edu              if (reg & CFG_PESEL) ;
6157371Sgblack@eecs.umich.edu              if (reg & CFG_BROM_DIS) ;
6167396Sgblack@eecs.umich.edu              if (reg & CFG_EXT_125) ;
6177396Sgblack@eecs.umich.edu              if (reg & CFG_BEM) ;
6187371Sgblack@eecs.umich.edu#endif
6197371Sgblack@eecs.umich.edu            break;
6207640Sgblack@eecs.umich.edu
6217643Sgblack@eecs.umich.edu          case MEAR:
6227396Sgblack@eecs.umich.edu            regs.mear = reg;
6237396Sgblack@eecs.umich.edu            /* since phy is completely faked, MEAR_MD* don't matter
6247639Sgblack@eecs.umich.edu               and since the driver never uses MEAR_EE*, they don't matter */
6257396Sgblack@eecs.umich.edu#if 0
6267639Sgblack@eecs.umich.edu            if (reg & MEAR_EEDI) ;
6277639Sgblack@eecs.umich.edu            if (reg & MEAR_EEDO) ; //this one is read only
6287643Sgblack@eecs.umich.edu            if (reg & MEAR_EECLK) ;
6297396Sgblack@eecs.umich.edu            if (reg & MEAR_EESEL) ;
6307396Sgblack@eecs.umich.edu            if (reg & MEAR_MDIO) ;
6317371Sgblack@eecs.umich.edu            if (reg & MEAR_MDDIR) ;
6327396Sgblack@eecs.umich.edu            if (reg & MEAR_MDC) ;
6337371Sgblack@eecs.umich.edu#endif
6347371Sgblack@eecs.umich.edu            break;
6357396Sgblack@eecs.umich.edu
6367396Sgblack@eecs.umich.edu          case PTSCR:
6377371Sgblack@eecs.umich.edu            regs.ptscr = reg & ~(PTSCR_RBIST_RDONLY);
6387371Sgblack@eecs.umich.edu            /* these control BISTs for various parts of chip - we don't care or do
6397640Sgblack@eecs.umich.edu               just fake that the BIST is done */
6407643Sgblack@eecs.umich.edu            if (reg & PTSCR_RBIST_EN)
6417396Sgblack@eecs.umich.edu                regs.ptscr |= PTSCR_RBIST_DONE;
6427639Sgblack@eecs.umich.edu            if (reg & PTSCR_EEBIST_EN)
6437639Sgblack@eecs.umich.edu                regs.ptscr &= ~PTSCR_EEBIST_EN;
6447639Sgblack@eecs.umich.edu            if (reg & PTSCR_EELOAD_EN)
6457643Sgblack@eecs.umich.edu                regs.ptscr &= ~PTSCR_EELOAD_EN;
6467371Sgblack@eecs.umich.edu            break;
6477396Sgblack@eecs.umich.edu
6487371Sgblack@eecs.umich.edu          case ISR: /* writing to the ISR has no effect */
6497371Sgblack@eecs.umich.edu            panic("ISR is a read only register!\n");
6507396Sgblack@eecs.umich.edu
6517396Sgblack@eecs.umich.edu          case IMR:
6527371Sgblack@eecs.umich.edu            regs.imr = reg;
6537371Sgblack@eecs.umich.edu            devIntrChangeMask();
6547640Sgblack@eecs.umich.edu            break;
6557643Sgblack@eecs.umich.edu
6567396Sgblack@eecs.umich.edu          case IER:
6577396Sgblack@eecs.umich.edu            regs.ier = reg;
6587639Sgblack@eecs.umich.edu            break;
6597396Sgblack@eecs.umich.edu
6607639Sgblack@eecs.umich.edu          case IHR:
6617639Sgblack@eecs.umich.edu            regs.ihr = reg;
6627643Sgblack@eecs.umich.edu            /* not going to implement real interrupt holdoff */
6637396Sgblack@eecs.umich.edu            break;
6647396Sgblack@eecs.umich.edu
6657371Sgblack@eecs.umich.edu          case TXDP:
6667396Sgblack@eecs.umich.edu            regs.txdp = (reg & 0xFFFFFFFC);
6677371Sgblack@eecs.umich.edu            assert(txState == txIdle);
6687371Sgblack@eecs.umich.edu            CTDD = false;
6697396Sgblack@eecs.umich.edu            break;
6707396Sgblack@eecs.umich.edu
6717371Sgblack@eecs.umich.edu          case TXDP_HI:
6727371Sgblack@eecs.umich.edu            regs.txdp_hi = reg;
6737640Sgblack@eecs.umich.edu            break;
6747643Sgblack@eecs.umich.edu
6757639Sgblack@eecs.umich.edu          case TXCFG:
6767639Sgblack@eecs.umich.edu            regs.txcfg = reg;
6777643Sgblack@eecs.umich.edu#if 0
6787371Sgblack@eecs.umich.edu            if (reg & TXCFG_CSI) ;
6797396Sgblack@eecs.umich.edu            if (reg & TXCFG_HBI) ;
6807371Sgblack@eecs.umich.edu            if (reg & TXCFG_MLB) ;
6817371Sgblack@eecs.umich.edu            if (reg & TXCFG_ATP) ;
6827396Sgblack@eecs.umich.edu            if (reg & TXCFG_ECRETRY) ;  /* this could easily be implemented, but
6837396Sgblack@eecs.umich.edu                                           considering the network is just a fake
6847371Sgblack@eecs.umich.edu                                           pipe, wouldn't make sense to do this */
6857371Sgblack@eecs.umich.edu
6867640Sgblack@eecs.umich.edu            if (reg & TXCFG_BRST_DIS) ;
6877643Sgblack@eecs.umich.edu#endif
6887396Sgblack@eecs.umich.edu
6897396Sgblack@eecs.umich.edu
6907639Sgblack@eecs.umich.edu            /* we handle our own DMA, ignore the kernel's exhortations */
6917639Sgblack@eecs.umich.edu            //if (reg & TXCFG_MXDMA) ;
6927643Sgblack@eecs.umich.edu
6937396Sgblack@eecs.umich.edu            //also, we currently don't care about fill/drain thresholds
6947396Sgblack@eecs.umich.edu            //though this may change in the future with more realistic
6957371Sgblack@eecs.umich.edu            //networks or a driver which changes it according to feedback
6967396Sgblack@eecs.umich.edu
6977371Sgblack@eecs.umich.edu            break;
6987371Sgblack@eecs.umich.edu
6997396Sgblack@eecs.umich.edu          case GPIOR:
7007396Sgblack@eecs.umich.edu            regs.gpior = reg;
7017371Sgblack@eecs.umich.edu            /* these just control general purpose i/o pins, don't matter */
7027381Sgblack@eecs.umich.edu            break;
7037381Sgblack@eecs.umich.edu
7047381Sgblack@eecs.umich.edu          case RXDP:
7057381Sgblack@eecs.umich.edu            regs.rxdp = reg;
7067381Sgblack@eecs.umich.edu            break;
7077381Sgblack@eecs.umich.edu
7087381Sgblack@eecs.umich.edu          case RXDP_HI:
7097373Sgblack@eecs.umich.edu            regs.rxdp_hi = reg;
7107640Sgblack@eecs.umich.edu            break;
7117643Sgblack@eecs.umich.edu
7127397Sgblack@eecs.umich.edu          case RXCFG:
7137381Sgblack@eecs.umich.edu            regs.rxcfg = reg;
7147373Sgblack@eecs.umich.edu#if 0
7157381Sgblack@eecs.umich.edu            if (reg & RXCFG_AEP) ;
7167639Sgblack@eecs.umich.edu            if (reg & RXCFG_ARP) ;
7177643Sgblack@eecs.umich.edu            if (reg & RXCFG_STRIPCRC) ;
7187373Sgblack@eecs.umich.edu            if (reg & RXCFG_RX_RD) ;
7197396Sgblack@eecs.umich.edu            if (reg & RXCFG_ALP) ;
7207373Sgblack@eecs.umich.edu            if (reg & RXCFG_AIRL) ;
7217373Sgblack@eecs.umich.edu#endif
7227396Sgblack@eecs.umich.edu
7237396Sgblack@eecs.umich.edu            /* we handle our own DMA, ignore what kernel says about it */
7247373Sgblack@eecs.umich.edu            //if (reg & RXCFG_MXDMA) ;
7257373Sgblack@eecs.umich.edu
7267640Sgblack@eecs.umich.edu#if 0
7277643Sgblack@eecs.umich.edu            //also, we currently don't care about fill/drain thresholds
7287397Sgblack@eecs.umich.edu            //though this may change in the future with more realistic
7297381Sgblack@eecs.umich.edu            //networks or a driver which changes it according to feedback
7307397Sgblack@eecs.umich.edu            if (reg & (RXCFG_DRTH | RXCFG_DRTH0)) ;
7317397Sgblack@eecs.umich.edu#endif
7327639Sgblack@eecs.umich.edu            break;
7337643Sgblack@eecs.umich.edu
7347397Sgblack@eecs.umich.edu          case PQCR:
7357397Sgblack@eecs.umich.edu            /* there is no priority queueing used in the linux 2.6 driver */
7367373Sgblack@eecs.umich.edu            regs.pqcr = reg;
7377396Sgblack@eecs.umich.edu            break;
7387373Sgblack@eecs.umich.edu
7397373Sgblack@eecs.umich.edu          case WCSR:
7407396Sgblack@eecs.umich.edu            /* not going to implement wake on LAN */
7417396Sgblack@eecs.umich.edu            regs.wcsr = reg;
7427373Sgblack@eecs.umich.edu            break;
7437373Sgblack@eecs.umich.edu
7447640Sgblack@eecs.umich.edu          case PCR:
7457643Sgblack@eecs.umich.edu            /* not going to implement pause control */
7467397Sgblack@eecs.umich.edu            regs.pcr = reg;
7477381Sgblack@eecs.umich.edu            break;
7487373Sgblack@eecs.umich.edu
7497381Sgblack@eecs.umich.edu          case RFCR:
7507639Sgblack@eecs.umich.edu            regs.rfcr = reg;
7517643Sgblack@eecs.umich.edu
7527373Sgblack@eecs.umich.edu            rxFilterEnable = (reg & RFCR_RFEN) ? true : false;
7537396Sgblack@eecs.umich.edu            acceptBroadcast = (reg & RFCR_AAB) ? true : false;
7547373Sgblack@eecs.umich.edu            acceptMulticast = (reg & RFCR_AAM) ? true : false;
7557373Sgblack@eecs.umich.edu            acceptUnicast = (reg & RFCR_AAU) ? true : false;
7567396Sgblack@eecs.umich.edu            acceptPerfect = (reg & RFCR_APM) ? true : false;
7577396Sgblack@eecs.umich.edu            acceptArp = (reg & RFCR_AARP) ? true : false;
7587373Sgblack@eecs.umich.edu
7597373Sgblack@eecs.umich.edu            if (reg & RFCR_APAT) ;
7607640Sgblack@eecs.umich.edu//                panic("RFCR_APAT not implemented!\n");
7617643Sgblack@eecs.umich.edu
7627397Sgblack@eecs.umich.edu            if (reg & RFCR_MHEN || reg & RFCR_UHEN)
7637381Sgblack@eecs.umich.edu                panic("hash filtering not implemented!\n");
7647397Sgblack@eecs.umich.edu
7657397Sgblack@eecs.umich.edu            if (reg & RFCR_ULM)
7667639Sgblack@eecs.umich.edu                panic("RFCR_ULM not implemented!\n");
7677643Sgblack@eecs.umich.edu
7687397Sgblack@eecs.umich.edu            break;
7697397Sgblack@eecs.umich.edu
7707373Sgblack@eecs.umich.edu          case RFDR:
7717396Sgblack@eecs.umich.edu            panic("the driver never writes to RFDR, something is wrong!\n");
7727373Sgblack@eecs.umich.edu
7737373Sgblack@eecs.umich.edu          case BRAR:
7747396Sgblack@eecs.umich.edu            panic("the driver never uses BRAR, something is wrong!\n");
7757396Sgblack@eecs.umich.edu
7767373Sgblack@eecs.umich.edu          case BRDR:
7777373Sgblack@eecs.umich.edu            panic("the driver never uses BRDR, something is wrong!\n");
7787640Sgblack@eecs.umich.edu
7797643Sgblack@eecs.umich.edu          case SRR:
7807397Sgblack@eecs.umich.edu            panic("SRR is read only register!\n");
7817397Sgblack@eecs.umich.edu
7827381Sgblack@eecs.umich.edu          case MIBC:
7837388Sgblack@eecs.umich.edu            panic("the driver never uses MIBC, something is wrong!\n");
7847381Sgblack@eecs.umich.edu
7857639Sgblack@eecs.umich.edu          case VRCR:
7867643Sgblack@eecs.umich.edu            regs.vrcr = reg;
7877380Sgblack@eecs.umich.edu            break;
7887396Sgblack@eecs.umich.edu
7897380Sgblack@eecs.umich.edu          case VTCR:
7907380Sgblack@eecs.umich.edu            regs.vtcr = reg;
7917396Sgblack@eecs.umich.edu            break;
7927396Sgblack@eecs.umich.edu
7937380Sgblack@eecs.umich.edu          case VDR:
7947380Sgblack@eecs.umich.edu            panic("the driver never uses VDR, something is wrong!\n");
7957640Sgblack@eecs.umich.edu            break;
7967643Sgblack@eecs.umich.edu
7977397Sgblack@eecs.umich.edu          case CCSR:
7987397Sgblack@eecs.umich.edu            /* not going to implement clockrun stuff */
7997397Sgblack@eecs.umich.edu            regs.ccsr = reg;
8007397Sgblack@eecs.umich.edu            break;
8017397Sgblack@eecs.umich.edu
8027381Sgblack@eecs.umich.edu          case TBICR:
8037639Sgblack@eecs.umich.edu            regs.tbicr = reg;
8047643Sgblack@eecs.umich.edu            if (reg & TBICR_MR_LOOPBACK)
8057380Sgblack@eecs.umich.edu                panic("TBICR_MR_LOOPBACK never used, something wrong!\n");
8067380Sgblack@eecs.umich.edu
8077396Sgblack@eecs.umich.edu            if (reg & TBICR_MR_AN_ENABLE) {
8087380Sgblack@eecs.umich.edu                regs.tanlpar = regs.tanar;
8097380Sgblack@eecs.umich.edu                regs.tbisr |= (TBISR_MR_AN_COMPLETE | TBISR_MR_LINK_STATUS);
8107396Sgblack@eecs.umich.edu            }
8117396Sgblack@eecs.umich.edu
8127380Sgblack@eecs.umich.edu#if 0
8137380Sgblack@eecs.umich.edu            if (reg & TBICR_MR_RESTART_AN) ;
8147640Sgblack@eecs.umich.edu#endif
8157643Sgblack@eecs.umich.edu
8167397Sgblack@eecs.umich.edu            break;
8177397Sgblack@eecs.umich.edu
8187381Sgblack@eecs.umich.edu          case TBISR:
8197388Sgblack@eecs.umich.edu            panic("TBISR is read only register!\n");
8207381Sgblack@eecs.umich.edu
8217639Sgblack@eecs.umich.edu          case TANAR:
8227643Sgblack@eecs.umich.edu            regs.tanar = reg;
8237380Sgblack@eecs.umich.edu            if (reg & TANAR_PS2)
8247396Sgblack@eecs.umich.edu                panic("this isn't used in driver, something wrong!\n");
8257380Sgblack@eecs.umich.edu
8267380Sgblack@eecs.umich.edu            if (reg & TANAR_PS1)
8277396Sgblack@eecs.umich.edu                panic("this isn't used in driver, something wrong!\n");
8287396Sgblack@eecs.umich.edu            break;
8297380Sgblack@eecs.umich.edu
8307380Sgblack@eecs.umich.edu          case TANLPAR:
8317640Sgblack@eecs.umich.edu            panic("this should only be written to by the fake phy!\n");
8327643Sgblack@eecs.umich.edu
8337397Sgblack@eecs.umich.edu          case TANER:
8347397Sgblack@eecs.umich.edu            panic("TANER is read only register!\n");
8357397Sgblack@eecs.umich.edu
8367397Sgblack@eecs.umich.edu          case TESR:
8377397Sgblack@eecs.umich.edu            regs.tesr = reg;
8387381Sgblack@eecs.umich.edu            break;
8397639Sgblack@eecs.umich.edu
8407643Sgblack@eecs.umich.edu          default:
8417380Sgblack@eecs.umich.edu            panic("thought i covered all the register, what is this? addr=%#x",
8427380Sgblack@eecs.umich.edu                  daddr);
8437396Sgblack@eecs.umich.edu        }
8447380Sgblack@eecs.umich.edu    } else
8457380Sgblack@eecs.umich.edu        panic("Invalid Request Size");
8467396Sgblack@eecs.umich.edu
8477396Sgblack@eecs.umich.edu    return No_Fault;
8487380Sgblack@eecs.umich.edu}
8497380Sgblack@eecs.umich.edu
8507640Sgblack@eecs.umich.eduvoid
8517643Sgblack@eecs.umich.eduNSGigE::devIntrPost(uint32_t interrupts)
8527397Sgblack@eecs.umich.edu{
8537397Sgblack@eecs.umich.edu    bool delay = false;
8547380Sgblack@eecs.umich.edu
8557381Sgblack@eecs.umich.edu    if (interrupts & ISR_RESERVE)
8567387Sgblack@eecs.umich.edu        panic("Cannot set a reserved interrupt");
8577381Sgblack@eecs.umich.edu
8587639Sgblack@eecs.umich.edu    if (interrupts & ISR_TXRCMP)
8597643Sgblack@eecs.umich.edu        regs.isr |= ISR_TXRCMP;
8607373Sgblack@eecs.umich.edu
8617396Sgblack@eecs.umich.edu    if (interrupts & ISR_RXRCMP)
8627373Sgblack@eecs.umich.edu        regs.isr |= ISR_RXRCMP;
8637373Sgblack@eecs.umich.edu
8647396Sgblack@eecs.umich.edu//ISR_DPERR  not implemented
8657396Sgblack@eecs.umich.edu//ISR_SSERR not implemented
8667373Sgblack@eecs.umich.edu//ISR_RMABT not implemented
8677373Sgblack@eecs.umich.edu//ISR_RXSOVR not implemented
8687640Sgblack@eecs.umich.edu//ISR_HIBINT not implemented
8697643Sgblack@eecs.umich.edu//ISR_PHY not implemented
8707397Sgblack@eecs.umich.edu//ISR_PME not implemented
8717397Sgblack@eecs.umich.edu
8727397Sgblack@eecs.umich.edu    if (interrupts & ISR_SWI)
8737380Sgblack@eecs.umich.edu        regs.isr |= ISR_SWI;
8747397Sgblack@eecs.umich.edu
8757397Sgblack@eecs.umich.edu//ISR_MIB not implemented
8767381Sgblack@eecs.umich.edu//ISR_TXURN not implemented
8777639Sgblack@eecs.umich.edu
8787643Sgblack@eecs.umich.edu    if (interrupts & ISR_TXIDLE)
8797373Sgblack@eecs.umich.edu        regs.isr |= ISR_TXIDLE;
8807373Sgblack@eecs.umich.edu
8817396Sgblack@eecs.umich.edu    if (interrupts & ISR_TXERR)
8827373Sgblack@eecs.umich.edu        regs.isr |= ISR_TXERR;
8837373Sgblack@eecs.umich.edu
8847396Sgblack@eecs.umich.edu    if (interrupts & ISR_TXDESC)
8857396Sgblack@eecs.umich.edu        regs.isr |= ISR_TXDESC;
8867373Sgblack@eecs.umich.edu
8877373Sgblack@eecs.umich.edu    if (interrupts & ISR_TXOK) {
8887640Sgblack@eecs.umich.edu        regs.isr |= ISR_TXOK;
8897643Sgblack@eecs.umich.edu        delay = true;
8907397Sgblack@eecs.umich.edu    }
8917397Sgblack@eecs.umich.edu
8927380Sgblack@eecs.umich.edu    if (interrupts & ISR_RXORN)
8937381Sgblack@eecs.umich.edu        regs.isr |= ISR_RXORN;
8947387Sgblack@eecs.umich.edu
8957381Sgblack@eecs.umich.edu    if (interrupts & ISR_RXIDLE)
8967639Sgblack@eecs.umich.edu        regs.isr |= ISR_RXIDLE;
8977643Sgblack@eecs.umich.edu
8987373Sgblack@eecs.umich.edu//ISR_RXEARLY not implemented
8997396Sgblack@eecs.umich.edu
9007373Sgblack@eecs.umich.edu    if (interrupts & ISR_RXERR)
9017373Sgblack@eecs.umich.edu        regs.isr |= ISR_RXERR;
9027396Sgblack@eecs.umich.edu
9037396Sgblack@eecs.umich.edu    if (interrupts & ISR_RXDESC)
9047373Sgblack@eecs.umich.edu        regs.isr |= ISR_RXDESC;
9057373Sgblack@eecs.umich.edu
9067640Sgblack@eecs.umich.edu    if (interrupts & ISR_RXOK) {
9077643Sgblack@eecs.umich.edu        delay = true;
9087397Sgblack@eecs.umich.edu        regs.isr |= ISR_RXOK;
9097397Sgblack@eecs.umich.edu    }
9107397Sgblack@eecs.umich.edu
9117380Sgblack@eecs.umich.edu    if ((regs.isr & regs.imr)) {
9127397Sgblack@eecs.umich.edu        Tick when = curTick;
9137397Sgblack@eecs.umich.edu        if (delay)
9147381Sgblack@eecs.umich.edu            when += intrDelay;
9157639Sgblack@eecs.umich.edu        cpuIntrPost(when);
9167643Sgblack@eecs.umich.edu    }
9177373Sgblack@eecs.umich.edu
9187373Sgblack@eecs.umich.edu    DPRINTF(EthernetIntr, "**interrupt written to ISR: intr=%#x isr=%#x imr=%#x\n",
9197396Sgblack@eecs.umich.edu            interrupts, regs.isr, regs.imr);
9207373Sgblack@eecs.umich.edu}
9217373Sgblack@eecs.umich.edu
9227396Sgblack@eecs.umich.eduvoid
9237396Sgblack@eecs.umich.eduNSGigE::devIntrClear(uint32_t interrupts)
9247373Sgblack@eecs.umich.edu{
9257374Sgblack@eecs.umich.edu    if (interrupts & ISR_RESERVE)
9267640Sgblack@eecs.umich.edu        panic("Cannot clear a reserved interrupt");
9277643Sgblack@eecs.umich.edu
9287397Sgblack@eecs.umich.edu    if (interrupts & ISR_TXRCMP)
9297397Sgblack@eecs.umich.edu        regs.isr &= ~ISR_TXRCMP;
9307381Sgblack@eecs.umich.edu
9317397Sgblack@eecs.umich.edu    if (interrupts & ISR_RXRCMP)
9327397Sgblack@eecs.umich.edu        regs.isr &= ~ISR_RXRCMP;
9337639Sgblack@eecs.umich.edu
9347643Sgblack@eecs.umich.edu//ISR_DPERR  not implemented
9357397Sgblack@eecs.umich.edu//ISR_SSERR not implemented
9367397Sgblack@eecs.umich.edu//ISR_RMABT not implemented
9377374Sgblack@eecs.umich.edu//ISR_RXSOVR not implemented
9387396Sgblack@eecs.umich.edu//ISR_HIBINT not implemented
9397374Sgblack@eecs.umich.edu//ISR_PHY not implemented
9407374Sgblack@eecs.umich.edu//ISR_PME not implemented
9417396Sgblack@eecs.umich.edu
9427396Sgblack@eecs.umich.edu    if (interrupts & ISR_SWI)
9437374Sgblack@eecs.umich.edu        regs.isr &= ~ISR_SWI;
9447374Sgblack@eecs.umich.edu
9457640Sgblack@eecs.umich.edu//ISR_MIB not implemented
9467643Sgblack@eecs.umich.edu//ISR_TXURN not implemented
9477397Sgblack@eecs.umich.edu
9487397Sgblack@eecs.umich.edu    if (interrupts & ISR_TXIDLE)
9497397Sgblack@eecs.umich.edu        regs.isr &= ~ISR_TXIDLE;
9507397Sgblack@eecs.umich.edu
9517397Sgblack@eecs.umich.edu    if (interrupts & ISR_TXERR)
9527381Sgblack@eecs.umich.edu        regs.isr &= ~ISR_TXERR;
9537639Sgblack@eecs.umich.edu
9547643Sgblack@eecs.umich.edu    if (interrupts & ISR_TXDESC)
9557374Sgblack@eecs.umich.edu        regs.isr &= ~ISR_TXDESC;
9567396Sgblack@eecs.umich.edu
9577374Sgblack@eecs.umich.edu    if (interrupts & ISR_TXOK)
9587374Sgblack@eecs.umich.edu        regs.isr &= ~ISR_TXOK;
9597396Sgblack@eecs.umich.edu
9607396Sgblack@eecs.umich.edu    if (interrupts & ISR_RXORN)
9617374Sgblack@eecs.umich.edu        regs.isr &= ~ISR_RXORN;
9627377Sgblack@eecs.umich.edu
9637640Sgblack@eecs.umich.edu    if (interrupts & ISR_RXIDLE)
9647643Sgblack@eecs.umich.edu        regs.isr &= ~ISR_RXIDLE;
9657398Sgblack@eecs.umich.edu
9667398Sgblack@eecs.umich.edu//ISR_RXEARLY not implemented
9677398Sgblack@eecs.umich.edu
9687639Sgblack@eecs.umich.edu    if (interrupts & ISR_RXERR)
9697639Sgblack@eecs.umich.edu        regs.isr &= ~ISR_RXERR;
9707398Sgblack@eecs.umich.edu
9717639Sgblack@eecs.umich.edu    if (interrupts & ISR_RXDESC)
9727643Sgblack@eecs.umich.edu        regs.isr &= ~ISR_RXDESC;
9737398Sgblack@eecs.umich.edu
9747398Sgblack@eecs.umich.edu    if (interrupts & ISR_RXOK)
9757398Sgblack@eecs.umich.edu        regs.isr &= ~ISR_RXOK;
9767398Sgblack@eecs.umich.edu
9777398Sgblack@eecs.umich.edu    if (!(regs.isr & regs.imr))
9787398Sgblack@eecs.umich.edu        cpuIntrClear();
9797398Sgblack@eecs.umich.edu
9807398Sgblack@eecs.umich.edu    DPRINTF(EthernetIntr, "**interrupt cleared from ISR: intr=%x isr=%x imr=%x\n",
9817640Sgblack@eecs.umich.edu            interrupts, regs.isr, regs.imr);
9827643Sgblack@eecs.umich.edu}
9837398Sgblack@eecs.umich.edu
9847398Sgblack@eecs.umich.eduvoid
9857639Sgblack@eecs.umich.eduNSGigE::devIntrChangeMask()
9867639Sgblack@eecs.umich.edu{
9877398Sgblack@eecs.umich.edu    DPRINTF(EthernetIntr, "interrupt mask changed\n");
9887639Sgblack@eecs.umich.edu
9897643Sgblack@eecs.umich.edu    if (regs.isr & regs.imr)
9907398Sgblack@eecs.umich.edu        cpuIntrPost(curTick);
9917398Sgblack@eecs.umich.edu    else
9927398Sgblack@eecs.umich.edu        cpuIntrClear();
9937398Sgblack@eecs.umich.edu}
9947398Sgblack@eecs.umich.edu
9957398Sgblack@eecs.umich.eduvoid
9967398Sgblack@eecs.umich.eduNSGigE::cpuIntrPost(Tick when)
9977398Sgblack@eecs.umich.edu{
9987640Sgblack@eecs.umich.edu    //If the interrupt you want to post is later than an
9997643Sgblack@eecs.umich.edu    //interrupt already scheduled, just let it post in the coming one and
10007398Sgblack@eecs.umich.edu    //don't schedule another.
10017398Sgblack@eecs.umich.edu    //HOWEVER, must be sure that the scheduled intrTick is in the future
10027639Sgblack@eecs.umich.edu    //(this was formerly the source of a bug)
10037639Sgblack@eecs.umich.edu    assert((intrTick >= curTick) || (intrTick == 0));
10047639Sgblack@eecs.umich.edu    if (when > intrTick && intrTick != 0)
10057639Sgblack@eecs.umich.edu        return;
10067639Sgblack@eecs.umich.edu
10077639Sgblack@eecs.umich.edu    intrTick = when;
10087639Sgblack@eecs.umich.edu
10097643Sgblack@eecs.umich.edu    if (intrEvent) {
10107398Sgblack@eecs.umich.edu        intrEvent->squash();
10117398Sgblack@eecs.umich.edu        intrEvent = 0;
10127398Sgblack@eecs.umich.edu    }
10137398Sgblack@eecs.umich.edu
10147398Sgblack@eecs.umich.edu    if (when < curTick) {
10157398Sgblack@eecs.umich.edu        cpuInterrupt();
10167398Sgblack@eecs.umich.edu    } else {
10177398Sgblack@eecs.umich.edu        DPRINTF(EthernetIntr, "going to schedule an interrupt for intrTick=%d\n",
10187640Sgblack@eecs.umich.edu                intrTick);
10197643Sgblack@eecs.umich.edu        intrEvent = new IntrEvent(this, true);
10207398Sgblack@eecs.umich.edu        intrEvent->schedule(intrTick);
10217398Sgblack@eecs.umich.edu    }
10227639Sgblack@eecs.umich.edu}
10237639Sgblack@eecs.umich.edu
10247639Sgblack@eecs.umich.eduvoid
10257639Sgblack@eecs.umich.eduNSGigE::cpuInterrupt()
10267639Sgblack@eecs.umich.edu{
10277639Sgblack@eecs.umich.edu    // Don't send an interrupt if there's already one
10287639Sgblack@eecs.umich.edu    if (cpuPendingIntr) {
10297643Sgblack@eecs.umich.edu        DPRINTF(EthernetIntr,
10307398Sgblack@eecs.umich.edu                "would send an interrupt now, but there's already pending\n");
10317398Sgblack@eecs.umich.edu        intrTick = 0;
10327398Sgblack@eecs.umich.edu        return;
10337398Sgblack@eecs.umich.edu    }
10347398Sgblack@eecs.umich.edu    // Don't send an interrupt if it's supposed to be delayed
10357398Sgblack@eecs.umich.edu    if (intrTick > curTick) {
10367398Sgblack@eecs.umich.edu        DPRINTF(EthernetIntr, "an interrupt is scheduled for %d, wait til then\n",
10377398Sgblack@eecs.umich.edu                intrTick);
10387640Sgblack@eecs.umich.edu        return;
10397643Sgblack@eecs.umich.edu    }
10407397Sgblack@eecs.umich.edu
10417377Sgblack@eecs.umich.edu    // Whether or not there's a pending interrupt, we don't care about
10427377Sgblack@eecs.umich.edu    // it anymore
10437377Sgblack@eecs.umich.edu    intrEvent = 0;
10447377Sgblack@eecs.umich.edu    intrTick = 0;
10457377Sgblack@eecs.umich.edu
10467377Sgblack@eecs.umich.edu    // Send interrupt
10477377Sgblack@eecs.umich.edu    cpuPendingIntr = true;
10487389Sgblack@eecs.umich.edu    /** @todo rework the intctrl to be tsunami ok */
10497389Sgblack@eecs.umich.edu    //intctrl->post(TheISA::INTLEVEL_IRQ1, TheISA::INTINDEX_ETHERNET);
10507396Sgblack@eecs.umich.edu    DPRINTF(EthernetIntr, "Posting interrupts to cchip!\n");
10517389Sgblack@eecs.umich.edu    tsunami->cchip->postDRIR(configData->config.hdr.pci0.interruptLine);
10527396Sgblack@eecs.umich.edu}
10537389Sgblack@eecs.umich.edu
10547389Sgblack@eecs.umich.eduvoid
10557377Sgblack@eecs.umich.eduNSGigE::cpuIntrClear()
10567377Sgblack@eecs.umich.edu{
10577643Sgblack@eecs.umich.edu    if (cpuPendingIntr) {
10587377Sgblack@eecs.umich.edu        cpuPendingIntr = false;
10597396Sgblack@eecs.umich.edu        /** @todo rework the intctrl to be tsunami ok */
10607377Sgblack@eecs.umich.edu        //intctrl->clear(TheISA::INTLEVEL_IRQ1, TheISA::INTINDEX_ETHERNET);
10617377Sgblack@eecs.umich.edu        DPRINTF(EthernetIntr, "clearing all interrupts from cchip\n");
10627396Sgblack@eecs.umich.edu        tsunami->cchip->clearDRIR(configData->config.hdr.pci0.interruptLine);
10637396Sgblack@eecs.umich.edu    }
10647377Sgblack@eecs.umich.edu}
10657377Sgblack@eecs.umich.edu
10667640Sgblack@eecs.umich.edubool
10677397Sgblack@eecs.umich.eduNSGigE::cpuIntrPending() const
10687397Sgblack@eecs.umich.edu{ return cpuPendingIntr; }
10697643Sgblack@eecs.umich.edu
10707397Sgblack@eecs.umich.eduvoid
10717397Sgblack@eecs.umich.eduNSGigE::txReset()
10727377Sgblack@eecs.umich.edu{
10737397Sgblack@eecs.umich.edu
10747377Sgblack@eecs.umich.edu    DPRINTF(Ethernet, "transmit reset\n");
10757397Sgblack@eecs.umich.edu
10767377Sgblack@eecs.umich.edu    CTDD = false;
10777377Sgblack@eecs.umich.edu    txFifoAvail = MAX_TX_FIFO_SIZE;
10787389Sgblack@eecs.umich.edu    txHalt = false;
10797397Sgblack@eecs.umich.edu    txFragPtr = 0;
10807397Sgblack@eecs.umich.edu    assert(txDescCnt == 0);
10817397Sgblack@eecs.umich.edu    txFifo.clear();
10827397Sgblack@eecs.umich.edu    regs.command &= ~CR_TXE;
10837389Sgblack@eecs.umich.edu    txState = txIdle;
10847389Sgblack@eecs.umich.edu    assert(txDmaState == dmaIdle);
10857377Sgblack@eecs.umich.edu}
10867377Sgblack@eecs.umich.edu
10877643Sgblack@eecs.umich.eduvoid
10887377Sgblack@eecs.umich.eduNSGigE::rxReset()
10897396Sgblack@eecs.umich.edu{
10907377Sgblack@eecs.umich.edu    DPRINTF(Ethernet, "receive reset\n");
10917377Sgblack@eecs.umich.edu
10927396Sgblack@eecs.umich.edu    CRDD = false;
10937396Sgblack@eecs.umich.edu    assert(rxPktBytes == 0);
10947377Sgblack@eecs.umich.edu    rxFifoCnt = 0;
10957377Sgblack@eecs.umich.edu    rxHalt = false;
10967640Sgblack@eecs.umich.edu    rxFragPtr = 0;
10977643Sgblack@eecs.umich.edu    assert(rxDescCnt == 0);
10987397Sgblack@eecs.umich.edu    assert(rxDmaState == dmaIdle);
10997389Sgblack@eecs.umich.edu    rxFifo.clear();
11007389Sgblack@eecs.umich.edu    regs.command &= ~CR_RXE;
11017377Sgblack@eecs.umich.edu    rxState = rxIdle;
11027377Sgblack@eecs.umich.edu}
11037377Sgblack@eecs.umich.edu
11047377Sgblack@eecs.umich.eduvoid NSGigE::regsReset()
11057377Sgblack@eecs.umich.edu{
11067377Sgblack@eecs.umich.edu    memset(&regs, 0, sizeof(regs));
11077377Sgblack@eecs.umich.edu    regs.config = 0x80000000;
11087389Sgblack@eecs.umich.edu    regs.mear = 0x12;
11097389Sgblack@eecs.umich.edu    regs.isr = 0x00608000;
11107396Sgblack@eecs.umich.edu    regs.txcfg = 0x120;
11117389Sgblack@eecs.umich.edu    regs.rxcfg = 0x4;
11127389Sgblack@eecs.umich.edu    regs.srr = 0x0103;
11137377Sgblack@eecs.umich.edu    regs.mibc = 0x2;
11147377Sgblack@eecs.umich.edu    regs.vdr = 0x81;
11157643Sgblack@eecs.umich.edu    regs.tesr = 0xc000;
11167377Sgblack@eecs.umich.edu
11177396Sgblack@eecs.umich.edu    extstsEnable = false;
11187377Sgblack@eecs.umich.edu    acceptBroadcast = false;
11197377Sgblack@eecs.umich.edu    acceptMulticast = false;
11207396Sgblack@eecs.umich.edu    acceptUnicast = false;
11217396Sgblack@eecs.umich.edu    acceptPerfect = false;
11227377Sgblack@eecs.umich.edu    acceptArp = false;
11237377Sgblack@eecs.umich.edu}
11247640Sgblack@eecs.umich.edu
11257389Sgblack@eecs.umich.eduvoid
11267389Sgblack@eecs.umich.eduNSGigE::rxDmaReadCopy()
11277397Sgblack@eecs.umich.edu{
11287643Sgblack@eecs.umich.edu    assert(rxDmaState == dmaReading);
11297397Sgblack@eecs.umich.edu
11307397Sgblack@eecs.umich.edu    memcpy(rxDmaData, physmem->dma_addr(rxDmaAddr, rxDmaLen), rxDmaLen);
11317377Sgblack@eecs.umich.edu    rxDmaState = dmaIdle;
11327397Sgblack@eecs.umich.edu
11337377Sgblack@eecs.umich.edu    DPRINTF(EthernetDMA, "rx dma read  paddr=%#x len=%d\n",
11347397Sgblack@eecs.umich.edu            rxDmaAddr, rxDmaLen);
11357377Sgblack@eecs.umich.edu    DDUMP(EthernetDMA, rxDmaData, rxDmaLen);
11367377Sgblack@eecs.umich.edu}
11377389Sgblack@eecs.umich.edu
11387397Sgblack@eecs.umich.edubool
11397397Sgblack@eecs.umich.eduNSGigE::doRxDmaRead()
11407389Sgblack@eecs.umich.edu{
11417389Sgblack@eecs.umich.edu    assert(rxDmaState == dmaIdle || rxDmaState == dmaReadWaiting);
11427377Sgblack@eecs.umich.edu    rxDmaState = dmaReading;
11437377Sgblack@eecs.umich.edu
11447643Sgblack@eecs.umich.edu    if (dmaInterface && !rxDmaFree) {
11457377Sgblack@eecs.umich.edu        if (dmaInterface->busy())
11467396Sgblack@eecs.umich.edu            rxDmaState = dmaReadWaiting;
11477377Sgblack@eecs.umich.edu        else
11487377Sgblack@eecs.umich.edu            dmaInterface->doDMA(Read, rxDmaAddr, rxDmaLen, curTick,
11497396Sgblack@eecs.umich.edu                                &rxDmaReadEvent);
11507396Sgblack@eecs.umich.edu        return true;
11517377Sgblack@eecs.umich.edu    }
11527389Sgblack@eecs.umich.edu
11537640Sgblack@eecs.umich.edu    if (dmaReadDelay == 0 && dmaReadFactor == 0) {
11547643Sgblack@eecs.umich.edu        rxDmaReadCopy();
11557397Sgblack@eecs.umich.edu        return false;
11567389Sgblack@eecs.umich.edu    }
11577389Sgblack@eecs.umich.edu
11587389Sgblack@eecs.umich.edu    Tick factor = ((rxDmaLen + ULL(63)) >> ULL(6)) * dmaReadFactor;
11597389Sgblack@eecs.umich.edu    Tick start = curTick + dmaReadDelay + factor;
11607389Sgblack@eecs.umich.edu    rxDmaReadEvent.schedule(start);
11617389Sgblack@eecs.umich.edu    return true;
11627389Sgblack@eecs.umich.edu}
11637389Sgblack@eecs.umich.edu
11647389Sgblack@eecs.umich.eduvoid
11657389Sgblack@eecs.umich.eduNSGigE::rxDmaReadDone()
11667643Sgblack@eecs.umich.edu{
11677389Sgblack@eecs.umich.edu    assert(rxDmaState == dmaReading);
11687396Sgblack@eecs.umich.edu    rxDmaReadCopy();
11697389Sgblack@eecs.umich.edu
11707389Sgblack@eecs.umich.edu    // If the transmit state machine has a pending DMA, let it go first
11717396Sgblack@eecs.umich.edu    if (txDmaState == dmaReadWaiting || txDmaState == dmaWriteWaiting)
11727396Sgblack@eecs.umich.edu        txKick();
11737389Sgblack@eecs.umich.edu
11747389Sgblack@eecs.umich.edu    rxKick();
11757640Sgblack@eecs.umich.edu}
11767397Sgblack@eecs.umich.edu
11777397Sgblack@eecs.umich.eduvoid
11787643Sgblack@eecs.umich.eduNSGigE::rxDmaWriteCopy()
11797397Sgblack@eecs.umich.edu{
11807397Sgblack@eecs.umich.edu    assert(rxDmaState == dmaWriting);
11817389Sgblack@eecs.umich.edu
11827397Sgblack@eecs.umich.edu    memcpy(physmem->dma_addr(rxDmaAddr, rxDmaLen), rxDmaData, rxDmaLen);
11837389Sgblack@eecs.umich.edu    rxDmaState = dmaIdle;
11847397Sgblack@eecs.umich.edu
11857389Sgblack@eecs.umich.edu    DPRINTF(EthernetDMA, "rx dma write paddr=%#x len=%d\n",
11867389Sgblack@eecs.umich.edu            rxDmaAddr, rxDmaLen);
11877389Sgblack@eecs.umich.edu    DDUMP(EthernetDMA, rxDmaData, rxDmaLen);
11887389Sgblack@eecs.umich.edu}
11897389Sgblack@eecs.umich.edu
11907643Sgblack@eecs.umich.edubool
11917389Sgblack@eecs.umich.eduNSGigE::doRxDmaWrite()
11927396Sgblack@eecs.umich.edu{
11937389Sgblack@eecs.umich.edu    assert(rxDmaState == dmaIdle || rxDmaState == dmaWriteWaiting);
11947389Sgblack@eecs.umich.edu    rxDmaState = dmaWriting;
11957396Sgblack@eecs.umich.edu
11967396Sgblack@eecs.umich.edu    if (dmaInterface && !rxDmaFree) {
11977389Sgblack@eecs.umich.edu        if (dmaInterface->busy())
11987389Sgblack@eecs.umich.edu            rxDmaState = dmaWriteWaiting;
11997640Sgblack@eecs.umich.edu        else
12007643Sgblack@eecs.umich.edu            dmaInterface->doDMA(WriteInvalidate, rxDmaAddr, rxDmaLen, curTick,
12017397Sgblack@eecs.umich.edu                                &rxDmaWriteEvent);
12027389Sgblack@eecs.umich.edu        return true;
12037389Sgblack@eecs.umich.edu    }
12047389Sgblack@eecs.umich.edu
12057389Sgblack@eecs.umich.edu    if (dmaWriteDelay == 0 && dmaWriteFactor == 0) {
12067389Sgblack@eecs.umich.edu        rxDmaWriteCopy();
12077389Sgblack@eecs.umich.edu        return false;
12087389Sgblack@eecs.umich.edu    }
12097389Sgblack@eecs.umich.edu
12107389Sgblack@eecs.umich.edu    Tick factor = ((rxDmaLen + ULL(63)) >> ULL(6)) * dmaWriteFactor;
12117389Sgblack@eecs.umich.edu    Tick start = curTick + dmaWriteDelay + factor;
12127643Sgblack@eecs.umich.edu    rxDmaWriteEvent.schedule(start);
12137389Sgblack@eecs.umich.edu    return true;
12147396Sgblack@eecs.umich.edu}
12157389Sgblack@eecs.umich.edu
12167389Sgblack@eecs.umich.eduvoid
12177396Sgblack@eecs.umich.eduNSGigE::rxDmaWriteDone()
12187396Sgblack@eecs.umich.edu{
12197389Sgblack@eecs.umich.edu    assert(rxDmaState == dmaWriting);
12207389Sgblack@eecs.umich.edu    rxDmaWriteCopy();
12217640Sgblack@eecs.umich.edu
12227397Sgblack@eecs.umich.edu    // If the transmit state machine has a pending DMA, let it go first
12237643Sgblack@eecs.umich.edu    if (txDmaState == dmaReadWaiting || txDmaState == dmaWriteWaiting)
12247397Sgblack@eecs.umich.edu        txKick();
12257397Sgblack@eecs.umich.edu
12267389Sgblack@eecs.umich.edu    rxKick();
12277397Sgblack@eecs.umich.edu}
12287389Sgblack@eecs.umich.edu
12297397Sgblack@eecs.umich.eduvoid
12307389Sgblack@eecs.umich.eduNSGigE::rxKick()
12317389Sgblack@eecs.umich.edu{
12327389Sgblack@eecs.umich.edu    DPRINTF(EthernetSM, "receive kick state=%s (rxBuf.size=%d)\n",
12337389Sgblack@eecs.umich.edu            NsRxStateStrings[rxState], rxFifo.size());
12347389Sgblack@eecs.umich.edu
12357643Sgblack@eecs.umich.edu    if (rxKickTick > curTick) {
12367389Sgblack@eecs.umich.edu        DPRINTF(EthernetSM, "receive kick exiting, can't run till %d\n",
12377396Sgblack@eecs.umich.edu                rxKickTick);
12387389Sgblack@eecs.umich.edu        return;
12397389Sgblack@eecs.umich.edu    }
12407396Sgblack@eecs.umich.edu
12417396Sgblack@eecs.umich.edu  next:
12427389Sgblack@eecs.umich.edu    switch(rxDmaState) {
12437322Sgblack@eecs.umich.edu      case dmaReadWaiting:
12447379Sgblack@eecs.umich.edu        if (doRxDmaRead())
12457379Sgblack@eecs.umich.edu            goto exit;
12467379Sgblack@eecs.umich.edu        break;
12477379Sgblack@eecs.umich.edu      case dmaWriteWaiting:
12487379Sgblack@eecs.umich.edu        if (doRxDmaWrite())
12497379Sgblack@eecs.umich.edu            goto exit;
12507379Sgblack@eecs.umich.edu        break;
12517640Sgblack@eecs.umich.edu      default:
12527643Sgblack@eecs.umich.edu        break;
12537397Sgblack@eecs.umich.edu    }
12547397Sgblack@eecs.umich.edu
12557381Sgblack@eecs.umich.edu    // see state machine from spec for details
12567379Sgblack@eecs.umich.edu    // the way this works is, if you finish work on one state and can go directly to
12577381Sgblack@eecs.umich.edu    // another, you do that through jumping to the label "next".  however, if you have
12587639Sgblack@eecs.umich.edu    // intermediate work, like DMA so that you can't go to the next state yet, you go to
12597643Sgblack@eecs.umich.edu    // exit and exit the loop.  however, when the DMA is done it will trigger an
12607379Sgblack@eecs.umich.edu    // event and come back to this loop.
12617396Sgblack@eecs.umich.edu    switch (rxState) {
12627379Sgblack@eecs.umich.edu      case rxIdle:
12637379Sgblack@eecs.umich.edu        if (!regs.command & CR_RXE) {
12647396Sgblack@eecs.umich.edu            DPRINTF(EthernetSM, "Receive Disabled! Nothing to do.\n");
12657396Sgblack@eecs.umich.edu            goto exit;
12667379Sgblack@eecs.umich.edu        }
12677379Sgblack@eecs.umich.edu
12687640Sgblack@eecs.umich.edu        if (CRDD) {
12697643Sgblack@eecs.umich.edu            rxState = rxDescRefr;
12707397Sgblack@eecs.umich.edu
12717397Sgblack@eecs.umich.edu            rxDmaAddr = regs.rxdp & 0x3fffffff;
12727397Sgblack@eecs.umich.edu            rxDmaData = &rxDescCache + offsetof(ns_desc, link);
12737397Sgblack@eecs.umich.edu            rxDmaLen = sizeof(rxDescCache.link);
12747397Sgblack@eecs.umich.edu            rxDmaFree = dmaDescFree;
12757381Sgblack@eecs.umich.edu
12767639Sgblack@eecs.umich.edu            if (doRxDmaRead())
12777643Sgblack@eecs.umich.edu                goto exit;
12787379Sgblack@eecs.umich.edu        } else {
12797379Sgblack@eecs.umich.edu            rxState = rxDescRead;
12807379Sgblack@eecs.umich.edu
12817396Sgblack@eecs.umich.edu            rxDmaAddr = regs.rxdp & 0x3fffffff;
12827379Sgblack@eecs.umich.edu            rxDmaData = &rxDescCache;
12837379Sgblack@eecs.umich.edu            rxDmaLen = sizeof(ns_desc);
12847396Sgblack@eecs.umich.edu            rxDmaFree = dmaDescFree;
12857396Sgblack@eecs.umich.edu
12867379Sgblack@eecs.umich.edu            if (doRxDmaRead())
12877379Sgblack@eecs.umich.edu                goto exit;
12887640Sgblack@eecs.umich.edu        }
12897643Sgblack@eecs.umich.edu        break;
12907397Sgblack@eecs.umich.edu
12917397Sgblack@eecs.umich.edu      case rxDescRefr:
12927381Sgblack@eecs.umich.edu        if (rxDmaState != dmaIdle)
12937379Sgblack@eecs.umich.edu            goto exit;
12947381Sgblack@eecs.umich.edu
12957639Sgblack@eecs.umich.edu        rxState = rxAdvance;
12967643Sgblack@eecs.umich.edu        break;
12977379Sgblack@eecs.umich.edu
12987396Sgblack@eecs.umich.edu     case rxDescRead:
12997379Sgblack@eecs.umich.edu        if (rxDmaState != dmaIdle)
13007379Sgblack@eecs.umich.edu            goto exit;
13017396Sgblack@eecs.umich.edu
13027396Sgblack@eecs.umich.edu        DPRINTF(EthernetDesc,
13037379Sgblack@eecs.umich.edu                "rxDescCache:\n\tlink=%08x\n\tbufptr=%08x\n\tcmdsts=%08x\n\textsts=%08x\n"
13047379Sgblack@eecs.umich.edu                ,rxDescCache.link, rxDescCache.bufptr, rxDescCache.cmdsts,
13057640Sgblack@eecs.umich.edu                rxDescCache.extsts);
13067643Sgblack@eecs.umich.edu
13077397Sgblack@eecs.umich.edu        if (rxDescCache.cmdsts & CMDSTS_OWN) {
13087397Sgblack@eecs.umich.edu            rxState = rxIdle;
13097397Sgblack@eecs.umich.edu        } else {
13107397Sgblack@eecs.umich.edu            rxState = rxFifoBlock;
13117397Sgblack@eecs.umich.edu            rxFragPtr = rxDescCache.bufptr;
13127381Sgblack@eecs.umich.edu            rxDescCnt = rxDescCache.cmdsts & CMDSTS_LEN_MASK;
13137639Sgblack@eecs.umich.edu        }
13147643Sgblack@eecs.umich.edu        break;
13157379Sgblack@eecs.umich.edu
13167379Sgblack@eecs.umich.edu      case rxFifoBlock:
13177379Sgblack@eecs.umich.edu        if (!rxPacket) {
13187396Sgblack@eecs.umich.edu            /**
13197379Sgblack@eecs.umich.edu             * @todo in reality, we should be able to start processing
13207379Sgblack@eecs.umich.edu             * the packet as it arrives, and not have to wait for the
13217396Sgblack@eecs.umich.edu             * full packet ot be in the receive fifo.
13227396Sgblack@eecs.umich.edu             */
13237379Sgblack@eecs.umich.edu            if (rxFifo.empty())
13247379Sgblack@eecs.umich.edu                goto exit;
13257640Sgblack@eecs.umich.edu
13267643Sgblack@eecs.umich.edu            DPRINTF(EthernetSM, "\n\n*****processing receive of new packet\n");
13277397Sgblack@eecs.umich.edu
13287381Sgblack@eecs.umich.edu            // If we don't have a packet, grab a new one from the fifo.
13297639Sgblack@eecs.umich.edu            rxPacket = rxFifo.front();
13307381Sgblack@eecs.umich.edu            rxPktBytes = rxPacket->length;
13317639Sgblack@eecs.umich.edu            rxPacketBufPtr = rxPacket->data;
13327643Sgblack@eecs.umich.edu
13337379Sgblack@eecs.umich.edu            if (DTRACE(Ethernet)) {
13347396Sgblack@eecs.umich.edu                if (rxPacket->isIpPkt()) {
13357379Sgblack@eecs.umich.edu                    ip_header *ip = rxPacket->getIpHdr();
13367379Sgblack@eecs.umich.edu                    DPRINTF(Ethernet, "ID is %d\n", reverseEnd16(ip->ID));
13377396Sgblack@eecs.umich.edu                    if (rxPacket->isTcpPkt()) {
13387396Sgblack@eecs.umich.edu                        tcp_header *tcp = rxPacket->getTcpHdr(ip);
13397379Sgblack@eecs.umich.edu                        DPRINTF(Ethernet, "Src Port = %d, Dest Port = %d\n",
13407379Sgblack@eecs.umich.edu                                reverseEnd16(tcp->src_port_num),
13417640Sgblack@eecs.umich.edu                                reverseEnd16(tcp->dest_port_num));
13427643Sgblack@eecs.umich.edu                    }
13437379Sgblack@eecs.umich.edu                }
13447397Sgblack@eecs.umich.edu            }
13457381Sgblack@eecs.umich.edu
13467639Sgblack@eecs.umich.edu            // sanity check - i think the driver behaves like this
13477397Sgblack@eecs.umich.edu            assert(rxDescCnt >= rxPktBytes);
13487639Sgblack@eecs.umich.edu
13497643Sgblack@eecs.umich.edu            // Must clear the value before popping to decrement the
13507397Sgblack@eecs.umich.edu            // reference count
13517397Sgblack@eecs.umich.edu            rxFifo.front() = NULL;
13527379Sgblack@eecs.umich.edu            rxFifo.pop_front();
13537396Sgblack@eecs.umich.edu            rxFifoCnt -= rxPacket->length;
13547379Sgblack@eecs.umich.edu        }
13557379Sgblack@eecs.umich.edu
13567396Sgblack@eecs.umich.edu
13577396Sgblack@eecs.umich.edu        // dont' need the && rxDescCnt > 0 if driver sanity check above holds
13587379Sgblack@eecs.umich.edu        if (rxPktBytes > 0) {
13597379Sgblack@eecs.umich.edu            rxState = rxFragWrite;
13607640Sgblack@eecs.umich.edu            // don't need min<>(rxPktBytes,rxDescCnt) if above sanity check holds
13617643Sgblack@eecs.umich.edu            rxXferLen = rxPktBytes;
13627397Sgblack@eecs.umich.edu
13637381Sgblack@eecs.umich.edu            rxDmaAddr = rxFragPtr & 0x3fffffff;
13647639Sgblack@eecs.umich.edu            rxDmaData = rxPacketBufPtr;
13657381Sgblack@eecs.umich.edu            rxDmaLen = rxXferLen;
13667639Sgblack@eecs.umich.edu            rxDmaFree = dmaDataFree;
13677643Sgblack@eecs.umich.edu
13687379Sgblack@eecs.umich.edu            if (doRxDmaWrite())
13697396Sgblack@eecs.umich.edu                goto exit;
13707379Sgblack@eecs.umich.edu
13717379Sgblack@eecs.umich.edu        } else {
13727396Sgblack@eecs.umich.edu            rxState = rxDescWrite;
13737396Sgblack@eecs.umich.edu
13747379Sgblack@eecs.umich.edu            //if (rxPktBytes == 0) {  /* packet is done */
13757379Sgblack@eecs.umich.edu            assert(rxPktBytes == 0);
13767640Sgblack@eecs.umich.edu            DPRINTF(EthernetSM, "done with receiving packet\n");
13777643Sgblack@eecs.umich.edu
13787379Sgblack@eecs.umich.edu            rxDescCache.cmdsts |= CMDSTS_OWN;
13797397Sgblack@eecs.umich.edu            rxDescCache.cmdsts &= ~CMDSTS_MORE;
13807381Sgblack@eecs.umich.edu            rxDescCache.cmdsts |= CMDSTS_OK;
13817639Sgblack@eecs.umich.edu            rxDescCache.cmdsts &= 0xffff0000;
13827397Sgblack@eecs.umich.edu            rxDescCache.cmdsts += rxPacket->length;   //i.e. set CMDSTS_SIZE
13837639Sgblack@eecs.umich.edu
13847643Sgblack@eecs.umich.edu#if 0
13857397Sgblack@eecs.umich.edu            /* all the driver uses these are for its own stats keeping
13867397Sgblack@eecs.umich.edu               which we don't care about, aren't necessary for functionality
13877379Sgblack@eecs.umich.edu               and doing this would just slow us down.  if they end up using
13887396Sgblack@eecs.umich.edu               this in a later version for functional purposes, just undef
13897379Sgblack@eecs.umich.edu            */
13907379Sgblack@eecs.umich.edu            if (rxFilterEnable) {
13917396Sgblack@eecs.umich.edu                rxDescCache.cmdsts &= ~CMDSTS_DEST_MASK;
13927396Sgblack@eecs.umich.edu                if (rxFifo.front()->IsUnicast())
13937379Sgblack@eecs.umich.edu                    rxDescCache.cmdsts |= CMDSTS_DEST_SELF;
13947379Sgblack@eecs.umich.edu                if (rxFifo.front()->IsMulticast())
13957640Sgblack@eecs.umich.edu                    rxDescCache.cmdsts |= CMDSTS_DEST_MULTI;
13967643Sgblack@eecs.umich.edu                if (rxFifo.front()->IsBroadcast())
13977397Sgblack@eecs.umich.edu                    rxDescCache.cmdsts |= CMDSTS_DEST_MASK;
13987397Sgblack@eecs.umich.edu            }
13997381Sgblack@eecs.umich.edu#endif
14007379Sgblack@eecs.umich.edu
14017381Sgblack@eecs.umich.edu            if (rxPacket->isIpPkt() && extstsEnable) {
14027639Sgblack@eecs.umich.edu                rxDescCache.extsts |= EXTSTS_IPPKT;
14037643Sgblack@eecs.umich.edu                if (!ipChecksum(rxPacket, false)) {
14047379Sgblack@eecs.umich.edu                    DPRINTF(EthernetCksum, "Rx IP Checksum Error\n");
14057379Sgblack@eecs.umich.edu                    rxDescCache.extsts |= EXTSTS_IPERR;
14067396Sgblack@eecs.umich.edu                }
14077379Sgblack@eecs.umich.edu                if (rxPacket->isTcpPkt()) {
14087379Sgblack@eecs.umich.edu                    rxDescCache.extsts |= EXTSTS_TCPPKT;
14097396Sgblack@eecs.umich.edu                    if (!tcpChecksum(rxPacket, false)) {
14107396Sgblack@eecs.umich.edu                        DPRINTF(EthernetCksum, "Rx TCP Checksum Error\n");
14117379Sgblack@eecs.umich.edu                        rxDescCache.extsts |= EXTSTS_TCPERR;
14127379Sgblack@eecs.umich.edu                    }
14137640Sgblack@eecs.umich.edu                } else if (rxPacket->isUdpPkt()) {
14147643Sgblack@eecs.umich.edu                    rxDescCache.extsts |= EXTSTS_UDPPKT;
14157397Sgblack@eecs.umich.edu                    if (!udpChecksum(rxPacket, false)) {
14167397Sgblack@eecs.umich.edu                        DPRINTF(EthernetCksum, "Rx UDP Checksum Error\n");
14177397Sgblack@eecs.umich.edu                        rxDescCache.extsts |= EXTSTS_UDPERR;
14187397Sgblack@eecs.umich.edu                    }
14197397Sgblack@eecs.umich.edu                }
14207381Sgblack@eecs.umich.edu            }
14217639Sgblack@eecs.umich.edu            rxPacket = 0;
14227643Sgblack@eecs.umich.edu
14237379Sgblack@eecs.umich.edu            /* the driver seems to always receive into desc buffers
14247379Sgblack@eecs.umich.edu               of size 1514, so you never have a pkt that is split
14257379Sgblack@eecs.umich.edu               into multiple descriptors on the receive side, so
14267379Sgblack@eecs.umich.edu               i don't implement that case, hence the assert above.
14277396Sgblack@eecs.umich.edu            */
14287379Sgblack@eecs.umich.edu
14297379Sgblack@eecs.umich.edu            DPRINTF(EthernetDesc, "rxDesc writeback:\n\tcmdsts=%08x\n\textsts=%08x\n",
14307396Sgblack@eecs.umich.edu                    rxDescCache.cmdsts, rxDescCache.extsts);
14317396Sgblack@eecs.umich.edu
14327379Sgblack@eecs.umich.edu            rxDmaAddr = (regs.rxdp + offsetof(ns_desc, cmdsts)) & 0x3fffffff;
14337379Sgblack@eecs.umich.edu            rxDmaData = &(rxDescCache.cmdsts);
14347640Sgblack@eecs.umich.edu            rxDmaLen = sizeof(rxDescCache.cmdsts) + sizeof(rxDescCache.extsts);
14357643Sgblack@eecs.umich.edu            rxDmaFree = dmaDescFree;
14367397Sgblack@eecs.umich.edu
14377397Sgblack@eecs.umich.edu            if (doRxDmaWrite())
14387381Sgblack@eecs.umich.edu                goto exit;
14397379Sgblack@eecs.umich.edu        }
14407381Sgblack@eecs.umich.edu        break;
14417639Sgblack@eecs.umich.edu
14427643Sgblack@eecs.umich.edu      case rxFragWrite:
14437379Sgblack@eecs.umich.edu        if (rxDmaState != dmaIdle)
14447379Sgblack@eecs.umich.edu            goto exit;
14457396Sgblack@eecs.umich.edu
14467379Sgblack@eecs.umich.edu        rxPacketBufPtr += rxXferLen;
14477379Sgblack@eecs.umich.edu        rxFragPtr += rxXferLen;
14487396Sgblack@eecs.umich.edu        rxPktBytes -= rxXferLen;
14497396Sgblack@eecs.umich.edu
14507379Sgblack@eecs.umich.edu        rxState = rxFifoBlock;
14517379Sgblack@eecs.umich.edu        break;
14527640Sgblack@eecs.umich.edu
14537643Sgblack@eecs.umich.edu      case rxDescWrite:
14547397Sgblack@eecs.umich.edu        if (rxDmaState != dmaIdle)
14557397Sgblack@eecs.umich.edu            goto exit;
14567397Sgblack@eecs.umich.edu
14577397Sgblack@eecs.umich.edu        assert(rxDescCache.cmdsts & CMDSTS_OWN);
14587397Sgblack@eecs.umich.edu
14597381Sgblack@eecs.umich.edu        assert(rxPacket == 0);
14607639Sgblack@eecs.umich.edu        devIntrPost(ISR_RXOK);
14617643Sgblack@eecs.umich.edu
14627379Sgblack@eecs.umich.edu        if (rxDescCache.cmdsts & CMDSTS_INTR)
14637379Sgblack@eecs.umich.edu            devIntrPost(ISR_RXDESC);
14647379Sgblack@eecs.umich.edu
14657379Sgblack@eecs.umich.edu        if (rxHalt) {
14667396Sgblack@eecs.umich.edu            DPRINTF(EthernetSM, "Halting the RX state machine\n");
14677379Sgblack@eecs.umich.edu            rxState = rxIdle;
14687379Sgblack@eecs.umich.edu            rxHalt = false;
14697396Sgblack@eecs.umich.edu        } else
14707396Sgblack@eecs.umich.edu            rxState = rxAdvance;
14717379Sgblack@eecs.umich.edu        break;
14727379Sgblack@eecs.umich.edu
14737640Sgblack@eecs.umich.edu      case rxAdvance:
14747643Sgblack@eecs.umich.edu        if (rxDescCache.link == 0) {
14757397Sgblack@eecs.umich.edu            rxState = rxIdle;
14767381Sgblack@eecs.umich.edu            return;
14777639Sgblack@eecs.umich.edu        } else {
14787381Sgblack@eecs.umich.edu            rxState = rxDescRead;
14797639Sgblack@eecs.umich.edu            regs.rxdp = rxDescCache.link;
14807643Sgblack@eecs.umich.edu            CRDD = false;
14817379Sgblack@eecs.umich.edu
14827379Sgblack@eecs.umich.edu            rxDmaAddr = regs.rxdp & 0x3fffffff;
14837396Sgblack@eecs.umich.edu            rxDmaData = &rxDescCache;
14847379Sgblack@eecs.umich.edu            rxDmaLen = sizeof(ns_desc);
14857379Sgblack@eecs.umich.edu            rxDmaFree = dmaDescFree;
14867396Sgblack@eecs.umich.edu
14877396Sgblack@eecs.umich.edu            if (doRxDmaRead())
14887379Sgblack@eecs.umich.edu                goto exit;
14897379Sgblack@eecs.umich.edu        }
14907640Sgblack@eecs.umich.edu        break;
14917643Sgblack@eecs.umich.edu
14927379Sgblack@eecs.umich.edu      default:
14937397Sgblack@eecs.umich.edu        panic("Invalid rxState!");
14947381Sgblack@eecs.umich.edu    }
14957639Sgblack@eecs.umich.edu
14967397Sgblack@eecs.umich.edu
14977639Sgblack@eecs.umich.edu    DPRINTF(EthernetSM, "entering next rx state = %s\n",
14987643Sgblack@eecs.umich.edu            NsRxStateStrings[rxState]);
14997397Sgblack@eecs.umich.edu
15007397Sgblack@eecs.umich.edu    if (rxState == rxIdle) {
15017379Sgblack@eecs.umich.edu        regs.command &= ~CR_RXE;
15027379Sgblack@eecs.umich.edu        devIntrPost(ISR_RXIDLE);
15037396Sgblack@eecs.umich.edu        return;
15047379Sgblack@eecs.umich.edu    }
15057379Sgblack@eecs.umich.edu
15067396Sgblack@eecs.umich.edu    goto next;
15077396Sgblack@eecs.umich.edu
15087379Sgblack@eecs.umich.edu  exit:
15097379Sgblack@eecs.umich.edu    /**
15107640Sgblack@eecs.umich.edu     * @todo do we want to schedule a future kick?
15117643Sgblack@eecs.umich.edu     */
15127397Sgblack@eecs.umich.edu    DPRINTF(EthernetSM, "rx state machine exited state=%s\n",
15137381Sgblack@eecs.umich.edu            NsRxStateStrings[rxState]);
15147639Sgblack@eecs.umich.edu}
15157381Sgblack@eecs.umich.edu
15167639Sgblack@eecs.umich.eduvoid
15177643Sgblack@eecs.umich.eduNSGigE::transmit()
15187379Sgblack@eecs.umich.edu{
15197379Sgblack@eecs.umich.edu    if (txFifo.empty()) {
15207396Sgblack@eecs.umich.edu        DPRINTF(Ethernet, "nothing to transmit\n");
15217379Sgblack@eecs.umich.edu        return;
15227379Sgblack@eecs.umich.edu    }
15237396Sgblack@eecs.umich.edu
15247396Sgblack@eecs.umich.edu    DPRINTF(Ethernet, "\n\nAttempt Pkt Transmit: txFifo length = %d\n",
15257379Sgblack@eecs.umich.edu            MAX_TX_FIFO_SIZE - txFifoAvail);
15267379Sgblack@eecs.umich.edu    if (interface->sendPacket(txFifo.front())) {
15277640Sgblack@eecs.umich.edu        if (DTRACE(Ethernet)) {
15287643Sgblack@eecs.umich.edu            if (txFifo.front()->isIpPkt()) {
15297379Sgblack@eecs.umich.edu                ip_header *ip = txFifo.front()->getIpHdr();
15307397Sgblack@eecs.umich.edu                DPRINTF(Ethernet, "ID is %d\n", reverseEnd16(ip->ID));
15317381Sgblack@eecs.umich.edu                if (txFifo.front()->isTcpPkt()) {
15327639Sgblack@eecs.umich.edu                    tcp_header *tcp = txFifo.front()->getTcpHdr(ip);
15337397Sgblack@eecs.umich.edu                    DPRINTF(Ethernet, "Src Port = %d, Dest Port = %d\n",
15347639Sgblack@eecs.umich.edu                            reverseEnd16(tcp->src_port_num),
15357643Sgblack@eecs.umich.edu                            reverseEnd16(tcp->dest_port_num));
15367397Sgblack@eecs.umich.edu                }
15377397Sgblack@eecs.umich.edu            }
15387379Sgblack@eecs.umich.edu        }
15397379Sgblack@eecs.umich.edu
15407396Sgblack@eecs.umich.edu        DDUMP(Ethernet, txFifo.front()->data, txFifo.front()->length);
15417379Sgblack@eecs.umich.edu        txBytes += txFifo.front()->length;
15427379Sgblack@eecs.umich.edu        txPackets++;
15437396Sgblack@eecs.umich.edu
15447396Sgblack@eecs.umich.edu        txFifoAvail += txFifo.front()->length;
15457379Sgblack@eecs.umich.edu
15467379Sgblack@eecs.umich.edu        DPRINTF(Ethernet, "Successful Xmit! now txFifoAvail is %d\n", txFifoAvail);
1547        txFifo.front() = NULL;
1548        txFifo.pop_front();
1549
1550        /* normally do a writeback of the descriptor here, and ONLY after that is
1551           done, send this interrupt.  but since our stuff never actually fails,
1552           just do this interrupt here, otherwise the code has to stray from this
1553           nice format.  besides, it's functionally the same.
1554        */
1555        devIntrPost(ISR_TXOK);
1556    } else
1557        DPRINTF(Ethernet, "May need to rethink always sending the descriptors back?\n");
1558
1559   if (!txFifo.empty() && !txEvent.scheduled()) {
1560       DPRINTF(Ethernet, "reschedule transmit\n");
1561       txEvent.schedule(curTick + 1000);
1562   }
1563}
1564
1565void
1566NSGigE::txDmaReadCopy()
1567{
1568    assert(txDmaState == dmaReading);
1569
1570    memcpy(txDmaData, physmem->dma_addr(txDmaAddr, txDmaLen), txDmaLen);
1571    txDmaState = dmaIdle;
1572
1573    DPRINTF(EthernetDMA, "tx dma read  paddr=%#x len=%d\n",
1574            txDmaAddr, txDmaLen);
1575    DDUMP(EthernetDMA, txDmaData, txDmaLen);
1576}
1577
1578bool
1579NSGigE::doTxDmaRead()
1580{
1581    assert(txDmaState == dmaIdle || txDmaState == dmaReadWaiting);
1582    txDmaState = dmaReading;
1583
1584    if (dmaInterface && !txDmaFree) {
1585        if (dmaInterface->busy())
1586            txDmaState = dmaReadWaiting;
1587        else
1588            dmaInterface->doDMA(Read, txDmaAddr, txDmaLen, curTick,
1589                                &txDmaReadEvent);
1590        return true;
1591    }
1592
1593    if (dmaReadDelay == 0 && dmaReadFactor == 0.0) {
1594        txDmaReadCopy();
1595        return false;
1596    }
1597
1598    Tick factor = ((txDmaLen + ULL(63)) >> ULL(6)) * dmaReadFactor;
1599    Tick start = curTick + dmaReadDelay + factor;
1600    txDmaReadEvent.schedule(start);
1601    return true;
1602}
1603
1604void
1605NSGigE::txDmaReadDone()
1606{
1607    assert(txDmaState == dmaReading);
1608    txDmaReadCopy();
1609
1610    // If the receive state machine  has a pending DMA, let it go first
1611    if (rxDmaState == dmaReadWaiting || rxDmaState == dmaWriteWaiting)
1612        rxKick();
1613
1614    txKick();
1615}
1616
1617void
1618NSGigE::txDmaWriteCopy()
1619{
1620    assert(txDmaState == dmaWriting);
1621
1622    memcpy(physmem->dma_addr(txDmaAddr, txDmaLen), txDmaData, txDmaLen);
1623    txDmaState = dmaIdle;
1624
1625    DPRINTF(EthernetDMA, "tx dma write paddr=%#x len=%d\n",
1626            txDmaAddr, txDmaLen);
1627    DDUMP(EthernetDMA, txDmaData, txDmaLen);
1628}
1629
1630bool
1631NSGigE::doTxDmaWrite()
1632{
1633    assert(txDmaState == dmaIdle || txDmaState == dmaWriteWaiting);
1634    txDmaState = dmaWriting;
1635
1636    if (dmaInterface && !txDmaFree) {
1637        if (dmaInterface->busy())
1638            txDmaState = dmaWriteWaiting;
1639        else
1640            dmaInterface->doDMA(WriteInvalidate, txDmaAddr, txDmaLen, curTick,
1641                                &txDmaWriteEvent);
1642        return true;
1643    }
1644
1645    if (dmaWriteDelay == 0 && dmaWriteFactor == 0.0) {
1646        txDmaWriteCopy();
1647        return false;
1648    }
1649
1650    Tick factor = ((txDmaLen + ULL(63)) >> ULL(6)) * dmaWriteFactor;
1651    Tick start = curTick + dmaWriteDelay + factor;
1652    txDmaWriteEvent.schedule(start);
1653    return true;
1654}
1655
1656void
1657NSGigE::txDmaWriteDone()
1658{
1659    assert(txDmaState == dmaWriting);
1660    txDmaWriteCopy();
1661
1662    // If the receive state machine  has a pending DMA, let it go first
1663    if (rxDmaState == dmaReadWaiting || rxDmaState == dmaWriteWaiting)
1664        rxKick();
1665
1666    txKick();
1667}
1668
1669void
1670NSGigE::txKick()
1671{
1672    DPRINTF(EthernetSM, "transmit kick state=%s\n", NsTxStateStrings[txState]);
1673
1674    if (txKickTick > curTick) {
1675        DPRINTF(EthernetSM, "transmit kick exiting, can't run till %d\n",
1676                txKickTick);
1677
1678        return;
1679    }
1680
1681  next:
1682    switch(txDmaState) {
1683      case dmaReadWaiting:
1684        if (doTxDmaRead())
1685            goto exit;
1686        break;
1687      case dmaWriteWaiting:
1688        if (doTxDmaWrite())
1689            goto exit;
1690        break;
1691      default:
1692        break;
1693    }
1694
1695    switch (txState) {
1696      case txIdle:
1697        if (!regs.command & CR_TXE) {
1698            DPRINTF(EthernetSM, "Transmit disabled.  Nothing to do.\n");
1699            goto exit;
1700        }
1701
1702        if (CTDD) {
1703            txState = txDescRefr;
1704
1705            txDmaAddr = regs.txdp & 0x3fffffff;
1706            txDmaData = &txDescCache + offsetof(ns_desc, link);
1707            txDmaLen = sizeof(txDescCache.link);
1708            txDmaFree = dmaDescFree;
1709
1710            if (doTxDmaRead())
1711                goto exit;
1712
1713        } else {
1714            txState = txDescRead;
1715
1716            txDmaAddr = regs.txdp & 0x3fffffff;
1717            txDmaData = &txDescCache;
1718            txDmaLen = sizeof(ns_desc);
1719            txDmaFree = dmaDescFree;
1720
1721            if (doTxDmaRead())
1722                goto exit;
1723        }
1724        break;
1725
1726      case txDescRefr:
1727        if (txDmaState != dmaIdle)
1728            goto exit;
1729
1730        txState = txAdvance;
1731        break;
1732
1733      case txDescRead:
1734        if (txDmaState != dmaIdle)
1735            goto exit;
1736
1737        DPRINTF(EthernetDesc,
1738                "txDescCache data:\n\tlink=%08x\n\tbufptr=%08x\n\tcmdsts=%08x\n\textsts=%08x\n"
1739                ,txDescCache.link, txDescCache.bufptr, txDescCache.cmdsts,
1740                txDescCache.extsts);
1741
1742        if (txDescCache.cmdsts & CMDSTS_OWN) {
1743            txState = txFifoBlock;
1744            txFragPtr = txDescCache.bufptr;
1745            txDescCnt = txDescCache.cmdsts & CMDSTS_LEN_MASK;
1746        } else {
1747            txState = txIdle;
1748        }
1749        break;
1750
1751      case txFifoBlock:
1752        if (!txPacket) {
1753            DPRINTF(EthernetSM, "\n\n*****starting the tx of a new packet\n");
1754            txPacket = new EtherPacket;
1755            txPacket->data = new uint8_t[16384];
1756            txPacketBufPtr = txPacket->data;
1757        }
1758
1759        if (txDescCnt == 0) {
1760            DPRINTF(EthernetSM, "the txDescCnt == 0, done with descriptor\n");
1761            if (txDescCache.cmdsts & CMDSTS_MORE) {
1762                DPRINTF(EthernetSM, "there are more descriptors to come\n");
1763                txState = txDescWrite;
1764
1765                txDescCache.cmdsts &= ~CMDSTS_OWN;
1766
1767                txDmaAddr = (regs.txdp + offsetof(ns_desc, cmdsts)) & 0x3fffffff;
1768                txDmaData = &(txDescCache.cmdsts);
1769                txDmaLen = sizeof(txDescCache.cmdsts);
1770                txDmaFree = dmaDescFree;
1771
1772                if (doTxDmaWrite())
1773                    goto exit;
1774
1775            } else { /* this packet is totally done */
1776                DPRINTF(EthernetSM, "This packet is done, let's wrap it up\n");
1777                /* deal with the the packet that just finished */
1778                if ((regs.vtcr & VTCR_PPCHK) && extstsEnable) {
1779                    if (txDescCache.extsts & EXTSTS_UDPPKT) {
1780                        udpChecksum(txPacket, true);
1781                    } else if (txDescCache.extsts & EXTSTS_TCPPKT) {
1782                        tcpChecksum(txPacket, true);
1783                    }
1784                    if (txDescCache.extsts & EXTSTS_IPPKT) {
1785                        ipChecksum(txPacket, true);
1786                    }
1787                }
1788
1789                txPacket->length = txPacketBufPtr - txPacket->data;
1790                /* this is just because the receive can't handle a packet bigger
1791                   want to make sure */
1792                assert(txPacket->length <= 1514);
1793                txFifo.push_back(txPacket);
1794
1795                /* this following section is not to spec, but functionally shouldn't
1796                   be any different.  normally, the chip will wait til the transmit has
1797                   occurred before writing back the descriptor because it has to wait
1798                   to see that it was successfully transmitted to decide whether to set
1799                   CMDSTS_OK or not.  however, in the simulator since it is always
1800                   successfully transmitted, and writing it exactly to spec would
1801                   complicate the code, we just do it here
1802                */
1803
1804                txDescCache.cmdsts &= ~CMDSTS_OWN;
1805                txDescCache.cmdsts |= CMDSTS_OK;
1806
1807                DPRINTF(EthernetDesc,
1808                        "txDesc writeback:\n\tcmdsts=%08x\n\textsts=%08x\n",
1809                        txDescCache.cmdsts, txDescCache.extsts);
1810
1811                txDmaAddr = (regs.txdp + offsetof(ns_desc, cmdsts)) & 0x3fffffff;
1812                txDmaData = &(txDescCache.cmdsts);
1813                txDmaLen = sizeof(txDescCache.cmdsts) + sizeof(txDescCache.extsts);
1814                txDmaFree = dmaDescFree;
1815
1816                if (doTxDmaWrite())
1817                    goto exit;
1818
1819                transmit();
1820
1821                txPacket = 0;
1822
1823                if (txHalt) {
1824                    DPRINTF(EthernetSM, "halting TX state machine\n");
1825                    txState = txIdle;
1826                    txHalt = false;
1827                } else
1828                    txState = txAdvance;
1829            }
1830        } else {
1831            DPRINTF(EthernetSM, "this descriptor isn't done yet\n");
1832            txState = txFragRead;
1833
1834            /* The number of bytes transferred is either whatever is left
1835               in the descriptor (txDescCnt), or if there is not enough
1836               room in the fifo, just whatever room is left in the fifo
1837            */
1838            txXferLen = min<uint32_t>(txDescCnt, txFifoAvail);
1839
1840            txDmaAddr = txFragPtr & 0x3fffffff;
1841            txDmaData = txPacketBufPtr;
1842            txDmaLen = txXferLen;
1843            txDmaFree = dmaDataFree;
1844
1845            if (doTxDmaRead())
1846                goto exit;
1847        }
1848        break;
1849
1850      case txFragRead:
1851        if (txDmaState != dmaIdle)
1852            goto exit;
1853
1854        txPacketBufPtr += txXferLen;
1855        txFragPtr += txXferLen;
1856        txDescCnt -= txXferLen;
1857        txFifoAvail -= txXferLen;
1858
1859        txState = txFifoBlock;
1860        break;
1861
1862      case txDescWrite:
1863        if (txDmaState != dmaIdle)
1864            goto exit;
1865
1866        if (txDescCache.cmdsts & CMDSTS_INTR) {
1867            devIntrPost(ISR_TXDESC);
1868        }
1869
1870        txState = txAdvance;
1871        break;
1872
1873      case txAdvance:
1874        if (txDescCache.link == 0) {
1875            txState = txIdle;
1876        } else {
1877            txState = txDescRead;
1878            regs.txdp = txDescCache.link;
1879            CTDD = false;
1880
1881            txDmaAddr = txDescCache.link & 0x3fffffff;
1882            txDmaData = &txDescCache;
1883            txDmaLen = sizeof(ns_desc);
1884            txDmaFree = dmaDescFree;
1885
1886            if (doTxDmaRead())
1887                goto exit;
1888        }
1889        break;
1890
1891      default:
1892        panic("invalid state");
1893    }
1894
1895    DPRINTF(EthernetSM, "entering next tx state=%s\n",
1896            NsTxStateStrings[txState]);
1897
1898    if (txState == txIdle) {
1899        regs.command &= ~CR_TXE;
1900        devIntrPost(ISR_TXIDLE);
1901        return;
1902    }
1903
1904    goto next;
1905
1906  exit:
1907    /**
1908     * @todo do we want to schedule a future kick?
1909     */
1910    DPRINTF(EthernetSM, "tx state machine exited state=%s\n",
1911            NsTxStateStrings[txState]);
1912}
1913
1914void
1915NSGigE::transferDone()
1916{
1917    if (txFifo.empty())
1918        return;
1919
1920    if (txEvent.scheduled())
1921        txEvent.reschedule(curTick + 1);
1922    else
1923        txEvent.schedule(curTick + 1);
1924}
1925
1926bool
1927NSGigE::rxFilter(PacketPtr packet)
1928{
1929    bool drop = true;
1930    string type;
1931
1932    if (packet->IsUnicast()) {
1933        type = "unicast";
1934
1935        // If we're accepting all unicast addresses
1936        if (acceptUnicast)
1937            drop = false;
1938
1939        // If we make a perfect match
1940        if ((acceptPerfect)
1941            && (memcmp(rom.perfectMatch, packet->data, sizeof(rom.perfectMatch)) == 0))
1942            drop = false;
1943
1944        eth_header *eth = (eth_header *) packet->data;
1945        if ((acceptArp) && (eth->type == 0x608))
1946            drop = false;
1947
1948    } else if (packet->IsBroadcast()) {
1949        type = "broadcast";
1950
1951        // if we're accepting broadcasts
1952        if (acceptBroadcast)
1953            drop = false;
1954
1955    } else if (packet->IsMulticast()) {
1956        type = "multicast";
1957
1958        // if we're accepting all multicasts
1959        if (acceptMulticast)
1960            drop = false;
1961
1962    } else {
1963        type = "unknown";
1964
1965        // oh well, punt on this one
1966    }
1967
1968    if (drop) {
1969        DPRINTF(Ethernet, "rxFilter drop\n");
1970        DDUMP(EthernetData, packet->data, packet->length);
1971    }
1972
1973    return drop;
1974}
1975
1976bool
1977NSGigE::recvPacket(PacketPtr packet)
1978{
1979    rxBytes += packet->length;
1980    rxPackets++;
1981
1982    DPRINTF(Ethernet, "\n\nReceiving packet from wire, rxFifoAvail = %d\n", MAX_RX_FIFO_SIZE - rxFifoCnt);
1983
1984    if (rxState == rxIdle) {
1985        DPRINTF(Ethernet, "receive disabled...packet dropped\n");
1986        interface->recvDone();
1987        return true;
1988    }
1989
1990    if (rxFilterEnable && rxFilter(packet)) {
1991        DPRINTF(Ethernet, "packet filtered...dropped\n");
1992        interface->recvDone();
1993        return true;
1994    }
1995
1996    if ((rxFifoCnt + packet->length) >= MAX_RX_FIFO_SIZE) {
1997        DPRINTF(Ethernet,
1998                "packet will not fit in receive buffer...packet dropped\n");
1999        devIntrPost(ISR_RXORN);
2000        return false;
2001    }
2002
2003    rxFifo.push_back(packet);
2004    rxFifoCnt += packet->length;
2005    interface->recvDone();
2006
2007    rxKick();
2008    return true;
2009}
2010
2011/**
2012 * does a udp checksum.  if gen is true, then it generates it and puts it in the right place
2013 * else, it just checks what it calculates against the value in the header in packet
2014 */
2015bool
2016NSGigE::udpChecksum(PacketPtr packet, bool gen)
2017{
2018    ip_header *ip = packet->getIpHdr();
2019    udp_header *hdr = packet->getUdpHdr(ip);
2020
2021    pseudo_header *pseudo = new pseudo_header;
2022
2023    pseudo->src_ip_addr = ip->src_ip_addr;
2024    pseudo->dest_ip_addr = ip->dest_ip_addr;
2025    pseudo->protocol = ip->protocol;
2026    pseudo->len = hdr->len;
2027
2028    uint16_t cksum = checksumCalc((uint16_t *) pseudo, (uint16_t *) hdr,
2029                                  (uint32_t) hdr->len);
2030
2031    delete pseudo;
2032    if (gen)
2033        hdr->chksum = cksum;
2034    else
2035        if (cksum != 0)
2036            return false;
2037
2038    return true;
2039}
2040
2041bool
2042NSGigE::tcpChecksum(PacketPtr packet, bool gen)
2043{
2044    ip_header *ip = packet->getIpHdr();
2045    tcp_header *hdr = packet->getTcpHdr(ip);
2046
2047    uint16_t cksum;
2048    pseudo_header *pseudo = new pseudo_header;
2049    if (!gen) {
2050        pseudo->src_ip_addr = ip->src_ip_addr;
2051        pseudo->dest_ip_addr = ip->dest_ip_addr;
2052        pseudo->protocol = reverseEnd16(ip->protocol);
2053        pseudo->len = reverseEnd16(reverseEnd16(ip->dgram_len) - (ip->vers_len & 0xf)*4);
2054
2055        cksum = checksumCalc((uint16_t *) pseudo, (uint16_t *) hdr,
2056                                  (uint32_t) reverseEnd16(pseudo->len));
2057    } else {
2058        pseudo->src_ip_addr = 0;
2059        pseudo->dest_ip_addr = 0;
2060        pseudo->protocol = hdr->chksum;
2061        pseudo->len = 0;
2062        hdr->chksum = 0;
2063        cksum = checksumCalc((uint16_t *) pseudo, (uint16_t *) hdr,
2064                             (uint32_t) (reverseEnd16(ip->dgram_len) - (ip->vers_len & 0xf)*4));
2065    }
2066
2067    delete pseudo;
2068    if (gen)
2069        hdr->chksum = cksum;
2070    else
2071        if (cksum != 0)
2072            return false;
2073
2074    return true;
2075}
2076
2077bool
2078NSGigE::ipChecksum(PacketPtr packet, bool gen)
2079{
2080    ip_header *hdr = packet->getIpHdr();
2081
2082    uint16_t cksum = checksumCalc(NULL, (uint16_t *) hdr, (hdr->vers_len & 0xf)*4);
2083
2084    if (gen) {
2085        DPRINTF(EthernetCksum, "generated checksum: %#x\n", cksum);
2086        hdr->hdr_chksum = cksum;
2087    }
2088    else
2089        if (cksum != 0)
2090            return false;
2091
2092    return true;
2093}
2094
2095uint16_t
2096NSGigE::checksumCalc(uint16_t *pseudo, uint16_t *buf, uint32_t len)
2097{
2098    uint32_t sum = 0;
2099
2100    uint16_t last_pad = 0;
2101    if (len & 1) {
2102        last_pad = buf[len/2] & 0xff;
2103        len--;
2104        sum += last_pad;
2105    }
2106
2107    if (pseudo) {
2108        sum = pseudo[0] + pseudo[1] + pseudo[2] +
2109            pseudo[3] + pseudo[4] + pseudo[5];
2110    }
2111
2112    for (int i=0; i < (len/2); ++i) {
2113        sum += buf[i];
2114    }
2115
2116    while (sum >> 16)
2117        sum = (sum >> 16) + (sum & 0xffff);
2118
2119    return ~sum;
2120}
2121
2122//=====================================================================
2123//
2124//
2125void
2126NSGigE::serialize(ostream &os)
2127{
2128    // Serialize the PciDev base class
2129    PciDev::serialize(os);
2130
2131    /*
2132     * Finalize any DMA events now.
2133     */
2134    if (rxDmaReadEvent.scheduled())
2135        rxDmaReadCopy();
2136    if (rxDmaWriteEvent.scheduled())
2137        rxDmaWriteCopy();
2138    if (txDmaReadEvent.scheduled())
2139        txDmaReadCopy();
2140    if (txDmaWriteEvent.scheduled())
2141        txDmaWriteCopy();
2142
2143    /*
2144     * Serialize the device registers
2145     */
2146    SERIALIZE_SCALAR(regs.command);
2147    SERIALIZE_SCALAR(regs.config);
2148    SERIALIZE_SCALAR(regs.mear);
2149    SERIALIZE_SCALAR(regs.ptscr);
2150    SERIALIZE_SCALAR(regs.isr);
2151    SERIALIZE_SCALAR(regs.imr);
2152    SERIALIZE_SCALAR(regs.ier);
2153    SERIALIZE_SCALAR(regs.ihr);
2154    SERIALIZE_SCALAR(regs.txdp);
2155    SERIALIZE_SCALAR(regs.txdp_hi);
2156    SERIALIZE_SCALAR(regs.txcfg);
2157    SERIALIZE_SCALAR(regs.gpior);
2158    SERIALIZE_SCALAR(regs.rxdp);
2159    SERIALIZE_SCALAR(regs.rxdp_hi);
2160    SERIALIZE_SCALAR(regs.rxcfg);
2161    SERIALIZE_SCALAR(regs.pqcr);
2162    SERIALIZE_SCALAR(regs.wcsr);
2163    SERIALIZE_SCALAR(regs.pcr);
2164    SERIALIZE_SCALAR(regs.rfcr);
2165    SERIALIZE_SCALAR(regs.rfdr);
2166    SERIALIZE_SCALAR(regs.srr);
2167    SERIALIZE_SCALAR(regs.mibc);
2168    SERIALIZE_SCALAR(regs.vrcr);
2169    SERIALIZE_SCALAR(regs.vtcr);
2170    SERIALIZE_SCALAR(regs.vdr);
2171    SERIALIZE_SCALAR(regs.ccsr);
2172    SERIALIZE_SCALAR(regs.tbicr);
2173    SERIALIZE_SCALAR(regs.tbisr);
2174    SERIALIZE_SCALAR(regs.tanar);
2175    SERIALIZE_SCALAR(regs.tanlpar);
2176    SERIALIZE_SCALAR(regs.taner);
2177    SERIALIZE_SCALAR(regs.tesr);
2178
2179    SERIALIZE_ARRAY(rom.perfectMatch, EADDR_LEN);
2180
2181    SERIALIZE_SCALAR(ioEnable);
2182
2183    /*
2184     * Serialize the data Fifos
2185     */
2186    int txNumPkts = txFifo.size();
2187    SERIALIZE_SCALAR(txNumPkts);
2188    int i = 0;
2189    pktiter_t end = txFifo.end();
2190    for (pktiter_t p = txFifo.begin(); p != end; ++p) {
2191        nameOut(os, csprintf("%s.txFifo%d", name(), i++));
2192        (*p)->serialize(os);
2193    }
2194
2195    int rxNumPkts = rxFifo.size();
2196    SERIALIZE_SCALAR(rxNumPkts);
2197    i = 0;
2198    end = rxFifo.end();
2199    for (pktiter_t p = rxFifo.begin(); p != end; ++p) {
2200        nameOut(os, csprintf("%s.rxFifo%d", name(), i++));
2201        (*p)->serialize(os);
2202    }
2203
2204    /*
2205     * Serialize the various helper variables
2206     */
2207    bool txPacketExists = txPacket;
2208    SERIALIZE_SCALAR(txPacketExists);
2209    if (txPacketExists) {
2210        nameOut(os, csprintf("%s.txPacket", name()));
2211        txPacket->serialize(os);
2212        uint32_t txPktBufPtr = (uint32_t) (txPacketBufPtr - txPacket->data);
2213        SERIALIZE_SCALAR(txPktBufPtr);
2214    }
2215
2216    bool rxPacketExists = rxPacket;
2217    SERIALIZE_SCALAR(rxPacketExists);
2218    if (rxPacketExists) {
2219        nameOut(os, csprintf("%s.rxPacket", name()));
2220        rxPacket->serialize(os);
2221        uint32_t rxPktBufPtr = (uint32_t) (rxPacketBufPtr - rxPacket->data);
2222        SERIALIZE_SCALAR(rxPktBufPtr);
2223    }
2224
2225    SERIALIZE_SCALAR(txXferLen);
2226    SERIALIZE_SCALAR(rxXferLen);
2227
2228    /*
2229     * Serialize DescCaches
2230     */
2231    SERIALIZE_SCALAR(txDescCache.link);
2232    SERIALIZE_SCALAR(txDescCache.bufptr);
2233    SERIALIZE_SCALAR(txDescCache.cmdsts);
2234    SERIALIZE_SCALAR(txDescCache.extsts);
2235    SERIALIZE_SCALAR(rxDescCache.link);
2236    SERIALIZE_SCALAR(rxDescCache.bufptr);
2237    SERIALIZE_SCALAR(rxDescCache.cmdsts);
2238    SERIALIZE_SCALAR(rxDescCache.extsts);
2239
2240    /*
2241     * Serialize tx state machine
2242     */
2243    int txState = this->txState;
2244    SERIALIZE_SCALAR(txState);
2245    SERIALIZE_SCALAR(CTDD);
2246    SERIALIZE_SCALAR(txFifoAvail);
2247    SERIALIZE_SCALAR(txHalt);
2248    SERIALIZE_SCALAR(txFragPtr);
2249    SERIALIZE_SCALAR(txDescCnt);
2250    int txDmaState = this->txDmaState;
2251    SERIALIZE_SCALAR(txDmaState);
2252
2253    /*
2254     * Serialize rx state machine
2255     */
2256    int rxState = this->rxState;
2257    SERIALIZE_SCALAR(rxState);
2258    SERIALIZE_SCALAR(CRDD);
2259    SERIALIZE_SCALAR(rxPktBytes);
2260    SERIALIZE_SCALAR(rxFifoCnt);
2261    SERIALIZE_SCALAR(rxHalt);
2262    SERIALIZE_SCALAR(rxDescCnt);
2263    int rxDmaState = this->rxDmaState;
2264    SERIALIZE_SCALAR(rxDmaState);
2265
2266    SERIALIZE_SCALAR(extstsEnable);
2267
2268    /*
2269     * If there's a pending transmit, store the time so we can
2270     * reschedule it later
2271     */
2272    Tick transmitTick = txEvent.scheduled() ? txEvent.when() - curTick : 0;
2273    SERIALIZE_SCALAR(transmitTick);
2274
2275    /*
2276     * receive address filter settings
2277     */
2278    SERIALIZE_SCALAR(rxFilterEnable);
2279    SERIALIZE_SCALAR(acceptBroadcast);
2280    SERIALIZE_SCALAR(acceptMulticast);
2281    SERIALIZE_SCALAR(acceptUnicast);
2282    SERIALIZE_SCALAR(acceptPerfect);
2283    SERIALIZE_SCALAR(acceptArp);
2284
2285    /*
2286     * Keep track of pending interrupt status.
2287     */
2288    SERIALIZE_SCALAR(intrTick);
2289    SERIALIZE_SCALAR(cpuPendingIntr);
2290    Tick intrEventTick = 0;
2291    if (intrEvent)
2292        intrEventTick = intrEvent->when();
2293    SERIALIZE_SCALAR(intrEventTick);
2294
2295}
2296
2297void
2298NSGigE::unserialize(Checkpoint *cp, const std::string &section)
2299{
2300    // Unserialize the PciDev base class
2301    PciDev::unserialize(cp, section);
2302
2303    UNSERIALIZE_SCALAR(regs.command);
2304    UNSERIALIZE_SCALAR(regs.config);
2305    UNSERIALIZE_SCALAR(regs.mear);
2306    UNSERIALIZE_SCALAR(regs.ptscr);
2307    UNSERIALIZE_SCALAR(regs.isr);
2308    UNSERIALIZE_SCALAR(regs.imr);
2309    UNSERIALIZE_SCALAR(regs.ier);
2310    UNSERIALIZE_SCALAR(regs.ihr);
2311    UNSERIALIZE_SCALAR(regs.txdp);
2312    UNSERIALIZE_SCALAR(regs.txdp_hi);
2313    UNSERIALIZE_SCALAR(regs.txcfg);
2314    UNSERIALIZE_SCALAR(regs.gpior);
2315    UNSERIALIZE_SCALAR(regs.rxdp);
2316    UNSERIALIZE_SCALAR(regs.rxdp_hi);
2317    UNSERIALIZE_SCALAR(regs.rxcfg);
2318    UNSERIALIZE_SCALAR(regs.pqcr);
2319    UNSERIALIZE_SCALAR(regs.wcsr);
2320    UNSERIALIZE_SCALAR(regs.pcr);
2321    UNSERIALIZE_SCALAR(regs.rfcr);
2322    UNSERIALIZE_SCALAR(regs.rfdr);
2323    UNSERIALIZE_SCALAR(regs.srr);
2324    UNSERIALIZE_SCALAR(regs.mibc);
2325    UNSERIALIZE_SCALAR(regs.vrcr);
2326    UNSERIALIZE_SCALAR(regs.vtcr);
2327    UNSERIALIZE_SCALAR(regs.vdr);
2328    UNSERIALIZE_SCALAR(regs.ccsr);
2329    UNSERIALIZE_SCALAR(regs.tbicr);
2330    UNSERIALIZE_SCALAR(regs.tbisr);
2331    UNSERIALIZE_SCALAR(regs.tanar);
2332    UNSERIALIZE_SCALAR(regs.tanlpar);
2333    UNSERIALIZE_SCALAR(regs.taner);
2334    UNSERIALIZE_SCALAR(regs.tesr);
2335
2336    UNSERIALIZE_ARRAY(rom.perfectMatch, EADDR_LEN);
2337
2338    UNSERIALIZE_SCALAR(ioEnable);
2339
2340    /*
2341     * unserialize the data fifos
2342     */
2343    int txNumPkts;
2344    UNSERIALIZE_SCALAR(txNumPkts);
2345    int i;
2346    for (i = 0; i < txNumPkts; ++i) {
2347        PacketPtr p = new EtherPacket;
2348        p->unserialize(cp, csprintf("%s.rxFifo%d", section, i));
2349        txFifo.push_back(p);
2350    }
2351
2352    int rxNumPkts;
2353    UNSERIALIZE_SCALAR(rxNumPkts);
2354    for (i = 0; i < rxNumPkts; ++i) {
2355        PacketPtr p = new EtherPacket;
2356        p->unserialize(cp, csprintf("%s.rxFifo%d", section, i));
2357        rxFifo.push_back(p);
2358    }
2359
2360    /*
2361     * unserialize the various helper variables
2362     */
2363    bool txPacketExists;
2364    UNSERIALIZE_SCALAR(txPacketExists);
2365    if (txPacketExists) {
2366        txPacket = new EtherPacket;
2367        txPacket->unserialize(cp, csprintf("%s.txPacket", section));
2368        uint32_t txPktBufPtr;
2369        UNSERIALIZE_SCALAR(txPktBufPtr);
2370        txPacketBufPtr = (uint8_t *) txPacket->data + txPktBufPtr;
2371    } else
2372        txPacket = 0;
2373
2374    bool rxPacketExists;
2375    UNSERIALIZE_SCALAR(rxPacketExists);
2376    rxPacket = 0;
2377    if (rxPacketExists) {
2378        rxPacket = new EtherPacket;
2379        rxPacket->unserialize(cp, csprintf("%s.rxPacket", section));
2380        uint32_t rxPktBufPtr;
2381        UNSERIALIZE_SCALAR(rxPktBufPtr);
2382        rxPacketBufPtr = (uint8_t *) rxPacket->data + rxPktBufPtr;
2383    } else
2384        rxPacket = 0;
2385
2386    UNSERIALIZE_SCALAR(txXferLen);
2387    UNSERIALIZE_SCALAR(rxXferLen);
2388
2389    /*
2390     * Unserialize DescCaches
2391     */
2392    UNSERIALIZE_SCALAR(txDescCache.link);
2393    UNSERIALIZE_SCALAR(txDescCache.bufptr);
2394    UNSERIALIZE_SCALAR(txDescCache.cmdsts);
2395    UNSERIALIZE_SCALAR(txDescCache.extsts);
2396    UNSERIALIZE_SCALAR(rxDescCache.link);
2397    UNSERIALIZE_SCALAR(rxDescCache.bufptr);
2398    UNSERIALIZE_SCALAR(rxDescCache.cmdsts);
2399    UNSERIALIZE_SCALAR(rxDescCache.extsts);
2400
2401    /*
2402     * unserialize tx state machine
2403     */
2404    int txState;
2405    UNSERIALIZE_SCALAR(txState);
2406    this->txState = (TxState) txState;
2407    UNSERIALIZE_SCALAR(CTDD);
2408    UNSERIALIZE_SCALAR(txFifoAvail);
2409    UNSERIALIZE_SCALAR(txHalt);
2410    UNSERIALIZE_SCALAR(txFragPtr);
2411    UNSERIALIZE_SCALAR(txDescCnt);
2412    int txDmaState;
2413    UNSERIALIZE_SCALAR(txDmaState);
2414    this->txDmaState = (DmaState) txDmaState;
2415
2416    /*
2417     * unserialize rx state machine
2418     */
2419    int rxState;
2420    UNSERIALIZE_SCALAR(rxState);
2421    this->rxState = (RxState) rxState;
2422    UNSERIALIZE_SCALAR(CRDD);
2423    UNSERIALIZE_SCALAR(rxPktBytes);
2424    UNSERIALIZE_SCALAR(rxFifoCnt);
2425    UNSERIALIZE_SCALAR(rxHalt);
2426    UNSERIALIZE_SCALAR(rxDescCnt);
2427    int rxDmaState;
2428    UNSERIALIZE_SCALAR(rxDmaState);
2429    this->rxDmaState = (DmaState) rxDmaState;
2430
2431    UNSERIALIZE_SCALAR(extstsEnable);
2432
2433     /*
2434     * If there's a pending transmit, reschedule it now
2435     */
2436    Tick transmitTick;
2437    UNSERIALIZE_SCALAR(transmitTick);
2438    if (transmitTick)
2439        txEvent.schedule(curTick + transmitTick);
2440
2441    /*
2442     * unserialize receive address filter settings
2443     */
2444    UNSERIALIZE_SCALAR(rxFilterEnable);
2445    UNSERIALIZE_SCALAR(acceptBroadcast);
2446    UNSERIALIZE_SCALAR(acceptMulticast);
2447    UNSERIALIZE_SCALAR(acceptUnicast);
2448    UNSERIALIZE_SCALAR(acceptPerfect);
2449    UNSERIALIZE_SCALAR(acceptArp);
2450
2451    /*
2452     * Keep track of pending interrupt status.
2453     */
2454    UNSERIALIZE_SCALAR(intrTick);
2455    UNSERIALIZE_SCALAR(cpuPendingIntr);
2456    Tick intrEventTick;
2457    UNSERIALIZE_SCALAR(intrEventTick);
2458    if (intrEventTick) {
2459        intrEvent = new IntrEvent(this, true);
2460        intrEvent->schedule(intrEventTick);
2461    }
2462
2463    /*
2464     * re-add addrRanges to bus bridges
2465     */
2466    if (pioInterface) {
2467        pioInterface->addAddrRange(BARAddrs[0], BARAddrs[0] + BARSize[0] - 1);
2468        pioInterface->addAddrRange(BARAddrs[1], BARAddrs[1] + BARSize[1] - 1);
2469    }
2470}
2471
2472Tick
2473NSGigE::cacheAccess(MemReqPtr &req)
2474{
2475    DPRINTF(EthernetPIO, "timing access to paddr=%#x (daddr=%#x)\n",
2476            req->paddr, req->paddr - addr);
2477    return curTick + pioLatency;
2478}
2479//=====================================================================
2480
2481
2482//********** helper functions******************************************
2483
2484uint16_t reverseEnd16(uint16_t num)
2485{
2486    uint16_t reverse = (num & 0xff)<<8;
2487    reverse += ((num & 0xff00) >> 8);
2488    return reverse;
2489}
2490
2491uint32_t reverseEnd32(uint32_t num)
2492{
2493    uint32_t reverse = (reverseEnd16(num & 0xffff)) << 16;
2494    reverse += reverseEnd16((uint16_t) ((num & 0xffff0000) >> 8));
2495    return reverse;
2496}
2497
2498
2499
2500//=====================================================================
2501
2502BEGIN_DECLARE_SIM_OBJECT_PARAMS(NSGigEInt)
2503
2504    SimObjectParam<EtherInt *> peer;
2505    SimObjectParam<NSGigE *> device;
2506
2507END_DECLARE_SIM_OBJECT_PARAMS(NSGigEInt)
2508
2509BEGIN_INIT_SIM_OBJECT_PARAMS(NSGigEInt)
2510
2511    INIT_PARAM_DFLT(peer, "peer interface", NULL),
2512    INIT_PARAM(device, "Ethernet device of this interface")
2513
2514END_INIT_SIM_OBJECT_PARAMS(NSGigEInt)
2515
2516CREATE_SIM_OBJECT(NSGigEInt)
2517{
2518    NSGigEInt *dev_int = new NSGigEInt(getInstanceName(), device);
2519
2520    EtherInt *p = (EtherInt *)peer;
2521    if (p) {
2522        dev_int->setPeer(p);
2523        p->setPeer(dev_int);
2524    }
2525
2526    return dev_int;
2527}
2528
2529REGISTER_SIM_OBJECT("NSGigEInt", NSGigEInt)
2530
2531
2532BEGIN_DECLARE_SIM_OBJECT_PARAMS(NSGigE)
2533
2534    Param<Tick> tx_delay;
2535    Param<Tick> rx_delay;
2536    SimObjectParam<IntrControl *> intr_ctrl;
2537    Param<Tick> intr_delay;
2538    SimObjectParam<MemoryController *> mmu;
2539    SimObjectParam<PhysicalMemory *> physmem;
2540    Param<bool> rx_filter;
2541    Param<string> hardware_address;
2542    SimObjectParam<Bus*> header_bus;
2543    SimObjectParam<Bus*> payload_bus;
2544    SimObjectParam<HierParams *> hier;
2545    Param<Tick> pio_latency;
2546    Param<bool> dma_desc_free;
2547    Param<bool> dma_data_free;
2548    Param<Tick> dma_read_delay;
2549    Param<Tick> dma_write_delay;
2550    Param<Tick> dma_read_factor;
2551    Param<Tick> dma_write_factor;
2552    SimObjectParam<PciConfigAll *> configspace;
2553    SimObjectParam<PciConfigData *> configdata;
2554    SimObjectParam<Tsunami *> tsunami;
2555    Param<uint32_t> pci_bus;
2556    Param<uint32_t> pci_dev;
2557    Param<uint32_t> pci_func;
2558
2559END_DECLARE_SIM_OBJECT_PARAMS(NSGigE)
2560
2561BEGIN_INIT_SIM_OBJECT_PARAMS(NSGigE)
2562
2563    INIT_PARAM_DFLT(tx_delay, "Transmit Delay", 1000),
2564    INIT_PARAM_DFLT(rx_delay, "Receive Delay", 1000),
2565    INIT_PARAM(intr_ctrl, "Interrupt Controller"),
2566    INIT_PARAM_DFLT(intr_delay, "Interrupt Delay in microseconds", 0),
2567    INIT_PARAM(mmu, "Memory Controller"),
2568    INIT_PARAM(physmem, "Physical Memory"),
2569    INIT_PARAM_DFLT(rx_filter, "Enable Receive Filter", true),
2570    INIT_PARAM_DFLT(hardware_address, "Ethernet Hardware Address",
2571                    "00:99:00:00:00:01"),
2572    INIT_PARAM_DFLT(header_bus, "The IO Bus to attach to for headers", NULL),
2573    INIT_PARAM_DFLT(payload_bus, "The IO Bus to attach to for payload", NULL),
2574    INIT_PARAM_DFLT(hier, "Hierarchy global variables", &defaultHierParams),
2575    INIT_PARAM_DFLT(pio_latency, "Programmed IO latency", 1000),
2576    INIT_PARAM_DFLT(dma_desc_free, "DMA of Descriptors is free", false),
2577    INIT_PARAM_DFLT(dma_data_free, "DMA of Data is free", false),
2578    INIT_PARAM_DFLT(dma_read_delay, "fixed delay for dma reads", 0),
2579    INIT_PARAM_DFLT(dma_write_delay, "fixed delay for dma writes", 0),
2580    INIT_PARAM_DFLT(dma_read_factor, "multiplier for dma reads", 0),
2581    INIT_PARAM_DFLT(dma_write_factor, "multiplier for dma writes", 0),
2582    INIT_PARAM(configspace, "PCI Configspace"),
2583    INIT_PARAM(configdata, "PCI Config data"),
2584    INIT_PARAM(tsunami, "Tsunami"),
2585    INIT_PARAM(pci_bus, "PCI bus"),
2586    INIT_PARAM(pci_dev, "PCI device number"),
2587    INIT_PARAM(pci_func, "PCI function code")
2588
2589END_INIT_SIM_OBJECT_PARAMS(NSGigE)
2590
2591
2592CREATE_SIM_OBJECT(NSGigE)
2593{
2594    int eaddr[6];
2595    sscanf(((string)hardware_address).c_str(), "%x:%x:%x:%x:%x:%x",
2596           &eaddr[0], &eaddr[1], &eaddr[2], &eaddr[3], &eaddr[4], &eaddr[5]);
2597
2598    return new NSGigE(getInstanceName(), intr_ctrl, intr_delay,
2599                      physmem, tx_delay, rx_delay, mmu, hier, header_bus,
2600                      payload_bus, pio_latency, dma_desc_free, dma_data_free,
2601                      dma_read_delay, dma_write_delay, dma_read_factor,
2602                      dma_write_factor, configspace, configdata,
2603                      tsunami, pci_bus, pci_dev, pci_func, rx_filter, eaddr);
2604}
2605
2606REGISTER_SIM_OBJECT("NSGigE", NSGigE)
2607