ns_gige.cc revision 961
16657Snate@binkert.org/*
26657Snate@binkert.org * Copyright (c) 2004 The Regents of The University of Michigan
36657Snate@binkert.org * All rights reserved.
46657Snate@binkert.org *
56657Snate@binkert.org * Redistribution and use in source and binary forms, with or without
66657Snate@binkert.org * modification, are permitted provided that the following conditions are
76657Snate@binkert.org * met: redistributions of source code must retain the above copyright
86657Snate@binkert.org * notice, this list of conditions and the following disclaimer;
96657Snate@binkert.org * redistributions in binary form must reproduce the above copyright
106657Snate@binkert.org * notice, this list of conditions and the following disclaimer in the
116657Snate@binkert.org * documentation and/or other materials provided with the distribution;
126657Snate@binkert.org * neither the name of the copyright holders nor the names of its
136657Snate@binkert.org * contributors may be used to endorse or promote products derived from
146657Snate@binkert.org * this software without specific prior written permission.
156657Snate@binkert.org *
166657Snate@binkert.org * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
176657Snate@binkert.org * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
186657Snate@binkert.org * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
196657Snate@binkert.org * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
206657Snate@binkert.org * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
216657Snate@binkert.org * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
226657Snate@binkert.org * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
236657Snate@binkert.org * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
246657Snate@binkert.org * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
256657Snate@binkert.org * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
266657Snate@binkert.org * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
276657Snate@binkert.org */
286999Snate@binkert.org
296657Snate@binkert.org/* @file
306657Snate@binkert.org * Device module for modelling the National Semiconductor
316657Snate@binkert.org * DP83820 ethernet controller.  Does not support priority queueing
326657Snate@binkert.org */
338189SLisa.Hsu@amd.com#include <cstdio>
346657Snate@binkert.org#include <deque>
359499Snilay@cs.wisc.edu#include <string>
369499Snilay@cs.wisc.edu
379364Snilay@cs.wisc.edu#include "base/inet.hh"
387055Snate@binkert.org#include "cpu/exec_context.hh"
396882SBrad.Beckmann@amd.com#include "cpu/intr_control.hh"
406882SBrad.Beckmann@amd.com#include "dev/dma.hh"
418191SLisa.Hsu@amd.com#include "dev/ns_gige.hh"
426882SBrad.Beckmann@amd.com#include "dev/etherlink.hh"
436882SBrad.Beckmann@amd.com#include "mem/bus/bus.hh"
449102SNuwan.Jayasena@amd.com#include "mem/bus/dma_interface.hh"
459366Snilay@cs.wisc.edu#include "mem/bus/pio_interface.hh"
469499Snilay@cs.wisc.edu#include "mem/bus/pio_interface_impl.hh"
479499Snilay@cs.wisc.edu#include "mem/functional_mem/memory_control.hh"
489499Snilay@cs.wisc.edu#include "mem/functional_mem/physical_memory.hh"
496882SBrad.Beckmann@amd.com#include "sim/builder.hh"
506657Snate@binkert.org#include "sim/host.hh"
516657Snate@binkert.org#include "sim/sim_stats.hh"
526657Snate@binkert.org#include "targetarch/vtophys.hh"
536657Snate@binkert.org#include "dev/pciconfigall.hh"
5410311Snilay@cs.wisc.edu#include "dev/tsunami_cchip.hh"
5510311Snilay@cs.wisc.edu
5610311Snilay@cs.wisc.educonst char *NsRxStateStrings[] =
5710311Snilay@cs.wisc.edu{
586657Snate@binkert.org    "rxIdle",
5910311Snilay@cs.wisc.edu    "rxDescRefr",
609366Snilay@cs.wisc.edu    "rxDescRead",
617839Snilay@cs.wisc.edu    "rxFifoBlock",
626657Snate@binkert.org    "rxFragWrite",
636882SBrad.Beckmann@amd.com    "rxDescWrite",
6410308Snilay@cs.wisc.edu    "rxAdvance"
6510308Snilay@cs.wisc.edu};
666882SBrad.Beckmann@amd.com
6710308Snilay@cs.wisc.educonst char *NsTxStateStrings[] =
6810308Snilay@cs.wisc.edu{
6910308Snilay@cs.wisc.edu    "txIdle",
7010308Snilay@cs.wisc.edu    "txDescRefr",
7110308Snilay@cs.wisc.edu    "txDescRead",
729366Snilay@cs.wisc.edu    "txFifoBlock",
739366Snilay@cs.wisc.edu    "txFragRead",
746657Snate@binkert.org    "txDescWrite",
756657Snate@binkert.org    "txAdvance"
766657Snate@binkert.org};
776657Snate@binkert.org
789104Shestness@cs.utexas.educonst char *NsDmaState[] =
796657Snate@binkert.org{
806657Snate@binkert.org    "dmaIdle",
816657Snate@binkert.org    "dmaReading",
8210311Snilay@cs.wisc.edu    "dmaWriting",
8310311Snilay@cs.wisc.edu    "dmaReadWaiting",
8410311Snilay@cs.wisc.edu    "dmaWriteWaiting"
8510311Snilay@cs.wisc.edu};
866657Snate@binkert.org
877839Snilay@cs.wisc.eduusing namespace std;
887839Snilay@cs.wisc.edu
896657Snate@binkert.org//helper function declarations
906657Snate@binkert.org//These functions reverse Endianness so we can evaluate network data correctly
916657Snate@binkert.orguint16_t reverseEnd16(uint16_t);
926657Snate@binkert.orguint32_t reverseEnd32(uint32_t);
936657Snate@binkert.org
946657Snate@binkert.org///////////////////////////////////////////////////////////////////////
956657Snate@binkert.org//
966657Snate@binkert.org// NSGigE PCI Device
976657Snate@binkert.org//
986657Snate@binkert.orgNSGigE::NSGigE(const std::string &name, IntrControl *i, Tick intr_delay,
996657Snate@binkert.org             PhysicalMemory *pmem, Tick tx_delay, Tick rx_delay,
1006657Snate@binkert.org             MemoryController *mmu, HierParams *hier, Bus *header_bus,
1016657Snate@binkert.org             Bus *payload_bus, Tick pio_latency, bool dma_desc_free,
1026657Snate@binkert.org             bool dma_data_free, Tick dma_read_delay, Tick dma_write_delay,
1036657Snate@binkert.org             Tick dma_read_factor, Tick dma_write_factor, PciConfigAll *cf,
1046657Snate@binkert.org             PciConfigData *cd, Tsunami *t, uint32_t bus, uint32_t dev,
1056657Snate@binkert.org             uint32_t func, bool rx_filter, const int eaddr[6])
1066657Snate@binkert.org    : PciDev(name, mmu, cf, cd, bus, dev, func), tsunami(t), ioEnable(false),
1076779SBrad.Beckmann@amd.com      txPacket(0), rxPacket(0), txPacketBufPtr(NULL), rxPacketBufPtr(NULL),
1086657Snate@binkert.org      txXferLen(0), rxXferLen(0), txState(txIdle), CTDD(false),
1096657Snate@binkert.org      txFifoAvail(MAX_TX_FIFO_SIZE), txHalt(false),
1106657Snate@binkert.org      txFragPtr(0), txDescCnt(0), txDmaState(dmaIdle), rxState(rxIdle),
1116657Snate@binkert.org      CRDD(false), rxPktBytes(0), rxFifoCnt(0), rxHalt(false),
1126657Snate@binkert.org      rxFragPtr(0), rxDescCnt(0), rxDmaState(dmaIdle), extstsEnable(false),
1136657Snate@binkert.org      rxDmaReadEvent(this), rxDmaWriteEvent(this),
1146657Snate@binkert.org      txDmaReadEvent(this), txDmaWriteEvent(this),
1156657Snate@binkert.org      dmaDescFree(dma_desc_free), dmaDataFree(dma_data_free),
1166657Snate@binkert.org      txDelay(tx_delay), rxDelay(rx_delay), rxKickTick(0), txKickTick(0),
1179104Shestness@cs.utexas.edu      txEvent(this), rxFilterEnable(rx_filter), acceptBroadcast(false),
1189104Shestness@cs.utexas.edu      acceptMulticast(false), acceptUnicast(false),
1199104Shestness@cs.utexas.edu      acceptPerfect(false), acceptArp(false),
1209104Shestness@cs.utexas.edu      physmem(pmem), intctrl(i), intrTick(0), cpuPendingIntr(false),
1216657Snate@binkert.org      intrEvent(0), interface(0), pioLatency(pio_latency)
1226657Snate@binkert.org{
1236657Snate@binkert.org    tsunami->ethernet = this;
1246657Snate@binkert.org
1256657Snate@binkert.org    if (header_bus) {
1266657Snate@binkert.org        pioInterface = newPioInterface(name, hier, header_bus, this,
1276657Snate@binkert.org                                       &NSGigE::cacheAccess);
1286657Snate@binkert.org
1296657Snate@binkert.org        if (payload_bus)
1306657Snate@binkert.org            dmaInterface = new DMAInterface<Bus>(name + ".dma",
1316657Snate@binkert.org                                                 header_bus, payload_bus, 1);
1326657Snate@binkert.org        else
1336657Snate@binkert.org            dmaInterface = new DMAInterface<Bus>(name + ".dma",
13410307Snilay@cs.wisc.edu                                                 header_bus, header_bus, 1);
1356657Snate@binkert.org    } else if (payload_bus) {
1366657Snate@binkert.org        pioInterface = newPioInterface(name, hier, payload_bus, this,
1377839Snilay@cs.wisc.edu                                       &NSGigE::cacheAccess);
1387839Snilay@cs.wisc.edu
1397839Snilay@cs.wisc.edu        dmaInterface = new DMAInterface<Bus>(name + ".dma", payload_bus,
1407839Snilay@cs.wisc.edu                                         payload_bus, 1);
1417839Snilay@cs.wisc.edu
1427839Snilay@cs.wisc.edu    }
1437839Snilay@cs.wisc.edu
1447839Snilay@cs.wisc.edu
1457839Snilay@cs.wisc.edu    intrDelay = US2Ticks(intr_delay);
1467839Snilay@cs.wisc.edu    dmaReadDelay = dma_read_delay;
1477839Snilay@cs.wisc.edu    dmaWriteDelay = dma_write_delay;
1487839Snilay@cs.wisc.edu    dmaReadFactor = dma_read_factor;
1497839Snilay@cs.wisc.edu    dmaWriteFactor = dma_write_factor;
1507839Snilay@cs.wisc.edu
1517839Snilay@cs.wisc.edu    regsReset();
1526657Snate@binkert.org    rom.perfectMatch[0] = eaddr[0];
1536657Snate@binkert.org    rom.perfectMatch[1] = eaddr[1];
1546657Snate@binkert.org    rom.perfectMatch[2] = eaddr[2];
1556657Snate@binkert.org    rom.perfectMatch[3] = eaddr[3];
1566657Snate@binkert.org    rom.perfectMatch[4] = eaddr[4];
1576657Snate@binkert.org    rom.perfectMatch[5] = eaddr[5];
1586657Snate@binkert.org}
1596657Snate@binkert.org
1606657Snate@binkert.orgNSGigE::~NSGigE()
1616657Snate@binkert.org{}
1626657Snate@binkert.org
1636657Snate@binkert.orgvoid
1646657Snate@binkert.orgNSGigE::regStats()
1656657Snate@binkert.org{
1666657Snate@binkert.org    txBytes
1676657Snate@binkert.org        .name(name() + ".txBytes")
1686657Snate@binkert.org        .desc("Bytes Transmitted")
1696657Snate@binkert.org        .prereq(txBytes)
1706657Snate@binkert.org        ;
1716657Snate@binkert.org
1726657Snate@binkert.org    rxBytes
1736657Snate@binkert.org        .name(name() + ".rxBytes")
1746657Snate@binkert.org        .desc("Bytes Received")
1756657Snate@binkert.org        .prereq(rxBytes)
1766657Snate@binkert.org        ;
1776657Snate@binkert.org
1786657Snate@binkert.org    txPackets
1796657Snate@binkert.org        .name(name() + ".txPackets")
1806657Snate@binkert.org        .desc("Number of Packets Transmitted")
1816657Snate@binkert.org        .prereq(txBytes)
1829219Spower.jg@gmail.com        ;
1836877Ssteve.reinhardt@amd.com
1846657Snate@binkert.org    rxPackets
1859219Spower.jg@gmail.com        .name(name() + ".rxPackets")
1866657Snate@binkert.org        .desc("Number of Packets Received")
1879219Spower.jg@gmail.com        .prereq(rxBytes)
1886657Snate@binkert.org        ;
1896877Ssteve.reinhardt@amd.com
1906999Snate@binkert.org    txIPChecksums
1916877Ssteve.reinhardt@amd.com        .name(name() + ".txIPChecksums")
19210308Snilay@cs.wisc.edu        .desc("Number of tx IP Checksums done by device")
1936877Ssteve.reinhardt@amd.com        .precision(0)
1946877Ssteve.reinhardt@amd.com        .prereq(txBytes)
19510308Snilay@cs.wisc.edu        ;
1966877Ssteve.reinhardt@amd.com
1976877Ssteve.reinhardt@amd.com    rxIPChecksums
1986877Ssteve.reinhardt@amd.com        .name(name() + ".rxIPChecksums")
1996877Ssteve.reinhardt@amd.com        .desc("Number of rx IP Checksums done by device")
2006877Ssteve.reinhardt@amd.com        .precision(0)
2016877Ssteve.reinhardt@amd.com        .prereq(rxBytes)
2026877Ssteve.reinhardt@amd.com        ;
2039338SAndreas.Sandberg@arm.com
2046877Ssteve.reinhardt@amd.com    txTCPChecksums
2056877Ssteve.reinhardt@amd.com        .name(name() + ".txTCPChecksums")
2066877Ssteve.reinhardt@amd.com        .desc("Number of tx TCP Checksums done by device")
2076877Ssteve.reinhardt@amd.com        .precision(0)
20810308Snilay@cs.wisc.edu        .prereq(txBytes)
20910308Snilay@cs.wisc.edu        ;
21010308Snilay@cs.wisc.edu
21110308Snilay@cs.wisc.edu    rxTCPChecksums
21210311Snilay@cs.wisc.edu        .name(name() + ".rxTCPChecksums")
21310311Snilay@cs.wisc.edu        .desc("Number of rx TCP Checksums done by device")
21410311Snilay@cs.wisc.edu        .precision(0)
21510311Snilay@cs.wisc.edu        .prereq(rxBytes)
21610311Snilay@cs.wisc.edu        ;
21710311Snilay@cs.wisc.edu
21810311Snilay@cs.wisc.edu    descDmaReads
2196882SBrad.Beckmann@amd.com        .name(name() + ".descDMAReads")
22010308Snilay@cs.wisc.edu        .desc("Number of descriptors the device read w/ DMA")
22110308Snilay@cs.wisc.edu        .precision(0)
2226882SBrad.Beckmann@amd.com        ;
2236882SBrad.Beckmann@amd.com
2246882SBrad.Beckmann@amd.com    descDmaWrites
2256882SBrad.Beckmann@amd.com        .name(name() + ".descDMAWrites")
2266877Ssteve.reinhardt@amd.com        .desc("Number of descriptors the device wrote w/ DMA")
2276877Ssteve.reinhardt@amd.com        .precision(0)
2286877Ssteve.reinhardt@amd.com        ;
2296877Ssteve.reinhardt@amd.com
2306657Snate@binkert.org    descDmaRdBytes
2316657Snate@binkert.org        .name(name() + ".descDmaReadBytes")
2326999Snate@binkert.org        .desc("number of descriptor bytes read w/ DMA")
2336657Snate@binkert.org        .precision(0)
2346657Snate@binkert.org        ;
2356657Snate@binkert.org
2366657Snate@binkert.org   descDmaWrBytes
2377007Snate@binkert.org        .name(name() + ".descDmaWriteBytes")
2386657Snate@binkert.org        .desc("number of descriptor bytes write w/ DMA")
2396657Snate@binkert.org        .precision(0)
2406657Snate@binkert.org        ;
2416657Snate@binkert.org
2426657Snate@binkert.org
2437007Snate@binkert.org    txBandwidth
2447007Snate@binkert.org        .name(name() + ".txBandwidth")
2456657Snate@binkert.org        .desc("Transmit Bandwidth (bits/s)")
2467002Snate@binkert.org        .precision(0)
2477002Snate@binkert.org        .prereq(txBytes)
2487002Snate@binkert.org        ;
2497002Snate@binkert.org
2506657Snate@binkert.org    rxBandwidth
2516657Snate@binkert.org        .name(name() + ".rxBandwidth")
2528229Snate@binkert.org        .desc("Receive Bandwidth (bits/s)")
2538229Snate@binkert.org        .precision(0)
2548229Snate@binkert.org        .prereq(rxBytes)
2558229Snate@binkert.org        ;
2566657Snate@binkert.org
2576657Snate@binkert.org    txPacketRate
2586657Snate@binkert.org        .name(name() + ".txPPS")
2596657Snate@binkert.org        .desc("Packet Tranmission Rate (packets/s)")
2606793SBrad.Beckmann@amd.com        .precision(0)
2616657Snate@binkert.org        .prereq(txBytes)
26210311Snilay@cs.wisc.edu        ;
2636657Snate@binkert.org
2646657Snate@binkert.org    rxPacketRate
2656657Snate@binkert.org        .name(name() + ".rxPPS")
2667002Snate@binkert.org        .desc("Packet Reception Rate (packets/s)")
2676657Snate@binkert.org        .precision(0)
2687007Snate@binkert.org        .prereq(rxBytes)
2697007Snate@binkert.org        ;
2709271Snilay@cs.wisc.edu
2716877Ssteve.reinhardt@amd.com    txBandwidth = txBytes * Stats::constant(8) / simSeconds;
2726877Ssteve.reinhardt@amd.com    rxBandwidth = rxBytes * Stats::constant(8) / simSeconds;
2736657Snate@binkert.org    txPacketRate = txPackets / simSeconds;
2746877Ssteve.reinhardt@amd.com    rxPacketRate = rxPackets / simSeconds;
27510311Snilay@cs.wisc.edu}
2766657Snate@binkert.org
27710311Snilay@cs.wisc.edu/**
2789745Snilay@cs.wisc.edu * This is to read the PCI general configuration registers
2797002Snate@binkert.org */
2806657Snate@binkert.orgvoid
28110012Snilay@cs.wisc.eduNSGigE::ReadConfig(int offset, int size, uint8_t *data)
2829745Snilay@cs.wisc.edu{
2839745Snilay@cs.wisc.edu    if (offset < PCI_DEVICE_SPECIFIC)
2849745Snilay@cs.wisc.edu        PciDev::ReadConfig(offset, size, data);
2858683Snilay@cs.wisc.edu    else
2868683Snilay@cs.wisc.edu        panic("Device specific PCI config space not implemented!\n");
2877007Snate@binkert.org}
28810524Snilay@cs.wisc.edu
2899302Snilay@cs.wisc.edu/**
2909745Snilay@cs.wisc.edu * This is to write to the PCI general configuration registers
2919745Snilay@cs.wisc.edu */
2929745Snilay@cs.wisc.eduvoid
2939745Snilay@cs.wisc.eduNSGigE::WriteConfig(int offset, int size, uint32_t data)
2949745Snilay@cs.wisc.edu{
2959745Snilay@cs.wisc.edu    if (offset < PCI_DEVICE_SPECIFIC)
2966657Snate@binkert.org        PciDev::WriteConfig(offset, size, data);
2976657Snate@binkert.org    else
2986657Snate@binkert.org        panic("Device specific PCI config space not implemented!\n");
2996657Snate@binkert.org
3006657Snate@binkert.org    // Need to catch writes to BARs to update the PIO interface
3016657Snate@binkert.org    switch (offset) {
3026882SBrad.Beckmann@amd.com        //seems to work fine without all these PCI settings, but i put in the IO
3036882SBrad.Beckmann@amd.com        //to double check, an assertion will fail if we need to properly
3046882SBrad.Beckmann@amd.com        // implement it
3056882SBrad.Beckmann@amd.com      case PCI_COMMAND:
3066657Snate@binkert.org        if (config.data[offset] & PCI_CMD_IOSE)
3076657Snate@binkert.org            ioEnable = true;
3087007Snate@binkert.org        else
3097839Snilay@cs.wisc.edu            ioEnable = false;
3107839Snilay@cs.wisc.edu
3117839Snilay@cs.wisc.edu#if 0
3127839Snilay@cs.wisc.edu        if (config.data[offset] & PCI_CMD_BME) {
3137839Snilay@cs.wisc.edu            bmEnabled = true;
3147839Snilay@cs.wisc.edu        }
3157839Snilay@cs.wisc.edu        else {
3167839Snilay@cs.wisc.edu            bmEnabled = false;
3177839Snilay@cs.wisc.edu        }
3187839Snilay@cs.wisc.edu
3197839Snilay@cs.wisc.edu        if (config.data[offset] & PCI_CMD_MSE) {
3207839Snilay@cs.wisc.edu            memEnable = true;
32110010Snilay@cs.wisc.edu        }
3227007Snate@binkert.org        else {
3237007Snate@binkert.org            memEnable = false;
3247007Snate@binkert.org        }
3257007Snate@binkert.org#endif
3267839Snilay@cs.wisc.edu        break;
3277839Snilay@cs.wisc.edu
3287839Snilay@cs.wisc.edu      case PCI0_BASE_ADDR0:
3297839Snilay@cs.wisc.edu        if (BARAddrs[0] != 0) {
3307839Snilay@cs.wisc.edu
3317839Snilay@cs.wisc.edu            if (pioInterface)
3327839Snilay@cs.wisc.edu                pioInterface->addAddrRange(BARAddrs[0], BARAddrs[0] + BARSize[0] - 1);
3337839Snilay@cs.wisc.edu
3347839Snilay@cs.wisc.edu            BARAddrs[0] &= PA_UNCACHED_MASK;
3357839Snilay@cs.wisc.edu
3367839Snilay@cs.wisc.edu        }
3377839Snilay@cs.wisc.edu        break;
3387007Snate@binkert.org      case PCI0_BASE_ADDR1:
3397007Snate@binkert.org        if (BARAddrs[1] != 0) {
3409745Snilay@cs.wisc.edu
3419745Snilay@cs.wisc.edu            if (pioInterface)
3429745Snilay@cs.wisc.edu                pioInterface->addAddrRange(BARAddrs[1], BARAddrs[1] + BARSize[1] - 1);
3439745Snilay@cs.wisc.edu
3449745Snilay@cs.wisc.edu            BARAddrs[1] &= PA_UNCACHED_MASK;
3459745Snilay@cs.wisc.edu
3466657Snate@binkert.org        }
3477007Snate@binkert.org        break;
3486657Snate@binkert.org    }
3496657Snate@binkert.org}
3506657Snate@binkert.org
3516657Snate@binkert.org/**
3526657Snate@binkert.org * This reads the device registers, which are detailed in the NS83820
3536657Snate@binkert.org * spec sheet
3546657Snate@binkert.org */
3556657Snate@binkert.orgFault
3567839Snilay@cs.wisc.eduNSGigE::read(MemReqPtr &req, uint8_t *data)
3577839Snilay@cs.wisc.edu{
3587839Snilay@cs.wisc.edu    assert(ioEnable);
3597839Snilay@cs.wisc.edu
3607839Snilay@cs.wisc.edu    //The mask is to give you only the offset into the device register file
3617839Snilay@cs.wisc.edu    Addr daddr = req->paddr & 0xfff;
3627839Snilay@cs.wisc.edu    DPRINTF(EthernetPIO, "read  da=%#x pa=%#x va=%#x size=%d\n",
3637839Snilay@cs.wisc.edu            daddr, req->paddr, req->vaddr, req->size);
3647839Snilay@cs.wisc.edu
3657839Snilay@cs.wisc.edu
3667839Snilay@cs.wisc.edu    //there are some reserved registers, you can see ns_gige_reg.h and
3677839Snilay@cs.wisc.edu    //the spec sheet for details
3687839Snilay@cs.wisc.edu    if (daddr > LAST && daddr <=  RESERVED) {
3697839Snilay@cs.wisc.edu        panic("Accessing reserved register");
3707839Snilay@cs.wisc.edu    } else if (daddr > RESERVED && daddr <= 0x3FC) {
3717839Snilay@cs.wisc.edu        ReadConfig(daddr & 0xff, req->size, data);
37210121Snilay@cs.wisc.edu        return No_Fault;
3736657Snate@binkert.org    } else if (daddr >= MIB_START && daddr <= MIB_END) {
3746657Snate@binkert.org        // don't implement all the MIB's.  hopefully the kernel
3756657Snate@binkert.org        // doesn't actually DEPEND upon their values
3766657Snate@binkert.org        // MIB are just hardware stats keepers
3777839Snilay@cs.wisc.edu        uint32_t &reg = *(uint32_t *) data;
3787839Snilay@cs.wisc.edu        reg = 0;
3797839Snilay@cs.wisc.edu        return No_Fault;
38010121Snilay@cs.wisc.edu    } else if (daddr > 0x3FC)
38110121Snilay@cs.wisc.edu        panic("Something is messed up!\n");
38210121Snilay@cs.wisc.edu
3837839Snilay@cs.wisc.edu    switch (req->size) {
3847839Snilay@cs.wisc.edu      case sizeof(uint32_t):
3857839Snilay@cs.wisc.edu        {
38610121Snilay@cs.wisc.edu            uint32_t &reg = *(uint32_t *)data;
38710121Snilay@cs.wisc.edu
3887839Snilay@cs.wisc.edu            switch (daddr) {
3897839Snilay@cs.wisc.edu              case CR:
3907839Snilay@cs.wisc.edu                reg = regs.command;
39110121Snilay@cs.wisc.edu                //these are supposed to be cleared on a read
39210121Snilay@cs.wisc.edu                reg &= ~(CR_RXD | CR_TXD | CR_TXR | CR_RXR);
3937839Snilay@cs.wisc.edu                break;
3947839Snilay@cs.wisc.edu
3957839Snilay@cs.wisc.edu              case CFG:
3967839Snilay@cs.wisc.edu                reg = regs.config;
3976657Snate@binkert.org                break;
3986657Snate@binkert.org
3996657Snate@binkert.org              case MEAR:
4006657Snate@binkert.org                reg = regs.mear;
4017007Snate@binkert.org                break;
4026657Snate@binkert.org
4036657Snate@binkert.org              case PTSCR:
4049273Snilay@cs.wisc.edu                reg = regs.ptscr;
40510305Snilay@cs.wisc.edu                break;
4066657Snate@binkert.org
4076657Snate@binkert.org              case ISR:
4086657Snate@binkert.org                reg = regs.isr;
4097007Snate@binkert.org                devIntrClear(ISR_ALL);
4106657Snate@binkert.org                break;
4116657Snate@binkert.org
4129219Spower.jg@gmail.com              case IMR:
4136657Snate@binkert.org                reg = regs.imr;
4146657Snate@binkert.org                break;
4156999Snate@binkert.org
4166657Snate@binkert.org              case IER:
4176657Snate@binkert.org                reg = regs.ier;
4186657Snate@binkert.org                break;
4196657Snate@binkert.org
4207007Snate@binkert.org              case IHR:
4216657Snate@binkert.org                reg = regs.ihr;
4226657Snate@binkert.org                break;
4236657Snate@binkert.org
4246657Snate@binkert.org              case TXDP:
4256657Snate@binkert.org                reg = regs.txdp;
4268946Sandreas.hansson@arm.com                break;
4278946Sandreas.hansson@arm.com
4288946Sandreas.hansson@arm.com              case TXDP_HI:
4297832Snate@binkert.org                reg = regs.txdp_hi;
4307002Snate@binkert.org                break;
4317002Snate@binkert.org
4327002Snate@binkert.org              case TXCFG:
4338641Snate@binkert.org                reg = regs.txcfg;
4347056Snate@binkert.org                break;
4358232Snate@binkert.org
4368232Snate@binkert.org              case GPIOR:
4376657Snate@binkert.org                reg = regs.gpior;
4388229Snate@binkert.org                break;
4396657Snate@binkert.org
4406657Snate@binkert.org              case RXDP:
4417056Snate@binkert.org                reg = regs.rxdp;
4426657Snate@binkert.org                break;
4439219Spower.jg@gmail.com
4449219Spower.jg@gmail.com              case RXDP_HI:
4459219Spower.jg@gmail.com                reg = regs.rxdp_hi;
4469219Spower.jg@gmail.com                break;
4479219Spower.jg@gmail.com
4487002Snate@binkert.org              case RXCFG:
4497002Snate@binkert.org                reg = regs.rxcfg;
4506657Snate@binkert.org                break;
4516657Snate@binkert.org
4526657Snate@binkert.org              case PQCR:
4536657Snate@binkert.org                reg = regs.pqcr;
4546657Snate@binkert.org                break;
4556793SBrad.Beckmann@amd.com
4566657Snate@binkert.org              case WCSR:
4576657Snate@binkert.org                reg = regs.wcsr;
4586657Snate@binkert.org                break;
45910121Snilay@cs.wisc.edu
46010121Snilay@cs.wisc.edu              case PCR:
4616657Snate@binkert.org                reg = regs.pcr;
4626877Ssteve.reinhardt@amd.com                break;
4636877Ssteve.reinhardt@amd.com
4646877Ssteve.reinhardt@amd.com                //see the spec sheet for how RFCR and RFDR work
4656877Ssteve.reinhardt@amd.com                //basically, you write to RFCR to tell the machine what you want to do next
4666877Ssteve.reinhardt@amd.com                //then you act upon RFDR, and the device will be prepared b/c
4676877Ssteve.reinhardt@amd.com                //of what you wrote to RFCR
4686657Snate@binkert.org              case RFCR:
4699745Snilay@cs.wisc.edu                reg = regs.rfcr;
4709745Snilay@cs.wisc.edu                break;
4716657Snate@binkert.org
4727007Snate@binkert.org              case RFDR:
4736657Snate@binkert.org                switch (regs.rfcr & RFCR_RFADDR) {
4749801Snilay@cs.wisc.edu                  case 0x000:
4759801Snilay@cs.wisc.edu                    reg = rom.perfectMatch[1];
4766657Snate@binkert.org                    reg = reg << 8;
4779801Snilay@cs.wisc.edu                    reg += rom.perfectMatch[0];
4789801Snilay@cs.wisc.edu                    break;
4799801Snilay@cs.wisc.edu                  case 0x002:
4807007Snate@binkert.org                    reg = rom.perfectMatch[3] << 8;
4816657Snate@binkert.org                    reg += rom.perfectMatch[2];
4826877Ssteve.reinhardt@amd.com                    break;
4836877Ssteve.reinhardt@amd.com                  case 0x004:
4846657Snate@binkert.org                    reg = rom.perfectMatch[5] << 8;
48510078Snilay@cs.wisc.edu                    reg += rom.perfectMatch[4];
48610078Snilay@cs.wisc.edu                    break;
48710121Snilay@cs.wisc.edu                  default:
48810121Snilay@cs.wisc.edu                    panic("reading from RFDR for something for other than PMATCH!\n");
48910121Snilay@cs.wisc.edu                    //didn't implement other RFDR functionality b/c driver didn't use
4906657Snate@binkert.org                }
4916657Snate@binkert.org                break;
4926882SBrad.Beckmann@amd.com
4936882SBrad.Beckmann@amd.com              case SRR:
4946882SBrad.Beckmann@amd.com                reg = regs.srr;
49510121Snilay@cs.wisc.edu                break;
49610121Snilay@cs.wisc.edu
4976882SBrad.Beckmann@amd.com              case MIBC:
4986877Ssteve.reinhardt@amd.com                reg = regs.mibc;
49910311Snilay@cs.wisc.edu                reg &= ~(MIBC_MIBS | MIBC_ACLR);
50010311Snilay@cs.wisc.edu                break;
50110311Snilay@cs.wisc.edu
50210311Snilay@cs.wisc.edu              case VRCR:
50310311Snilay@cs.wisc.edu                reg = regs.vrcr;
50410311Snilay@cs.wisc.edu                break;
5056882SBrad.Beckmann@amd.com
50610308Snilay@cs.wisc.edu              case VTCR:
5076882SBrad.Beckmann@amd.com                reg = regs.vtcr;
50810308Snilay@cs.wisc.edu                break;
50910311Snilay@cs.wisc.edu
51010308Snilay@cs.wisc.edu              case VDR:
51110308Snilay@cs.wisc.edu                reg = regs.vdr;
5126888SBrad.Beckmann@amd.com                break;
5136657Snate@binkert.org
5146657Snate@binkert.org              case CCSR:
5159508Snilay@cs.wisc.edu                reg = regs.ccsr;
51610305Snilay@cs.wisc.edu                break;
51710305Snilay@cs.wisc.edu
5189508Snilay@cs.wisc.edu              case TBICR:
5196657Snate@binkert.org                reg = regs.tbicr;
5209595Snilay@cs.wisc.edu                break;
5219745Snilay@cs.wisc.edu
5229745Snilay@cs.wisc.edu              case TBISR:
5239745Snilay@cs.wisc.edu                reg = regs.tbisr;
5249745Snilay@cs.wisc.edu                break;
5259745Snilay@cs.wisc.edu
5269745Snilay@cs.wisc.edu              case TANAR:
5279745Snilay@cs.wisc.edu                reg = regs.tanar;
5289745Snilay@cs.wisc.edu                break;
5299745Snilay@cs.wisc.edu
5309745Snilay@cs.wisc.edu              case TANLPAR:
5319595Snilay@cs.wisc.edu                reg = regs.tanlpar;
5326657Snate@binkert.org                break;
5336657Snate@binkert.org
5346657Snate@binkert.org              case TANER:
5356657Snate@binkert.org                reg = regs.taner;
5367007Snate@binkert.org                break;
53710311Snilay@cs.wisc.edu
53810311Snilay@cs.wisc.edu              case TESR:
53910311Snilay@cs.wisc.edu                reg = regs.tesr;
54010311Snilay@cs.wisc.edu                break;
54110311Snilay@cs.wisc.edu
54210311Snilay@cs.wisc.edu              default:
54310311Snilay@cs.wisc.edu                panic("reading unimplemented register: addr = %#x", daddr);
54410311Snilay@cs.wisc.edu            }
54510311Snilay@cs.wisc.edu
54610311Snilay@cs.wisc.edu            DPRINTF(EthernetPIO, "read from %#x: data=%d data=%#x\n",
54710311Snilay@cs.wisc.edu                    daddr, reg, reg);
54810311Snilay@cs.wisc.edu        }
54910311Snilay@cs.wisc.edu        break;
55010311Snilay@cs.wisc.edu
55110311Snilay@cs.wisc.edu      default:
55210311Snilay@cs.wisc.edu        panic("accessing register with invalid size: addr=%#x, size=%d",
55310311Snilay@cs.wisc.edu              daddr, req->size);
55410311Snilay@cs.wisc.edu    }
55510311Snilay@cs.wisc.edu
55610311Snilay@cs.wisc.edu    return No_Fault;
55710311Snilay@cs.wisc.edu}
55810311Snilay@cs.wisc.edu
55910311Snilay@cs.wisc.eduFault
56010311Snilay@cs.wisc.eduNSGigE::write(MemReqPtr &req, const uint8_t *data)
56110311Snilay@cs.wisc.edu{
56210311Snilay@cs.wisc.edu    assert(ioEnable);
56310311Snilay@cs.wisc.edu
56410311Snilay@cs.wisc.edu    Addr daddr = req->paddr & 0xfff;
56510311Snilay@cs.wisc.edu    DPRINTF(EthernetPIO, "write da=%#x pa=%#x va=%#x size=%d\n",
56610311Snilay@cs.wisc.edu            daddr, req->paddr, req->vaddr, req->size);
56710311Snilay@cs.wisc.edu
56810311Snilay@cs.wisc.edu    if (daddr > LAST && daddr <=  RESERVED) {
56910311Snilay@cs.wisc.edu        panic("Accessing reserved register");
57010311Snilay@cs.wisc.edu    } else if (daddr > RESERVED && daddr <= 0x3FC) {
57110311Snilay@cs.wisc.edu        WriteConfig(daddr & 0xff, req->size, *(uint32_t *)data);
57210311Snilay@cs.wisc.edu        return No_Fault;
57310311Snilay@cs.wisc.edu    } else if (daddr > 0x3FC)
57410311Snilay@cs.wisc.edu        panic("Something is messed up!\n");
57510311Snilay@cs.wisc.edu
57610311Snilay@cs.wisc.edu    if (req->size == sizeof(uint32_t)) {
57710311Snilay@cs.wisc.edu        uint32_t reg = *(uint32_t *)data;
57810311Snilay@cs.wisc.edu        DPRINTF(EthernetPIO, "write data=%d data=%#x\n", reg, reg);
57910311Snilay@cs.wisc.edu
58010311Snilay@cs.wisc.edu        switch (daddr) {
58110311Snilay@cs.wisc.edu          case CR:
58210311Snilay@cs.wisc.edu            regs.command = reg;
58310311Snilay@cs.wisc.edu            if ((reg & (CR_TXE | CR_TXD)) == (CR_TXE | CR_TXD)) {
58410311Snilay@cs.wisc.edu                txHalt = true;
58510311Snilay@cs.wisc.edu            } else if (reg & CR_TXE) {
58610311Snilay@cs.wisc.edu                //the kernel is enabling the transmit machine
58710311Snilay@cs.wisc.edu                if (txState == txIdle)
58810311Snilay@cs.wisc.edu                    txKick();
58910311Snilay@cs.wisc.edu            } else if (reg & CR_TXD) {
59010311Snilay@cs.wisc.edu                txHalt = true;
59110311Snilay@cs.wisc.edu            }
59210311Snilay@cs.wisc.edu
59310311Snilay@cs.wisc.edu            if ((reg & (CR_RXE | CR_RXD)) == (CR_RXE | CR_RXD)) {
59410311Snilay@cs.wisc.edu                rxHalt = true;
59510311Snilay@cs.wisc.edu            } else if (reg & CR_RXE) {
59610311Snilay@cs.wisc.edu                if (rxState == rxIdle) {
59710311Snilay@cs.wisc.edu                    rxKick();
59810311Snilay@cs.wisc.edu                }
59910311Snilay@cs.wisc.edu            } else if (reg & CR_RXD) {
60010311Snilay@cs.wisc.edu                rxHalt = true;
60110311Snilay@cs.wisc.edu            }
60210311Snilay@cs.wisc.edu
60310311Snilay@cs.wisc.edu            if (reg & CR_TXR)
60410311Snilay@cs.wisc.edu                txReset();
60510311Snilay@cs.wisc.edu
60610311Snilay@cs.wisc.edu            if (reg & CR_RXR)
60710311Snilay@cs.wisc.edu                rxReset();
60810311Snilay@cs.wisc.edu
60910311Snilay@cs.wisc.edu            if (reg & CR_SWI)
61010311Snilay@cs.wisc.edu                devIntrPost(ISR_SWI);
61110311Snilay@cs.wisc.edu
61210311Snilay@cs.wisc.edu            if (reg & CR_RST) {
61310311Snilay@cs.wisc.edu                txReset();
61410311Snilay@cs.wisc.edu                rxReset();
6157007Snate@binkert.org
6166657Snate@binkert.org                regsReset();
6177007Snate@binkert.org            }
6187007Snate@binkert.org            break;
6196657Snate@binkert.org
6206657Snate@binkert.org          case CFG:
6216657Snate@binkert.org            if (reg & CFG_LNKSTS || reg & CFG_SPDSTS || reg & CFG_DUPSTS
62210311Snilay@cs.wisc.edu                || reg & CFG_RESERVED || reg & CFG_T64ADDR
6236657Snate@binkert.org                || reg & CFG_PCI64_DET)
6246657Snate@binkert.org                panic("writing to read-only or reserved CFG bits!\n");
62510305Snilay@cs.wisc.edu
6266657Snate@binkert.org            regs.config |= reg & ~(CFG_LNKSTS | CFG_SPDSTS | CFG_DUPSTS | CFG_RESERVED |
6276657Snate@binkert.org                                  CFG_T64ADDR | CFG_PCI64_DET);
6286657Snate@binkert.org
6296657Snate@binkert.org// all these #if 0's are because i don't THINK the kernel needs to have these implemented
6306657Snate@binkert.org// if there is a problem relating to one of these, you may need to add functionality in
6316657Snate@binkert.org#if 0
6326657Snate@binkert.org              if (reg & CFG_TBI_EN) ;
6336657Snate@binkert.org              if (reg & CFG_MODE_1000) ;
6349595Snilay@cs.wisc.edu#endif
6359273Snilay@cs.wisc.edu
6366657Snate@binkert.org            if (reg & CFG_AUTO_1000)
6376657Snate@binkert.org                panic("CFG_AUTO_1000 not implemented!\n");
6386657Snate@binkert.org
6399364Snilay@cs.wisc.edu#if 0
6407007Snate@binkert.org            if (reg & CFG_PINT_DUPSTS || reg & CFG_PINT_LNKSTS || reg & CFG_PINT_SPDSTS) ;
6416657Snate@binkert.org            if (reg & CFG_TMRTEST) ;
6426657Snate@binkert.org            if (reg & CFG_MRM_DIS) ;
6436657Snate@binkert.org            if (reg & CFG_MWI_DIS) ;
6446657Snate@binkert.org
6457007Snate@binkert.org            if (reg & CFG_T64ADDR)
6466657Snate@binkert.org                panic("CFG_T64ADDR is read only register!\n");
6477007Snate@binkert.org
6487007Snate@binkert.org            if (reg & CFG_PCI64_DET)
6496657Snate@binkert.org                panic("CFG_PCI64_DET is read only register!\n");
6506657Snate@binkert.org
6519508Snilay@cs.wisc.edu            if (reg & CFG_DATA64_EN) ;
6526657Snate@binkert.org            if (reg & CFG_M64ADDR) ;
6536657Snate@binkert.org            if (reg & CFG_PHY_RST) ;
6546657Snate@binkert.org            if (reg & CFG_PHY_DIS) ;
6556657Snate@binkert.org#endif
6566657Snate@binkert.org
6576657Snate@binkert.org            if (reg & CFG_EXTSTS_EN)
6586657Snate@binkert.org                extstsEnable = true;
6596657Snate@binkert.org            else
6606657Snate@binkert.org                extstsEnable = false;
6619508Snilay@cs.wisc.edu
6626657Snate@binkert.org#if 0
6637566SBrad.Beckmann@amd.com              if (reg & CFG_REQALG) ;
6649508Snilay@cs.wisc.edu              if (reg & CFG_SB) ;
6659508Snilay@cs.wisc.edu              if (reg & CFG_POW) ;
6669508Snilay@cs.wisc.edu              if (reg & CFG_EXD) ;
6679508Snilay@cs.wisc.edu              if (reg & CFG_PESEL) ;
6689508Snilay@cs.wisc.edu              if (reg & CFG_BROM_DIS) ;
6699508Snilay@cs.wisc.edu              if (reg & CFG_EXT_125) ;
6709604Snilay@cs.wisc.edu              if (reg & CFG_BEM) ;
6719604Snilay@cs.wisc.edu#endif
6729604Snilay@cs.wisc.edu            break;
6739508Snilay@cs.wisc.edu
6747566SBrad.Beckmann@amd.com          case MEAR:
6757566SBrad.Beckmann@amd.com            regs.mear = reg;
6769499Snilay@cs.wisc.edu            /* since phy is completely faked, MEAR_MD* don't matter
6779499Snilay@cs.wisc.edu               and since the driver never uses MEAR_EE*, they don't matter */
6787566SBrad.Beckmann@amd.com#if 0
6797566SBrad.Beckmann@amd.com            if (reg & MEAR_EEDI) ;
6807566SBrad.Beckmann@amd.com            if (reg & MEAR_EEDO) ; //this one is read only
6819366Snilay@cs.wisc.edu            if (reg & MEAR_EECLK) ;
6829366Snilay@cs.wisc.edu            if (reg & MEAR_EESEL) ;
6839366Snilay@cs.wisc.edu            if (reg & MEAR_MDIO) ;
6849366Snilay@cs.wisc.edu            if (reg & MEAR_MDDIR) ;
6857566SBrad.Beckmann@amd.com            if (reg & MEAR_MDC) ;
6867672Snate@binkert.org#endif
6876657Snate@binkert.org            break;
6889465Snilay@cs.wisc.edu
6896657Snate@binkert.org          case PTSCR:
6909465Snilay@cs.wisc.edu            regs.ptscr = reg & ~(PTSCR_RBIST_RDONLY);
6917056Snate@binkert.org            /* these control BISTs for various parts of chip - we don't care or do
6926657Snate@binkert.org               just fake that the BIST is done */
6936657Snate@binkert.org            if (reg & PTSCR_RBIST_EN)
6947672Snate@binkert.org                regs.ptscr |= PTSCR_RBIST_DONE;
6956657Snate@binkert.org            if (reg & PTSCR_EEBIST_EN)
6966657Snate@binkert.org                regs.ptscr &= ~PTSCR_EEBIST_EN;
6976657Snate@binkert.org            if (reg & PTSCR_EELOAD_EN)
6986657Snate@binkert.org                regs.ptscr &= ~PTSCR_EELOAD_EN;
6996657Snate@binkert.org            break;
7006657Snate@binkert.org
7016657Snate@binkert.org          case ISR: /* writing to the ISR has no effect */
7026657Snate@binkert.org            panic("ISR is a read only register!\n");
7036657Snate@binkert.org
7046657Snate@binkert.org          case IMR:
7056657Snate@binkert.org            regs.imr = reg;
7069745Snilay@cs.wisc.edu            devIntrChangeMask();
7076657Snate@binkert.org            break;
7086657Snate@binkert.org
7099496Snilay@cs.wisc.edu          case IER:
7109496Snilay@cs.wisc.edu            regs.ier = reg;
71110012Snilay@cs.wisc.edu            break;
7129496Snilay@cs.wisc.edu
7139496Snilay@cs.wisc.edu          case IHR:
7146657Snate@binkert.org            regs.ihr = reg;
71510121Snilay@cs.wisc.edu            /* not going to implement real interrupt holdoff */
7166657Snate@binkert.org            break;
7176657Snate@binkert.org
71810305Snilay@cs.wisc.edu          case TXDP:
7196657Snate@binkert.org            regs.txdp = (reg & 0xFFFFFFFC);
7208683Snilay@cs.wisc.edu            assert(txState == txIdle);
7218683Snilay@cs.wisc.edu            CTDD = false;
72210308Snilay@cs.wisc.edu            break;
7238683Snilay@cs.wisc.edu
72410308Snilay@cs.wisc.edu          case TXDP_HI:
7258683Snilay@cs.wisc.edu            regs.txdp_hi = reg;
7266657Snate@binkert.org            break;
7279745Snilay@cs.wisc.edu
7289745Snilay@cs.wisc.edu          case TXCFG:
7299745Snilay@cs.wisc.edu            regs.txcfg = reg;
7309745Snilay@cs.wisc.edu#if 0
73110012Snilay@cs.wisc.edu            if (reg & TXCFG_CSI) ;
73210012Snilay@cs.wisc.edu            if (reg & TXCFG_HBI) ;
7339745Snilay@cs.wisc.edu            if (reg & TXCFG_MLB) ;
7349745Snilay@cs.wisc.edu            if (reg & TXCFG_ATP) ;
7359745Snilay@cs.wisc.edu            if (reg & TXCFG_ECRETRY) ;  /* this could easily be implemented, but
7369745Snilay@cs.wisc.edu                                           considering the network is just a fake
7379745Snilay@cs.wisc.edu                                           pipe, wouldn't make sense to do this */
73810012Snilay@cs.wisc.edu
73910012Snilay@cs.wisc.edu            if (reg & TXCFG_BRST_DIS) ;
7409745Snilay@cs.wisc.edu#endif
7419745Snilay@cs.wisc.edu
7429745Snilay@cs.wisc.edu
7439745Snilay@cs.wisc.edu            /* we handle our own DMA, ignore the kernel's exhortations */
7449745Snilay@cs.wisc.edu            //if (reg & TXCFG_MXDMA) ;
7459745Snilay@cs.wisc.edu
7469745Snilay@cs.wisc.edu            //also, we currently don't care about fill/drain thresholds
7479745Snilay@cs.wisc.edu            //though this may change in the future with more realistic
7489745Snilay@cs.wisc.edu            //networks or a driver which changes it according to feedback
7499745Snilay@cs.wisc.edu
7509745Snilay@cs.wisc.edu            break;
7519745Snilay@cs.wisc.edu
7529745Snilay@cs.wisc.edu          case GPIOR:
7539745Snilay@cs.wisc.edu            regs.gpior = reg;
7549745Snilay@cs.wisc.edu            /* these just control general purpose i/o pins, don't matter */
7559745Snilay@cs.wisc.edu            break;
75610012Snilay@cs.wisc.edu
75710012Snilay@cs.wisc.edu          case RXDP:
7589745Snilay@cs.wisc.edu            regs.rxdp = reg;
7599745Snilay@cs.wisc.edu            break;
7609745Snilay@cs.wisc.edu
7619745Snilay@cs.wisc.edu          case RXDP_HI:
7629745Snilay@cs.wisc.edu            regs.rxdp_hi = reg;
7639745Snilay@cs.wisc.edu            break;
7649745Snilay@cs.wisc.edu
7659745Snilay@cs.wisc.edu          case RXCFG:
7669745Snilay@cs.wisc.edu            regs.rxcfg = reg;
7679745Snilay@cs.wisc.edu#if 0
7689745Snilay@cs.wisc.edu            if (reg & RXCFG_AEP) ;
7699745Snilay@cs.wisc.edu            if (reg & RXCFG_ARP) ;
7709745Snilay@cs.wisc.edu            if (reg & RXCFG_STRIPCRC) ;
7719745Snilay@cs.wisc.edu            if (reg & RXCFG_RX_RD) ;
7729745Snilay@cs.wisc.edu            if (reg & RXCFG_ALP) ;
7739745Snilay@cs.wisc.edu            if (reg & RXCFG_AIRL) ;
7749745Snilay@cs.wisc.edu#endif
7759745Snilay@cs.wisc.edu
7769745Snilay@cs.wisc.edu            /* we handle our own DMA, ignore what kernel says about it */
7779745Snilay@cs.wisc.edu            //if (reg & RXCFG_MXDMA) ;
7789745Snilay@cs.wisc.edu
7799745Snilay@cs.wisc.edu#if 0
7809745Snilay@cs.wisc.edu            //also, we currently don't care about fill/drain thresholds
7819745Snilay@cs.wisc.edu            //though this may change in the future with more realistic
7829745Snilay@cs.wisc.edu            //networks or a driver which changes it according to feedback
7839745Snilay@cs.wisc.edu            if (reg & (RXCFG_DRTH | RXCFG_DRTH0)) ;
7849745Snilay@cs.wisc.edu#endif
7859745Snilay@cs.wisc.edu            break;
7869745Snilay@cs.wisc.edu
7879745Snilay@cs.wisc.edu          case PQCR:
7889745Snilay@cs.wisc.edu            /* there is no priority queueing used in the linux 2.6 driver */
7899745Snilay@cs.wisc.edu            regs.pqcr = reg;
7909745Snilay@cs.wisc.edu            break;
7919745Snilay@cs.wisc.edu
7929745Snilay@cs.wisc.edu          case WCSR:
7939745Snilay@cs.wisc.edu            /* not going to implement wake on LAN */
7949745Snilay@cs.wisc.edu            regs.wcsr = reg;
7959745Snilay@cs.wisc.edu            break;
7969745Snilay@cs.wisc.edu
7979745Snilay@cs.wisc.edu          case PCR:
7989745Snilay@cs.wisc.edu            /* not going to implement pause control */
7999745Snilay@cs.wisc.edu            regs.pcr = reg;
8009745Snilay@cs.wisc.edu            break;
8019745Snilay@cs.wisc.edu
8029745Snilay@cs.wisc.edu          case RFCR:
8039745Snilay@cs.wisc.edu            regs.rfcr = reg;
8049745Snilay@cs.wisc.edu
8059745Snilay@cs.wisc.edu            rxFilterEnable = (reg & RFCR_RFEN) ? true : false;
8069745Snilay@cs.wisc.edu            acceptBroadcast = (reg & RFCR_AAB) ? true : false;
8079745Snilay@cs.wisc.edu            acceptMulticast = (reg & RFCR_AAM) ? true : false;
8089745Snilay@cs.wisc.edu            acceptUnicast = (reg & RFCR_AAU) ? true : false;
8099745Snilay@cs.wisc.edu            acceptPerfect = (reg & RFCR_APM) ? true : false;
8109745Snilay@cs.wisc.edu            acceptArp = (reg & RFCR_AARP) ? true : false;
8119745Snilay@cs.wisc.edu
8129745Snilay@cs.wisc.edu            if (reg & RFCR_APAT) ;
8139745Snilay@cs.wisc.edu//                panic("RFCR_APAT not implemented!\n");
8149745Snilay@cs.wisc.edu
8159745Snilay@cs.wisc.edu            if (reg & RFCR_MHEN || reg & RFCR_UHEN)
8169745Snilay@cs.wisc.edu                panic("hash filtering not implemented!\n");
8179745Snilay@cs.wisc.edu
8189745Snilay@cs.wisc.edu            if (reg & RFCR_ULM)
8199745Snilay@cs.wisc.edu                panic("RFCR_ULM not implemented!\n");
8209745Snilay@cs.wisc.edu
8219745Snilay@cs.wisc.edu            break;
8229745Snilay@cs.wisc.edu
8239745Snilay@cs.wisc.edu          case RFDR:
8249745Snilay@cs.wisc.edu            panic("the driver never writes to RFDR, something is wrong!\n");
8259745Snilay@cs.wisc.edu
8269745Snilay@cs.wisc.edu          case BRAR:
8279745Snilay@cs.wisc.edu            panic("the driver never uses BRAR, something is wrong!\n");
8289745Snilay@cs.wisc.edu
8299745Snilay@cs.wisc.edu          case BRDR:
8309745Snilay@cs.wisc.edu            panic("the driver never uses BRDR, something is wrong!\n");
8319745Snilay@cs.wisc.edu
8327007Snate@binkert.org          case SRR:
8337007Snate@binkert.org            panic("SRR is read only register!\n");
8347007Snate@binkert.org
8356657Snate@binkert.org          case MIBC:
8366657Snate@binkert.org            panic("the driver never uses MIBC, something is wrong!\n");
8376657Snate@binkert.org
8387007Snate@binkert.org          case VRCR:
8397007Snate@binkert.org            regs.vrcr = reg;
8407007Snate@binkert.org            break;
8416657Snate@binkert.org
8426657Snate@binkert.org          case VTCR:
8436657Snate@binkert.org            regs.vtcr = reg;
8448683Snilay@cs.wisc.edu            break;
8458683Snilay@cs.wisc.edu
8468683Snilay@cs.wisc.edu          case VDR:
8478683Snilay@cs.wisc.edu            panic("the driver never uses VDR, something is wrong!\n");
8488683Snilay@cs.wisc.edu            break;
8498683Snilay@cs.wisc.edu
8507007Snate@binkert.org          case CCSR:
8517007Snate@binkert.org            /* not going to implement clockrun stuff */
8527007Snate@binkert.org            regs.ccsr = reg;
8537007Snate@binkert.org            break;
8547007Snate@binkert.org
8556657Snate@binkert.org          case TBICR:
85610012Snilay@cs.wisc.edu            regs.tbicr = reg;
8579745Snilay@cs.wisc.edu            if (reg & TBICR_MR_LOOPBACK)
8589745Snilay@cs.wisc.edu                panic("TBICR_MR_LOOPBACK never used, something wrong!\n");
8599745Snilay@cs.wisc.edu
8609745Snilay@cs.wisc.edu            if (reg & TBICR_MR_AN_ENABLE) {
8619745Snilay@cs.wisc.edu                regs.tanlpar = regs.tanar;
8629745Snilay@cs.wisc.edu                regs.tbisr |= (TBISR_MR_AN_COMPLETE | TBISR_MR_LINK_STATUS);
8636902SBrad.Beckmann@amd.com            }
8649745Snilay@cs.wisc.edu
8659745Snilay@cs.wisc.edu#if 0
8669745Snilay@cs.wisc.edu            if (reg & TBICR_MR_RESTART_AN) ;
8679745Snilay@cs.wisc.edu#endif
86810012Snilay@cs.wisc.edu
8696902SBrad.Beckmann@amd.com            break;
8707839Snilay@cs.wisc.edu
8717839Snilay@cs.wisc.edu          case TBISR:
8727839Snilay@cs.wisc.edu            panic("TBISR is read only register!\n");
8737839Snilay@cs.wisc.edu
8747839Snilay@cs.wisc.edu          case TANAR:
8757839Snilay@cs.wisc.edu            regs.tanar = reg;
8767839Snilay@cs.wisc.edu            if (reg & TANAR_PS2)
8777839Snilay@cs.wisc.edu                panic("this isn't used in driver, something wrong!\n");
8787839Snilay@cs.wisc.edu
8797839Snilay@cs.wisc.edu            if (reg & TANAR_PS1)
8807839Snilay@cs.wisc.edu                panic("this isn't used in driver, something wrong!\n");
8817839Snilay@cs.wisc.edu            break;
8827839Snilay@cs.wisc.edu
8837839Snilay@cs.wisc.edu          case TANLPAR:
8847839Snilay@cs.wisc.edu            panic("this should only be written to by the fake phy!\n");
8857839Snilay@cs.wisc.edu
8867839Snilay@cs.wisc.edu          case TANER:
8877839Snilay@cs.wisc.edu            panic("TANER is read only register!\n");
8887839Snilay@cs.wisc.edu
8897839Snilay@cs.wisc.edu          case TESR:
8907839Snilay@cs.wisc.edu            regs.tesr = reg;
8917839Snilay@cs.wisc.edu            break;
8927839Snilay@cs.wisc.edu
8937839Snilay@cs.wisc.edu          default:
8947839Snilay@cs.wisc.edu            panic("thought i covered all the register, what is this? addr=%#x",
8957839Snilay@cs.wisc.edu                  daddr);
8967839Snilay@cs.wisc.edu        }
8977839Snilay@cs.wisc.edu    } else
8987839Snilay@cs.wisc.edu        panic("Invalid Request Size");
8997839Snilay@cs.wisc.edu
9007839Snilay@cs.wisc.edu    return No_Fault;
9017839Snilay@cs.wisc.edu}
9027839Snilay@cs.wisc.edu
9037839Snilay@cs.wisc.eduvoid
9047839Snilay@cs.wisc.eduNSGigE::devIntrPost(uint32_t interrupts)
9057839Snilay@cs.wisc.edu{
9067839Snilay@cs.wisc.edu    bool delay = false;
9076902SBrad.Beckmann@amd.com
9088683Snilay@cs.wisc.edu    if (interrupts & ISR_RESERVE)
9098683Snilay@cs.wisc.edu        panic("Cannot set a reserved interrupt");
9108683Snilay@cs.wisc.edu
9118683Snilay@cs.wisc.edu    if (interrupts & ISR_TXRCMP)
9128683Snilay@cs.wisc.edu        regs.isr |= ISR_TXRCMP;
9138683Snilay@cs.wisc.edu
9148683Snilay@cs.wisc.edu    if (interrupts & ISR_RXRCMP)
9158683Snilay@cs.wisc.edu        regs.isr |= ISR_RXRCMP;
9168683Snilay@cs.wisc.edu
9178683Snilay@cs.wisc.edu//ISR_DPERR  not implemented
9188683Snilay@cs.wisc.edu//ISR_SSERR not implemented
9198683Snilay@cs.wisc.edu//ISR_RMABT not implemented
9208683Snilay@cs.wisc.edu//ISR_RXSOVR not implemented
9218683Snilay@cs.wisc.edu//ISR_HIBINT not implemented
9228683Snilay@cs.wisc.edu//ISR_PHY not implemented
9238683Snilay@cs.wisc.edu//ISR_PME not implemented
9248683Snilay@cs.wisc.edu
9256657Snate@binkert.org    if (interrupts & ISR_SWI)
9266657Snate@binkert.org        regs.isr |= ISR_SWI;
9277839Snilay@cs.wisc.edu
9287839Snilay@cs.wisc.edu//ISR_MIB not implemented
9297839Snilay@cs.wisc.edu//ISR_TXURN not implemented
9307839Snilay@cs.wisc.edu
9316657Snate@binkert.org    if (interrupts & ISR_TXIDLE)
9327839Snilay@cs.wisc.edu        regs.isr |= ISR_TXIDLE;
9337839Snilay@cs.wisc.edu
9347839Snilay@cs.wisc.edu    if (interrupts & ISR_TXERR)
9357839Snilay@cs.wisc.edu        regs.isr |= ISR_TXERR;
9367839Snilay@cs.wisc.edu
9378055Sksewell@umich.edu    if (interrupts & ISR_TXDESC)
9387839Snilay@cs.wisc.edu        regs.isr |= ISR_TXDESC;
9397839Snilay@cs.wisc.edu
9406657Snate@binkert.org    if (interrupts & ISR_TXOK) {
9417839Snilay@cs.wisc.edu        regs.isr |= ISR_TXOK;
9427839Snilay@cs.wisc.edu        delay = true;
9437839Snilay@cs.wisc.edu    }
9447839Snilay@cs.wisc.edu
9457839Snilay@cs.wisc.edu    if (interrupts & ISR_RXORN)
9467839Snilay@cs.wisc.edu        regs.isr |= ISR_RXORN;
9477839Snilay@cs.wisc.edu
9487839Snilay@cs.wisc.edu    if (interrupts & ISR_RXIDLE)
9497839Snilay@cs.wisc.edu        regs.isr |= ISR_RXIDLE;
9507839Snilay@cs.wisc.edu
9517839Snilay@cs.wisc.edu//ISR_RXEARLY not implemented
9528055Sksewell@umich.edu
9537839Snilay@cs.wisc.edu    if (interrupts & ISR_RXERR)
9547839Snilay@cs.wisc.edu        regs.isr |= ISR_RXERR;
9557839Snilay@cs.wisc.edu
9567839Snilay@cs.wisc.edu    if (interrupts & ISR_RXDESC)
9577839Snilay@cs.wisc.edu        regs.isr |= ISR_RXDESC;
9587839Snilay@cs.wisc.edu
9597839Snilay@cs.wisc.edu    if (interrupts & ISR_RXOK) {
9607839Snilay@cs.wisc.edu        delay = true;
9617839Snilay@cs.wisc.edu        regs.isr |= ISR_RXOK;
9627839Snilay@cs.wisc.edu    }
9637839Snilay@cs.wisc.edu
9647839Snilay@cs.wisc.edu    if ((regs.isr & regs.imr)) {
9657839Snilay@cs.wisc.edu        Tick when = curTick;
9667839Snilay@cs.wisc.edu        if (delay)
9678055Sksewell@umich.edu            when += intrDelay;
9687839Snilay@cs.wisc.edu        cpuIntrPost(when);
9697839Snilay@cs.wisc.edu    }
9707839Snilay@cs.wisc.edu
9717839Snilay@cs.wisc.edu    DPRINTF(EthernetIntr, "**interrupt written to ISR: intr=%#x isr=%#x imr=%#x\n",
9727839Snilay@cs.wisc.edu            interrupts, regs.isr, regs.imr);
9737839Snilay@cs.wisc.edu}
9747839Snilay@cs.wisc.edu
9757839Snilay@cs.wisc.eduvoid
9767839Snilay@cs.wisc.eduNSGigE::devIntrClear(uint32_t interrupts)
9777839Snilay@cs.wisc.edu{
9786657Snate@binkert.org    if (interrupts & ISR_RESERVE)
9797007Snate@binkert.org        panic("Cannot clear a reserved interrupt");
9807007Snate@binkert.org
9816657Snate@binkert.org    if (interrupts & ISR_TXRCMP)
9828055Sksewell@umich.edu        regs.isr &= ~ISR_TXRCMP;
9836657Snate@binkert.org
9846657Snate@binkert.org    if (interrupts & ISR_RXRCMP)
9856657Snate@binkert.org        regs.isr &= ~ISR_RXRCMP;
9866657Snate@binkert.org
9878478Snilay@cs.wisc.edu//ISR_DPERR  not implemented
9888478Snilay@cs.wisc.edu//ISR_SSERR not implemented
9898478Snilay@cs.wisc.edu//ISR_RMABT not implemented
9909302Snilay@cs.wisc.edu//ISR_RXSOVR not implemented
9919302Snilay@cs.wisc.edu//ISR_HIBINT not implemented
99210524Snilay@cs.wisc.edu//ISR_PHY not implemented
9939302Snilay@cs.wisc.edu//ISR_PME not implemented
9949302Snilay@cs.wisc.edu
99510524Snilay@cs.wisc.edu    if (interrupts & ISR_SWI)
9969302Snilay@cs.wisc.edu        regs.isr &= ~ISR_SWI;
9979302Snilay@cs.wisc.edu
9989302Snilay@cs.wisc.edu//ISR_MIB not implemented
9999302Snilay@cs.wisc.edu//ISR_TXURN not implemented
100010305Snilay@cs.wisc.edu
10019302Snilay@cs.wisc.edu    if (interrupts & ISR_TXIDLE)
100210311Snilay@cs.wisc.edu        regs.isr &= ~ISR_TXIDLE;
100310311Snilay@cs.wisc.edu
100410311Snilay@cs.wisc.edu    if (interrupts & ISR_TXERR)
100510311Snilay@cs.wisc.edu        regs.isr &= ~ISR_TXERR;
100610311Snilay@cs.wisc.edu
100710311Snilay@cs.wisc.edu    if (interrupts & ISR_TXDESC)
100810311Snilay@cs.wisc.edu        regs.isr &= ~ISR_TXDESC;
10099302Snilay@cs.wisc.edu
10109302Snilay@cs.wisc.edu    if (interrupts & ISR_TXOK)
10119302Snilay@cs.wisc.edu        regs.isr &= ~ISR_TXOK;
10129302Snilay@cs.wisc.edu
10139302Snilay@cs.wisc.edu    if (interrupts & ISR_RXORN)
10146657Snate@binkert.org        regs.isr &= ~ISR_RXORN;
10156657Snate@binkert.org
10169219Spower.jg@gmail.com    if (interrupts & ISR_RXIDLE)
10176657Snate@binkert.org        regs.isr &= ~ISR_RXIDLE;
10186657Snate@binkert.org
10196999Snate@binkert.org//ISR_RXEARLY not implemented
10206657Snate@binkert.org
10216657Snate@binkert.org    if (interrupts & ISR_RXERR)
10229104Shestness@cs.utexas.edu        regs.isr &= ~ISR_RXERR;
10239104Shestness@cs.utexas.edu
10249104Shestness@cs.utexas.edu    if (interrupts & ISR_RXDESC)
10259104Shestness@cs.utexas.edu        regs.isr &= ~ISR_RXDESC;
10266657Snate@binkert.org
10276657Snate@binkert.org    if (interrupts & ISR_RXOK)
10286657Snate@binkert.org        regs.isr &= ~ISR_RXOK;
10296657Snate@binkert.org
10308946Sandreas.hansson@arm.com    if (!(regs.isr & regs.imr))
10318946Sandreas.hansson@arm.com        cpuIntrClear();
10328946Sandreas.hansson@arm.com
10337832Snate@binkert.org    DPRINTF(EthernetIntr, "**interrupt cleared from ISR: intr=%x isr=%x imr=%x\n",
10347832Snate@binkert.org            interrupts, regs.isr, regs.imr);
10357007Snate@binkert.org}
10368232Snate@binkert.org
10378229Snate@binkert.orgvoid
10388229Snate@binkert.orgNSGigE::devIntrChangeMask()
10398229Snate@binkert.org{
10409104Shestness@cs.utexas.edu    DPRINTF(EthernetIntr, "interrupt mask changed\n");
10419104Shestness@cs.utexas.edu
10429104Shestness@cs.utexas.edu    if (regs.isr & regs.imr)
10439104Shestness@cs.utexas.edu        cpuIntrPost(curTick);
10449104Shestness@cs.utexas.edu    else
10459104Shestness@cs.utexas.edu        cpuIntrClear();
10468229Snate@binkert.org}
10476657Snate@binkert.org
10486657Snate@binkert.orgvoid
10499219Spower.jg@gmail.comNSGigE::cpuIntrPost(Tick when)
10509219Spower.jg@gmail.com{
10519219Spower.jg@gmail.com    //If the interrupt you want to post is later than an
10529219Spower.jg@gmail.com    //interrupt already scheduled, just let it post in the coming one and
10539219Spower.jg@gmail.com    //don't schedule another.
10549219Spower.jg@gmail.com    //HOWEVER, must be sure that the scheduled intrTick is in the future
10559219Spower.jg@gmail.com    //(this was formerly the source of a bug)
10566657Snate@binkert.org    assert((intrTick >= curTick) || (intrTick == 0));
10577055Snate@binkert.org    if (when > intrTick && intrTick != 0)
10587055Snate@binkert.org        return;
10597007Snate@binkert.org
10607007Snate@binkert.org    intrTick = when;
10616657Snate@binkert.org
10626657Snate@binkert.org    if (intrEvent) {
10636657Snate@binkert.org        intrEvent->squash();
10646657Snate@binkert.org        intrEvent = 0;
10656657Snate@binkert.org    }
10666657Snate@binkert.org
10677007Snate@binkert.org    if (when < curTick) {
10689496Snilay@cs.wisc.edu        cpuInterrupt();
10697007Snate@binkert.org    } else {
10707007Snate@binkert.org        DPRINTF(EthernetIntr, "going to schedule an interrupt for intrTick=%d\n",
10719499Snilay@cs.wisc.edu                intrTick);
10726657Snate@binkert.org        intrEvent = new IntrEvent(this, true);
10736657Snate@binkert.org        intrEvent->schedule(intrTick);
10746657Snate@binkert.org    }
10756657Snate@binkert.org}
10766657Snate@binkert.org
10776657Snate@binkert.orgvoid
10786657Snate@binkert.orgNSGigE::cpuInterrupt()
10796657Snate@binkert.org{
10806657Snate@binkert.org    // Don't send an interrupt if there's already one
10816657Snate@binkert.org    if (cpuPendingIntr) {
10826657Snate@binkert.org        DPRINTF(EthernetIntr,
10836657Snate@binkert.org                "would send an interrupt now, but there's already pending\n");
10847567SBrad.Beckmann@amd.com        intrTick = 0;
10859996Snilay@cs.wisc.edu        return;
10867567SBrad.Beckmann@amd.com    }
10879996Snilay@cs.wisc.edu    // Don't send an interrupt if it's supposed to be delayed
10886657Snate@binkert.org    if (intrTick > curTick) {
10896657Snate@binkert.org        DPRINTF(EthernetIntr, "an interrupt is scheduled for %d, wait til then\n",
10906657Snate@binkert.org                intrTick);
10916657Snate@binkert.org        return;
10926657Snate@binkert.org    }
10936657Snate@binkert.org
10946657Snate@binkert.org    // Whether or not there's a pending interrupt, we don't care about
10956657Snate@binkert.org    // it anymore
10966657Snate@binkert.org    intrEvent = 0;
10976657Snate@binkert.org    intrTick = 0;
10986657Snate@binkert.org
10996657Snate@binkert.org    // Send interrupt
11006657Snate@binkert.org    cpuPendingIntr = true;
11016657Snate@binkert.org    /** @todo rework the intctrl to be tsunami ok */
11026657Snate@binkert.org    //intctrl->post(TheISA::INTLEVEL_IRQ1, TheISA::INTINDEX_ETHERNET);
11036657Snate@binkert.org    DPRINTF(EthernetIntr, "Posting interrupts to cchip!\n");
11046657Snate@binkert.org    tsunami->cchip->postDRIR(configData->config.hdr.pci0.interruptLine);
11056657Snate@binkert.org}
11066999Snate@binkert.org
11076657Snate@binkert.orgvoid
11086657Snate@binkert.orgNSGigE::cpuIntrClear()
11096657Snate@binkert.org{
11106657Snate@binkert.org    if (cpuPendingIntr) {
11116657Snate@binkert.org        cpuPendingIntr = false;
11126657Snate@binkert.org        /** @todo rework the intctrl to be tsunami ok */
11137832Snate@binkert.org        //intctrl->clear(TheISA::INTLEVEL_IRQ1, TheISA::INTINDEX_ETHERNET);
11147832Snate@binkert.org        DPRINTF(EthernetIntr, "clearing all interrupts from cchip\n");
11157805Snilay@cs.wisc.edu        tsunami->cchip->clearDRIR(configData->config.hdr.pci0.interruptLine);
11167832Snate@binkert.org    }
11178232Snate@binkert.org}
11188232Snate@binkert.org
11198229Snate@binkert.orgbool
11208229Snate@binkert.orgNSGigE::cpuIntrPending() const
11218229Snate@binkert.org{ return cpuPendingIntr; }
11228229Snate@binkert.org
11236657Snate@binkert.orgvoid
11246657Snate@binkert.orgNSGigE::txReset()
11256657Snate@binkert.org{
11266657Snate@binkert.org
11276657Snate@binkert.org    DPRINTF(Ethernet, "transmit reset\n");
11286657Snate@binkert.org
11296657Snate@binkert.org    CTDD = false;
11306657Snate@binkert.org    txFifoAvail = MAX_TX_FIFO_SIZE;
11317007Snate@binkert.org    txHalt = false;
11327007Snate@binkert.org    txFragPtr = 0;
11337839Snilay@cs.wisc.edu    assert(txDescCnt == 0);
11347839Snilay@cs.wisc.edu    txFifo.clear();
11357839Snilay@cs.wisc.edu    regs.command &= ~CR_TXE;
11367839Snilay@cs.wisc.edu    txState = txIdle;
11377839Snilay@cs.wisc.edu    assert(txDmaState == dmaIdle);
11387839Snilay@cs.wisc.edu}
11397839Snilay@cs.wisc.edu
11407839Snilay@cs.wisc.eduvoid
11417839Snilay@cs.wisc.eduNSGigE::rxReset()
11427839Snilay@cs.wisc.edu{
114310010Snilay@cs.wisc.edu    DPRINTF(Ethernet, "receive reset\n");
11446657Snate@binkert.org
11457839Snilay@cs.wisc.edu    CRDD = false;
114610305Snilay@cs.wisc.edu    assert(rxPktBytes == 0);
114710305Snilay@cs.wisc.edu    rxFifoCnt = 0;
11487839Snilay@cs.wisc.edu    rxHalt = false;
11498337Snilay@cs.wisc.edu    rxFragPtr = 0;
11507839Snilay@cs.wisc.edu    assert(rxDescCnt == 0);
11518337Snilay@cs.wisc.edu    assert(rxDmaState == dmaIdle);
11527839Snilay@cs.wisc.edu    rxFifo.clear();
11538337Snilay@cs.wisc.edu    regs.command &= ~CR_RXE;
11547839Snilay@cs.wisc.edu    rxState = rxIdle;
11558337Snilay@cs.wisc.edu}
11567839Snilay@cs.wisc.edu
11577839Snilay@cs.wisc.eduvoid NSGigE::regsReset()
115810305Snilay@cs.wisc.edu{
11596657Snate@binkert.org    memset(&regs, 0, sizeof(regs));
116010305Snilay@cs.wisc.edu    regs.config = 0x80000000;
116110305Snilay@cs.wisc.edu    regs.mear = 0x12;
116210305Snilay@cs.wisc.edu    regs.isr = 0x00608000;
11636657Snate@binkert.org    regs.txcfg = 0x120;
116410305Snilay@cs.wisc.edu    regs.rxcfg = 0x4;
11657839Snilay@cs.wisc.edu    regs.srr = 0x0103;
11667839Snilay@cs.wisc.edu    regs.mibc = 0x2;
11677839Snilay@cs.wisc.edu    regs.vdr = 0x81;
11687839Snilay@cs.wisc.edu    regs.tesr = 0xc000;
11697839Snilay@cs.wisc.edu
11707839Snilay@cs.wisc.edu    extstsEnable = false;
11717839Snilay@cs.wisc.edu    acceptBroadcast = false;
11727839Snilay@cs.wisc.edu    acceptMulticast = false;
11737839Snilay@cs.wisc.edu    acceptUnicast = false;
11746657Snate@binkert.org    acceptPerfect = false;
11757839Snilay@cs.wisc.edu    acceptArp = false;
11766657Snate@binkert.org}
117710305Snilay@cs.wisc.edu
117810305Snilay@cs.wisc.eduvoid
117910305Snilay@cs.wisc.eduNSGigE::rxDmaReadCopy()
118010305Snilay@cs.wisc.edu{
118110305Snilay@cs.wisc.edu    assert(rxDmaState == dmaReading);
118210305Snilay@cs.wisc.edu
118310305Snilay@cs.wisc.edu    memcpy(rxDmaData, physmem->dma_addr(rxDmaAddr, rxDmaLen), rxDmaLen);
118410305Snilay@cs.wisc.edu    rxDmaState = dmaIdle;
118510305Snilay@cs.wisc.edu
118610305Snilay@cs.wisc.edu    DPRINTF(EthernetDMA, "rx dma read  paddr=%#x len=%d\n",
118710305Snilay@cs.wisc.edu            rxDmaAddr, rxDmaLen);
118810305Snilay@cs.wisc.edu    DDUMP(EthernetDMA, rxDmaData, rxDmaLen);
118910305Snilay@cs.wisc.edu}
11907839Snilay@cs.wisc.edu
11917839Snilay@cs.wisc.edubool
11928337Snilay@cs.wisc.eduNSGigE::doRxDmaRead()
11938341Snilay@cs.wisc.edu{
11947839Snilay@cs.wisc.edu    assert(rxDmaState == dmaIdle || rxDmaState == dmaReadWaiting);
11958337Snilay@cs.wisc.edu    rxDmaState = dmaReading;
11968341Snilay@cs.wisc.edu
11977839Snilay@cs.wisc.edu    if (dmaInterface && !rxDmaFree) {
11988337Snilay@cs.wisc.edu        if (dmaInterface->busy())
11998341Snilay@cs.wisc.edu            rxDmaState = dmaReadWaiting;
12007839Snilay@cs.wisc.edu        else
12018337Snilay@cs.wisc.edu            dmaInterface->doDMA(Read, rxDmaAddr, rxDmaLen, curTick,
12028341Snilay@cs.wisc.edu                                &rxDmaReadEvent, true);
12037839Snilay@cs.wisc.edu        return true;
12047839Snilay@cs.wisc.edu    }
120510305Snilay@cs.wisc.edu
120610305Snilay@cs.wisc.edu    if (dmaReadDelay == 0 && dmaReadFactor == 0) {
120710305Snilay@cs.wisc.edu        rxDmaReadCopy();
120810305Snilay@cs.wisc.edu        return false;
120910305Snilay@cs.wisc.edu    }
121010305Snilay@cs.wisc.edu
121110305Snilay@cs.wisc.edu    Tick factor = ((rxDmaLen + ULL(63)) >> ULL(6)) * dmaReadFactor;
121210305Snilay@cs.wisc.edu    Tick start = curTick + dmaReadDelay + factor;
121310305Snilay@cs.wisc.edu    rxDmaReadEvent.schedule(start);
121410305Snilay@cs.wisc.edu    return true;
121510305Snilay@cs.wisc.edu}
121610305Snilay@cs.wisc.edu
121710305Snilay@cs.wisc.eduvoid
121810305Snilay@cs.wisc.eduNSGigE::rxDmaReadDone()
121910305Snilay@cs.wisc.edu{
122010305Snilay@cs.wisc.edu    assert(rxDmaState == dmaReading);
12216657Snate@binkert.org    rxDmaReadCopy();
122210305Snilay@cs.wisc.edu
122310305Snilay@cs.wisc.edu    // If the transmit state machine has a pending DMA, let it go first
122410305Snilay@cs.wisc.edu    if (txDmaState == dmaReadWaiting || txDmaState == dmaWriteWaiting)
122510305Snilay@cs.wisc.edu        txKick();
12266657Snate@binkert.org
12276657Snate@binkert.org    rxKick();
12287007Snate@binkert.org}
12297007Snate@binkert.org
12307007Snate@binkert.orgvoid
12317007Snate@binkert.orgNSGigE::rxDmaWriteCopy()
12327839Snilay@cs.wisc.edu{
12337839Snilay@cs.wisc.edu    assert(rxDmaState == dmaWriting);
12347839Snilay@cs.wisc.edu
12357839Snilay@cs.wisc.edu    memcpy(physmem->dma_addr(rxDmaAddr, rxDmaLen), rxDmaData, rxDmaLen);
12367839Snilay@cs.wisc.edu    rxDmaState = dmaIdle;
12377839Snilay@cs.wisc.edu
12387839Snilay@cs.wisc.edu    DPRINTF(EthernetDMA, "rx dma write paddr=%#x len=%d\n",
12397839Snilay@cs.wisc.edu            rxDmaAddr, rxDmaLen);
12407839Snilay@cs.wisc.edu    DDUMP(EthernetDMA, rxDmaData, rxDmaLen);
12417839Snilay@cs.wisc.edu}
12427839Snilay@cs.wisc.edu
12437007Snate@binkert.orgbool
12446657Snate@binkert.orgNSGigE::doRxDmaWrite()
12456657Snate@binkert.org{
12466657Snate@binkert.org    assert(rxDmaState == dmaIdle || rxDmaState == dmaWriteWaiting);
12476657Snate@binkert.org    rxDmaState = dmaWriting;
12486657Snate@binkert.org
12496657Snate@binkert.org    if (dmaInterface && !rxDmaFree) {
12506657Snate@binkert.org        if (dmaInterface->busy())
12516657Snate@binkert.org            rxDmaState = dmaWriteWaiting;
12526657Snate@binkert.org        else
12536657Snate@binkert.org            dmaInterface->doDMA(WriteInvalidate, rxDmaAddr, rxDmaLen, curTick,
12546657Snate@binkert.org                                &rxDmaWriteEvent, true);
12556999Snate@binkert.org        return true;
12566657Snate@binkert.org    }
12576657Snate@binkert.org
12586657Snate@binkert.org    if (dmaWriteDelay == 0 && dmaWriteFactor == 0) {
12596657Snate@binkert.org        rxDmaWriteCopy();
12606657Snate@binkert.org        return false;
12616657Snate@binkert.org    }
12629104Shestness@cs.utexas.edu
12636657Snate@binkert.org    Tick factor = ((rxDmaLen + ULL(63)) >> ULL(6)) * dmaWriteFactor;
12646657Snate@binkert.org    Tick start = curTick + dmaWriteDelay + factor;
12656657Snate@binkert.org    rxDmaWriteEvent.schedule(start);
12666657Snate@binkert.org    return true;
12676657Snate@binkert.org}
126810228Snilay@cs.wisc.edu
12697007Snate@binkert.orgvoid
12706657Snate@binkert.orgNSGigE::rxDmaWriteDone()
12716657Snate@binkert.org{
12726657Snate@binkert.org    assert(rxDmaState == dmaWriting);
12736657Snate@binkert.org    rxDmaWriteCopy();
12749105SBrad.Beckmann@amd.com
12759105SBrad.Beckmann@amd.com    // If the transmit state machine has a pending DMA, let it go first
12769105SBrad.Beckmann@amd.com    if (txDmaState == dmaReadWaiting || txDmaState == dmaWriteWaiting)
12779105SBrad.Beckmann@amd.com        txKick();
12789105SBrad.Beckmann@amd.com
12799105SBrad.Beckmann@amd.com    rxKick();
12809105SBrad.Beckmann@amd.com}
12819105SBrad.Beckmann@amd.com
12826657Snate@binkert.orgvoid
12836657Snate@binkert.orgNSGigE::rxKick()
12846657Snate@binkert.org{
12856657Snate@binkert.org    DPRINTF(EthernetSM, "receive kick state=%s (rxBuf.size=%d)\n",
12866657Snate@binkert.org            NsRxStateStrings[rxState], rxFifo.size());
12876657Snate@binkert.org
12886657Snate@binkert.org    if (rxKickTick > curTick) {
12899104Shestness@cs.utexas.edu        DPRINTF(EthernetSM, "receive kick exiting, can't run till %d\n",
12909104Shestness@cs.utexas.edu                rxKickTick);
12919104Shestness@cs.utexas.edu        return;
12929104Shestness@cs.utexas.edu    }
12936657Snate@binkert.org
12946657Snate@binkert.org  next:
12956657Snate@binkert.org    switch(rxDmaState) {
12966657Snate@binkert.org      case dmaReadWaiting:
12976657Snate@binkert.org        if (doRxDmaRead())
12986657Snate@binkert.org            goto exit;
12996657Snate@binkert.org        break;
13006657Snate@binkert.org      case dmaWriteWaiting:
13016657Snate@binkert.org        if (doRxDmaWrite())
13026657Snate@binkert.org            goto exit;
13037839Snilay@cs.wisc.edu        break;
13047839Snilay@cs.wisc.edu      default:
13057839Snilay@cs.wisc.edu        break;
13067839Snilay@cs.wisc.edu    }
13077839Snilay@cs.wisc.edu
13087839Snilay@cs.wisc.edu    // see state machine from spec for details
13097839Snilay@cs.wisc.edu    // the way this works is, if you finish work on one state and can go directly to
13107839Snilay@cs.wisc.edu    // another, you do that through jumping to the label "next".  however, if you have
13117839Snilay@cs.wisc.edu    // intermediate work, like DMA so that you can't go to the next state yet, you go to
13127839Snilay@cs.wisc.edu    // exit and exit the loop.  however, when the DMA is done it will trigger an
13137839Snilay@cs.wisc.edu    // event and come back to this loop.
13147839Snilay@cs.wisc.edu    switch (rxState) {
13156657Snate@binkert.org      case rxIdle:
13166657Snate@binkert.org        if (!regs.command & CR_RXE) {
13176657Snate@binkert.org            DPRINTF(EthernetSM, "Receive Disabled! Nothing to do.\n");
13186657Snate@binkert.org            goto exit;
13196657Snate@binkert.org        }
13206657Snate@binkert.org
13216657Snate@binkert.org        if (CRDD) {
13226657Snate@binkert.org            rxState = rxDescRefr;
13236657Snate@binkert.org
13246657Snate@binkert.org            rxDmaAddr = regs.rxdp & 0x3fffffff;
13256657Snate@binkert.org            rxDmaData = &rxDescCache + offsetof(ns_desc, link);
13266657Snate@binkert.org            rxDmaLen = sizeof(rxDescCache.link);
13276657Snate@binkert.org            rxDmaFree = dmaDescFree;
13286657Snate@binkert.org
13296657Snate@binkert.org            descDmaReads++;
13306657Snate@binkert.org            descDmaRdBytes += rxDmaLen;
13316657Snate@binkert.org
133210305Snilay@cs.wisc.edu            if (doRxDmaRead())
13336657Snate@binkert.org                goto exit;
13346657Snate@binkert.org        } else {
13356657Snate@binkert.org            rxState = rxDescRead;
13367805Snilay@cs.wisc.edu
13378159SBrad.Beckmann@amd.com            rxDmaAddr = regs.rxdp & 0x3fffffff;
13389465Snilay@cs.wisc.edu            rxDmaData = &rxDescCache;
13396657Snate@binkert.org            rxDmaLen = sizeof(ns_desc);
134010305Snilay@cs.wisc.edu            rxDmaFree = dmaDescFree;
13416657Snate@binkert.org
13426657Snate@binkert.org            descDmaReads++;
13436657Snate@binkert.org            descDmaRdBytes += rxDmaLen;
13446657Snate@binkert.org
13456657Snate@binkert.org            if (doRxDmaRead())
13466657Snate@binkert.org                goto exit;
13476657Snate@binkert.org        }
13486657Snate@binkert.org        break;
13496657Snate@binkert.org
13507007Snate@binkert.org      case rxDescRefr:
13516999Snate@binkert.org        if (rxDmaState != dmaIdle)
13527007Snate@binkert.org            goto exit;
13537007Snate@binkert.org
13547007Snate@binkert.org        rxState = rxAdvance;
13557007Snate@binkert.org        break;
13567007Snate@binkert.org
13577007Snate@binkert.org     case rxDescRead:
13586657Snate@binkert.org        if (rxDmaState != dmaIdle)
13596657Snate@binkert.org            goto exit;
13606657Snate@binkert.org
13616657Snate@binkert.org        DPRINTF(EthernetDesc,
13626657Snate@binkert.org                "rxDescCache:\n\tlink=%08x\n\tbufptr=%08x\n\tcmdsts=%08x\n\textsts=%08x\n"
13636657Snate@binkert.org                ,rxDescCache.link, rxDescCache.bufptr, rxDescCache.cmdsts,
13646657Snate@binkert.org                rxDescCache.extsts);
13656657Snate@binkert.org
13666657Snate@binkert.org        if (rxDescCache.cmdsts & CMDSTS_OWN) {
13676657Snate@binkert.org            rxState = rxIdle;
13686657Snate@binkert.org        } else {
13696657Snate@binkert.org            rxState = rxFifoBlock;
13706657Snate@binkert.org            rxFragPtr = rxDescCache.bufptr;
13716657Snate@binkert.org            rxDescCnt = rxDescCache.cmdsts & CMDSTS_LEN_MASK;
13726657Snate@binkert.org        }
13736657Snate@binkert.org        break;
13746657Snate@binkert.org
13756657Snate@binkert.org      case rxFifoBlock:
13766657Snate@binkert.org        if (!rxPacket) {
13776657Snate@binkert.org            /**
13786657Snate@binkert.org             * @todo in reality, we should be able to start processing
13796657Snate@binkert.org             * the packet as it arrives, and not have to wait for the
13806657Snate@binkert.org             * full packet ot be in the receive fifo.
13816657Snate@binkert.org             */
13826657Snate@binkert.org            if (rxFifo.empty())
13836657Snate@binkert.org                goto exit;
13846657Snate@binkert.org
13856657Snate@binkert.org            DPRINTF(EthernetSM, "\n\n*****processing receive of new packet\n");
13866657Snate@binkert.org
13876999Snate@binkert.org            // If we don't have a packet, grab a new one from the fifo.
13886657Snate@binkert.org            rxPacket = rxFifo.front();
13896657Snate@binkert.org            rxPktBytes = rxPacket->length;
13907007Snate@binkert.org            rxPacketBufPtr = rxPacket->data;
13917007Snate@binkert.org
13926657Snate@binkert.org            if (DTRACE(Ethernet)) {
13936657Snate@binkert.org                if (rxPacket->isIpPkt()) {
13946657Snate@binkert.org                    ip_header *ip = rxPacket->getIpHdr();
13956657Snate@binkert.org                    DPRINTF(Ethernet, "ID is %d\n", reverseEnd16(ip->ID));
13966657Snate@binkert.org                    if (rxPacket->isTcpPkt()) {
13976657Snate@binkert.org                        tcp_header *tcp = rxPacket->getTcpHdr(ip);
13986657Snate@binkert.org                        DPRINTF(Ethernet, "Src Port = %d, Dest Port = %d\n",
13996657Snate@binkert.org                                reverseEnd16(tcp->src_port_num),
14006657Snate@binkert.org                                reverseEnd16(tcp->dest_port_num));
14016657Snate@binkert.org                    }
14026657Snate@binkert.org                }
14036657Snate@binkert.org            }
14046657Snate@binkert.org
14056657Snate@binkert.org            // sanity check - i think the driver behaves like this
14066657Snate@binkert.org            assert(rxDescCnt >= rxPktBytes);
14076657Snate@binkert.org
14086657Snate@binkert.org            // Must clear the value before popping to decrement the
14096657Snate@binkert.org            // reference count
14106657Snate@binkert.org            rxFifo.front() = NULL;
14116657Snate@binkert.org            rxFifo.pop_front();
14126657Snate@binkert.org            rxFifoCnt -= rxPacket->length;
14136657Snate@binkert.org        }
14146657Snate@binkert.org
14156657Snate@binkert.org
14166657Snate@binkert.org        // dont' need the && rxDescCnt > 0 if driver sanity check above holds
14176657Snate@binkert.org        if (rxPktBytes > 0) {
14186657Snate@binkert.org            rxState = rxFragWrite;
14196657Snate@binkert.org            // don't need min<>(rxPktBytes,rxDescCnt) if above sanity check holds
14206657Snate@binkert.org            rxXferLen = rxPktBytes;
14216657Snate@binkert.org
14226657Snate@binkert.org            rxDmaAddr = rxFragPtr & 0x3fffffff;
14236657Snate@binkert.org            rxDmaData = rxPacketBufPtr;
14246657Snate@binkert.org            rxDmaLen = rxXferLen;
14256657Snate@binkert.org            rxDmaFree = dmaDataFree;
14266657Snate@binkert.org
14276657Snate@binkert.org            if (doRxDmaWrite())
14286657Snate@binkert.org                goto exit;
14296657Snate@binkert.org
14306657Snate@binkert.org        } else {
14316657Snate@binkert.org            rxState = rxDescWrite;
14326657Snate@binkert.org
14336657Snate@binkert.org            //if (rxPktBytes == 0) {  /* packet is done */
14346657Snate@binkert.org            assert(rxPktBytes == 0);
14356657Snate@binkert.org            DPRINTF(EthernetSM, "done with receiving packet\n");
14366657Snate@binkert.org
14376657Snate@binkert.org            rxDescCache.cmdsts |= CMDSTS_OWN;
14386657Snate@binkert.org            rxDescCache.cmdsts &= ~CMDSTS_MORE;
14396657Snate@binkert.org            rxDescCache.cmdsts |= CMDSTS_OK;
14406657Snate@binkert.org            rxDescCache.cmdsts &= 0xffff0000;
14416657Snate@binkert.org            rxDescCache.cmdsts += rxPacket->length;   //i.e. set CMDSTS_SIZE
14426657Snate@binkert.org
14436657Snate@binkert.org#if 0
14446657Snate@binkert.org            /* all the driver uses these are for its own stats keeping
14456657Snate@binkert.org               which we don't care about, aren't necessary for functionality
14466657Snate@binkert.org               and doing this would just slow us down.  if they end up using
14476657Snate@binkert.org               this in a later version for functional purposes, just undef
14486657Snate@binkert.org            */
14496657Snate@binkert.org            if (rxFilterEnable) {
14506657Snate@binkert.org                rxDescCache.cmdsts &= ~CMDSTS_DEST_MASK;
14516657Snate@binkert.org                if (rxFifo.front()->IsUnicast())
14526657Snate@binkert.org                    rxDescCache.cmdsts |= CMDSTS_DEST_SELF;
14536657Snate@binkert.org                if (rxFifo.front()->IsMulticast())
14546657Snate@binkert.org                    rxDescCache.cmdsts |= CMDSTS_DEST_MULTI;
14556657Snate@binkert.org                if (rxFifo.front()->IsBroadcast())
14566657Snate@binkert.org                    rxDescCache.cmdsts |= CMDSTS_DEST_MASK;
14576657Snate@binkert.org            }
14586657Snate@binkert.org#endif
14596657Snate@binkert.org
14606657Snate@binkert.org            if (rxPacket->isIpPkt() && extstsEnable) {
14616657Snate@binkert.org                rxDescCache.extsts |= EXTSTS_IPPKT;
14626657Snate@binkert.org                rxIPChecksums++;
14636657Snate@binkert.org                if (!ipChecksum(rxPacket, false)) {
14646657Snate@binkert.org                    DPRINTF(EthernetCksum, "Rx IP Checksum Error\n");
14656657Snate@binkert.org                    rxDescCache.extsts |= EXTSTS_IPERR;
14666657Snate@binkert.org                }
14676657Snate@binkert.org                if (rxPacket->isTcpPkt()) {
14686657Snate@binkert.org                    rxDescCache.extsts |= EXTSTS_TCPPKT;
14696657Snate@binkert.org                    rxTCPChecksums++;
14706657Snate@binkert.org                    if (!tcpChecksum(rxPacket, false)) {
14716657Snate@binkert.org                        DPRINTF(EthernetCksum, "Rx TCP Checksum Error\n");
14726657Snate@binkert.org                        rxDescCache.extsts |= EXTSTS_TCPERR;
14736657Snate@binkert.org
14746657Snate@binkert.org                    }
14756657Snate@binkert.org                } else if (rxPacket->isUdpPkt()) {
14766657Snate@binkert.org                    rxDescCache.extsts |= EXTSTS_UDPPKT;
14776657Snate@binkert.org                    if (!udpChecksum(rxPacket, false)) {
14786657Snate@binkert.org                        DPRINTF(EthernetCksum, "Rx UDP Checksum Error\n");
14796657Snate@binkert.org                        rxDescCache.extsts |= EXTSTS_UDPERR;
14807007Snate@binkert.org                    }
14816657Snate@binkert.org                }
14826657Snate@binkert.org            }
14836657Snate@binkert.org            rxPacket = 0;
14846657Snate@binkert.org
14856657Snate@binkert.org            /* the driver seems to always receive into desc buffers
14866657Snate@binkert.org               of size 1514, so you never have a pkt that is split
14876657Snate@binkert.org               into multiple descriptors on the receive side, so
14887007Snate@binkert.org               i don't implement that case, hence the assert above.
14896657Snate@binkert.org            */
14906657Snate@binkert.org
14916657Snate@binkert.org            DPRINTF(EthernetDesc, "rxDesc writeback:\n\tcmdsts=%08x\n\textsts=%08x\n",
14926657Snate@binkert.org                    rxDescCache.cmdsts, rxDescCache.extsts);
14936657Snate@binkert.org
14946657Snate@binkert.org            rxDmaAddr = (regs.rxdp + offsetof(ns_desc, cmdsts)) & 0x3fffffff;
14956657Snate@binkert.org            rxDmaData = &(rxDescCache.cmdsts);
14966657Snate@binkert.org            rxDmaLen = sizeof(rxDescCache.cmdsts) + sizeof(rxDescCache.extsts);
14976657Snate@binkert.org            rxDmaFree = dmaDescFree;
14986657Snate@binkert.org
14996657Snate@binkert.org            descDmaWrites++;
15006657Snate@binkert.org            descDmaWrBytes += rxDmaLen;
15016657Snate@binkert.org
15026657Snate@binkert.org            if (doRxDmaWrite())
15036657Snate@binkert.org                goto exit;
15047007Snate@binkert.org        }
15056657Snate@binkert.org        break;
15066657Snate@binkert.org
15076657Snate@binkert.org      case rxFragWrite:
15086657Snate@binkert.org        if (rxDmaState != dmaIdle)
15096657Snate@binkert.org            goto exit;
15106657Snate@binkert.org
15116657Snate@binkert.org        rxPacketBufPtr += rxXferLen;
15126657Snate@binkert.org        rxFragPtr += rxXferLen;
15136657Snate@binkert.org        rxPktBytes -= rxXferLen;
15146657Snate@binkert.org
15156657Snate@binkert.org        rxState = rxFifoBlock;
15166657Snate@binkert.org        break;
15176657Snate@binkert.org
15186657Snate@binkert.org      case rxDescWrite:
15196657Snate@binkert.org        if (rxDmaState != dmaIdle)
15206657Snate@binkert.org            goto exit;
15216657Snate@binkert.org
15226657Snate@binkert.org        assert(rxDescCache.cmdsts & CMDSTS_OWN);
15236657Snate@binkert.org
15246657Snate@binkert.org        assert(rxPacket == 0);
15256657Snate@binkert.org        devIntrPost(ISR_RXOK);
15266657Snate@binkert.org
1527        if (rxDescCache.cmdsts & CMDSTS_INTR)
1528            devIntrPost(ISR_RXDESC);
1529
1530        if (rxHalt) {
1531            DPRINTF(EthernetSM, "Halting the RX state machine\n");
1532            rxState = rxIdle;
1533            rxHalt = false;
1534        } else
1535            rxState = rxAdvance;
1536        break;
1537
1538      case rxAdvance:
1539        if (rxDescCache.link == 0) {
1540            rxState = rxIdle;
1541            return;
1542        } else {
1543            rxState = rxDescRead;
1544            regs.rxdp = rxDescCache.link;
1545            CRDD = false;
1546
1547            rxDmaAddr = regs.rxdp & 0x3fffffff;
1548            rxDmaData = &rxDescCache;
1549            rxDmaLen = sizeof(ns_desc);
1550            rxDmaFree = dmaDescFree;
1551
1552            if (doRxDmaRead())
1553                goto exit;
1554        }
1555        break;
1556
1557      default:
1558        panic("Invalid rxState!");
1559    }
1560
1561
1562    DPRINTF(EthernetSM, "entering next rx state = %s\n",
1563            NsRxStateStrings[rxState]);
1564
1565    if (rxState == rxIdle) {
1566        regs.command &= ~CR_RXE;
1567        devIntrPost(ISR_RXIDLE);
1568        return;
1569    }
1570
1571    goto next;
1572
1573  exit:
1574    /**
1575     * @todo do we want to schedule a future kick?
1576     */
1577    DPRINTF(EthernetSM, "rx state machine exited state=%s\n",
1578            NsRxStateStrings[rxState]);
1579}
1580
1581void
1582NSGigE::transmit()
1583{
1584    if (txFifo.empty()) {
1585        DPRINTF(Ethernet, "nothing to transmit\n");
1586        return;
1587    }
1588
1589    DPRINTF(Ethernet, "\n\nAttempt Pkt Transmit: txFifo length = %d\n",
1590            MAX_TX_FIFO_SIZE - txFifoAvail);
1591    if (interface->sendPacket(txFifo.front())) {
1592        if (DTRACE(Ethernet)) {
1593            if (txFifo.front()->isIpPkt()) {
1594                ip_header *ip = txFifo.front()->getIpHdr();
1595                DPRINTF(Ethernet, "ID is %d\n", reverseEnd16(ip->ID));
1596                if (txFifo.front()->isTcpPkt()) {
1597                    tcp_header *tcp = txFifo.front()->getTcpHdr(ip);
1598                    DPRINTF(Ethernet, "Src Port = %d, Dest Port = %d\n",
1599                            reverseEnd16(tcp->src_port_num),
1600                            reverseEnd16(tcp->dest_port_num));
1601                }
1602            }
1603        }
1604
1605        DDUMP(Ethernet, txFifo.front()->data, txFifo.front()->length);
1606        txBytes += txFifo.front()->length;
1607        txPackets++;
1608
1609        txFifoAvail += txFifo.front()->length;
1610
1611        DPRINTF(Ethernet, "Successful Xmit! now txFifoAvail is %d\n", txFifoAvail);
1612        txFifo.front() = NULL;
1613        txFifo.pop_front();
1614
1615        /* normally do a writeback of the descriptor here, and ONLY after that is
1616           done, send this interrupt.  but since our stuff never actually fails,
1617           just do this interrupt here, otherwise the code has to stray from this
1618           nice format.  besides, it's functionally the same.
1619        */
1620        devIntrPost(ISR_TXOK);
1621    } else
1622        DPRINTF(Ethernet, "May need to rethink always sending the descriptors back?\n");
1623
1624   if (!txFifo.empty() && !txEvent.scheduled()) {
1625       DPRINTF(Ethernet, "reschedule transmit\n");
1626       txEvent.schedule(curTick + 1000);
1627   }
1628}
1629
1630void
1631NSGigE::txDmaReadCopy()
1632{
1633    assert(txDmaState == dmaReading);
1634
1635    memcpy(txDmaData, physmem->dma_addr(txDmaAddr, txDmaLen), txDmaLen);
1636    txDmaState = dmaIdle;
1637
1638    DPRINTF(EthernetDMA, "tx dma read  paddr=%#x len=%d\n",
1639            txDmaAddr, txDmaLen);
1640    DDUMP(EthernetDMA, txDmaData, txDmaLen);
1641}
1642
1643bool
1644NSGigE::doTxDmaRead()
1645{
1646    assert(txDmaState == dmaIdle || txDmaState == dmaReadWaiting);
1647    txDmaState = dmaReading;
1648
1649    if (dmaInterface && !txDmaFree) {
1650        if (dmaInterface->busy())
1651            txDmaState = dmaReadWaiting;
1652        else
1653            dmaInterface->doDMA(Read, txDmaAddr, txDmaLen, curTick,
1654                                &txDmaReadEvent, true);
1655        return true;
1656    }
1657
1658    if (dmaReadDelay == 0 && dmaReadFactor == 0.0) {
1659        txDmaReadCopy();
1660        return false;
1661    }
1662
1663    Tick factor = ((txDmaLen + ULL(63)) >> ULL(6)) * dmaReadFactor;
1664    Tick start = curTick + dmaReadDelay + factor;
1665    txDmaReadEvent.schedule(start);
1666    return true;
1667}
1668
1669void
1670NSGigE::txDmaReadDone()
1671{
1672    assert(txDmaState == dmaReading);
1673    txDmaReadCopy();
1674
1675    // If the receive state machine  has a pending DMA, let it go first
1676    if (rxDmaState == dmaReadWaiting || rxDmaState == dmaWriteWaiting)
1677        rxKick();
1678
1679    txKick();
1680}
1681
1682void
1683NSGigE::txDmaWriteCopy()
1684{
1685    assert(txDmaState == dmaWriting);
1686
1687    memcpy(physmem->dma_addr(txDmaAddr, txDmaLen), txDmaData, txDmaLen);
1688    txDmaState = dmaIdle;
1689
1690    DPRINTF(EthernetDMA, "tx dma write paddr=%#x len=%d\n",
1691            txDmaAddr, txDmaLen);
1692    DDUMP(EthernetDMA, txDmaData, txDmaLen);
1693}
1694
1695bool
1696NSGigE::doTxDmaWrite()
1697{
1698    assert(txDmaState == dmaIdle || txDmaState == dmaWriteWaiting);
1699    txDmaState = dmaWriting;
1700
1701    if (dmaInterface && !txDmaFree) {
1702        if (dmaInterface->busy())
1703            txDmaState = dmaWriteWaiting;
1704        else
1705            dmaInterface->doDMA(WriteInvalidate, txDmaAddr, txDmaLen, curTick,
1706                                &txDmaWriteEvent, true);
1707        return true;
1708    }
1709
1710    if (dmaWriteDelay == 0 && dmaWriteFactor == 0.0) {
1711        txDmaWriteCopy();
1712        return false;
1713    }
1714
1715    Tick factor = ((txDmaLen + ULL(63)) >> ULL(6)) * dmaWriteFactor;
1716    Tick start = curTick + dmaWriteDelay + factor;
1717    txDmaWriteEvent.schedule(start);
1718    return true;
1719}
1720
1721void
1722NSGigE::txDmaWriteDone()
1723{
1724    assert(txDmaState == dmaWriting);
1725    txDmaWriteCopy();
1726
1727    // If the receive state machine  has a pending DMA, let it go first
1728    if (rxDmaState == dmaReadWaiting || rxDmaState == dmaWriteWaiting)
1729        rxKick();
1730
1731    txKick();
1732}
1733
1734void
1735NSGigE::txKick()
1736{
1737    DPRINTF(EthernetSM, "transmit kick state=%s\n", NsTxStateStrings[txState]);
1738
1739    if (txKickTick > curTick) {
1740        DPRINTF(EthernetSM, "transmit kick exiting, can't run till %d\n",
1741                txKickTick);
1742
1743        return;
1744    }
1745
1746  next:
1747    switch(txDmaState) {
1748      case dmaReadWaiting:
1749        if (doTxDmaRead())
1750            goto exit;
1751        break;
1752      case dmaWriteWaiting:
1753        if (doTxDmaWrite())
1754            goto exit;
1755        break;
1756      default:
1757        break;
1758    }
1759
1760    switch (txState) {
1761      case txIdle:
1762        if (!regs.command & CR_TXE) {
1763            DPRINTF(EthernetSM, "Transmit disabled.  Nothing to do.\n");
1764            goto exit;
1765        }
1766
1767        if (CTDD) {
1768            txState = txDescRefr;
1769
1770            txDmaAddr = regs.txdp & 0x3fffffff;
1771            txDmaData = &txDescCache + offsetof(ns_desc, link);
1772            txDmaLen = sizeof(txDescCache.link);
1773            txDmaFree = dmaDescFree;
1774
1775            descDmaReads++;
1776            descDmaRdBytes += txDmaLen;
1777
1778            if (doTxDmaRead())
1779                goto exit;
1780
1781        } else {
1782            txState = txDescRead;
1783
1784            txDmaAddr = regs.txdp & 0x3fffffff;
1785            txDmaData = &txDescCache;
1786            txDmaLen = sizeof(ns_desc);
1787            txDmaFree = dmaDescFree;
1788
1789            descDmaReads++;
1790            descDmaRdBytes += txDmaLen;
1791
1792            if (doTxDmaRead())
1793                goto exit;
1794        }
1795        break;
1796
1797      case txDescRefr:
1798        if (txDmaState != dmaIdle)
1799            goto exit;
1800
1801        txState = txAdvance;
1802        break;
1803
1804      case txDescRead:
1805        if (txDmaState != dmaIdle)
1806            goto exit;
1807
1808        DPRINTF(EthernetDesc,
1809                "txDescCache data:\n\tlink=%08x\n\tbufptr=%08x\n\tcmdsts=%08x\n\textsts=%08x\n"
1810                ,txDescCache.link, txDescCache.bufptr, txDescCache.cmdsts,
1811                txDescCache.extsts);
1812
1813        if (txDescCache.cmdsts & CMDSTS_OWN) {
1814            txState = txFifoBlock;
1815            txFragPtr = txDescCache.bufptr;
1816            txDescCnt = txDescCache.cmdsts & CMDSTS_LEN_MASK;
1817        } else {
1818            txState = txIdle;
1819        }
1820        break;
1821
1822      case txFifoBlock:
1823        if (!txPacket) {
1824            DPRINTF(EthernetSM, "\n\n*****starting the tx of a new packet\n");
1825            txPacket = new EtherPacket;
1826            txPacket->data = new uint8_t[16384];
1827            txPacketBufPtr = txPacket->data;
1828        }
1829
1830        if (txDescCnt == 0) {
1831            DPRINTF(EthernetSM, "the txDescCnt == 0, done with descriptor\n");
1832            if (txDescCache.cmdsts & CMDSTS_MORE) {
1833                DPRINTF(EthernetSM, "there are more descriptors to come\n");
1834                txState = txDescWrite;
1835
1836                txDescCache.cmdsts &= ~CMDSTS_OWN;
1837
1838                txDmaAddr = (regs.txdp + offsetof(ns_desc, cmdsts)) & 0x3fffffff;
1839                txDmaData = &(txDescCache.cmdsts);
1840                txDmaLen = sizeof(txDescCache.cmdsts);
1841                txDmaFree = dmaDescFree;
1842
1843                if (doTxDmaWrite())
1844                    goto exit;
1845
1846            } else { /* this packet is totally done */
1847                DPRINTF(EthernetSM, "This packet is done, let's wrap it up\n");
1848                /* deal with the the packet that just finished */
1849                if ((regs.vtcr & VTCR_PPCHK) && extstsEnable) {
1850                    if (txDescCache.extsts & EXTSTS_UDPPKT) {
1851                        udpChecksum(txPacket, true);
1852                    } else if (txDescCache.extsts & EXTSTS_TCPPKT) {
1853                        tcpChecksum(txPacket, true);
1854                        txTCPChecksums++;
1855                    }
1856                    if (txDescCache.extsts & EXTSTS_IPPKT) {
1857                        ipChecksum(txPacket, true);
1858                        txIPChecksums++;
1859                    }
1860                }
1861
1862                txPacket->length = txPacketBufPtr - txPacket->data;
1863                /* this is just because the receive can't handle a packet bigger
1864                   want to make sure */
1865                assert(txPacket->length <= 1514);
1866                txFifo.push_back(txPacket);
1867
1868                /* this following section is not to spec, but functionally shouldn't
1869                   be any different.  normally, the chip will wait til the transmit has
1870                   occurred before writing back the descriptor because it has to wait
1871                   to see that it was successfully transmitted to decide whether to set
1872                   CMDSTS_OK or not.  however, in the simulator since it is always
1873                   successfully transmitted, and writing it exactly to spec would
1874                   complicate the code, we just do it here
1875                */
1876
1877                txDescCache.cmdsts &= ~CMDSTS_OWN;
1878                txDescCache.cmdsts |= CMDSTS_OK;
1879
1880                DPRINTF(EthernetDesc,
1881                        "txDesc writeback:\n\tcmdsts=%08x\n\textsts=%08x\n",
1882                        txDescCache.cmdsts, txDescCache.extsts);
1883
1884                txDmaAddr = (regs.txdp + offsetof(ns_desc, cmdsts)) & 0x3fffffff;
1885                txDmaData = &(txDescCache.cmdsts);
1886                txDmaLen = sizeof(txDescCache.cmdsts) + sizeof(txDescCache.extsts);
1887                txDmaFree = dmaDescFree;
1888
1889                descDmaWrites++;
1890                descDmaWrBytes += txDmaLen;
1891
1892                if (doTxDmaWrite())
1893                    goto exit;
1894
1895                transmit();
1896
1897                txPacket = 0;
1898
1899                if (txHalt) {
1900                    DPRINTF(EthernetSM, "halting TX state machine\n");
1901                    txState = txIdle;
1902                    txHalt = false;
1903                } else
1904                    txState = txAdvance;
1905            }
1906        } else {
1907            DPRINTF(EthernetSM, "this descriptor isn't done yet\n");
1908            txState = txFragRead;
1909
1910            /* The number of bytes transferred is either whatever is left
1911               in the descriptor (txDescCnt), or if there is not enough
1912               room in the fifo, just whatever room is left in the fifo
1913            */
1914            txXferLen = min<uint32_t>(txDescCnt, txFifoAvail);
1915
1916            txDmaAddr = txFragPtr & 0x3fffffff;
1917            txDmaData = txPacketBufPtr;
1918            txDmaLen = txXferLen;
1919            txDmaFree = dmaDataFree;
1920
1921            if (doTxDmaRead())
1922                goto exit;
1923        }
1924        break;
1925
1926      case txFragRead:
1927        if (txDmaState != dmaIdle)
1928            goto exit;
1929
1930        txPacketBufPtr += txXferLen;
1931        txFragPtr += txXferLen;
1932        txDescCnt -= txXferLen;
1933        txFifoAvail -= txXferLen;
1934
1935        txState = txFifoBlock;
1936        break;
1937
1938      case txDescWrite:
1939        if (txDmaState != dmaIdle)
1940            goto exit;
1941
1942        if (txDescCache.cmdsts & CMDSTS_INTR) {
1943            devIntrPost(ISR_TXDESC);
1944        }
1945
1946        txState = txAdvance;
1947        break;
1948
1949      case txAdvance:
1950        if (txDescCache.link == 0) {
1951            txState = txIdle;
1952        } else {
1953            txState = txDescRead;
1954            regs.txdp = txDescCache.link;
1955            CTDD = false;
1956
1957            txDmaAddr = txDescCache.link & 0x3fffffff;
1958            txDmaData = &txDescCache;
1959            txDmaLen = sizeof(ns_desc);
1960            txDmaFree = dmaDescFree;
1961
1962            if (doTxDmaRead())
1963                goto exit;
1964        }
1965        break;
1966
1967      default:
1968        panic("invalid state");
1969    }
1970
1971    DPRINTF(EthernetSM, "entering next tx state=%s\n",
1972            NsTxStateStrings[txState]);
1973
1974    if (txState == txIdle) {
1975        regs.command &= ~CR_TXE;
1976        devIntrPost(ISR_TXIDLE);
1977        return;
1978    }
1979
1980    goto next;
1981
1982  exit:
1983    /**
1984     * @todo do we want to schedule a future kick?
1985     */
1986    DPRINTF(EthernetSM, "tx state machine exited state=%s\n",
1987            NsTxStateStrings[txState]);
1988}
1989
1990void
1991NSGigE::transferDone()
1992{
1993    if (txFifo.empty())
1994        return;
1995
1996    if (txEvent.scheduled())
1997        txEvent.reschedule(curTick + 1);
1998    else
1999        txEvent.schedule(curTick + 1);
2000}
2001
2002bool
2003NSGigE::rxFilter(PacketPtr packet)
2004{
2005    bool drop = true;
2006    string type;
2007
2008    if (packet->IsUnicast()) {
2009        type = "unicast";
2010
2011        // If we're accepting all unicast addresses
2012        if (acceptUnicast)
2013            drop = false;
2014
2015        // If we make a perfect match
2016        if ((acceptPerfect)
2017            && (memcmp(rom.perfectMatch, packet->data, sizeof(rom.perfectMatch)) == 0))
2018            drop = false;
2019
2020        eth_header *eth = (eth_header *) packet->data;
2021        if ((acceptArp) && (eth->type == 0x608))
2022            drop = false;
2023
2024    } else if (packet->IsBroadcast()) {
2025        type = "broadcast";
2026
2027        // if we're accepting broadcasts
2028        if (acceptBroadcast)
2029            drop = false;
2030
2031    } else if (packet->IsMulticast()) {
2032        type = "multicast";
2033
2034        // if we're accepting all multicasts
2035        if (acceptMulticast)
2036            drop = false;
2037
2038    } else {
2039        type = "unknown";
2040
2041        // oh well, punt on this one
2042    }
2043
2044    if (drop) {
2045        DPRINTF(Ethernet, "rxFilter drop\n");
2046        DDUMP(EthernetData, packet->data, packet->length);
2047    }
2048
2049    return drop;
2050}
2051
2052bool
2053NSGigE::recvPacket(PacketPtr packet)
2054{
2055    rxBytes += packet->length;
2056    rxPackets++;
2057
2058    DPRINTF(Ethernet, "\n\nReceiving packet from wire, rxFifoAvail = %d\n", MAX_RX_FIFO_SIZE - rxFifoCnt);
2059
2060    if (rxState == rxIdle) {
2061        DPRINTF(Ethernet, "receive disabled...packet dropped\n");
2062        interface->recvDone();
2063        return true;
2064    }
2065
2066    if (rxFilterEnable && rxFilter(packet)) {
2067        DPRINTF(Ethernet, "packet filtered...dropped\n");
2068        interface->recvDone();
2069        return true;
2070    }
2071
2072    if ((rxFifoCnt + packet->length) >= MAX_RX_FIFO_SIZE) {
2073        DPRINTF(Ethernet,
2074                "packet will not fit in receive buffer...packet dropped\n");
2075        devIntrPost(ISR_RXORN);
2076        return false;
2077    }
2078
2079    rxFifo.push_back(packet);
2080    rxFifoCnt += packet->length;
2081    interface->recvDone();
2082
2083    rxKick();
2084    return true;
2085}
2086
2087/**
2088 * does a udp checksum.  if gen is true, then it generates it and puts it in the right place
2089 * else, it just checks what it calculates against the value in the header in packet
2090 */
2091bool
2092NSGigE::udpChecksum(PacketPtr packet, bool gen)
2093{
2094    ip_header *ip = packet->getIpHdr();
2095    udp_header *hdr = packet->getUdpHdr(ip);
2096
2097    pseudo_header *pseudo = new pseudo_header;
2098
2099    pseudo->src_ip_addr = ip->src_ip_addr;
2100    pseudo->dest_ip_addr = ip->dest_ip_addr;
2101    pseudo->protocol = ip->protocol;
2102    pseudo->len = hdr->len;
2103
2104    uint16_t cksum = checksumCalc((uint16_t *) pseudo, (uint16_t *) hdr,
2105                                  (uint32_t) hdr->len);
2106
2107    delete pseudo;
2108    if (gen)
2109        hdr->chksum = cksum;
2110    else
2111        if (cksum != 0)
2112            return false;
2113
2114    return true;
2115}
2116
2117bool
2118NSGigE::tcpChecksum(PacketPtr packet, bool gen)
2119{
2120    ip_header *ip = packet->getIpHdr();
2121    tcp_header *hdr = packet->getTcpHdr(ip);
2122
2123    uint16_t cksum;
2124    pseudo_header *pseudo = new pseudo_header;
2125    if (!gen) {
2126        pseudo->src_ip_addr = ip->src_ip_addr;
2127        pseudo->dest_ip_addr = ip->dest_ip_addr;
2128        pseudo->protocol = reverseEnd16(ip->protocol);
2129        pseudo->len = reverseEnd16(reverseEnd16(ip->dgram_len) - (ip->vers_len & 0xf)*4);
2130
2131        cksum = checksumCalc((uint16_t *) pseudo, (uint16_t *) hdr,
2132                                  (uint32_t) reverseEnd16(pseudo->len));
2133    } else {
2134        pseudo->src_ip_addr = 0;
2135        pseudo->dest_ip_addr = 0;
2136        pseudo->protocol = hdr->chksum;
2137        pseudo->len = 0;
2138        hdr->chksum = 0;
2139        cksum = checksumCalc((uint16_t *) pseudo, (uint16_t *) hdr,
2140                             (uint32_t) (reverseEnd16(ip->dgram_len) - (ip->vers_len & 0xf)*4));
2141    }
2142
2143    delete pseudo;
2144    if (gen)
2145        hdr->chksum = cksum;
2146    else
2147        if (cksum != 0)
2148            return false;
2149
2150    return true;
2151}
2152
2153bool
2154NSGigE::ipChecksum(PacketPtr packet, bool gen)
2155{
2156    ip_header *hdr = packet->getIpHdr();
2157
2158    uint16_t cksum = checksumCalc(NULL, (uint16_t *) hdr, (hdr->vers_len & 0xf)*4);
2159
2160    if (gen) {
2161        DPRINTF(EthernetCksum, "generated checksum: %#x\n", cksum);
2162        hdr->hdr_chksum = cksum;
2163    }
2164    else
2165        if (cksum != 0)
2166            return false;
2167
2168    return true;
2169}
2170
2171uint16_t
2172NSGigE::checksumCalc(uint16_t *pseudo, uint16_t *buf, uint32_t len)
2173{
2174    uint32_t sum = 0;
2175
2176    uint16_t last_pad = 0;
2177    if (len & 1) {
2178        last_pad = buf[len/2] & 0xff;
2179        len--;
2180        sum += last_pad;
2181    }
2182
2183    if (pseudo) {
2184        sum = pseudo[0] + pseudo[1] + pseudo[2] +
2185            pseudo[3] + pseudo[4] + pseudo[5];
2186    }
2187
2188    for (int i=0; i < (len/2); ++i) {
2189        sum += buf[i];
2190    }
2191
2192    while (sum >> 16)
2193        sum = (sum >> 16) + (sum & 0xffff);
2194
2195    return ~sum;
2196}
2197
2198//=====================================================================
2199//
2200//
2201void
2202NSGigE::serialize(ostream &os)
2203{
2204    // Serialize the PciDev base class
2205    PciDev::serialize(os);
2206
2207    /*
2208     * Finalize any DMA events now.
2209     */
2210    if (rxDmaReadEvent.scheduled())
2211        rxDmaReadCopy();
2212    if (rxDmaWriteEvent.scheduled())
2213        rxDmaWriteCopy();
2214    if (txDmaReadEvent.scheduled())
2215        txDmaReadCopy();
2216    if (txDmaWriteEvent.scheduled())
2217        txDmaWriteCopy();
2218
2219    /*
2220     * Serialize the device registers
2221     */
2222    SERIALIZE_SCALAR(regs.command);
2223    SERIALIZE_SCALAR(regs.config);
2224    SERIALIZE_SCALAR(regs.mear);
2225    SERIALIZE_SCALAR(regs.ptscr);
2226    SERIALIZE_SCALAR(regs.isr);
2227    SERIALIZE_SCALAR(regs.imr);
2228    SERIALIZE_SCALAR(regs.ier);
2229    SERIALIZE_SCALAR(regs.ihr);
2230    SERIALIZE_SCALAR(regs.txdp);
2231    SERIALIZE_SCALAR(regs.txdp_hi);
2232    SERIALIZE_SCALAR(regs.txcfg);
2233    SERIALIZE_SCALAR(regs.gpior);
2234    SERIALIZE_SCALAR(regs.rxdp);
2235    SERIALIZE_SCALAR(regs.rxdp_hi);
2236    SERIALIZE_SCALAR(regs.rxcfg);
2237    SERIALIZE_SCALAR(regs.pqcr);
2238    SERIALIZE_SCALAR(regs.wcsr);
2239    SERIALIZE_SCALAR(regs.pcr);
2240    SERIALIZE_SCALAR(regs.rfcr);
2241    SERIALIZE_SCALAR(regs.rfdr);
2242    SERIALIZE_SCALAR(regs.srr);
2243    SERIALIZE_SCALAR(regs.mibc);
2244    SERIALIZE_SCALAR(regs.vrcr);
2245    SERIALIZE_SCALAR(regs.vtcr);
2246    SERIALIZE_SCALAR(regs.vdr);
2247    SERIALIZE_SCALAR(regs.ccsr);
2248    SERIALIZE_SCALAR(regs.tbicr);
2249    SERIALIZE_SCALAR(regs.tbisr);
2250    SERIALIZE_SCALAR(regs.tanar);
2251    SERIALIZE_SCALAR(regs.tanlpar);
2252    SERIALIZE_SCALAR(regs.taner);
2253    SERIALIZE_SCALAR(regs.tesr);
2254
2255    SERIALIZE_ARRAY(rom.perfectMatch, EADDR_LEN);
2256
2257    SERIALIZE_SCALAR(ioEnable);
2258
2259    /*
2260     * Serialize the data Fifos
2261     */
2262    int txNumPkts = txFifo.size();
2263    SERIALIZE_SCALAR(txNumPkts);
2264    int i = 0;
2265    pktiter_t end = txFifo.end();
2266    for (pktiter_t p = txFifo.begin(); p != end; ++p) {
2267        nameOut(os, csprintf("%s.txFifo%d", name(), i++));
2268        (*p)->serialize(os);
2269    }
2270
2271    int rxNumPkts = rxFifo.size();
2272    SERIALIZE_SCALAR(rxNumPkts);
2273    i = 0;
2274    end = rxFifo.end();
2275    for (pktiter_t p = rxFifo.begin(); p != end; ++p) {
2276        nameOut(os, csprintf("%s.rxFifo%d", name(), i++));
2277        (*p)->serialize(os);
2278    }
2279
2280    /*
2281     * Serialize the various helper variables
2282     */
2283    bool txPacketExists = txPacket;
2284    SERIALIZE_SCALAR(txPacketExists);
2285    if (txPacketExists) {
2286        nameOut(os, csprintf("%s.txPacket", name()));
2287        txPacket->serialize(os);
2288        uint32_t txPktBufPtr = (uint32_t) (txPacketBufPtr - txPacket->data);
2289        SERIALIZE_SCALAR(txPktBufPtr);
2290    }
2291
2292    bool rxPacketExists = rxPacket;
2293    SERIALIZE_SCALAR(rxPacketExists);
2294    if (rxPacketExists) {
2295        nameOut(os, csprintf("%s.rxPacket", name()));
2296        rxPacket->serialize(os);
2297        uint32_t rxPktBufPtr = (uint32_t) (rxPacketBufPtr - rxPacket->data);
2298        SERIALIZE_SCALAR(rxPktBufPtr);
2299    }
2300
2301    SERIALIZE_SCALAR(txXferLen);
2302    SERIALIZE_SCALAR(rxXferLen);
2303
2304    /*
2305     * Serialize DescCaches
2306     */
2307    SERIALIZE_SCALAR(txDescCache.link);
2308    SERIALIZE_SCALAR(txDescCache.bufptr);
2309    SERIALIZE_SCALAR(txDescCache.cmdsts);
2310    SERIALIZE_SCALAR(txDescCache.extsts);
2311    SERIALIZE_SCALAR(rxDescCache.link);
2312    SERIALIZE_SCALAR(rxDescCache.bufptr);
2313    SERIALIZE_SCALAR(rxDescCache.cmdsts);
2314    SERIALIZE_SCALAR(rxDescCache.extsts);
2315
2316    /*
2317     * Serialize tx state machine
2318     */
2319    int txState = this->txState;
2320    SERIALIZE_SCALAR(txState);
2321    SERIALIZE_SCALAR(CTDD);
2322    SERIALIZE_SCALAR(txFifoAvail);
2323    SERIALIZE_SCALAR(txHalt);
2324    SERIALIZE_SCALAR(txFragPtr);
2325    SERIALIZE_SCALAR(txDescCnt);
2326    int txDmaState = this->txDmaState;
2327    SERIALIZE_SCALAR(txDmaState);
2328
2329    /*
2330     * Serialize rx state machine
2331     */
2332    int rxState = this->rxState;
2333    SERIALIZE_SCALAR(rxState);
2334    SERIALIZE_SCALAR(CRDD);
2335    SERIALIZE_SCALAR(rxPktBytes);
2336    SERIALIZE_SCALAR(rxFifoCnt);
2337    SERIALIZE_SCALAR(rxHalt);
2338    SERIALIZE_SCALAR(rxDescCnt);
2339    int rxDmaState = this->rxDmaState;
2340    SERIALIZE_SCALAR(rxDmaState);
2341
2342    SERIALIZE_SCALAR(extstsEnable);
2343
2344    /*
2345     * If there's a pending transmit, store the time so we can
2346     * reschedule it later
2347     */
2348    Tick transmitTick = txEvent.scheduled() ? txEvent.when() - curTick : 0;
2349    SERIALIZE_SCALAR(transmitTick);
2350
2351    /*
2352     * receive address filter settings
2353     */
2354    SERIALIZE_SCALAR(rxFilterEnable);
2355    SERIALIZE_SCALAR(acceptBroadcast);
2356    SERIALIZE_SCALAR(acceptMulticast);
2357    SERIALIZE_SCALAR(acceptUnicast);
2358    SERIALIZE_SCALAR(acceptPerfect);
2359    SERIALIZE_SCALAR(acceptArp);
2360
2361    /*
2362     * Keep track of pending interrupt status.
2363     */
2364    SERIALIZE_SCALAR(intrTick);
2365    SERIALIZE_SCALAR(cpuPendingIntr);
2366    Tick intrEventTick = 0;
2367    if (intrEvent)
2368        intrEventTick = intrEvent->when();
2369    SERIALIZE_SCALAR(intrEventTick);
2370
2371}
2372
2373void
2374NSGigE::unserialize(Checkpoint *cp, const std::string &section)
2375{
2376    // Unserialize the PciDev base class
2377    PciDev::unserialize(cp, section);
2378
2379    UNSERIALIZE_SCALAR(regs.command);
2380    UNSERIALIZE_SCALAR(regs.config);
2381    UNSERIALIZE_SCALAR(regs.mear);
2382    UNSERIALIZE_SCALAR(regs.ptscr);
2383    UNSERIALIZE_SCALAR(regs.isr);
2384    UNSERIALIZE_SCALAR(regs.imr);
2385    UNSERIALIZE_SCALAR(regs.ier);
2386    UNSERIALIZE_SCALAR(regs.ihr);
2387    UNSERIALIZE_SCALAR(regs.txdp);
2388    UNSERIALIZE_SCALAR(regs.txdp_hi);
2389    UNSERIALIZE_SCALAR(regs.txcfg);
2390    UNSERIALIZE_SCALAR(regs.gpior);
2391    UNSERIALIZE_SCALAR(regs.rxdp);
2392    UNSERIALIZE_SCALAR(regs.rxdp_hi);
2393    UNSERIALIZE_SCALAR(regs.rxcfg);
2394    UNSERIALIZE_SCALAR(regs.pqcr);
2395    UNSERIALIZE_SCALAR(regs.wcsr);
2396    UNSERIALIZE_SCALAR(regs.pcr);
2397    UNSERIALIZE_SCALAR(regs.rfcr);
2398    UNSERIALIZE_SCALAR(regs.rfdr);
2399    UNSERIALIZE_SCALAR(regs.srr);
2400    UNSERIALIZE_SCALAR(regs.mibc);
2401    UNSERIALIZE_SCALAR(regs.vrcr);
2402    UNSERIALIZE_SCALAR(regs.vtcr);
2403    UNSERIALIZE_SCALAR(regs.vdr);
2404    UNSERIALIZE_SCALAR(regs.ccsr);
2405    UNSERIALIZE_SCALAR(regs.tbicr);
2406    UNSERIALIZE_SCALAR(regs.tbisr);
2407    UNSERIALIZE_SCALAR(regs.tanar);
2408    UNSERIALIZE_SCALAR(regs.tanlpar);
2409    UNSERIALIZE_SCALAR(regs.taner);
2410    UNSERIALIZE_SCALAR(regs.tesr);
2411
2412    UNSERIALIZE_ARRAY(rom.perfectMatch, EADDR_LEN);
2413
2414    UNSERIALIZE_SCALAR(ioEnable);
2415
2416    /*
2417     * unserialize the data fifos
2418     */
2419    int txNumPkts;
2420    UNSERIALIZE_SCALAR(txNumPkts);
2421    int i;
2422    for (i = 0; i < txNumPkts; ++i) {
2423        PacketPtr p = new EtherPacket;
2424        p->unserialize(cp, csprintf("%s.rxFifo%d", section, i));
2425        txFifo.push_back(p);
2426    }
2427
2428    int rxNumPkts;
2429    UNSERIALIZE_SCALAR(rxNumPkts);
2430    for (i = 0; i < rxNumPkts; ++i) {
2431        PacketPtr p = new EtherPacket;
2432        p->unserialize(cp, csprintf("%s.rxFifo%d", section, i));
2433        rxFifo.push_back(p);
2434    }
2435
2436    /*
2437     * unserialize the various helper variables
2438     */
2439    bool txPacketExists;
2440    UNSERIALIZE_SCALAR(txPacketExists);
2441    if (txPacketExists) {
2442        txPacket = new EtherPacket;
2443        txPacket->unserialize(cp, csprintf("%s.txPacket", section));
2444        uint32_t txPktBufPtr;
2445        UNSERIALIZE_SCALAR(txPktBufPtr);
2446        txPacketBufPtr = (uint8_t *) txPacket->data + txPktBufPtr;
2447    } else
2448        txPacket = 0;
2449
2450    bool rxPacketExists;
2451    UNSERIALIZE_SCALAR(rxPacketExists);
2452    rxPacket = 0;
2453    if (rxPacketExists) {
2454        rxPacket = new EtherPacket;
2455        rxPacket->unserialize(cp, csprintf("%s.rxPacket", section));
2456        uint32_t rxPktBufPtr;
2457        UNSERIALIZE_SCALAR(rxPktBufPtr);
2458        rxPacketBufPtr = (uint8_t *) rxPacket->data + rxPktBufPtr;
2459    } else
2460        rxPacket = 0;
2461
2462    UNSERIALIZE_SCALAR(txXferLen);
2463    UNSERIALIZE_SCALAR(rxXferLen);
2464
2465    /*
2466     * Unserialize DescCaches
2467     */
2468    UNSERIALIZE_SCALAR(txDescCache.link);
2469    UNSERIALIZE_SCALAR(txDescCache.bufptr);
2470    UNSERIALIZE_SCALAR(txDescCache.cmdsts);
2471    UNSERIALIZE_SCALAR(txDescCache.extsts);
2472    UNSERIALIZE_SCALAR(rxDescCache.link);
2473    UNSERIALIZE_SCALAR(rxDescCache.bufptr);
2474    UNSERIALIZE_SCALAR(rxDescCache.cmdsts);
2475    UNSERIALIZE_SCALAR(rxDescCache.extsts);
2476
2477    /*
2478     * unserialize tx state machine
2479     */
2480    int txState;
2481    UNSERIALIZE_SCALAR(txState);
2482    this->txState = (TxState) txState;
2483    UNSERIALIZE_SCALAR(CTDD);
2484    UNSERIALIZE_SCALAR(txFifoAvail);
2485    UNSERIALIZE_SCALAR(txHalt);
2486    UNSERIALIZE_SCALAR(txFragPtr);
2487    UNSERIALIZE_SCALAR(txDescCnt);
2488    int txDmaState;
2489    UNSERIALIZE_SCALAR(txDmaState);
2490    this->txDmaState = (DmaState) txDmaState;
2491
2492    /*
2493     * unserialize rx state machine
2494     */
2495    int rxState;
2496    UNSERIALIZE_SCALAR(rxState);
2497    this->rxState = (RxState) rxState;
2498    UNSERIALIZE_SCALAR(CRDD);
2499    UNSERIALIZE_SCALAR(rxPktBytes);
2500    UNSERIALIZE_SCALAR(rxFifoCnt);
2501    UNSERIALIZE_SCALAR(rxHalt);
2502    UNSERIALIZE_SCALAR(rxDescCnt);
2503    int rxDmaState;
2504    UNSERIALIZE_SCALAR(rxDmaState);
2505    this->rxDmaState = (DmaState) rxDmaState;
2506
2507    UNSERIALIZE_SCALAR(extstsEnable);
2508
2509     /*
2510     * If there's a pending transmit, reschedule it now
2511     */
2512    Tick transmitTick;
2513    UNSERIALIZE_SCALAR(transmitTick);
2514    if (transmitTick)
2515        txEvent.schedule(curTick + transmitTick);
2516
2517    /*
2518     * unserialize receive address filter settings
2519     */
2520    UNSERIALIZE_SCALAR(rxFilterEnable);
2521    UNSERIALIZE_SCALAR(acceptBroadcast);
2522    UNSERIALIZE_SCALAR(acceptMulticast);
2523    UNSERIALIZE_SCALAR(acceptUnicast);
2524    UNSERIALIZE_SCALAR(acceptPerfect);
2525    UNSERIALIZE_SCALAR(acceptArp);
2526
2527    /*
2528     * Keep track of pending interrupt status.
2529     */
2530    UNSERIALIZE_SCALAR(intrTick);
2531    UNSERIALIZE_SCALAR(cpuPendingIntr);
2532    Tick intrEventTick;
2533    UNSERIALIZE_SCALAR(intrEventTick);
2534    if (intrEventTick) {
2535        intrEvent = new IntrEvent(this, true);
2536        intrEvent->schedule(intrEventTick);
2537    }
2538
2539    /*
2540     * re-add addrRanges to bus bridges
2541     */
2542    if (pioInterface) {
2543        pioInterface->addAddrRange(BARAddrs[0], BARAddrs[0] + BARSize[0] - 1);
2544        pioInterface->addAddrRange(BARAddrs[1], BARAddrs[1] + BARSize[1] - 1);
2545    }
2546}
2547
2548Tick
2549NSGigE::cacheAccess(MemReqPtr &req)
2550{
2551    DPRINTF(EthernetPIO, "timing access to paddr=%#x (daddr=%#x)\n",
2552            req->paddr, req->paddr - addr);
2553    return curTick + pioLatency;
2554}
2555//=====================================================================
2556
2557
2558//********** helper functions******************************************
2559
2560uint16_t reverseEnd16(uint16_t num)
2561{
2562    uint16_t reverse = (num & 0xff)<<8;
2563    reverse += ((num & 0xff00) >> 8);
2564    return reverse;
2565}
2566
2567uint32_t reverseEnd32(uint32_t num)
2568{
2569    uint32_t reverse = (reverseEnd16(num & 0xffff)) << 16;
2570    reverse += reverseEnd16((uint16_t) ((num & 0xffff0000) >> 8));
2571    return reverse;
2572}
2573
2574
2575
2576//=====================================================================
2577
2578BEGIN_DECLARE_SIM_OBJECT_PARAMS(NSGigEInt)
2579
2580    SimObjectParam<EtherInt *> peer;
2581    SimObjectParam<NSGigE *> device;
2582
2583END_DECLARE_SIM_OBJECT_PARAMS(NSGigEInt)
2584
2585BEGIN_INIT_SIM_OBJECT_PARAMS(NSGigEInt)
2586
2587    INIT_PARAM_DFLT(peer, "peer interface", NULL),
2588    INIT_PARAM(device, "Ethernet device of this interface")
2589
2590END_INIT_SIM_OBJECT_PARAMS(NSGigEInt)
2591
2592CREATE_SIM_OBJECT(NSGigEInt)
2593{
2594    NSGigEInt *dev_int = new NSGigEInt(getInstanceName(), device);
2595
2596    EtherInt *p = (EtherInt *)peer;
2597    if (p) {
2598        dev_int->setPeer(p);
2599        p->setPeer(dev_int);
2600    }
2601
2602    return dev_int;
2603}
2604
2605REGISTER_SIM_OBJECT("NSGigEInt", NSGigEInt)
2606
2607
2608BEGIN_DECLARE_SIM_OBJECT_PARAMS(NSGigE)
2609
2610    Param<Tick> tx_delay;
2611    Param<Tick> rx_delay;
2612    SimObjectParam<IntrControl *> intr_ctrl;
2613    Param<Tick> intr_delay;
2614    SimObjectParam<MemoryController *> mmu;
2615    SimObjectParam<PhysicalMemory *> physmem;
2616    Param<bool> rx_filter;
2617    Param<string> hardware_address;
2618    SimObjectParam<Bus*> header_bus;
2619    SimObjectParam<Bus*> payload_bus;
2620    SimObjectParam<HierParams *> hier;
2621    Param<Tick> pio_latency;
2622    Param<bool> dma_desc_free;
2623    Param<bool> dma_data_free;
2624    Param<Tick> dma_read_delay;
2625    Param<Tick> dma_write_delay;
2626    Param<Tick> dma_read_factor;
2627    Param<Tick> dma_write_factor;
2628    SimObjectParam<PciConfigAll *> configspace;
2629    SimObjectParam<PciConfigData *> configdata;
2630    SimObjectParam<Tsunami *> tsunami;
2631    Param<uint32_t> pci_bus;
2632    Param<uint32_t> pci_dev;
2633    Param<uint32_t> pci_func;
2634
2635END_DECLARE_SIM_OBJECT_PARAMS(NSGigE)
2636
2637BEGIN_INIT_SIM_OBJECT_PARAMS(NSGigE)
2638
2639    INIT_PARAM_DFLT(tx_delay, "Transmit Delay", 1000),
2640    INIT_PARAM_DFLT(rx_delay, "Receive Delay", 1000),
2641    INIT_PARAM(intr_ctrl, "Interrupt Controller"),
2642    INIT_PARAM_DFLT(intr_delay, "Interrupt Delay in microseconds", 0),
2643    INIT_PARAM(mmu, "Memory Controller"),
2644    INIT_PARAM(physmem, "Physical Memory"),
2645    INIT_PARAM_DFLT(rx_filter, "Enable Receive Filter", true),
2646    INIT_PARAM_DFLT(hardware_address, "Ethernet Hardware Address",
2647                    "00:99:00:00:00:01"),
2648    INIT_PARAM_DFLT(header_bus, "The IO Bus to attach to for headers", NULL),
2649    INIT_PARAM_DFLT(payload_bus, "The IO Bus to attach to for payload", NULL),
2650    INIT_PARAM_DFLT(hier, "Hierarchy global variables", &defaultHierParams),
2651    INIT_PARAM_DFLT(pio_latency, "Programmed IO latency", 1000),
2652    INIT_PARAM_DFLT(dma_desc_free, "DMA of Descriptors is free", false),
2653    INIT_PARAM_DFLT(dma_data_free, "DMA of Data is free", false),
2654    INIT_PARAM_DFLT(dma_read_delay, "fixed delay for dma reads", 0),
2655    INIT_PARAM_DFLT(dma_write_delay, "fixed delay for dma writes", 0),
2656    INIT_PARAM_DFLT(dma_read_factor, "multiplier for dma reads", 0),
2657    INIT_PARAM_DFLT(dma_write_factor, "multiplier for dma writes", 0),
2658    INIT_PARAM(configspace, "PCI Configspace"),
2659    INIT_PARAM(configdata, "PCI Config data"),
2660    INIT_PARAM(tsunami, "Tsunami"),
2661    INIT_PARAM(pci_bus, "PCI bus"),
2662    INIT_PARAM(pci_dev, "PCI device number"),
2663    INIT_PARAM(pci_func, "PCI function code")
2664
2665END_INIT_SIM_OBJECT_PARAMS(NSGigE)
2666
2667
2668CREATE_SIM_OBJECT(NSGigE)
2669{
2670    int eaddr[6];
2671    sscanf(((string)hardware_address).c_str(), "%x:%x:%x:%x:%x:%x",
2672           &eaddr[0], &eaddr[1], &eaddr[2], &eaddr[3], &eaddr[4], &eaddr[5]);
2673
2674    return new NSGigE(getInstanceName(), intr_ctrl, intr_delay,
2675                      physmem, tx_delay, rx_delay, mmu, hier, header_bus,
2676                      payload_bus, pio_latency, dma_desc_free, dma_data_free,
2677                      dma_read_delay, dma_write_delay, dma_read_factor,
2678                      dma_write_factor, configspace, configdata,
2679                      tsunami, pci_bus, pci_dev, pci_func, rx_filter, eaddr);
2680}
2681
2682REGISTER_SIM_OBJECT("NSGigE", NSGigE)
2683