ns_gige.cc revision 986
17202Sgblack@eecs.umich.edu/*
27202Sgblack@eecs.umich.edu * Copyright (c) 2004 The Regents of The University of Michigan
312503Snikos.nikoleris@arm.com * All rights reserved.
47202Sgblack@eecs.umich.edu *
57202Sgblack@eecs.umich.edu * Redistribution and use in source and binary forms, with or without
67202Sgblack@eecs.umich.edu * modification, are permitted provided that the following conditions are
77202Sgblack@eecs.umich.edu * met: redistributions of source code must retain the above copyright
87202Sgblack@eecs.umich.edu * notice, this list of conditions and the following disclaimer;
97202Sgblack@eecs.umich.edu * redistributions in binary form must reproduce the above copyright
107202Sgblack@eecs.umich.edu * notice, this list of conditions and the following disclaimer in the
117202Sgblack@eecs.umich.edu * documentation and/or other materials provided with the distribution;
127202Sgblack@eecs.umich.edu * neither the name of the copyright holders nor the names of its
137202Sgblack@eecs.umich.edu * contributors may be used to endorse or promote products derived from
147202Sgblack@eecs.umich.edu * this software without specific prior written permission.
157202Sgblack@eecs.umich.edu *
167202Sgblack@eecs.umich.edu * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
177202Sgblack@eecs.umich.edu * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
187202Sgblack@eecs.umich.edu * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
197202Sgblack@eecs.umich.edu * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
207202Sgblack@eecs.umich.edu * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
217202Sgblack@eecs.umich.edu * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
227202Sgblack@eecs.umich.edu * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
237202Sgblack@eecs.umich.edu * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
247202Sgblack@eecs.umich.edu * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
257202Sgblack@eecs.umich.edu * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
267202Sgblack@eecs.umich.edu * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
277202Sgblack@eecs.umich.edu */
287202Sgblack@eecs.umich.edu
297202Sgblack@eecs.umich.edu/* @file
307202Sgblack@eecs.umich.edu * Device module for modelling the National Semiconductor
317202Sgblack@eecs.umich.edu * DP83820 ethernet controller.  Does not support priority queueing
327202Sgblack@eecs.umich.edu */
337202Sgblack@eecs.umich.edu#include <cstdio>
347202Sgblack@eecs.umich.edu#include <deque>
357202Sgblack@eecs.umich.edu#include <string>
367202Sgblack@eecs.umich.edu
377202Sgblack@eecs.umich.edu#include "base/inet.hh"
387202Sgblack@eecs.umich.edu#include "cpu/exec_context.hh"
397202Sgblack@eecs.umich.edu#include "cpu/intr_control.hh"
407202Sgblack@eecs.umich.edu#include "dev/dma.hh"
417202Sgblack@eecs.umich.edu#include "dev/ns_gige.hh"
427202Sgblack@eecs.umich.edu#include "dev/etherlink.hh"
437202Sgblack@eecs.umich.edu#include "mem/bus/bus.hh"
447202Sgblack@eecs.umich.edu#include "mem/bus/dma_interface.hh"
457202Sgblack@eecs.umich.edu#include "mem/bus/pio_interface.hh"
467202Sgblack@eecs.umich.edu#include "mem/bus/pio_interface_impl.hh"
4712616Sgabeblack@google.com#include "mem/functional_mem/memory_control.hh"
487202Sgblack@eecs.umich.edu#include "mem/functional_mem/physical_memory.hh"
497202Sgblack@eecs.umich.edu#include "sim/builder.hh"
507202Sgblack@eecs.umich.edu#include "sim/host.hh"
517202Sgblack@eecs.umich.edu#include "sim/sim_stats.hh"
5210184SCurtis.Dunham@arm.com#include "targetarch/vtophys.hh"
537202Sgblack@eecs.umich.edu#include "dev/pciconfigall.hh"
547202Sgblack@eecs.umich.edu#include "dev/tsunami_cchip.hh"
557202Sgblack@eecs.umich.edu
567202Sgblack@eecs.umich.educonst char *NsRxStateStrings[] =
577848SAli.Saidi@ARM.com{
587848SAli.Saidi@ARM.com    "rxIdle",
597848SAli.Saidi@ARM.com    "rxDescRefr",
607848SAli.Saidi@ARM.com    "rxDescRead",
617848SAli.Saidi@ARM.com    "rxFifoBlock",
627202Sgblack@eecs.umich.edu    "rxFragWrite",
637202Sgblack@eecs.umich.edu    "rxDescWrite",
647202Sgblack@eecs.umich.edu    "rxAdvance"
6510037SARM gem5 Developers};
6610037SARM gem5 Developers
6710037SARM gem5 Developersconst char *NsTxStateStrings[] =
6810037SARM gem5 Developers{
6910037SARM gem5 Developers    "txIdle",
7010037SARM gem5 Developers    "txDescRefr",
7110037SARM gem5 Developers    "txDescRead",
7210037SARM gem5 Developers    "txFifoBlock",
7310037SARM gem5 Developers    "txFragRead",
7410037SARM gem5 Developers    "txDescWrite",
7510037SARM gem5 Developers    "txAdvance"
7612616Sgabeblack@google.com};
7710037SARM gem5 Developers
7810037SARM gem5 Developersconst char *NsDmaState[] =
7910037SARM gem5 Developers{
8010037SARM gem5 Developers    "dmaIdle",
8110184SCurtis.Dunham@arm.com    "dmaReading",
8210037SARM gem5 Developers    "dmaWriting",
8310037SARM gem5 Developers    "dmaReadWaiting",
8410037SARM gem5 Developers    "dmaWriteWaiting"
8510037SARM gem5 Developers};
8610037SARM gem5 Developers
8710037SARM gem5 Developersusing namespace std;
8810037SARM gem5 Developers
8910037SARM gem5 Developers//helper function declarations
9010037SARM gem5 Developers//These functions reverse Endianness so we can evaluate network data correctly
9110037SARM gem5 Developersuint16_t reverseEnd16(uint16_t);
9210037SARM gem5 Developersuint32_t reverseEnd32(uint32_t);
9310037SARM gem5 Developers
9410037SARM gem5 Developers///////////////////////////////////////////////////////////////////////
9510037SARM gem5 Developers//
9610037SARM gem5 Developers// NSGigE PCI Device
9710037SARM gem5 Developers//
9810037SARM gem5 DevelopersNSGigE::NSGigE(const std::string &name, IntrControl *i, Tick intr_delay,
9910037SARM gem5 Developers             PhysicalMemory *pmem, Tick tx_delay, Tick rx_delay,
10010037SARM gem5 Developers             MemoryController *mmu, HierParams *hier, Bus *header_bus,
10110037SARM gem5 Developers             Bus *payload_bus, Tick pio_latency, bool dma_desc_free,
10210037SARM gem5 Developers             bool dma_data_free, Tick dma_read_delay, Tick dma_write_delay,
10310037SARM gem5 Developers             Tick dma_read_factor, Tick dma_write_factor, PciConfigAll *cf,
10410037SARM gem5 Developers             PciConfigData *cd, Tsunami *t, uint32_t bus, uint32_t dev,
10510037SARM gem5 Developers             uint32_t func, bool rx_filter, const int eaddr[6])
10610037SARM gem5 Developers    : PciDev(name, mmu, cf, cd, bus, dev, func), tsunami(t), ioEnable(false),
10712616Sgabeblack@google.com      txPacket(0), rxPacket(0), txPacketBufPtr(NULL), rxPacketBufPtr(NULL),
10810037SARM gem5 Developers      txXferLen(0), rxXferLen(0), txState(txIdle), CTDD(false),
10910037SARM gem5 Developers      txFifoAvail(MAX_TX_FIFO_SIZE), txHalt(false),
11010037SARM gem5 Developers      txFragPtr(0), txDescCnt(0), txDmaState(dmaIdle), rxState(rxIdle),
11110037SARM gem5 Developers      CRDD(false), rxPktBytes(0), rxFifoCnt(0), rxHalt(false),
11210184SCurtis.Dunham@arm.com      rxFragPtr(0), rxDescCnt(0), rxDmaState(dmaIdle), extstsEnable(false),
11310037SARM gem5 Developers      rxDmaReadEvent(this), rxDmaWriteEvent(this),
11410037SARM gem5 Developers      txDmaReadEvent(this), txDmaWriteEvent(this),
11510037SARM gem5 Developers      dmaDescFree(dma_desc_free), dmaDataFree(dma_data_free),
11610037SARM gem5 Developers      txDelay(tx_delay), rxDelay(rx_delay), rxKickTick(0), txKickTick(0),
11710037SARM gem5 Developers      txEvent(this), rxFilterEnable(rx_filter), acceptBroadcast(false),
11810037SARM gem5 Developers      acceptMulticast(false), acceptUnicast(false),
11910037SARM gem5 Developers      acceptPerfect(false), acceptArp(false),
12010037SARM gem5 Developers      physmem(pmem), intctrl(i), intrTick(0), cpuPendingIntr(false),
12110037SARM gem5 Developers      intrEvent(0), interface(0), pioLatency(pio_latency)
12210037SARM gem5 Developers{
12310037SARM gem5 Developers    tsunami->ethernet = this;
12410037SARM gem5 Developers
12510037SARM gem5 Developers    if (header_bus) {
12610037SARM gem5 Developers        pioInterface = newPioInterface(name, hier, header_bus, this,
12710037SARM gem5 Developers                                       &NSGigE::cacheAccess);
1287202Sgblack@eecs.umich.edu
1297202Sgblack@eecs.umich.edu        if (payload_bus)
1307202Sgblack@eecs.umich.edu            dmaInterface = new DMAInterface<Bus>(name + ".dma",
1317202Sgblack@eecs.umich.edu                                                 header_bus, payload_bus, 1);
1327202Sgblack@eecs.umich.edu        else
1337202Sgblack@eecs.umich.edu            dmaInterface = new DMAInterface<Bus>(name + ".dma",
1347202Sgblack@eecs.umich.edu                                                 header_bus, header_bus, 1);
13512616Sgabeblack@google.com    } else if (payload_bus) {
1367202Sgblack@eecs.umich.edu        pioInterface = newPioInterface(name, hier, payload_bus, this,
1377202Sgblack@eecs.umich.edu                                       &NSGigE::cacheAccess);
1387202Sgblack@eecs.umich.edu
1397202Sgblack@eecs.umich.edu        dmaInterface = new DMAInterface<Bus>(name + ".dma", payload_bus,
14010184SCurtis.Dunham@arm.com                                         payload_bus, 1);
1417202Sgblack@eecs.umich.edu
1427202Sgblack@eecs.umich.edu    }
1437202Sgblack@eecs.umich.edu
1447202Sgblack@eecs.umich.edu
1457202Sgblack@eecs.umich.edu    intrDelay = US2Ticks(intr_delay);
1467848SAli.Saidi@ARM.com    dmaReadDelay = dma_read_delay;
1477848SAli.Saidi@ARM.com    dmaWriteDelay = dma_write_delay;
1487848SAli.Saidi@ARM.com    dmaReadFactor = dma_read_factor;
1497848SAli.Saidi@ARM.com    dmaWriteFactor = dma_write_factor;
1507848SAli.Saidi@ARM.com
1517202Sgblack@eecs.umich.edu    regsReset();
1527202Sgblack@eecs.umich.edu    rom.perfectMatch[0] = eaddr[0];
1537202Sgblack@eecs.umich.edu    rom.perfectMatch[1] = eaddr[1];
1547202Sgblack@eecs.umich.edu    rom.perfectMatch[2] = eaddr[2];
1557202Sgblack@eecs.umich.edu    rom.perfectMatch[3] = eaddr[3];
1567202Sgblack@eecs.umich.edu    rom.perfectMatch[4] = eaddr[4];
1577202Sgblack@eecs.umich.edu    rom.perfectMatch[5] = eaddr[5];
1587202Sgblack@eecs.umich.edu}
1597202Sgblack@eecs.umich.edu
1607202Sgblack@eecs.umich.eduNSGigE::~NSGigE()
16112616Sgabeblack@google.com{}
1627202Sgblack@eecs.umich.edu
1637202Sgblack@eecs.umich.eduvoid
1647202Sgblack@eecs.umich.eduNSGigE::regStats()
1657202Sgblack@eecs.umich.edu{
16610184SCurtis.Dunham@arm.com    txBytes
1677202Sgblack@eecs.umich.edu        .name(name() + ".txBytes")
1687202Sgblack@eecs.umich.edu        .desc("Bytes Transmitted")
1697202Sgblack@eecs.umich.edu        .prereq(txBytes)
1707202Sgblack@eecs.umich.edu        ;
1717202Sgblack@eecs.umich.edu
1727848SAli.Saidi@ARM.com    rxBytes
1737848SAli.Saidi@ARM.com        .name(name() + ".rxBytes")
1747848SAli.Saidi@ARM.com        .desc("Bytes Received")
1757848SAli.Saidi@ARM.com        .prereq(rxBytes)
1767848SAli.Saidi@ARM.com        ;
1777202Sgblack@eecs.umich.edu
1787202Sgblack@eecs.umich.edu    txPackets
1797208Sgblack@eecs.umich.edu        .name(name() + ".txPackets")
18010037SARM gem5 Developers        .desc("Number of Packets Transmitted")
18110037SARM gem5 Developers        .prereq(txBytes)
18210037SARM gem5 Developers        ;
18310037SARM gem5 Developers
18410037SARM gem5 Developers    rxPackets
18510037SARM gem5 Developers        .name(name() + ".rxPackets")
18610420Sandreas.hansson@arm.com        .desc("Number of Packets Received")
18710037SARM gem5 Developers        .prereq(rxBytes)
18812616Sgabeblack@google.com        ;
18910037SARM gem5 Developers
19010037SARM gem5 Developers    txIPChecksums
19110037SARM gem5 Developers        .name(name() + ".txIPChecksums")
19210037SARM gem5 Developers        .desc("Number of tx IP Checksums done by device")
19310184SCurtis.Dunham@arm.com        .precision(0)
19410420Sandreas.hansson@arm.com        .prereq(txBytes)
19510037SARM gem5 Developers        ;
19610037SARM gem5 Developers
19710037SARM gem5 Developers    rxIPChecksums
19810037SARM gem5 Developers        .name(name() + ".rxIPChecksums")
19910037SARM gem5 Developers        .desc("Number of rx IP Checksums done by device")
20010037SARM gem5 Developers        .precision(0)
20110037SARM gem5 Developers        .prereq(rxBytes)
20210037SARM gem5 Developers        ;
20310037SARM gem5 Developers
20410037SARM gem5 Developers    txTCPChecksums
20510037SARM gem5 Developers        .name(name() + ".txTCPChecksums")
20610037SARM gem5 Developers        .desc("Number of tx TCP Checksums done by device")
20710037SARM gem5 Developers        .precision(0)
20810037SARM gem5 Developers        .prereq(txBytes)
20910037SARM gem5 Developers        ;
21010037SARM gem5 Developers
21110037SARM gem5 Developers    rxTCPChecksums
21210037SARM gem5 Developers        .name(name() + ".rxTCPChecksums")
21310037SARM gem5 Developers        .desc("Number of rx TCP Checksums done by device")
21410037SARM gem5 Developers        .precision(0)
21510037SARM gem5 Developers        .prereq(rxBytes)
21610037SARM gem5 Developers        ;
21710420Sandreas.hansson@arm.com
21812616Sgabeblack@google.com    descDmaReads
21910037SARM gem5 Developers        .name(name() + ".descDMAReads")
22010037SARM gem5 Developers        .desc("Number of descriptors the device read w/ DMA")
22110037SARM gem5 Developers        .precision(0)
22210037SARM gem5 Developers        ;
22310184SCurtis.Dunham@arm.com
22410037SARM gem5 Developers    descDmaWrites
22510037SARM gem5 Developers        .name(name() + ".descDMAWrites")
22610420Sandreas.hansson@arm.com        .desc("Number of descriptors the device wrote w/ DMA")
22710037SARM gem5 Developers        .precision(0)
22810037SARM gem5 Developers        ;
22910037SARM gem5 Developers
23010037SARM gem5 Developers    descDmaRdBytes
23110037SARM gem5 Developers        .name(name() + ".descDmaReadBytes")
23210037SARM gem5 Developers        .desc("number of descriptor bytes read w/ DMA")
23310037SARM gem5 Developers        .precision(0)
23410037SARM gem5 Developers        ;
23510037SARM gem5 Developers
23610037SARM gem5 Developers   descDmaWrBytes
23710037SARM gem5 Developers        .name(name() + ".descDmaWriteBytes")
23810037SARM gem5 Developers        .desc("number of descriptor bytes write w/ DMA")
23910037SARM gem5 Developers        .precision(0)
2407306Sgblack@eecs.umich.edu        ;
2417306Sgblack@eecs.umich.edu
2427306Sgblack@eecs.umich.edu
2437306Sgblack@eecs.umich.edu    txBandwidth
2447306Sgblack@eecs.umich.edu        .name(name() + ".txBandwidth")
2457306Sgblack@eecs.umich.edu        .desc("Transmit Bandwidth (bits/s)")
2467330Sgblack@eecs.umich.edu        .precision(0)
24712616Sgabeblack@google.com        .prereq(txBytes)
2487306Sgblack@eecs.umich.edu        ;
2497306Sgblack@eecs.umich.edu
2507306Sgblack@eecs.umich.edu    rxBandwidth
2517306Sgblack@eecs.umich.edu        .name(name() + ".rxBandwidth")
25210184SCurtis.Dunham@arm.com        .desc("Receive Bandwidth (bits/s)")
2537306Sgblack@eecs.umich.edu        .precision(0)
2547306Sgblack@eecs.umich.edu        .prereq(rxBytes)
2557306Sgblack@eecs.umich.edu        ;
2567848SAli.Saidi@ARM.com
2577848SAli.Saidi@ARM.com    txPacketRate
2587848SAli.Saidi@ARM.com        .name(name() + ".txPPS")
2597848SAli.Saidi@ARM.com        .desc("Packet Tranmission Rate (packets/s)")
2607848SAli.Saidi@ARM.com        .precision(0)
2617306Sgblack@eecs.umich.edu        .prereq(txBytes)
2627306Sgblack@eecs.umich.edu        ;
2637306Sgblack@eecs.umich.edu
2647332Sgblack@eecs.umich.edu    rxPacketRate
2657332Sgblack@eecs.umich.edu        .name(name() + ".rxPPS")
2667332Sgblack@eecs.umich.edu        .desc("Packet Reception Rate (packets/s)")
2677332Sgblack@eecs.umich.edu        .precision(0)
2687332Sgblack@eecs.umich.edu        .prereq(rxBytes)
2697332Sgblack@eecs.umich.edu        ;
2707332Sgblack@eecs.umich.edu
27112616Sgabeblack@google.com    txBandwidth = txBytes * Stats::constant(8) / simSeconds;
2727332Sgblack@eecs.umich.edu    rxBandwidth = rxBytes * Stats::constant(8) / simSeconds;
2737332Sgblack@eecs.umich.edu    txPacketRate = txPackets / simSeconds;
2747332Sgblack@eecs.umich.edu    rxPacketRate = rxPackets / simSeconds;
2757332Sgblack@eecs.umich.edu}
27610184SCurtis.Dunham@arm.com
2777332Sgblack@eecs.umich.edu/**
2787332Sgblack@eecs.umich.edu * This is to read the PCI general configuration registers
2797332Sgblack@eecs.umich.edu */
2807332Sgblack@eecs.umich.eduvoid
2817848SAli.Saidi@ARM.comNSGigE::ReadConfig(int offset, int size, uint8_t *data)
2827848SAli.Saidi@ARM.com{
2837848SAli.Saidi@ARM.com    if (offset < PCI_DEVICE_SPECIFIC)
2847848SAli.Saidi@ARM.com        PciDev::ReadConfig(offset, size, data);
2857848SAli.Saidi@ARM.com    else
2867332Sgblack@eecs.umich.edu        panic("Device specific PCI config space not implemented!\n");
2877332Sgblack@eecs.umich.edu}
2887332Sgblack@eecs.umich.edu
2897261Sgblack@eecs.umich.edu/**
2907208Sgblack@eecs.umich.edu * This is to write to the PCI general configuration registers
2917208Sgblack@eecs.umich.edu */
2927208Sgblack@eecs.umich.eduvoid
2937208Sgblack@eecs.umich.eduNSGigE::WriteConfig(int offset, int size, uint32_t data)
2947208Sgblack@eecs.umich.edu{
2957208Sgblack@eecs.umich.edu    if (offset < PCI_DEVICE_SPECIFIC)
2967208Sgblack@eecs.umich.edu        PciDev::WriteConfig(offset, size, data);
29712616Sgabeblack@google.com    else
2987208Sgblack@eecs.umich.edu        panic("Device specific PCI config space not implemented!\n");
2997208Sgblack@eecs.umich.edu
3007208Sgblack@eecs.umich.edu    // Need to catch writes to BARs to update the PIO interface
3017261Sgblack@eecs.umich.edu    switch (offset) {
30210184SCurtis.Dunham@arm.com        //seems to work fine without all these PCI settings, but i put in the IO
3037208Sgblack@eecs.umich.edu        //to double check, an assertion will fail if we need to properly
3047208Sgblack@eecs.umich.edu        // implement it
3057208Sgblack@eecs.umich.edu      case PCI_COMMAND:
3067208Sgblack@eecs.umich.edu        if (config.data[offset] & PCI_CMD_IOSE)
3077848SAli.Saidi@ARM.com            ioEnable = true;
3087848SAli.Saidi@ARM.com        else
3097848SAli.Saidi@ARM.com            ioEnable = false;
3107848SAli.Saidi@ARM.com
3117848SAli.Saidi@ARM.com#if 0
3127208Sgblack@eecs.umich.edu        if (config.data[offset] & PCI_CMD_BME) {
3137208Sgblack@eecs.umich.edu            bmEnabled = true;
3147225Sgblack@eecs.umich.edu        }
3157233Sgblack@eecs.umich.edu        else {
3167233Sgblack@eecs.umich.edu            bmEnabled = false;
3177233Sgblack@eecs.umich.edu        }
3187233Sgblack@eecs.umich.edu
3197233Sgblack@eecs.umich.edu        if (config.data[offset] & PCI_CMD_MSE) {
3207233Sgblack@eecs.umich.edu            memEnable = true;
3217233Sgblack@eecs.umich.edu        }
3227233Sgblack@eecs.umich.edu        else {
3237330Sgblack@eecs.umich.edu            memEnable = false;
32412616Sgabeblack@google.com        }
3257233Sgblack@eecs.umich.edu#endif
3267233Sgblack@eecs.umich.edu        break;
3277233Sgblack@eecs.umich.edu
3287233Sgblack@eecs.umich.edu      case PCI0_BASE_ADDR0:
32910184SCurtis.Dunham@arm.com        if (BARAddrs[0] != 0) {
3307233Sgblack@eecs.umich.edu
3317233Sgblack@eecs.umich.edu            if (pioInterface)
3327233Sgblack@eecs.umich.edu                pioInterface->addAddrRange(BARAddrs[0], BARAddrs[0] + BARSize[0] - 1);
3337330Sgblack@eecs.umich.edu
3347233Sgblack@eecs.umich.edu            BARAddrs[0] &= PA_UNCACHED_MASK;
3357233Sgblack@eecs.umich.edu
3367233Sgblack@eecs.umich.edu        }
3377233Sgblack@eecs.umich.edu        break;
3387848SAli.Saidi@ARM.com      case PCI0_BASE_ADDR1:
3397848SAli.Saidi@ARM.com        if (BARAddrs[1] != 0) {
3407848SAli.Saidi@ARM.com
3417848SAli.Saidi@ARM.com            if (pioInterface)
3427848SAli.Saidi@ARM.com                pioInterface->addAddrRange(BARAddrs[1], BARAddrs[1] + BARSize[1] - 1);
3437233Sgblack@eecs.umich.edu
3447233Sgblack@eecs.umich.edu            BARAddrs[1] &= PA_UNCACHED_MASK;
3457233Sgblack@eecs.umich.edu
3467241Sgblack@eecs.umich.edu        }
3477241Sgblack@eecs.umich.edu        break;
3487241Sgblack@eecs.umich.edu    }
3497241Sgblack@eecs.umich.edu}
3507241Sgblack@eecs.umich.edu
3517241Sgblack@eecs.umich.edu/**
3527241Sgblack@eecs.umich.edu * This reads the device registers, which are detailed in the NS83820
3537241Sgblack@eecs.umich.edu * spec sheet
3547241Sgblack@eecs.umich.edu */
35512616Sgabeblack@google.comFault
3567241Sgblack@eecs.umich.eduNSGigE::read(MemReqPtr &req, uint8_t *data)
3577241Sgblack@eecs.umich.edu{
3587241Sgblack@eecs.umich.edu    assert(ioEnable);
3597241Sgblack@eecs.umich.edu
36010184SCurtis.Dunham@arm.com    //The mask is to give you only the offset into the device register file
3617241Sgblack@eecs.umich.edu    Addr daddr = req->paddr & 0xfff;
3627241Sgblack@eecs.umich.edu    DPRINTF(EthernetPIO, "read  da=%#x pa=%#x va=%#x size=%d\n",
3637241Sgblack@eecs.umich.edu            daddr, req->paddr, req->vaddr, req->size);
3647241Sgblack@eecs.umich.edu
3657241Sgblack@eecs.umich.edu
3667241Sgblack@eecs.umich.edu    //there are some reserved registers, you can see ns_gige_reg.h and
3677241Sgblack@eecs.umich.edu    //the spec sheet for details
3687241Sgblack@eecs.umich.edu    if (daddr > LAST && daddr <=  RESERVED) {
3697848SAli.Saidi@ARM.com        panic("Accessing reserved register");
3707848SAli.Saidi@ARM.com    } else if (daddr > RESERVED && daddr <= 0x3FC) {
3717848SAli.Saidi@ARM.com        ReadConfig(daddr & 0xff, req->size, data);
3727848SAli.Saidi@ARM.com        return No_Fault;
3737848SAli.Saidi@ARM.com    } else if (daddr >= MIB_START && daddr <= MIB_END) {
3747241Sgblack@eecs.umich.edu        // don't implement all the MIB's.  hopefully the kernel
3757241Sgblack@eecs.umich.edu        // doesn't actually DEPEND upon their values
3767241Sgblack@eecs.umich.edu        // MIB are just hardware stats keepers
3777238Sgblack@eecs.umich.edu        uint32_t &reg = *(uint32_t *) data;
3787238Sgblack@eecs.umich.edu        reg = 0;
3797238Sgblack@eecs.umich.edu        return No_Fault;
3807238Sgblack@eecs.umich.edu    } else if (daddr > 0x3FC)
3817238Sgblack@eecs.umich.edu        panic("Something is messed up!\n");
3827238Sgblack@eecs.umich.edu
3837238Sgblack@eecs.umich.edu    switch (req->size) {
3847238Sgblack@eecs.umich.edu      case sizeof(uint32_t):
38512616Sgabeblack@google.com        {
3867238Sgblack@eecs.umich.edu            uint32_t &reg = *(uint32_t *)data;
3877238Sgblack@eecs.umich.edu
3887238Sgblack@eecs.umich.edu            switch (daddr) {
3897238Sgblack@eecs.umich.edu              case CR:
39010184SCurtis.Dunham@arm.com                reg = regs.command;
3917238Sgblack@eecs.umich.edu                //these are supposed to be cleared on a read
3927238Sgblack@eecs.umich.edu                reg &= ~(CR_RXD | CR_TXD | CR_TXR | CR_RXR);
3937238Sgblack@eecs.umich.edu                break;
3947238Sgblack@eecs.umich.edu
3957238Sgblack@eecs.umich.edu              case CFG:
3967238Sgblack@eecs.umich.edu                reg = regs.config;
3977238Sgblack@eecs.umich.edu                break;
3987848SAli.Saidi@ARM.com
3997848SAli.Saidi@ARM.com              case MEAR:
4007848SAli.Saidi@ARM.com                reg = regs.mear;
4017848SAli.Saidi@ARM.com                break;
4027848SAli.Saidi@ARM.com
4037238Sgblack@eecs.umich.edu              case PTSCR:
4047238Sgblack@eecs.umich.edu                reg = regs.ptscr;
4057238Sgblack@eecs.umich.edu                break;
4067331Sgblack@eecs.umich.edu
4077331Sgblack@eecs.umich.edu              case ISR:
4087331Sgblack@eecs.umich.edu                reg = regs.isr;
4097331Sgblack@eecs.umich.edu                devIntrClear(ISR_ALL);
4107331Sgblack@eecs.umich.edu                break;
4117331Sgblack@eecs.umich.edu
4127331Sgblack@eecs.umich.edu              case IMR:
4137331Sgblack@eecs.umich.edu                reg = regs.imr;
4147331Sgblack@eecs.umich.edu                break;
41512616Sgabeblack@google.com
4167331Sgblack@eecs.umich.edu              case IER:
4177331Sgblack@eecs.umich.edu                reg = regs.ier;
4187331Sgblack@eecs.umich.edu                break;
4197331Sgblack@eecs.umich.edu
42010184SCurtis.Dunham@arm.com              case IHR:
4217331Sgblack@eecs.umich.edu                reg = regs.ihr;
4227331Sgblack@eecs.umich.edu                break;
4237331Sgblack@eecs.umich.edu
4247331Sgblack@eecs.umich.edu              case TXDP:
4257331Sgblack@eecs.umich.edu                reg = regs.txdp;
4267331Sgblack@eecs.umich.edu                break;
4277331Sgblack@eecs.umich.edu
4287848SAli.Saidi@ARM.com              case TXDP_HI:
4297848SAli.Saidi@ARM.com                reg = regs.txdp_hi;
4307848SAli.Saidi@ARM.com                break;
4317848SAli.Saidi@ARM.com
4327848SAli.Saidi@ARM.com              case TXCFG:
4337331Sgblack@eecs.umich.edu                reg = regs.txcfg;
4347331Sgblack@eecs.umich.edu                break;
4357331Sgblack@eecs.umich.edu
43610418Sandreas.hansson@arm.com              case GPIOR:
43710418Sandreas.hansson@arm.com                reg = regs.gpior;
43810418Sandreas.hansson@arm.com                break;
43910418Sandreas.hansson@arm.com
44010418Sandreas.hansson@arm.com              case RXDP:
44110418Sandreas.hansson@arm.com                reg = regs.rxdp;
44210418Sandreas.hansson@arm.com                break;
44310418Sandreas.hansson@arm.com
44410418Sandreas.hansson@arm.com              case RXDP_HI:
44512616Sgabeblack@google.com                reg = regs.rxdp_hi;
44610418Sandreas.hansson@arm.com                break;
44710418Sandreas.hansson@arm.com
44810418Sandreas.hansson@arm.com              case RXCFG:
44910418Sandreas.hansson@arm.com                reg = regs.rxcfg;
45010418Sandreas.hansson@arm.com                break;
45110418Sandreas.hansson@arm.com
45210418Sandreas.hansson@arm.com              case PQCR:
45310418Sandreas.hansson@arm.com                reg = regs.pqcr;
45410418Sandreas.hansson@arm.com                break;
45510418Sandreas.hansson@arm.com
45610418Sandreas.hansson@arm.com              case WCSR:
45710418Sandreas.hansson@arm.com                reg = regs.wcsr;
45810418Sandreas.hansson@arm.com                break;
45910418Sandreas.hansson@arm.com
46010418Sandreas.hansson@arm.com              case PCR:
46110418Sandreas.hansson@arm.com                reg = regs.pcr;
46210418Sandreas.hansson@arm.com                break;
46310418Sandreas.hansson@arm.com
46410418Sandreas.hansson@arm.com                //see the spec sheet for how RFCR and RFDR work
46510418Sandreas.hansson@arm.com                //basically, you write to RFCR to tell the machine what you want to do next
46610418Sandreas.hansson@arm.com                //then you act upon RFDR, and the device will be prepared b/c
46710418Sandreas.hansson@arm.com                //of what you wrote to RFCR
46810418Sandreas.hansson@arm.com              case RFCR:
46910418Sandreas.hansson@arm.com                reg = regs.rfcr;
47010418Sandreas.hansson@arm.com                break;
47110418Sandreas.hansson@arm.com
47210418Sandreas.hansson@arm.com              case RFDR:
47310418Sandreas.hansson@arm.com                switch (regs.rfcr & RFCR_RFADDR) {
47410418Sandreas.hansson@arm.com                  case 0x000:
47512616Sgabeblack@google.com                    reg = rom.perfectMatch[1];
47610418Sandreas.hansson@arm.com                    reg = reg << 8;
47710418Sandreas.hansson@arm.com                    reg += rom.perfectMatch[0];
47810418Sandreas.hansson@arm.com                    break;
47910418Sandreas.hansson@arm.com                  case 0x002:
48010418Sandreas.hansson@arm.com                    reg = rom.perfectMatch[3] << 8;
48110418Sandreas.hansson@arm.com                    reg += rom.perfectMatch[2];
48210418Sandreas.hansson@arm.com                    break;
48310418Sandreas.hansson@arm.com                  case 0x004:
48410418Sandreas.hansson@arm.com                    reg = rom.perfectMatch[5] << 8;
48510418Sandreas.hansson@arm.com                    reg += rom.perfectMatch[4];
48610418Sandreas.hansson@arm.com                    break;
48710418Sandreas.hansson@arm.com                  default:
48810418Sandreas.hansson@arm.com                    panic("reading from RFDR for something for other than PMATCH!\n");
48910418Sandreas.hansson@arm.com                    //didn't implement other RFDR functionality b/c driver didn't use
49010418Sandreas.hansson@arm.com                }
49110418Sandreas.hansson@arm.com                break;
49210418Sandreas.hansson@arm.com
49310418Sandreas.hansson@arm.com              case SRR:
49410418Sandreas.hansson@arm.com                reg = regs.srr;
49510418Sandreas.hansson@arm.com                break;
49610037SARM gem5 Developers
49710037SARM gem5 Developers              case MIBC:
49810037SARM gem5 Developers                reg = regs.mibc;
49910037SARM gem5 Developers                reg &= ~(MIBC_MIBS | MIBC_ACLR);
50010037SARM gem5 Developers                break;
50110037SARM gem5 Developers
50210037SARM gem5 Developers              case VRCR:
50310037SARM gem5 Developers                reg = regs.vrcr;
50412616Sgabeblack@google.com                break;
50510037SARM gem5 Developers
50610037SARM gem5 Developers              case VTCR:
50710037SARM gem5 Developers                reg = regs.vtcr;
50810037SARM gem5 Developers                break;
50910184SCurtis.Dunham@arm.com
51010037SARM gem5 Developers              case VDR:
51110037SARM gem5 Developers                reg = regs.vdr;
51210037SARM gem5 Developers                break;
51310037SARM gem5 Developers
51410037SARM gem5 Developers              case CCSR:
51510037SARM gem5 Developers                reg = regs.ccsr;
51610037SARM gem5 Developers                break;
51710037SARM gem5 Developers
51810037SARM gem5 Developers              case TBICR:
51910037SARM gem5 Developers                reg = regs.tbicr;
52010037SARM gem5 Developers                break;
52110037SARM gem5 Developers
52210037SARM gem5 Developers              case TBISR:
52310037SARM gem5 Developers                reg = regs.tbisr;
52410037SARM gem5 Developers                break;
5257253Sgblack@eecs.umich.edu
5267253Sgblack@eecs.umich.edu              case TANAR:
5277253Sgblack@eecs.umich.edu                reg = regs.tanar;
5287253Sgblack@eecs.umich.edu                break;
5297253Sgblack@eecs.umich.edu
5307253Sgblack@eecs.umich.edu              case TANLPAR:
5317253Sgblack@eecs.umich.edu                reg = regs.tanlpar;
5327253Sgblack@eecs.umich.edu                break;
5337330Sgblack@eecs.umich.edu
53412616Sgabeblack@google.com              case TANER:
5357253Sgblack@eecs.umich.edu                reg = regs.taner;
5367253Sgblack@eecs.umich.edu                break;
5377253Sgblack@eecs.umich.edu
5387253Sgblack@eecs.umich.edu              case TESR:
53910184SCurtis.Dunham@arm.com                reg = regs.tesr;
5407253Sgblack@eecs.umich.edu                break;
5417253Sgblack@eecs.umich.edu
5427330Sgblack@eecs.umich.edu              default:
5437330Sgblack@eecs.umich.edu                panic("reading unimplemented register: addr = %#x", daddr);
5447253Sgblack@eecs.umich.edu            }
5457253Sgblack@eecs.umich.edu
5467253Sgblack@eecs.umich.edu            DPRINTF(EthernetPIO, "read from %#x: data=%d data=%#x\n",
5477253Sgblack@eecs.umich.edu                    daddr, reg, reg);
5487848SAli.Saidi@ARM.com        }
5497848SAli.Saidi@ARM.com        break;
5507848SAli.Saidi@ARM.com
5517848SAli.Saidi@ARM.com      default:
5527848SAli.Saidi@ARM.com        panic("accessing register with invalid size: addr=%#x, size=%d",
5537253Sgblack@eecs.umich.edu              daddr, req->size);
5547253Sgblack@eecs.umich.edu    }
5557253Sgblack@eecs.umich.edu
5567232Sgblack@eecs.umich.edu    return No_Fault;
5577225Sgblack@eecs.umich.edu}
5587225Sgblack@eecs.umich.edu
5597225Sgblack@eecs.umich.eduFault
5607225Sgblack@eecs.umich.eduNSGigE::write(MemReqPtr &req, const uint8_t *data)
5617225Sgblack@eecs.umich.edu{
5627225Sgblack@eecs.umich.edu    assert(ioEnable);
5637330Sgblack@eecs.umich.edu
56412616Sgabeblack@google.com    Addr daddr = req->paddr & 0xfff;
5657225Sgblack@eecs.umich.edu    DPRINTF(EthernetPIO, "write da=%#x pa=%#x va=%#x size=%d\n",
5667225Sgblack@eecs.umich.edu            daddr, req->paddr, req->vaddr, req->size);
5677225Sgblack@eecs.umich.edu
5687232Sgblack@eecs.umich.edu    if (daddr > LAST && daddr <=  RESERVED) {
56910184SCurtis.Dunham@arm.com        panic("Accessing reserved register");
5707225Sgblack@eecs.umich.edu    } else if (daddr > RESERVED && daddr <= 0x3FC) {
5717330Sgblack@eecs.umich.edu        WriteConfig(daddr & 0xff, req->size, *(uint32_t *)data);
5727225Sgblack@eecs.umich.edu        return No_Fault;
5737225Sgblack@eecs.umich.edu    } else if (daddr > 0x3FC)
5747232Sgblack@eecs.umich.edu        panic("Something is messed up!\n");
5757225Sgblack@eecs.umich.edu
5767225Sgblack@eecs.umich.edu    if (req->size == sizeof(uint32_t)) {
5777848SAli.Saidi@ARM.com        uint32_t reg = *(uint32_t *)data;
5787848SAli.Saidi@ARM.com        DPRINTF(EthernetPIO, "write data=%d data=%#x\n", reg, reg);
5797848SAli.Saidi@ARM.com
5807848SAli.Saidi@ARM.com        switch (daddr) {
5817848SAli.Saidi@ARM.com          case CR:
5827225Sgblack@eecs.umich.edu            regs.command = reg;
5837225Sgblack@eecs.umich.edu            if ((reg & (CR_TXE | CR_TXD)) == (CR_TXE | CR_TXD)) {
5847225Sgblack@eecs.umich.edu                txHalt = true;
5857232Sgblack@eecs.umich.edu            } else if (reg & CR_TXE) {
5867225Sgblack@eecs.umich.edu                //the kernel is enabling the transmit machine
5877225Sgblack@eecs.umich.edu                if (txState == txIdle)
5887225Sgblack@eecs.umich.edu                    txKick();
5897225Sgblack@eecs.umich.edu            } else if (reg & CR_TXD) {
5907225Sgblack@eecs.umich.edu                txHalt = true;
5917225Sgblack@eecs.umich.edu            }
5927330Sgblack@eecs.umich.edu
5937225Sgblack@eecs.umich.edu            if ((reg & (CR_RXE | CR_RXD)) == (CR_RXE | CR_RXD)) {
59412616Sgabeblack@google.com                rxHalt = true;
5957225Sgblack@eecs.umich.edu            } else if (reg & CR_RXE) {
5967225Sgblack@eecs.umich.edu                if (rxState == rxIdle) {
5977225Sgblack@eecs.umich.edu                    rxKick();
5987232Sgblack@eecs.umich.edu                }
59910184SCurtis.Dunham@arm.com            } else if (reg & CR_RXD) {
6007225Sgblack@eecs.umich.edu                rxHalt = true;
6017330Sgblack@eecs.umich.edu            }
6027225Sgblack@eecs.umich.edu
6037225Sgblack@eecs.umich.edu            if (reg & CR_TXR)
6047225Sgblack@eecs.umich.edu                txReset();
6057225Sgblack@eecs.umich.edu
6067232Sgblack@eecs.umich.edu            if (reg & CR_RXR)
6077225Sgblack@eecs.umich.edu                rxReset();
6087225Sgblack@eecs.umich.edu
6097848SAli.Saidi@ARM.com            if (reg & CR_SWI)
6107848SAli.Saidi@ARM.com                devIntrPost(ISR_SWI);
6117848SAli.Saidi@ARM.com
6127848SAli.Saidi@ARM.com            if (reg & CR_RST) {
6137848SAli.Saidi@ARM.com                txReset();
6147225Sgblack@eecs.umich.edu                rxReset();
6157225Sgblack@eecs.umich.edu
6167609SGene.Wu@arm.com                regsReset();
61712358Snikos.nikoleris@arm.com            }
61812358Snikos.nikoleris@arm.com            break;
61912358Snikos.nikoleris@arm.com
62012358Snikos.nikoleris@arm.com          case CFG:
62112358Snikos.nikoleris@arm.com            if (reg & CFG_LNKSTS || reg & CFG_SPDSTS || reg & CFG_DUPSTS
62212358Snikos.nikoleris@arm.com                || reg & CFG_RESERVED || reg & CFG_T64ADDR
62312358Snikos.nikoleris@arm.com                || reg & CFG_PCI64_DET)
62412358Snikos.nikoleris@arm.com                panic("writing to read-only or reserved CFG bits!\n");
62512358Snikos.nikoleris@arm.com
62612616Sgabeblack@google.com            regs.config |= reg & ~(CFG_LNKSTS | CFG_SPDSTS | CFG_DUPSTS | CFG_RESERVED |
62712616Sgabeblack@google.com                                  CFG_T64ADDR | CFG_PCI64_DET);
62812616Sgabeblack@google.com
62912616Sgabeblack@google.com// all these #if 0's are because i don't THINK the kernel needs to have these implemented
63012358Snikos.nikoleris@arm.com// if there is a problem relating to one of these, you may need to add functionality in
63112358Snikos.nikoleris@arm.com#if 0
63212358Snikos.nikoleris@arm.com              if (reg & CFG_TBI_EN) ;
63312358Snikos.nikoleris@arm.com              if (reg & CFG_MODE_1000) ;
63412358Snikos.nikoleris@arm.com#endif
63512358Snikos.nikoleris@arm.com
63612358Snikos.nikoleris@arm.com            if (reg & CFG_AUTO_1000)
63712358Snikos.nikoleris@arm.com                panic("CFG_AUTO_1000 not implemented!\n");
63812358Snikos.nikoleris@arm.com
63912358Snikos.nikoleris@arm.com#if 0
64012358Snikos.nikoleris@arm.com            if (reg & CFG_PINT_DUPSTS || reg & CFG_PINT_LNKSTS || reg & CFG_PINT_SPDSTS) ;
64112358Snikos.nikoleris@arm.com            if (reg & CFG_TMRTEST) ;
64212358Snikos.nikoleris@arm.com            if (reg & CFG_MRM_DIS) ;
64312358Snikos.nikoleris@arm.com            if (reg & CFG_MWI_DIS) ;
64412358Snikos.nikoleris@arm.com
64512358Snikos.nikoleris@arm.com            if (reg & CFG_T64ADDR)
64612358Snikos.nikoleris@arm.com                panic("CFG_T64ADDR is read only register!\n");
64712358Snikos.nikoleris@arm.com
64812358Snikos.nikoleris@arm.com            if (reg & CFG_PCI64_DET)
64912358Snikos.nikoleris@arm.com                panic("CFG_PCI64_DET is read only register!\n");
65012503Snikos.nikoleris@arm.com
65112503Snikos.nikoleris@arm.com            if (reg & CFG_DATA64_EN) ;
65212503Snikos.nikoleris@arm.com            if (reg & CFG_M64ADDR) ;
65312358Snikos.nikoleris@arm.com            if (reg & CFG_PHY_RST) ;
65412358Snikos.nikoleris@arm.com            if (reg & CFG_PHY_DIS) ;
65512358Snikos.nikoleris@arm.com#endif
65612358Snikos.nikoleris@arm.com
65712358Snikos.nikoleris@arm.com            if (reg & CFG_EXTSTS_EN)
65812358Snikos.nikoleris@arm.com                extstsEnable = true;
65912358Snikos.nikoleris@arm.com            else
66012358Snikos.nikoleris@arm.com                extstsEnable = false;
66112358Snikos.nikoleris@arm.com
66212358Snikos.nikoleris@arm.com#if 0
66312358Snikos.nikoleris@arm.com              if (reg & CFG_REQALG) ;
66412358Snikos.nikoleris@arm.com              if (reg & CFG_SB) ;
66512358Snikos.nikoleris@arm.com              if (reg & CFG_POW) ;
66612358Snikos.nikoleris@arm.com              if (reg & CFG_EXD) ;
66712358Snikos.nikoleris@arm.com              if (reg & CFG_PESEL) ;
66812358Snikos.nikoleris@arm.com              if (reg & CFG_BROM_DIS) ;
66912358Snikos.nikoleris@arm.com              if (reg & CFG_EXT_125) ;
67012358Snikos.nikoleris@arm.com              if (reg & CFG_BEM) ;
67112358Snikos.nikoleris@arm.com#endif
67212358Snikos.nikoleris@arm.com            break;
67312358Snikos.nikoleris@arm.com
67412358Snikos.nikoleris@arm.com          case MEAR:
67512358Snikos.nikoleris@arm.com            regs.mear = reg;
67612358Snikos.nikoleris@arm.com            /* since phy is completely faked, MEAR_MD* don't matter
67712358Snikos.nikoleris@arm.com               and since the driver never uses MEAR_EE*, they don't matter */
67812358Snikos.nikoleris@arm.com#if 0
67912503Snikos.nikoleris@arm.com            if (reg & MEAR_EEDI) ;
68012503Snikos.nikoleris@arm.com            if (reg & MEAR_EEDO) ; //this one is read only
68112503Snikos.nikoleris@arm.com            if (reg & MEAR_EECLK) ;
68212358Snikos.nikoleris@arm.com            if (reg & MEAR_EESEL) ;
68312358Snikos.nikoleris@arm.com            if (reg & MEAR_MDIO) ;
68412358Snikos.nikoleris@arm.com            if (reg & MEAR_MDDIR) ;
68512358Snikos.nikoleris@arm.com            if (reg & MEAR_MDC) ;
68612358Snikos.nikoleris@arm.com#endif
68712358Snikos.nikoleris@arm.com            break;
68812358Snikos.nikoleris@arm.com
68912358Snikos.nikoleris@arm.com          case PTSCR:
69012358Snikos.nikoleris@arm.com            regs.ptscr = reg & ~(PTSCR_RBIST_RDONLY);
69112358Snikos.nikoleris@arm.com            /* these control BISTs for various parts of chip - we don't care or do
69212358Snikos.nikoleris@arm.com               just fake that the BIST is done */
69312358Snikos.nikoleris@arm.com            if (reg & PTSCR_RBIST_EN)
69412358Snikos.nikoleris@arm.com                regs.ptscr |= PTSCR_RBIST_DONE;
69512358Snikos.nikoleris@arm.com            if (reg & PTSCR_EEBIST_EN)
69612358Snikos.nikoleris@arm.com                regs.ptscr &= ~PTSCR_EEBIST_EN;
69712358Snikos.nikoleris@arm.com            if (reg & PTSCR_EELOAD_EN)
69812358Snikos.nikoleris@arm.com                regs.ptscr &= ~PTSCR_EELOAD_EN;
699            break;
700
701          case ISR: /* writing to the ISR has no effect */
702            panic("ISR is a read only register!\n");
703
704          case IMR:
705            regs.imr = reg;
706            devIntrChangeMask();
707            break;
708
709          case IER:
710            regs.ier = reg;
711            break;
712
713          case IHR:
714            regs.ihr = reg;
715            /* not going to implement real interrupt holdoff */
716            break;
717
718          case TXDP:
719            regs.txdp = (reg & 0xFFFFFFFC);
720            assert(txState == txIdle);
721            CTDD = false;
722            break;
723
724          case TXDP_HI:
725            regs.txdp_hi = reg;
726            break;
727
728          case TXCFG:
729            regs.txcfg = reg;
730#if 0
731            if (reg & TXCFG_CSI) ;
732            if (reg & TXCFG_HBI) ;
733            if (reg & TXCFG_MLB) ;
734            if (reg & TXCFG_ATP) ;
735            if (reg & TXCFG_ECRETRY) ;  /* this could easily be implemented, but
736                                           considering the network is just a fake
737                                           pipe, wouldn't make sense to do this */
738
739            if (reg & TXCFG_BRST_DIS) ;
740#endif
741
742
743            /* we handle our own DMA, ignore the kernel's exhortations */
744            //if (reg & TXCFG_MXDMA) ;
745
746            //also, we currently don't care about fill/drain thresholds
747            //though this may change in the future with more realistic
748            //networks or a driver which changes it according to feedback
749
750            break;
751
752          case GPIOR:
753            regs.gpior = reg;
754            /* these just control general purpose i/o pins, don't matter */
755            break;
756
757          case RXDP:
758            regs.rxdp = reg;
759            break;
760
761          case RXDP_HI:
762            regs.rxdp_hi = reg;
763            break;
764
765          case RXCFG:
766            regs.rxcfg = reg;
767#if 0
768            if (reg & RXCFG_AEP) ;
769            if (reg & RXCFG_ARP) ;
770            if (reg & RXCFG_STRIPCRC) ;
771            if (reg & RXCFG_RX_RD) ;
772            if (reg & RXCFG_ALP) ;
773            if (reg & RXCFG_AIRL) ;
774#endif
775
776            /* we handle our own DMA, ignore what kernel says about it */
777            //if (reg & RXCFG_MXDMA) ;
778
779#if 0
780            //also, we currently don't care about fill/drain thresholds
781            //though this may change in the future with more realistic
782            //networks or a driver which changes it according to feedback
783            if (reg & (RXCFG_DRTH | RXCFG_DRTH0)) ;
784#endif
785            break;
786
787          case PQCR:
788            /* there is no priority queueing used in the linux 2.6 driver */
789            regs.pqcr = reg;
790            break;
791
792          case WCSR:
793            /* not going to implement wake on LAN */
794            regs.wcsr = reg;
795            break;
796
797          case PCR:
798            /* not going to implement pause control */
799            regs.pcr = reg;
800            break;
801
802          case RFCR:
803            regs.rfcr = reg;
804
805            rxFilterEnable = (reg & RFCR_RFEN) ? true : false;
806            acceptBroadcast = (reg & RFCR_AAB) ? true : false;
807            acceptMulticast = (reg & RFCR_AAM) ? true : false;
808            acceptUnicast = (reg & RFCR_AAU) ? true : false;
809            acceptPerfect = (reg & RFCR_APM) ? true : false;
810            acceptArp = (reg & RFCR_AARP) ? true : false;
811
812            if (reg & RFCR_APAT) ;
813//                panic("RFCR_APAT not implemented!\n");
814
815            if (reg & RFCR_MHEN || reg & RFCR_UHEN)
816                panic("hash filtering not implemented!\n");
817
818            if (reg & RFCR_ULM)
819                panic("RFCR_ULM not implemented!\n");
820
821            break;
822
823          case RFDR:
824            panic("the driver never writes to RFDR, something is wrong!\n");
825
826          case BRAR:
827            panic("the driver never uses BRAR, something is wrong!\n");
828
829          case BRDR:
830            panic("the driver never uses BRDR, something is wrong!\n");
831
832          case SRR:
833            panic("SRR is read only register!\n");
834
835          case MIBC:
836            panic("the driver never uses MIBC, something is wrong!\n");
837
838          case VRCR:
839            regs.vrcr = reg;
840            break;
841
842          case VTCR:
843            regs.vtcr = reg;
844            break;
845
846          case VDR:
847            panic("the driver never uses VDR, something is wrong!\n");
848            break;
849
850          case CCSR:
851            /* not going to implement clockrun stuff */
852            regs.ccsr = reg;
853            break;
854
855          case TBICR:
856            regs.tbicr = reg;
857            if (reg & TBICR_MR_LOOPBACK)
858                panic("TBICR_MR_LOOPBACK never used, something wrong!\n");
859
860            if (reg & TBICR_MR_AN_ENABLE) {
861                regs.tanlpar = regs.tanar;
862                regs.tbisr |= (TBISR_MR_AN_COMPLETE | TBISR_MR_LINK_STATUS);
863            }
864
865#if 0
866            if (reg & TBICR_MR_RESTART_AN) ;
867#endif
868
869            break;
870
871          case TBISR:
872            panic("TBISR is read only register!\n");
873
874          case TANAR:
875            regs.tanar = reg;
876            if (reg & TANAR_PS2)
877                panic("this isn't used in driver, something wrong!\n");
878
879            if (reg & TANAR_PS1)
880                panic("this isn't used in driver, something wrong!\n");
881            break;
882
883          case TANLPAR:
884            panic("this should only be written to by the fake phy!\n");
885
886          case TANER:
887            panic("TANER is read only register!\n");
888
889          case TESR:
890            regs.tesr = reg;
891            break;
892
893          default:
894            panic("thought i covered all the register, what is this? addr=%#x",
895                  daddr);
896        }
897    } else
898        panic("Invalid Request Size");
899
900    return No_Fault;
901}
902
903void
904NSGigE::devIntrPost(uint32_t interrupts)
905{
906    bool delay = false;
907
908    if (interrupts & ISR_RESERVE)
909        panic("Cannot set a reserved interrupt");
910
911    if (interrupts & ISR_TXRCMP)
912        regs.isr |= ISR_TXRCMP;
913
914    if (interrupts & ISR_RXRCMP)
915        regs.isr |= ISR_RXRCMP;
916
917//ISR_DPERR  not implemented
918//ISR_SSERR not implemented
919//ISR_RMABT not implemented
920//ISR_RXSOVR not implemented
921//ISR_HIBINT not implemented
922//ISR_PHY not implemented
923//ISR_PME not implemented
924
925    if (interrupts & ISR_SWI)
926        regs.isr |= ISR_SWI;
927
928//ISR_MIB not implemented
929//ISR_TXURN not implemented
930
931    if (interrupts & ISR_TXIDLE)
932        regs.isr |= ISR_TXIDLE;
933
934    if (interrupts & ISR_TXERR)
935        regs.isr |= ISR_TXERR;
936
937    if (interrupts & ISR_TXDESC)
938        regs.isr |= ISR_TXDESC;
939
940    if (interrupts & ISR_TXOK) {
941        regs.isr |= ISR_TXOK;
942        delay = true;
943    }
944
945    if (interrupts & ISR_RXORN)
946        regs.isr |= ISR_RXORN;
947
948    if (interrupts & ISR_RXIDLE)
949        regs.isr |= ISR_RXIDLE;
950
951//ISR_RXEARLY not implemented
952
953    if (interrupts & ISR_RXERR)
954        regs.isr |= ISR_RXERR;
955
956    if (interrupts & ISR_RXDESC)
957        regs.isr |= ISR_RXDESC;
958
959    if (interrupts & ISR_RXOK) {
960        delay = true;
961        regs.isr |= ISR_RXOK;
962    }
963
964    if ((regs.isr & regs.imr)) {
965        Tick when = curTick;
966        if (delay)
967            when += intrDelay;
968        cpuIntrPost(when);
969    }
970
971    DPRINTF(EthernetIntr, "**interrupt written to ISR: intr=%#x isr=%#x imr=%#x\n",
972            interrupts, regs.isr, regs.imr);
973}
974
975void
976NSGigE::devIntrClear(uint32_t interrupts)
977{
978    if (interrupts & ISR_RESERVE)
979        panic("Cannot clear a reserved interrupt");
980
981    if (interrupts & ISR_TXRCMP)
982        regs.isr &= ~ISR_TXRCMP;
983
984    if (interrupts & ISR_RXRCMP)
985        regs.isr &= ~ISR_RXRCMP;
986
987//ISR_DPERR  not implemented
988//ISR_SSERR not implemented
989//ISR_RMABT not implemented
990//ISR_RXSOVR not implemented
991//ISR_HIBINT not implemented
992//ISR_PHY not implemented
993//ISR_PME not implemented
994
995    if (interrupts & ISR_SWI)
996        regs.isr &= ~ISR_SWI;
997
998//ISR_MIB not implemented
999//ISR_TXURN not implemented
1000
1001    if (interrupts & ISR_TXIDLE)
1002        regs.isr &= ~ISR_TXIDLE;
1003
1004    if (interrupts & ISR_TXERR)
1005        regs.isr &= ~ISR_TXERR;
1006
1007    if (interrupts & ISR_TXDESC)
1008        regs.isr &= ~ISR_TXDESC;
1009
1010    if (interrupts & ISR_TXOK)
1011        regs.isr &= ~ISR_TXOK;
1012
1013    if (interrupts & ISR_RXORN)
1014        regs.isr &= ~ISR_RXORN;
1015
1016    if (interrupts & ISR_RXIDLE)
1017        regs.isr &= ~ISR_RXIDLE;
1018
1019//ISR_RXEARLY not implemented
1020
1021    if (interrupts & ISR_RXERR)
1022        regs.isr &= ~ISR_RXERR;
1023
1024    if (interrupts & ISR_RXDESC)
1025        regs.isr &= ~ISR_RXDESC;
1026
1027    if (interrupts & ISR_RXOK)
1028        regs.isr &= ~ISR_RXOK;
1029
1030    if (!(regs.isr & regs.imr))
1031        cpuIntrClear();
1032
1033    DPRINTF(EthernetIntr, "**interrupt cleared from ISR: intr=%x isr=%x imr=%x\n",
1034            interrupts, regs.isr, regs.imr);
1035}
1036
1037void
1038NSGigE::devIntrChangeMask()
1039{
1040    DPRINTF(EthernetIntr, "interrupt mask changed\n");
1041
1042    if (regs.isr & regs.imr)
1043        cpuIntrPost(curTick);
1044    else
1045        cpuIntrClear();
1046}
1047
1048void
1049NSGigE::cpuIntrPost(Tick when)
1050{
1051    //If the interrupt you want to post is later than an
1052    //interrupt already scheduled, just let it post in the coming one and
1053    //don't schedule another.
1054    //HOWEVER, must be sure that the scheduled intrTick is in the future
1055    //(this was formerly the source of a bug)
1056    assert((intrTick >= curTick) || (intrTick == 0));
1057    if (when > intrTick && intrTick != 0)
1058        return;
1059
1060    intrTick = when;
1061
1062    if (intrEvent) {
1063        intrEvent->squash();
1064        intrEvent = 0;
1065    }
1066
1067    if (when < curTick) {
1068        cpuInterrupt();
1069    } else {
1070        DPRINTF(EthernetIntr, "going to schedule an interrupt for intrTick=%d\n",
1071                intrTick);
1072        intrEvent = new IntrEvent(this, true);
1073        intrEvent->schedule(intrTick);
1074    }
1075}
1076
1077void
1078NSGigE::cpuInterrupt()
1079{
1080    // Don't send an interrupt if there's already one
1081    if (cpuPendingIntr) {
1082        DPRINTF(EthernetIntr,
1083                "would send an interrupt now, but there's already pending\n");
1084        intrTick = 0;
1085        return;
1086    }
1087    // Don't send an interrupt if it's supposed to be delayed
1088    if (intrTick > curTick) {
1089        DPRINTF(EthernetIntr, "an interrupt is scheduled for %d, wait til then\n",
1090                intrTick);
1091        return;
1092    }
1093
1094    // Whether or not there's a pending interrupt, we don't care about
1095    // it anymore
1096    intrEvent = 0;
1097    intrTick = 0;
1098
1099    // Send interrupt
1100    cpuPendingIntr = true;
1101    /** @todo rework the intctrl to be tsunami ok */
1102    //intctrl->post(TheISA::INTLEVEL_IRQ1, TheISA::INTINDEX_ETHERNET);
1103    DPRINTF(EthernetIntr, "Posting interrupts to cchip!\n");
1104    tsunami->cchip->postDRIR(configData->config.hdr.pci0.interruptLine);
1105}
1106
1107void
1108NSGigE::cpuIntrClear()
1109{
1110    if (cpuPendingIntr) {
1111        cpuPendingIntr = false;
1112        /** @todo rework the intctrl to be tsunami ok */
1113        //intctrl->clear(TheISA::INTLEVEL_IRQ1, TheISA::INTINDEX_ETHERNET);
1114        DPRINTF(EthernetIntr, "clearing all interrupts from cchip\n");
1115        tsunami->cchip->clearDRIR(configData->config.hdr.pci0.interruptLine);
1116    }
1117}
1118
1119bool
1120NSGigE::cpuIntrPending() const
1121{ return cpuPendingIntr; }
1122
1123void
1124NSGigE::txReset()
1125{
1126
1127    DPRINTF(Ethernet, "transmit reset\n");
1128
1129    CTDD = false;
1130    txFifoAvail = MAX_TX_FIFO_SIZE;
1131    txHalt = false;
1132    txFragPtr = 0;
1133    assert(txDescCnt == 0);
1134    txFifo.clear();
1135    regs.command &= ~CR_TXE;
1136    txState = txIdle;
1137    assert(txDmaState == dmaIdle);
1138}
1139
1140void
1141NSGigE::rxReset()
1142{
1143    DPRINTF(Ethernet, "receive reset\n");
1144
1145    CRDD = false;
1146    assert(rxPktBytes == 0);
1147    rxFifoCnt = 0;
1148    rxHalt = false;
1149    rxFragPtr = 0;
1150    assert(rxDescCnt == 0);
1151    assert(rxDmaState == dmaIdle);
1152    rxFifo.clear();
1153    regs.command &= ~CR_RXE;
1154    rxState = rxIdle;
1155}
1156
1157void NSGigE::regsReset()
1158{
1159    memset(&regs, 0, sizeof(regs));
1160    regs.config = 0x80000000;
1161    regs.mear = 0x12;
1162    regs.isr = 0x00608000;
1163    regs.txcfg = 0x120;
1164    regs.rxcfg = 0x4;
1165    regs.srr = 0x0103;
1166    regs.mibc = 0x2;
1167    regs.vdr = 0x81;
1168    regs.tesr = 0xc000;
1169
1170    extstsEnable = false;
1171    acceptBroadcast = false;
1172    acceptMulticast = false;
1173    acceptUnicast = false;
1174    acceptPerfect = false;
1175    acceptArp = false;
1176}
1177
1178void
1179NSGigE::rxDmaReadCopy()
1180{
1181    assert(rxDmaState == dmaReading);
1182
1183    memcpy(rxDmaData, physmem->dma_addr(rxDmaAddr, rxDmaLen), rxDmaLen);
1184    rxDmaState = dmaIdle;
1185
1186    DPRINTF(EthernetDMA, "rx dma read  paddr=%#x len=%d\n",
1187            rxDmaAddr, rxDmaLen);
1188    DDUMP(EthernetDMA, rxDmaData, rxDmaLen);
1189}
1190
1191bool
1192NSGigE::doRxDmaRead()
1193{
1194    assert(rxDmaState == dmaIdle || rxDmaState == dmaReadWaiting);
1195    rxDmaState = dmaReading;
1196
1197    if (dmaInterface && !rxDmaFree) {
1198        if (dmaInterface->busy())
1199            rxDmaState = dmaReadWaiting;
1200        else
1201            dmaInterface->doDMA(Read, rxDmaAddr, rxDmaLen, curTick,
1202                                &rxDmaReadEvent, true);
1203        return true;
1204    }
1205
1206    if (dmaReadDelay == 0 && dmaReadFactor == 0) {
1207        rxDmaReadCopy();
1208        return false;
1209    }
1210
1211    Tick factor = ((rxDmaLen + ULL(63)) >> ULL(6)) * dmaReadFactor;
1212    Tick start = curTick + dmaReadDelay + factor;
1213    rxDmaReadEvent.schedule(start);
1214    return true;
1215}
1216
1217void
1218NSGigE::rxDmaReadDone()
1219{
1220    assert(rxDmaState == dmaReading);
1221    rxDmaReadCopy();
1222
1223    // If the transmit state machine has a pending DMA, let it go first
1224    if (txDmaState == dmaReadWaiting || txDmaState == dmaWriteWaiting)
1225        txKick();
1226
1227    rxKick();
1228}
1229
1230void
1231NSGigE::rxDmaWriteCopy()
1232{
1233    assert(rxDmaState == dmaWriting);
1234
1235    memcpy(physmem->dma_addr(rxDmaAddr, rxDmaLen), rxDmaData, rxDmaLen);
1236    rxDmaState = dmaIdle;
1237
1238    DPRINTF(EthernetDMA, "rx dma write paddr=%#x len=%d\n",
1239            rxDmaAddr, rxDmaLen);
1240    DDUMP(EthernetDMA, rxDmaData, rxDmaLen);
1241}
1242
1243bool
1244NSGigE::doRxDmaWrite()
1245{
1246    assert(rxDmaState == dmaIdle || rxDmaState == dmaWriteWaiting);
1247    rxDmaState = dmaWriting;
1248
1249    if (dmaInterface && !rxDmaFree) {
1250        if (dmaInterface->busy())
1251            rxDmaState = dmaWriteWaiting;
1252        else
1253            dmaInterface->doDMA(WriteInvalidate, rxDmaAddr, rxDmaLen, curTick,
1254                                &rxDmaWriteEvent, true);
1255        return true;
1256    }
1257
1258    if (dmaWriteDelay == 0 && dmaWriteFactor == 0) {
1259        rxDmaWriteCopy();
1260        return false;
1261    }
1262
1263    Tick factor = ((rxDmaLen + ULL(63)) >> ULL(6)) * dmaWriteFactor;
1264    Tick start = curTick + dmaWriteDelay + factor;
1265    rxDmaWriteEvent.schedule(start);
1266    return true;
1267}
1268
1269void
1270NSGigE::rxDmaWriteDone()
1271{
1272    assert(rxDmaState == dmaWriting);
1273    rxDmaWriteCopy();
1274
1275    // If the transmit state machine has a pending DMA, let it go first
1276    if (txDmaState == dmaReadWaiting || txDmaState == dmaWriteWaiting)
1277        txKick();
1278
1279    rxKick();
1280}
1281
1282void
1283NSGigE::rxKick()
1284{
1285    DPRINTF(EthernetSM, "receive kick state=%s (rxBuf.size=%d)\n",
1286            NsRxStateStrings[rxState], rxFifo.size());
1287
1288    if (rxKickTick > curTick) {
1289        DPRINTF(EthernetSM, "receive kick exiting, can't run till %d\n",
1290                rxKickTick);
1291        return;
1292    }
1293
1294  next:
1295    switch(rxDmaState) {
1296      case dmaReadWaiting:
1297        if (doRxDmaRead())
1298            goto exit;
1299        break;
1300      case dmaWriteWaiting:
1301        if (doRxDmaWrite())
1302            goto exit;
1303        break;
1304      default:
1305        break;
1306    }
1307
1308    // see state machine from spec for details
1309    // the way this works is, if you finish work on one state and can go directly to
1310    // another, you do that through jumping to the label "next".  however, if you have
1311    // intermediate work, like DMA so that you can't go to the next state yet, you go to
1312    // exit and exit the loop.  however, when the DMA is done it will trigger an
1313    // event and come back to this loop.
1314    switch (rxState) {
1315      case rxIdle:
1316        if (!regs.command & CR_RXE) {
1317            DPRINTF(EthernetSM, "Receive Disabled! Nothing to do.\n");
1318            goto exit;
1319        }
1320
1321        if (CRDD) {
1322            rxState = rxDescRefr;
1323
1324            rxDmaAddr = regs.rxdp & 0x3fffffff;
1325            rxDmaData = &rxDescCache + offsetof(ns_desc, link);
1326            rxDmaLen = sizeof(rxDescCache.link);
1327            rxDmaFree = dmaDescFree;
1328
1329            descDmaReads++;
1330            descDmaRdBytes += rxDmaLen;
1331
1332            if (doRxDmaRead())
1333                goto exit;
1334        } else {
1335            rxState = rxDescRead;
1336
1337            rxDmaAddr = regs.rxdp & 0x3fffffff;
1338            rxDmaData = &rxDescCache;
1339            rxDmaLen = sizeof(ns_desc);
1340            rxDmaFree = dmaDescFree;
1341
1342            descDmaReads++;
1343            descDmaRdBytes += rxDmaLen;
1344
1345            if (doRxDmaRead())
1346                goto exit;
1347        }
1348        break;
1349
1350      case rxDescRefr:
1351        if (rxDmaState != dmaIdle)
1352            goto exit;
1353
1354        rxState = rxAdvance;
1355        break;
1356
1357     case rxDescRead:
1358        if (rxDmaState != dmaIdle)
1359            goto exit;
1360
1361        DPRINTF(EthernetDesc,
1362                "rxDescCache:\n\tlink=%08x\n\tbufptr=%08x\n\tcmdsts=%08x\n\textsts=%08x\n"
1363                ,rxDescCache.link, rxDescCache.bufptr, rxDescCache.cmdsts,
1364                rxDescCache.extsts);
1365
1366        if (rxDescCache.cmdsts & CMDSTS_OWN) {
1367            rxState = rxIdle;
1368        } else {
1369            rxState = rxFifoBlock;
1370            rxFragPtr = rxDescCache.bufptr;
1371            rxDescCnt = rxDescCache.cmdsts & CMDSTS_LEN_MASK;
1372        }
1373        break;
1374
1375      case rxFifoBlock:
1376        if (!rxPacket) {
1377            /**
1378             * @todo in reality, we should be able to start processing
1379             * the packet as it arrives, and not have to wait for the
1380             * full packet ot be in the receive fifo.
1381             */
1382            if (rxFifo.empty())
1383                goto exit;
1384
1385            DPRINTF(EthernetSM, "\n\n*****processing receive of new packet\n");
1386
1387            // If we don't have a packet, grab a new one from the fifo.
1388            rxPacket = rxFifo.front();
1389            rxPktBytes = rxPacket->length;
1390            rxPacketBufPtr = rxPacket->data;
1391
1392            if (DTRACE(Ethernet)) {
1393                if (rxPacket->isIpPkt()) {
1394                    ip_header *ip = rxPacket->getIpHdr();
1395                    DPRINTF(Ethernet, "ID is %d\n", reverseEnd16(ip->ID));
1396                    if (rxPacket->isTcpPkt()) {
1397                        tcp_header *tcp = rxPacket->getTcpHdr(ip);
1398                        DPRINTF(Ethernet, "Src Port = %d, Dest Port = %d\n",
1399                                reverseEnd16(tcp->src_port_num),
1400                                reverseEnd16(tcp->dest_port_num));
1401                    }
1402                }
1403            }
1404
1405            // sanity check - i think the driver behaves like this
1406            assert(rxDescCnt >= rxPktBytes);
1407
1408            // Must clear the value before popping to decrement the
1409            // reference count
1410            rxFifo.front() = NULL;
1411            rxFifo.pop_front();
1412            rxFifoCnt -= rxPacket->length;
1413        }
1414
1415
1416        // dont' need the && rxDescCnt > 0 if driver sanity check above holds
1417        if (rxPktBytes > 0) {
1418            rxState = rxFragWrite;
1419            // don't need min<>(rxPktBytes,rxDescCnt) if above sanity check holds
1420            rxXferLen = rxPktBytes;
1421
1422            rxDmaAddr = rxFragPtr & 0x3fffffff;
1423            rxDmaData = rxPacketBufPtr;
1424            rxDmaLen = rxXferLen;
1425            rxDmaFree = dmaDataFree;
1426
1427            if (doRxDmaWrite())
1428                goto exit;
1429
1430        } else {
1431            rxState = rxDescWrite;
1432
1433            //if (rxPktBytes == 0) {  /* packet is done */
1434            assert(rxPktBytes == 0);
1435            DPRINTF(EthernetSM, "done with receiving packet\n");
1436
1437            rxDescCache.cmdsts |= CMDSTS_OWN;
1438            rxDescCache.cmdsts &= ~CMDSTS_MORE;
1439            rxDescCache.cmdsts |= CMDSTS_OK;
1440            rxDescCache.cmdsts &= 0xffff0000;
1441            rxDescCache.cmdsts += rxPacket->length;   //i.e. set CMDSTS_SIZE
1442
1443#if 0
1444            /* all the driver uses these are for its own stats keeping
1445               which we don't care about, aren't necessary for functionality
1446               and doing this would just slow us down.  if they end up using
1447               this in a later version for functional purposes, just undef
1448            */
1449            if (rxFilterEnable) {
1450                rxDescCache.cmdsts &= ~CMDSTS_DEST_MASK;
1451                if (rxFifo.front()->IsUnicast())
1452                    rxDescCache.cmdsts |= CMDSTS_DEST_SELF;
1453                if (rxFifo.front()->IsMulticast())
1454                    rxDescCache.cmdsts |= CMDSTS_DEST_MULTI;
1455                if (rxFifo.front()->IsBroadcast())
1456                    rxDescCache.cmdsts |= CMDSTS_DEST_MASK;
1457            }
1458#endif
1459
1460            if (rxPacket->isIpPkt() && extstsEnable) {
1461                rxDescCache.extsts |= EXTSTS_IPPKT;
1462                rxIPChecksums++;
1463                if (!ipChecksum(rxPacket, false)) {
1464                    DPRINTF(EthernetCksum, "Rx IP Checksum Error\n");
1465                    rxDescCache.extsts |= EXTSTS_IPERR;
1466                }
1467                if (rxPacket->isTcpPkt()) {
1468                    rxDescCache.extsts |= EXTSTS_TCPPKT;
1469                    rxTCPChecksums++;
1470                    if (!tcpChecksum(rxPacket, false)) {
1471                        DPRINTF(EthernetCksum, "Rx TCP Checksum Error\n");
1472                        rxDescCache.extsts |= EXTSTS_TCPERR;
1473
1474                    }
1475                } else if (rxPacket->isUdpPkt()) {
1476                    rxDescCache.extsts |= EXTSTS_UDPPKT;
1477                    if (!udpChecksum(rxPacket, false)) {
1478                        DPRINTF(EthernetCksum, "Rx UDP Checksum Error\n");
1479                        rxDescCache.extsts |= EXTSTS_UDPERR;
1480                    }
1481                }
1482            }
1483            rxPacket = 0;
1484
1485            /* the driver seems to always receive into desc buffers
1486               of size 1514, so you never have a pkt that is split
1487               into multiple descriptors on the receive side, so
1488               i don't implement that case, hence the assert above.
1489            */
1490
1491            DPRINTF(EthernetDesc, "rxDesc writeback:\n\tcmdsts=%08x\n\textsts=%08x\n",
1492                    rxDescCache.cmdsts, rxDescCache.extsts);
1493
1494            rxDmaAddr = (regs.rxdp + offsetof(ns_desc, cmdsts)) & 0x3fffffff;
1495            rxDmaData = &(rxDescCache.cmdsts);
1496            rxDmaLen = sizeof(rxDescCache.cmdsts) + sizeof(rxDescCache.extsts);
1497            rxDmaFree = dmaDescFree;
1498
1499            descDmaWrites++;
1500            descDmaWrBytes += rxDmaLen;
1501
1502            if (doRxDmaWrite())
1503                goto exit;
1504        }
1505        break;
1506
1507      case rxFragWrite:
1508        if (rxDmaState != dmaIdle)
1509            goto exit;
1510
1511        rxPacketBufPtr += rxXferLen;
1512        rxFragPtr += rxXferLen;
1513        rxPktBytes -= rxXferLen;
1514
1515        rxState = rxFifoBlock;
1516        break;
1517
1518      case rxDescWrite:
1519        if (rxDmaState != dmaIdle)
1520            goto exit;
1521
1522        assert(rxDescCache.cmdsts & CMDSTS_OWN);
1523
1524        assert(rxPacket == 0);
1525        devIntrPost(ISR_RXOK);
1526
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                transmit();
1893                txPacket = 0;
1894
1895                if (txHalt) {
1896                    DPRINTF(EthernetSM, "halting TX state machine\n");
1897                    txState = txIdle;
1898                    txHalt = false;
1899                } else
1900                    txState = txAdvance;
1901
1902                if (doTxDmaWrite())
1903                    goto exit;
1904            }
1905        } else {
1906            DPRINTF(EthernetSM, "this descriptor isn't done yet\n");
1907            txState = txFragRead;
1908
1909            /* The number of bytes transferred is either whatever is left
1910               in the descriptor (txDescCnt), or if there is not enough
1911               room in the fifo, just whatever room is left in the fifo
1912            */
1913            txXferLen = min<uint32_t>(txDescCnt, txFifoAvail);
1914
1915            txDmaAddr = txFragPtr & 0x3fffffff;
1916            txDmaData = txPacketBufPtr;
1917            txDmaLen = txXferLen;
1918            txDmaFree = dmaDataFree;
1919
1920            if (doTxDmaRead())
1921                goto exit;
1922        }
1923        break;
1924
1925      case txFragRead:
1926        if (txDmaState != dmaIdle)
1927            goto exit;
1928
1929        txPacketBufPtr += txXferLen;
1930        txFragPtr += txXferLen;
1931        txDescCnt -= txXferLen;
1932        txFifoAvail -= txXferLen;
1933
1934        txState = txFifoBlock;
1935        break;
1936
1937      case txDescWrite:
1938        if (txDmaState != dmaIdle)
1939            goto exit;
1940
1941        if (txDescCache.cmdsts & CMDSTS_INTR) {
1942            devIntrPost(ISR_TXDESC);
1943        }
1944
1945        txState = txAdvance;
1946        break;
1947
1948      case txAdvance:
1949        if (txDescCache.link == 0) {
1950            txState = txIdle;
1951        } else {
1952            txState = txDescRead;
1953            regs.txdp = txDescCache.link;
1954            CTDD = false;
1955
1956            txDmaAddr = txDescCache.link & 0x3fffffff;
1957            txDmaData = &txDescCache;
1958            txDmaLen = sizeof(ns_desc);
1959            txDmaFree = dmaDescFree;
1960
1961            if (doTxDmaRead())
1962                goto exit;
1963        }
1964        break;
1965
1966      default:
1967        panic("invalid state");
1968    }
1969
1970    DPRINTF(EthernetSM, "entering next tx state=%s\n",
1971            NsTxStateStrings[txState]);
1972
1973    if (txState == txIdle) {
1974        regs.command &= ~CR_TXE;
1975        devIntrPost(ISR_TXIDLE);
1976        return;
1977    }
1978
1979    goto next;
1980
1981  exit:
1982    /**
1983     * @todo do we want to schedule a future kick?
1984     */
1985    DPRINTF(EthernetSM, "tx state machine exited state=%s\n",
1986            NsTxStateStrings[txState]);
1987}
1988
1989void
1990NSGigE::transferDone()
1991{
1992    if (txFifo.empty())
1993        return;
1994
1995    if (txEvent.scheduled())
1996        txEvent.reschedule(curTick + 1);
1997    else
1998        txEvent.schedule(curTick + 1);
1999}
2000
2001bool
2002NSGigE::rxFilter(PacketPtr packet)
2003{
2004    bool drop = true;
2005    string type;
2006
2007    if (packet->IsUnicast()) {
2008        type = "unicast";
2009
2010        // If we're accepting all unicast addresses
2011        if (acceptUnicast)
2012            drop = false;
2013
2014        // If we make a perfect match
2015        if ((acceptPerfect)
2016            && (memcmp(rom.perfectMatch, packet->data, sizeof(rom.perfectMatch)) == 0))
2017            drop = false;
2018
2019        eth_header *eth = (eth_header *) packet->data;
2020        if ((acceptArp) && (eth->type == 0x608))
2021            drop = false;
2022
2023    } else if (packet->IsBroadcast()) {
2024        type = "broadcast";
2025
2026        // if we're accepting broadcasts
2027        if (acceptBroadcast)
2028            drop = false;
2029
2030    } else if (packet->IsMulticast()) {
2031        type = "multicast";
2032
2033        // if we're accepting all multicasts
2034        if (acceptMulticast)
2035            drop = false;
2036
2037    } else {
2038        type = "unknown";
2039
2040        // oh well, punt on this one
2041    }
2042
2043    if (drop) {
2044        DPRINTF(Ethernet, "rxFilter drop\n");
2045        DDUMP(EthernetData, packet->data, packet->length);
2046    }
2047
2048    return drop;
2049}
2050
2051bool
2052NSGigE::recvPacket(PacketPtr packet)
2053{
2054    rxBytes += packet->length;
2055    rxPackets++;
2056
2057    DPRINTF(Ethernet, "\n\nReceiving packet from wire, rxFifoAvail = %d\n", MAX_RX_FIFO_SIZE - rxFifoCnt);
2058
2059    if (rxState == rxIdle) {
2060        DPRINTF(Ethernet, "receive disabled...packet dropped\n");
2061        interface->recvDone();
2062        return true;
2063    }
2064
2065    if (rxFilterEnable && rxFilter(packet)) {
2066        DPRINTF(Ethernet, "packet filtered...dropped\n");
2067        interface->recvDone();
2068        return true;
2069    }
2070
2071    if ((rxFifoCnt + packet->length) >= MAX_RX_FIFO_SIZE) {
2072        DPRINTF(Ethernet,
2073                "packet will not fit in receive buffer...packet dropped\n");
2074        devIntrPost(ISR_RXORN);
2075        return false;
2076    }
2077
2078    rxFifo.push_back(packet);
2079    rxFifoCnt += packet->length;
2080    interface->recvDone();
2081
2082    rxKick();
2083    return true;
2084}
2085
2086/**
2087 * does a udp checksum.  if gen is true, then it generates it and puts it in the right place
2088 * else, it just checks what it calculates against the value in the header in packet
2089 */
2090bool
2091NSGigE::udpChecksum(PacketPtr packet, bool gen)
2092{
2093    ip_header *ip = packet->getIpHdr();
2094    udp_header *hdr = packet->getUdpHdr(ip);
2095
2096    pseudo_header *pseudo = new pseudo_header;
2097
2098    pseudo->src_ip_addr = ip->src_ip_addr;
2099    pseudo->dest_ip_addr = ip->dest_ip_addr;
2100    pseudo->protocol = ip->protocol;
2101    pseudo->len = hdr->len;
2102
2103    uint16_t cksum = checksumCalc((uint16_t *) pseudo, (uint16_t *) hdr,
2104                                  (uint32_t) hdr->len);
2105
2106    delete pseudo;
2107    if (gen)
2108        hdr->chksum = cksum;
2109    else
2110        if (cksum != 0)
2111            return false;
2112
2113    return true;
2114}
2115
2116bool
2117NSGigE::tcpChecksum(PacketPtr packet, bool gen)
2118{
2119    ip_header *ip = packet->getIpHdr();
2120    tcp_header *hdr = packet->getTcpHdr(ip);
2121
2122    uint16_t cksum;
2123    pseudo_header *pseudo = new pseudo_header;
2124    if (!gen) {
2125        pseudo->src_ip_addr = ip->src_ip_addr;
2126        pseudo->dest_ip_addr = ip->dest_ip_addr;
2127        pseudo->protocol = reverseEnd16(ip->protocol);
2128        pseudo->len = reverseEnd16(reverseEnd16(ip->dgram_len) - (ip->vers_len & 0xf)*4);
2129
2130        cksum = checksumCalc((uint16_t *) pseudo, (uint16_t *) hdr,
2131                                  (uint32_t) reverseEnd16(pseudo->len));
2132    } else {
2133        pseudo->src_ip_addr = 0;
2134        pseudo->dest_ip_addr = 0;
2135        pseudo->protocol = hdr->chksum;
2136        pseudo->len = 0;
2137        hdr->chksum = 0;
2138        cksum = checksumCalc((uint16_t *) pseudo, (uint16_t *) hdr,
2139                             (uint32_t) (reverseEnd16(ip->dgram_len) - (ip->vers_len & 0xf)*4));
2140    }
2141
2142    delete pseudo;
2143    if (gen)
2144        hdr->chksum = cksum;
2145    else
2146        if (cksum != 0)
2147            return false;
2148
2149    return true;
2150}
2151
2152bool
2153NSGigE::ipChecksum(PacketPtr packet, bool gen)
2154{
2155    ip_header *hdr = packet->getIpHdr();
2156
2157    uint16_t cksum = checksumCalc(NULL, (uint16_t *) hdr, (hdr->vers_len & 0xf)*4);
2158
2159    if (gen) {
2160        DPRINTF(EthernetCksum, "generated checksum: %#x\n", cksum);
2161        hdr->hdr_chksum = cksum;
2162    }
2163    else
2164        if (cksum != 0)
2165            return false;
2166
2167    return true;
2168}
2169
2170uint16_t
2171NSGigE::checksumCalc(uint16_t *pseudo, uint16_t *buf, uint32_t len)
2172{
2173    uint32_t sum = 0;
2174
2175    uint16_t last_pad = 0;
2176    if (len & 1) {
2177        last_pad = buf[len/2] & 0xff;
2178        len--;
2179        sum += last_pad;
2180    }
2181
2182    if (pseudo) {
2183        sum = pseudo[0] + pseudo[1] + pseudo[2] +
2184            pseudo[3] + pseudo[4] + pseudo[5];
2185    }
2186
2187    for (int i=0; i < (len/2); ++i) {
2188        sum += buf[i];
2189    }
2190
2191    while (sum >> 16)
2192        sum = (sum >> 16) + (sum & 0xffff);
2193
2194    return ~sum;
2195}
2196
2197//=====================================================================
2198//
2199//
2200void
2201NSGigE::serialize(ostream &os)
2202{
2203    // Serialize the PciDev base class
2204    PciDev::serialize(os);
2205
2206    /*
2207     * Finalize any DMA events now.
2208     */
2209    if (rxDmaReadEvent.scheduled())
2210        rxDmaReadCopy();
2211    if (rxDmaWriteEvent.scheduled())
2212        rxDmaWriteCopy();
2213    if (txDmaReadEvent.scheduled())
2214        txDmaReadCopy();
2215    if (txDmaWriteEvent.scheduled())
2216        txDmaWriteCopy();
2217
2218    /*
2219     * Serialize the device registers
2220     */
2221    SERIALIZE_SCALAR(regs.command);
2222    SERIALIZE_SCALAR(regs.config);
2223    SERIALIZE_SCALAR(regs.mear);
2224    SERIALIZE_SCALAR(regs.ptscr);
2225    SERIALIZE_SCALAR(regs.isr);
2226    SERIALIZE_SCALAR(regs.imr);
2227    SERIALIZE_SCALAR(regs.ier);
2228    SERIALIZE_SCALAR(regs.ihr);
2229    SERIALIZE_SCALAR(regs.txdp);
2230    SERIALIZE_SCALAR(regs.txdp_hi);
2231    SERIALIZE_SCALAR(regs.txcfg);
2232    SERIALIZE_SCALAR(regs.gpior);
2233    SERIALIZE_SCALAR(regs.rxdp);
2234    SERIALIZE_SCALAR(regs.rxdp_hi);
2235    SERIALIZE_SCALAR(regs.rxcfg);
2236    SERIALIZE_SCALAR(regs.pqcr);
2237    SERIALIZE_SCALAR(regs.wcsr);
2238    SERIALIZE_SCALAR(regs.pcr);
2239    SERIALIZE_SCALAR(regs.rfcr);
2240    SERIALIZE_SCALAR(regs.rfdr);
2241    SERIALIZE_SCALAR(regs.srr);
2242    SERIALIZE_SCALAR(regs.mibc);
2243    SERIALIZE_SCALAR(regs.vrcr);
2244    SERIALIZE_SCALAR(regs.vtcr);
2245    SERIALIZE_SCALAR(regs.vdr);
2246    SERIALIZE_SCALAR(regs.ccsr);
2247    SERIALIZE_SCALAR(regs.tbicr);
2248    SERIALIZE_SCALAR(regs.tbisr);
2249    SERIALIZE_SCALAR(regs.tanar);
2250    SERIALIZE_SCALAR(regs.tanlpar);
2251    SERIALIZE_SCALAR(regs.taner);
2252    SERIALIZE_SCALAR(regs.tesr);
2253
2254    SERIALIZE_ARRAY(rom.perfectMatch, EADDR_LEN);
2255
2256    SERIALIZE_SCALAR(ioEnable);
2257
2258    /*
2259     * Serialize the data Fifos
2260     */
2261    int txNumPkts = txFifo.size();
2262    SERIALIZE_SCALAR(txNumPkts);
2263    int i = 0;
2264    pktiter_t end = txFifo.end();
2265    for (pktiter_t p = txFifo.begin(); p != end; ++p) {
2266        nameOut(os, csprintf("%s.txFifo%d", name(), i++));
2267        (*p)->serialize(os);
2268    }
2269
2270    int rxNumPkts = rxFifo.size();
2271    SERIALIZE_SCALAR(rxNumPkts);
2272    i = 0;
2273    end = rxFifo.end();
2274    for (pktiter_t p = rxFifo.begin(); p != end; ++p) {
2275        nameOut(os, csprintf("%s.rxFifo%d", name(), i++));
2276        (*p)->serialize(os);
2277    }
2278
2279    /*
2280     * Serialize the various helper variables
2281     */
2282    bool txPacketExists = txPacket;
2283    SERIALIZE_SCALAR(txPacketExists);
2284    if (txPacketExists) {
2285        nameOut(os, csprintf("%s.txPacket", name()));
2286        txPacket->serialize(os);
2287        uint32_t txPktBufPtr = (uint32_t) (txPacketBufPtr - txPacket->data);
2288        SERIALIZE_SCALAR(txPktBufPtr);
2289    }
2290
2291    bool rxPacketExists = rxPacket;
2292    SERIALIZE_SCALAR(rxPacketExists);
2293    if (rxPacketExists) {
2294        nameOut(os, csprintf("%s.rxPacket", name()));
2295        rxPacket->serialize(os);
2296        uint32_t rxPktBufPtr = (uint32_t) (rxPacketBufPtr - rxPacket->data);
2297        SERIALIZE_SCALAR(rxPktBufPtr);
2298    }
2299
2300    SERIALIZE_SCALAR(txXferLen);
2301    SERIALIZE_SCALAR(rxXferLen);
2302
2303    /*
2304     * Serialize DescCaches
2305     */
2306    SERIALIZE_SCALAR(txDescCache.link);
2307    SERIALIZE_SCALAR(txDescCache.bufptr);
2308    SERIALIZE_SCALAR(txDescCache.cmdsts);
2309    SERIALIZE_SCALAR(txDescCache.extsts);
2310    SERIALIZE_SCALAR(rxDescCache.link);
2311    SERIALIZE_SCALAR(rxDescCache.bufptr);
2312    SERIALIZE_SCALAR(rxDescCache.cmdsts);
2313    SERIALIZE_SCALAR(rxDescCache.extsts);
2314
2315    /*
2316     * Serialize tx state machine
2317     */
2318    int txState = this->txState;
2319    SERIALIZE_SCALAR(txState);
2320    SERIALIZE_SCALAR(CTDD);
2321    SERIALIZE_SCALAR(txFifoAvail);
2322    SERIALIZE_SCALAR(txHalt);
2323    SERIALIZE_SCALAR(txFragPtr);
2324    SERIALIZE_SCALAR(txDescCnt);
2325    int txDmaState = this->txDmaState;
2326    SERIALIZE_SCALAR(txDmaState);
2327
2328    /*
2329     * Serialize rx state machine
2330     */
2331    int rxState = this->rxState;
2332    SERIALIZE_SCALAR(rxState);
2333    SERIALIZE_SCALAR(CRDD);
2334    SERIALIZE_SCALAR(rxPktBytes);
2335    SERIALIZE_SCALAR(rxFifoCnt);
2336    SERIALIZE_SCALAR(rxHalt);
2337    SERIALIZE_SCALAR(rxDescCnt);
2338    int rxDmaState = this->rxDmaState;
2339    SERIALIZE_SCALAR(rxDmaState);
2340
2341    SERIALIZE_SCALAR(extstsEnable);
2342
2343    /*
2344     * If there's a pending transmit, store the time so we can
2345     * reschedule it later
2346     */
2347    Tick transmitTick = txEvent.scheduled() ? txEvent.when() - curTick : 0;
2348    SERIALIZE_SCALAR(transmitTick);
2349
2350    /*
2351     * receive address filter settings
2352     */
2353    SERIALIZE_SCALAR(rxFilterEnable);
2354    SERIALIZE_SCALAR(acceptBroadcast);
2355    SERIALIZE_SCALAR(acceptMulticast);
2356    SERIALIZE_SCALAR(acceptUnicast);
2357    SERIALIZE_SCALAR(acceptPerfect);
2358    SERIALIZE_SCALAR(acceptArp);
2359
2360    /*
2361     * Keep track of pending interrupt status.
2362     */
2363    SERIALIZE_SCALAR(intrTick);
2364    SERIALIZE_SCALAR(cpuPendingIntr);
2365    Tick intrEventTick = 0;
2366    if (intrEvent)
2367        intrEventTick = intrEvent->when();
2368    SERIALIZE_SCALAR(intrEventTick);
2369
2370}
2371
2372void
2373NSGigE::unserialize(Checkpoint *cp, const std::string &section)
2374{
2375    // Unserialize the PciDev base class
2376    PciDev::unserialize(cp, section);
2377
2378    UNSERIALIZE_SCALAR(regs.command);
2379    UNSERIALIZE_SCALAR(regs.config);
2380    UNSERIALIZE_SCALAR(regs.mear);
2381    UNSERIALIZE_SCALAR(regs.ptscr);
2382    UNSERIALIZE_SCALAR(regs.isr);
2383    UNSERIALIZE_SCALAR(regs.imr);
2384    UNSERIALIZE_SCALAR(regs.ier);
2385    UNSERIALIZE_SCALAR(regs.ihr);
2386    UNSERIALIZE_SCALAR(regs.txdp);
2387    UNSERIALIZE_SCALAR(regs.txdp_hi);
2388    UNSERIALIZE_SCALAR(regs.txcfg);
2389    UNSERIALIZE_SCALAR(regs.gpior);
2390    UNSERIALIZE_SCALAR(regs.rxdp);
2391    UNSERIALIZE_SCALAR(regs.rxdp_hi);
2392    UNSERIALIZE_SCALAR(regs.rxcfg);
2393    UNSERIALIZE_SCALAR(regs.pqcr);
2394    UNSERIALIZE_SCALAR(regs.wcsr);
2395    UNSERIALIZE_SCALAR(regs.pcr);
2396    UNSERIALIZE_SCALAR(regs.rfcr);
2397    UNSERIALIZE_SCALAR(regs.rfdr);
2398    UNSERIALIZE_SCALAR(regs.srr);
2399    UNSERIALIZE_SCALAR(regs.mibc);
2400    UNSERIALIZE_SCALAR(regs.vrcr);
2401    UNSERIALIZE_SCALAR(regs.vtcr);
2402    UNSERIALIZE_SCALAR(regs.vdr);
2403    UNSERIALIZE_SCALAR(regs.ccsr);
2404    UNSERIALIZE_SCALAR(regs.tbicr);
2405    UNSERIALIZE_SCALAR(regs.tbisr);
2406    UNSERIALIZE_SCALAR(regs.tanar);
2407    UNSERIALIZE_SCALAR(regs.tanlpar);
2408    UNSERIALIZE_SCALAR(regs.taner);
2409    UNSERIALIZE_SCALAR(regs.tesr);
2410
2411    UNSERIALIZE_ARRAY(rom.perfectMatch, EADDR_LEN);
2412
2413    UNSERIALIZE_SCALAR(ioEnable);
2414
2415    /*
2416     * unserialize the data fifos
2417     */
2418    int txNumPkts;
2419    UNSERIALIZE_SCALAR(txNumPkts);
2420    int i;
2421    for (i = 0; i < txNumPkts; ++i) {
2422        PacketPtr p = new EtherPacket;
2423        p->unserialize(cp, csprintf("%s.rxFifo%d", section, i));
2424        txFifo.push_back(p);
2425    }
2426
2427    int rxNumPkts;
2428    UNSERIALIZE_SCALAR(rxNumPkts);
2429    for (i = 0; i < rxNumPkts; ++i) {
2430        PacketPtr p = new EtherPacket;
2431        p->unserialize(cp, csprintf("%s.rxFifo%d", section, i));
2432        rxFifo.push_back(p);
2433    }
2434
2435    /*
2436     * unserialize the various helper variables
2437     */
2438    bool txPacketExists;
2439    UNSERIALIZE_SCALAR(txPacketExists);
2440    if (txPacketExists) {
2441        txPacket = new EtherPacket;
2442        txPacket->unserialize(cp, csprintf("%s.txPacket", section));
2443        uint32_t txPktBufPtr;
2444        UNSERIALIZE_SCALAR(txPktBufPtr);
2445        txPacketBufPtr = (uint8_t *) txPacket->data + txPktBufPtr;
2446    } else
2447        txPacket = 0;
2448
2449    bool rxPacketExists;
2450    UNSERIALIZE_SCALAR(rxPacketExists);
2451    rxPacket = 0;
2452    if (rxPacketExists) {
2453        rxPacket = new EtherPacket;
2454        rxPacket->unserialize(cp, csprintf("%s.rxPacket", section));
2455        uint32_t rxPktBufPtr;
2456        UNSERIALIZE_SCALAR(rxPktBufPtr);
2457        rxPacketBufPtr = (uint8_t *) rxPacket->data + rxPktBufPtr;
2458    } else
2459        rxPacket = 0;
2460
2461    UNSERIALIZE_SCALAR(txXferLen);
2462    UNSERIALIZE_SCALAR(rxXferLen);
2463
2464    /*
2465     * Unserialize DescCaches
2466     */
2467    UNSERIALIZE_SCALAR(txDescCache.link);
2468    UNSERIALIZE_SCALAR(txDescCache.bufptr);
2469    UNSERIALIZE_SCALAR(txDescCache.cmdsts);
2470    UNSERIALIZE_SCALAR(txDescCache.extsts);
2471    UNSERIALIZE_SCALAR(rxDescCache.link);
2472    UNSERIALIZE_SCALAR(rxDescCache.bufptr);
2473    UNSERIALIZE_SCALAR(rxDescCache.cmdsts);
2474    UNSERIALIZE_SCALAR(rxDescCache.extsts);
2475
2476    /*
2477     * unserialize tx state machine
2478     */
2479    int txState;
2480    UNSERIALIZE_SCALAR(txState);
2481    this->txState = (TxState) txState;
2482    UNSERIALIZE_SCALAR(CTDD);
2483    UNSERIALIZE_SCALAR(txFifoAvail);
2484    UNSERIALIZE_SCALAR(txHalt);
2485    UNSERIALIZE_SCALAR(txFragPtr);
2486    UNSERIALIZE_SCALAR(txDescCnt);
2487    int txDmaState;
2488    UNSERIALIZE_SCALAR(txDmaState);
2489    this->txDmaState = (DmaState) txDmaState;
2490
2491    /*
2492     * unserialize rx state machine
2493     */
2494    int rxState;
2495    UNSERIALIZE_SCALAR(rxState);
2496    this->rxState = (RxState) rxState;
2497    UNSERIALIZE_SCALAR(CRDD);
2498    UNSERIALIZE_SCALAR(rxPktBytes);
2499    UNSERIALIZE_SCALAR(rxFifoCnt);
2500    UNSERIALIZE_SCALAR(rxHalt);
2501    UNSERIALIZE_SCALAR(rxDescCnt);
2502    int rxDmaState;
2503    UNSERIALIZE_SCALAR(rxDmaState);
2504    this->rxDmaState = (DmaState) rxDmaState;
2505
2506    UNSERIALIZE_SCALAR(extstsEnable);
2507
2508     /*
2509     * If there's a pending transmit, reschedule it now
2510     */
2511    Tick transmitTick;
2512    UNSERIALIZE_SCALAR(transmitTick);
2513    if (transmitTick)
2514        txEvent.schedule(curTick + transmitTick);
2515
2516    /*
2517     * unserialize receive address filter settings
2518     */
2519    UNSERIALIZE_SCALAR(rxFilterEnable);
2520    UNSERIALIZE_SCALAR(acceptBroadcast);
2521    UNSERIALIZE_SCALAR(acceptMulticast);
2522    UNSERIALIZE_SCALAR(acceptUnicast);
2523    UNSERIALIZE_SCALAR(acceptPerfect);
2524    UNSERIALIZE_SCALAR(acceptArp);
2525
2526    /*
2527     * Keep track of pending interrupt status.
2528     */
2529    UNSERIALIZE_SCALAR(intrTick);
2530    UNSERIALIZE_SCALAR(cpuPendingIntr);
2531    Tick intrEventTick;
2532    UNSERIALIZE_SCALAR(intrEventTick);
2533    if (intrEventTick) {
2534        intrEvent = new IntrEvent(this, true);
2535        intrEvent->schedule(intrEventTick);
2536    }
2537
2538    /*
2539     * re-add addrRanges to bus bridges
2540     */
2541    if (pioInterface) {
2542        pioInterface->addAddrRange(BARAddrs[0], BARAddrs[0] + BARSize[0] - 1);
2543        pioInterface->addAddrRange(BARAddrs[1], BARAddrs[1] + BARSize[1] - 1);
2544    }
2545}
2546
2547Tick
2548NSGigE::cacheAccess(MemReqPtr &req)
2549{
2550    DPRINTF(EthernetPIO, "timing access to paddr=%#x (daddr=%#x)\n",
2551            req->paddr, req->paddr - addr);
2552    return curTick + pioLatency;
2553}
2554//=====================================================================
2555
2556
2557//********** helper functions******************************************
2558
2559uint16_t reverseEnd16(uint16_t num)
2560{
2561    uint16_t reverse = (num & 0xff)<<8;
2562    reverse += ((num & 0xff00) >> 8);
2563    return reverse;
2564}
2565
2566uint32_t reverseEnd32(uint32_t num)
2567{
2568    uint32_t reverse = (reverseEnd16(num & 0xffff)) << 16;
2569    reverse += reverseEnd16((uint16_t) ((num & 0xffff0000) >> 8));
2570    return reverse;
2571}
2572
2573
2574
2575//=====================================================================
2576
2577BEGIN_DECLARE_SIM_OBJECT_PARAMS(NSGigEInt)
2578
2579    SimObjectParam<EtherInt *> peer;
2580    SimObjectParam<NSGigE *> device;
2581
2582END_DECLARE_SIM_OBJECT_PARAMS(NSGigEInt)
2583
2584BEGIN_INIT_SIM_OBJECT_PARAMS(NSGigEInt)
2585
2586    INIT_PARAM_DFLT(peer, "peer interface", NULL),
2587    INIT_PARAM(device, "Ethernet device of this interface")
2588
2589END_INIT_SIM_OBJECT_PARAMS(NSGigEInt)
2590
2591CREATE_SIM_OBJECT(NSGigEInt)
2592{
2593    NSGigEInt *dev_int = new NSGigEInt(getInstanceName(), device);
2594
2595    EtherInt *p = (EtherInt *)peer;
2596    if (p) {
2597        dev_int->setPeer(p);
2598        p->setPeer(dev_int);
2599    }
2600
2601    return dev_int;
2602}
2603
2604REGISTER_SIM_OBJECT("NSGigEInt", NSGigEInt)
2605
2606
2607BEGIN_DECLARE_SIM_OBJECT_PARAMS(NSGigE)
2608
2609    Param<Tick> tx_delay;
2610    Param<Tick> rx_delay;
2611    SimObjectParam<IntrControl *> intr_ctrl;
2612    Param<Tick> intr_delay;
2613    SimObjectParam<MemoryController *> mmu;
2614    SimObjectParam<PhysicalMemory *> physmem;
2615    Param<bool> rx_filter;
2616    Param<string> hardware_address;
2617    SimObjectParam<Bus*> header_bus;
2618    SimObjectParam<Bus*> payload_bus;
2619    SimObjectParam<HierParams *> hier;
2620    Param<Tick> pio_latency;
2621    Param<bool> dma_desc_free;
2622    Param<bool> dma_data_free;
2623    Param<Tick> dma_read_delay;
2624    Param<Tick> dma_write_delay;
2625    Param<Tick> dma_read_factor;
2626    Param<Tick> dma_write_factor;
2627    SimObjectParam<PciConfigAll *> configspace;
2628    SimObjectParam<PciConfigData *> configdata;
2629    SimObjectParam<Tsunami *> tsunami;
2630    Param<uint32_t> pci_bus;
2631    Param<uint32_t> pci_dev;
2632    Param<uint32_t> pci_func;
2633
2634END_DECLARE_SIM_OBJECT_PARAMS(NSGigE)
2635
2636BEGIN_INIT_SIM_OBJECT_PARAMS(NSGigE)
2637
2638    INIT_PARAM_DFLT(tx_delay, "Transmit Delay", 1000),
2639    INIT_PARAM_DFLT(rx_delay, "Receive Delay", 1000),
2640    INIT_PARAM(intr_ctrl, "Interrupt Controller"),
2641    INIT_PARAM_DFLT(intr_delay, "Interrupt Delay in microseconds", 0),
2642    INIT_PARAM(mmu, "Memory Controller"),
2643    INIT_PARAM(physmem, "Physical Memory"),
2644    INIT_PARAM_DFLT(rx_filter, "Enable Receive Filter", true),
2645    INIT_PARAM_DFLT(hardware_address, "Ethernet Hardware Address",
2646                    "00:99:00:00:00:01"),
2647    INIT_PARAM_DFLT(header_bus, "The IO Bus to attach to for headers", NULL),
2648    INIT_PARAM_DFLT(payload_bus, "The IO Bus to attach to for payload", NULL),
2649    INIT_PARAM_DFLT(hier, "Hierarchy global variables", &defaultHierParams),
2650    INIT_PARAM_DFLT(pio_latency, "Programmed IO latency", 1000),
2651    INIT_PARAM_DFLT(dma_desc_free, "DMA of Descriptors is free", false),
2652    INIT_PARAM_DFLT(dma_data_free, "DMA of Data is free", false),
2653    INIT_PARAM_DFLT(dma_read_delay, "fixed delay for dma reads", 0),
2654    INIT_PARAM_DFLT(dma_write_delay, "fixed delay for dma writes", 0),
2655    INIT_PARAM_DFLT(dma_read_factor, "multiplier for dma reads", 0),
2656    INIT_PARAM_DFLT(dma_write_factor, "multiplier for dma writes", 0),
2657    INIT_PARAM(configspace, "PCI Configspace"),
2658    INIT_PARAM(configdata, "PCI Config data"),
2659    INIT_PARAM(tsunami, "Tsunami"),
2660    INIT_PARAM(pci_bus, "PCI bus"),
2661    INIT_PARAM(pci_dev, "PCI device number"),
2662    INIT_PARAM(pci_func, "PCI function code")
2663
2664END_INIT_SIM_OBJECT_PARAMS(NSGigE)
2665
2666
2667CREATE_SIM_OBJECT(NSGigE)
2668{
2669    int eaddr[6];
2670    sscanf(((string)hardware_address).c_str(), "%x:%x:%x:%x:%x:%x",
2671           &eaddr[0], &eaddr[1], &eaddr[2], &eaddr[3], &eaddr[4], &eaddr[5]);
2672
2673    return new NSGigE(getInstanceName(), intr_ctrl, intr_delay,
2674                      physmem, tx_delay, rx_delay, mmu, hier, header_bus,
2675                      payload_bus, pio_latency, dma_desc_free, dma_data_free,
2676                      dma_read_delay, dma_write_delay, dma_read_factor,
2677                      dma_write_factor, configspace, configdata,
2678                      tsunami, pci_bus, pci_dev, pci_func, rx_filter, eaddr);
2679}
2680
2681REGISTER_SIM_OBJECT("NSGigE", NSGigE)
2682