ns_gige.cc revision 881
16657Snate@binkert.org/*
26657Snate@binkert.org * Copyright (c) 2003 The Regents of The University of Michigan
36657Snate@binkert.org * All rights reserved.
46657Snate@binkert.org *
56657Snate@binkert.org * Redistribution and use in source and binary forms, with or without
66657Snate@binkert.org * modification, are permitted provided that the following conditions are
76657Snate@binkert.org * met: redistributions of source code must retain the above copyright
86657Snate@binkert.org * notice, this list of conditions and the following disclaimer;
96657Snate@binkert.org * redistributions in binary form must reproduce the above copyright
106657Snate@binkert.org * notice, this list of conditions and the following disclaimer in the
116657Snate@binkert.org * documentation and/or other materials provided with the distribution;
126657Snate@binkert.org * neither the name of the copyright holders nor the names of its
136657Snate@binkert.org * contributors may be used to endorse or promote products derived from
146657Snate@binkert.org * this software without specific prior written permission.
156657Snate@binkert.org *
166657Snate@binkert.org * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
176657Snate@binkert.org * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
186657Snate@binkert.org * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
196657Snate@binkert.org * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
206657Snate@binkert.org * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
216657Snate@binkert.org * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
226657Snate@binkert.org * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
236657Snate@binkert.org * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
246657Snate@binkert.org * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
256657Snate@binkert.org * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
266657Snate@binkert.org * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
276657Snate@binkert.org */
286999Snate@binkert.org
296657Snate@binkert.org/* @file
306657Snate@binkert.org * Device module for modelling the National Semiconductor
316657Snate@binkert.org * DP83820 ethernet controller.  Does not support priority queueing
326657Snate@binkert.org */
336657Snate@binkert.org#include <cstdio>
346882SBrad.Beckmann@amd.com#include <deque>
356882SBrad.Beckmann@amd.com#include <string>
366882SBrad.Beckmann@amd.com
376882SBrad.Beckmann@amd.com#include "base/inet.hh"
386882SBrad.Beckmann@amd.com#include "cpu/exec_context.hh"
396882SBrad.Beckmann@amd.com#include "cpu/intr_control.hh"
406882SBrad.Beckmann@amd.com#include "dev/dma.hh"
416888SBrad.Beckmann@amd.com#include "dev/ns_gige.hh"
426882SBrad.Beckmann@amd.com#include "dev/etherlink.hh"
436882SBrad.Beckmann@amd.com#include "mem/bus/bus.hh"
446657Snate@binkert.org#include "mem/bus/dma_interface.hh"
456657Snate@binkert.org#include "mem/bus/pio_interface.hh"
466657Snate@binkert.org#include "mem/bus/pio_interface_impl.hh"
476657Snate@binkert.org#include "mem/functional_mem/memory_control.hh"
486657Snate@binkert.org#include "mem/functional_mem/physical_memory.hh"
496657Snate@binkert.org#include "sim/builder.hh"
506882SBrad.Beckmann@amd.com#include "sim/host.hh"
516882SBrad.Beckmann@amd.com#include "sim/sim_stats.hh"
526882SBrad.Beckmann@amd.com#include "targetarch/vtophys.hh"
536882SBrad.Beckmann@amd.com#include "dev/pciconfigall.hh"
546882SBrad.Beckmann@amd.com#include "dev/tsunami_cchip.hh"
556882SBrad.Beckmann@amd.com
566657Snate@binkert.orgconst char *NsRxStateStrings[] =
576657Snate@binkert.org{
586657Snate@binkert.org    "rxIdle",
596657Snate@binkert.org    "rxDescRefr",
606657Snate@binkert.org    "rxDescRead",
616657Snate@binkert.org    "rxFifoBlock",
626657Snate@binkert.org    "rxFragWrite",
636657Snate@binkert.org    "rxDescWrite",
646657Snate@binkert.org    "rxAdvance"
656657Snate@binkert.org};
666657Snate@binkert.org
676657Snate@binkert.orgconst char *NsTxStateStrings[] =
686657Snate@binkert.org{
696657Snate@binkert.org    "txIdle",
706657Snate@binkert.org    "txDescRefr",
716657Snate@binkert.org    "txDescRead",
726657Snate@binkert.org    "txFifoBlock",
736657Snate@binkert.org    "txFragRead",
746657Snate@binkert.org    "txDescWrite",
756657Snate@binkert.org    "txAdvance"
766657Snate@binkert.org};
776657Snate@binkert.org
786657Snate@binkert.orgconst char *NsDmaState[] =
796657Snate@binkert.org{
806657Snate@binkert.org    "dmaIdle",
816657Snate@binkert.org    "dmaReading",
826657Snate@binkert.org    "dmaWriting",
836657Snate@binkert.org    "dmaReadWaiting",
846657Snate@binkert.org    "dmaWriteWaiting"
856779SBrad.Beckmann@amd.com};
866657Snate@binkert.org
876657Snate@binkert.orgusing namespace std;
886657Snate@binkert.org
896657Snate@binkert.org///////////////////////////////////////////////////////////////////////
906657Snate@binkert.org//
916657Snate@binkert.org// NSGigE PCI Device
926657Snate@binkert.org//
936657Snate@binkert.orgNSGigE::NSGigE(const std::string &name, IntrControl *i, Tick intr_delay,
946657Snate@binkert.org             PhysicalMemory *pmem, Tick tx_delay, Tick rx_delay,
956657Snate@binkert.org             MemoryController *mmu, HierParams *hier, Bus *header_bus,
966657Snate@binkert.org             Bus *payload_bus, Tick pio_latency, bool dma_desc_free,
976657Snate@binkert.org             bool dma_data_free, Tick dma_read_delay, Tick dma_write_delay,
986657Snate@binkert.org             Tick dma_read_factor, Tick dma_write_factor, PciConfigAll *cf,
996657Snate@binkert.org             PciConfigData *cd, Tsunami *t, uint32_t bus, uint32_t dev,
1006657Snate@binkert.org             uint32_t func, bool rx_filter, const int eaddr[6], Addr addr)
1016657Snate@binkert.org    : PciDev(name, mmu, cf, cd, bus, dev, func), tsunami(t),
1026657Snate@binkert.org      addr(addr), txPacketBufPtr(NULL), rxPacketBufPtr(NULL),
1036657Snate@binkert.org      txXferLen(0), rxXferLen(0), txPktXmitted(0), txState(txIdle), CTDD(false),
1046657Snate@binkert.org      txFifoCnt(0), txFifoAvail(MAX_TX_FIFO_SIZE), txHalt(false),
1056657Snate@binkert.org      txFragPtr(0), txDescCnt(0), txDmaState(dmaIdle), rxState(rxIdle),
1066657Snate@binkert.org      CRDD(false), rxPktBytes(0), rxFifoCnt(0), rxHalt(false),
1076657Snate@binkert.org      rxFragPtr(0), rxDescCnt(0), rxDmaState(dmaIdle), extstsEnable(false),
1086657Snate@binkert.org      rxDmaReadEvent(this), rxDmaWriteEvent(this),
1096657Snate@binkert.org      txDmaReadEvent(this), txDmaWriteEvent(this),
1106657Snate@binkert.org      dmaDescFree(dma_desc_free), dmaDataFree(dma_data_free),
1116657Snate@binkert.org      txDelay(tx_delay), rxDelay(rx_delay), rxKickTick(0), txKickTick(0),
1126657Snate@binkert.org      txEvent(this), rxFilterEnable(rx_filter), acceptBroadcast(false),
1136657Snate@binkert.org      acceptMulticast(false), acceptUnicast(false),
1146657Snate@binkert.org      acceptPerfect(false), acceptArp(false),
1156657Snate@binkert.org      physmem(pmem), intctrl(i), intrTick(0),
1166657Snate@binkert.org      cpuPendingIntr(false), intrEvent(0), interface(0), pioLatency(pio_latency)
1176657Snate@binkert.org{
1186657Snate@binkert.org    mmu->add_child(this, Range<Addr>(addr, addr + size));
1196657Snate@binkert.org    tsunami->ethernet = this;
1206657Snate@binkert.org
1216657Snate@binkert.org    if (header_bus) {
1226657Snate@binkert.org        pioInterface = newPioInterface(name, hier, header_bus, this,
1236657Snate@binkert.org                                       &NSGigE::cacheAccess);
1246657Snate@binkert.org        pioInterface->addAddrRange(addr, addr + size - 1);
1256657Snate@binkert.org        if (payload_bus)
1266657Snate@binkert.org            dmaInterface = new DMAInterface<Bus>(name + ".dma",
1276657Snate@binkert.org                                                 header_bus, payload_bus, 1);
1286657Snate@binkert.org        else
1296657Snate@binkert.org            dmaInterface = new DMAInterface<Bus>(name + ".dma",
1306657Snate@binkert.org                                                 header_bus, header_bus, 1);
1316657Snate@binkert.org    } else if (payload_bus) {
1326657Snate@binkert.org        pioInterface = newPioInterface(name, hier, payload_bus, this,
1336657Snate@binkert.org                                       &NSGigE::cacheAccess);
1346657Snate@binkert.org        pioInterface->addAddrRange(addr, addr + size - 1);
1356657Snate@binkert.org        dmaInterface = new DMAInterface<Bus>(name + ".dma",
1366657Snate@binkert.org                                             payload_bus, payload_bus, 1);
1376657Snate@binkert.org
1386657Snate@binkert.org    }
1396657Snate@binkert.org
1406657Snate@binkert.org
1416877Ssteve.reinhardt@amd.com    intrDelay = US2Ticks(intr_delay);
1426657Snate@binkert.org    dmaReadDelay = dma_read_delay;
1436657Snate@binkert.org    dmaWriteDelay = dma_write_delay;
1446657Snate@binkert.org    dmaReadFactor = dma_read_factor;
1456657Snate@binkert.org    dmaWriteFactor = dma_write_factor;
1466657Snate@binkert.org
1476657Snate@binkert.org    memset(&regs, 0, sizeof(regs));
1486657Snate@binkert.org    regsReset();
1496657Snate@binkert.org    rom.perfectMatch[0] = eaddr[0];
1506657Snate@binkert.org    rom.perfectMatch[1] = eaddr[1];
1516657Snate@binkert.org    rom.perfectMatch[2] = eaddr[2];
1526877Ssteve.reinhardt@amd.com    rom.perfectMatch[3] = eaddr[3];
1536999Snate@binkert.org    rom.perfectMatch[4] = eaddr[4];
1546877Ssteve.reinhardt@amd.com    rom.perfectMatch[5] = eaddr[5];
1556877Ssteve.reinhardt@amd.com}
1566877Ssteve.reinhardt@amd.com
1576877Ssteve.reinhardt@amd.comNSGigE::~NSGigE()
1586877Ssteve.reinhardt@amd.com{}
1596877Ssteve.reinhardt@amd.com
1606877Ssteve.reinhardt@amd.comvoid
1616877Ssteve.reinhardt@amd.comNSGigE::regStats()
1626877Ssteve.reinhardt@amd.com{
1636877Ssteve.reinhardt@amd.com    txBytes
1646877Ssteve.reinhardt@amd.com        .name(name() + ".txBytes")
1656877Ssteve.reinhardt@amd.com        .desc("Bytes Transmitted")
1666877Ssteve.reinhardt@amd.com        .prereq(txBytes)
1676877Ssteve.reinhardt@amd.com        ;
1686877Ssteve.reinhardt@amd.com
1696877Ssteve.reinhardt@amd.com    rxBytes
1706882SBrad.Beckmann@amd.com        .name(name() + ".rxBytes")
1716882SBrad.Beckmann@amd.com        .desc("Bytes Received")
1726882SBrad.Beckmann@amd.com        .prereq(rxBytes)
1736882SBrad.Beckmann@amd.com        ;
1746882SBrad.Beckmann@amd.com
1756882SBrad.Beckmann@amd.com    txPackets
1766882SBrad.Beckmann@amd.com        .name(name() + ".txPackets")
1776877Ssteve.reinhardt@amd.com        .desc("Number of Packets Transmitted")
1786877Ssteve.reinhardt@amd.com        .prereq(txBytes)
1796877Ssteve.reinhardt@amd.com        ;
1806877Ssteve.reinhardt@amd.com
1816657Snate@binkert.org    rxPackets
1826657Snate@binkert.org        .name(name() + ".rxPackets")
1836999Snate@binkert.org        .desc("Number of Packets Received")
1846657Snate@binkert.org        .prereq(rxBytes)
1856657Snate@binkert.org        ;
1866657Snate@binkert.org
1876657Snate@binkert.org    txBandwidth
1886657Snate@binkert.org        .name(name() + ".txBandwidth")
1896657Snate@binkert.org        .desc("Transmit Bandwidth (bits/s)")
1906657Snate@binkert.org        .precision(0)
1916657Snate@binkert.org        .prereq(txBytes)
1926657Snate@binkert.org        ;
1936657Snate@binkert.org
1946657Snate@binkert.org    rxBandwidth
1956657Snate@binkert.org        .name(name() + ".rxBandwidth")
1966657Snate@binkert.org        .desc("Receive Bandwidth (bits/s)")
1976657Snate@binkert.org        .precision(0)
1986657Snate@binkert.org        .prereq(rxBytes)
1997002Snate@binkert.org        ;
2007002Snate@binkert.org
2017002Snate@binkert.org    txPacketRate
2027002Snate@binkert.org        .name(name() + ".txPPS")
2036877Ssteve.reinhardt@amd.com        .desc("Packet Tranmission Rate (packets/s)")
2046877Ssteve.reinhardt@amd.com        .precision(0)
2056657Snate@binkert.org        .prereq(txBytes)
2066657Snate@binkert.org        ;
2076657Snate@binkert.org
2086657Snate@binkert.org    rxPacketRate
2096657Snate@binkert.org        .name(name() + ".rxPPS")
2106657Snate@binkert.org        .desc("Packet Reception Rate (packets/s)")
2116657Snate@binkert.org        .precision(0)
2126657Snate@binkert.org        .prereq(rxBytes)
2136657Snate@binkert.org        ;
2146657Snate@binkert.org
2156793SBrad.Beckmann@amd.com    txBandwidth = txBytes * Stats::constant(8) / simSeconds;
2166657Snate@binkert.org    rxBandwidth = rxBytes * Stats::constant(8) / simSeconds;
2176657Snate@binkert.org    txPacketRate = txPackets / simSeconds;
2186657Snate@binkert.org    rxPacketRate = rxPackets / simSeconds;
2196657Snate@binkert.org}
2206657Snate@binkert.org
2217002Snate@binkert.org/**
2226657Snate@binkert.org * This is to read the PCI general configuration registers
2236657Snate@binkert.org */
2246657Snate@binkert.orgvoid
2256657Snate@binkert.orgNSGigE::ReadConfig(int offset, int size, uint8_t *data)
2266657Snate@binkert.org{
2276877Ssteve.reinhardt@amd.com    if (offset < PCI_DEVICE_SPECIFIC)
2286877Ssteve.reinhardt@amd.com        PciDev::ReadConfig(offset, size, data);
2296657Snate@binkert.org    else {
2306877Ssteve.reinhardt@amd.com        panic("need to do this\n");
2316657Snate@binkert.org    }
2326657Snate@binkert.org}
2337002Snate@binkert.org
2347002Snate@binkert.org/**
2356657Snate@binkert.org * This is to write to the PCI general configuration registers
2366881SBrad.Beckmann@amd.com */
2377002Snate@binkert.orgvoid
2387002Snate@binkert.orgNSGigE::WriteConfig(int offset, int size, uint32_t data)
2396657Snate@binkert.org{
2407002Snate@binkert.org    if (offset < PCI_DEVICE_SPECIFIC)
2416902SBrad.Beckmann@amd.com        PciDev::WriteConfig(offset, size, data);
2426863Sdrh5@cs.wisc.edu    else
2436863Sdrh5@cs.wisc.edu        panic("Need to do that\n");
2446657Snate@binkert.org}
2456657Snate@binkert.org
2466657Snate@binkert.org/**
2476657Snate@binkert.org * This reads the device registers, which are detailed in the NS83820
2486657Snate@binkert.org * spec sheet
2496657Snate@binkert.org */
2506882SBrad.Beckmann@amd.comFault
2516882SBrad.Beckmann@amd.comNSGigE::read(MemReqPtr &req, uint8_t *data)
2526882SBrad.Beckmann@amd.com{
2536882SBrad.Beckmann@amd.com    //The mask is to give you only the offset into the device register file
2546657Snate@binkert.org    Addr daddr = req->paddr & 0xfff;
2556657Snate@binkert.org    DPRINTF(EthernetPIO, "read  da=%#x pa=%#x va=%#x size=%d\n",
2566657Snate@binkert.org            daddr, req->paddr, req->vaddr, req->size);
2576657Snate@binkert.org
2586657Snate@binkert.org
2596657Snate@binkert.org    //there are some reserved registers, you can see ns_gige_reg.h and
2607002Snate@binkert.org    //the spec sheet for details
2616657Snate@binkert.org    if (daddr > LAST && daddr <=  RESERVED) {
2626657Snate@binkert.org        panic("Accessing reserved register");
2636657Snate@binkert.org    } else if (daddr > RESERVED && daddr <= 0x3FC) {
2647002Snate@binkert.org        ReadConfig(daddr & 0xff, req->size, data);
2656657Snate@binkert.org        return No_Fault;
2666657Snate@binkert.org    } else if (daddr >= MIB_START && daddr <= MIB_END) {
2676657Snate@binkert.org        // don't implement all the MIB's.  hopefully the kernel
2686863Sdrh5@cs.wisc.edu        // doesn't actually DEPEND upon their values
2696863Sdrh5@cs.wisc.edu        // MIB are just hardware stats keepers
2706657Snate@binkert.org        uint32_t &reg = *(uint32_t *) data;
2716657Snate@binkert.org        reg = 0;
2726657Snate@binkert.org        return No_Fault;
2736657Snate@binkert.org    } else if (daddr > 0x3FC)
2746657Snate@binkert.org        panic("Something is messed up!\n");
2756657Snate@binkert.org
2766657Snate@binkert.org    switch (req->size) {
2776657Snate@binkert.org      case sizeof(uint32_t):
2786657Snate@binkert.org        {
2796657Snate@binkert.org            uint32_t &reg = *(uint32_t *)data;
2806657Snate@binkert.org
2816657Snate@binkert.org            switch (daddr) {
2826657Snate@binkert.org              case CR:
2836657Snate@binkert.org                reg = regs.command;
2846657Snate@binkert.org                //these are supposed to be cleared on a read
2856657Snate@binkert.org                reg &= ~(CR_RXD | CR_TXD | CR_TXR | CR_RXR);
2866657Snate@binkert.org                break;
2876657Snate@binkert.org
2886657Snate@binkert.org              case CFG:
2896657Snate@binkert.org                reg = regs.config;
2906657Snate@binkert.org                break;
2916657Snate@binkert.org
2926657Snate@binkert.org              case MEAR:
2936657Snate@binkert.org                reg = regs.mear;
2946657Snate@binkert.org                break;
2956657Snate@binkert.org
2966657Snate@binkert.org              case PTSCR:
2976657Snate@binkert.org                reg = regs.ptscr;
2986657Snate@binkert.org                break;
2996657Snate@binkert.org
3006657Snate@binkert.org              case ISR:
3016657Snate@binkert.org                reg = regs.isr;
3026657Snate@binkert.org                devIntrClear(ISR_ALL);
3036657Snate@binkert.org                break;
3046657Snate@binkert.org
3056657Snate@binkert.org              case IMR:
3066657Snate@binkert.org                reg = regs.imr;
3076657Snate@binkert.org                break;
3086999Snate@binkert.org
3096657Snate@binkert.org              case IER:
3106657Snate@binkert.org                reg = regs.ier;
3116657Snate@binkert.org                break;
3126657Snate@binkert.org
3136657Snate@binkert.org              case IHR:
3146657Snate@binkert.org                reg = regs.ihr;
3156657Snate@binkert.org                break;
3166657Snate@binkert.org
3176657Snate@binkert.org              case TXDP:
3186657Snate@binkert.org                reg = regs.txdp;
3197002Snate@binkert.org                break;
3207002Snate@binkert.org
3217002Snate@binkert.org              case TXDP_HI:
3226657Snate@binkert.org                reg = regs.txdp_hi;
3236657Snate@binkert.org                break;
3246657Snate@binkert.org
3256657Snate@binkert.org              case TXCFG:
3266657Snate@binkert.org                reg = regs.txcfg;
3276657Snate@binkert.org                break;
3286657Snate@binkert.org
3297002Snate@binkert.org              case GPIOR:
3307002Snate@binkert.org                reg = regs.gpior;
3316657Snate@binkert.org                break;
3326657Snate@binkert.org
3336657Snate@binkert.org              case RXDP:
3346657Snate@binkert.org                reg = regs.rxdp;
3356657Snate@binkert.org                break;
3366793SBrad.Beckmann@amd.com
3376657Snate@binkert.org              case RXDP_HI:
3386657Snate@binkert.org                reg = regs.rxdp_hi;
3396657Snate@binkert.org                break;
3406657Snate@binkert.org
3416877Ssteve.reinhardt@amd.com              case RXCFG:
3426877Ssteve.reinhardt@amd.com                reg = regs.rxcfg;
3436877Ssteve.reinhardt@amd.com                break;
3446877Ssteve.reinhardt@amd.com
3456877Ssteve.reinhardt@amd.com              case PQCR:
3466877Ssteve.reinhardt@amd.com                reg = regs.pqcr;
3476877Ssteve.reinhardt@amd.com                break;
3486657Snate@binkert.org
3496657Snate@binkert.org              case WCSR:
3506657Snate@binkert.org                reg = regs.wcsr;
3516657Snate@binkert.org                break;
3526657Snate@binkert.org
3536877Ssteve.reinhardt@amd.com              case PCR:
3546877Ssteve.reinhardt@amd.com                reg = regs.pcr;
3556657Snate@binkert.org                break;
3566877Ssteve.reinhardt@amd.com
3576877Ssteve.reinhardt@amd.com                //see the spec sheet for how RFCR and RFDR work
3586877Ssteve.reinhardt@amd.com                //basically, you write to RFCR to tell the machine what you want to do next
3596877Ssteve.reinhardt@amd.com                //then you act upon RFDR, and the device will be prepared b/c
3606877Ssteve.reinhardt@amd.com                //of what you wrote to RFCR
3616969SBrad.Beckmann@amd.com              case RFCR:
3626657Snate@binkert.org                reg = regs.rfcr;
3636657Snate@binkert.org                break;
3646882SBrad.Beckmann@amd.com
3656882SBrad.Beckmann@amd.com              case RFDR:
3666882SBrad.Beckmann@amd.com                switch (regs.rfcr & RFCR_RFADDR) {
3676882SBrad.Beckmann@amd.com                  case 0x000:
3686882SBrad.Beckmann@amd.com                    reg = rom.perfectMatch[1];
3696882SBrad.Beckmann@amd.com                    reg = reg << 8;
3706882SBrad.Beckmann@amd.com                    reg += rom.perfectMatch[0];
3716882SBrad.Beckmann@amd.com                    break;
3726877Ssteve.reinhardt@amd.com                  case 0x002:
3736888SBrad.Beckmann@amd.com                    reg = rom.perfectMatch[3] << 8;
3746882SBrad.Beckmann@amd.com                    reg += rom.perfectMatch[2];
3756882SBrad.Beckmann@amd.com                    break;
3766882SBrad.Beckmann@amd.com                  case 0x004:
3776882SBrad.Beckmann@amd.com                    reg = rom.perfectMatch[5] << 8;
3786882SBrad.Beckmann@amd.com                    reg += rom.perfectMatch[4];
3796882SBrad.Beckmann@amd.com                    break;
3806882SBrad.Beckmann@amd.com                  default:
3816882SBrad.Beckmann@amd.com                    panic("reading from RFDR for something for other than PMATCH!\n");
3826882SBrad.Beckmann@amd.com                    //didn't implement other RFDR functionality b/c driver didn't use
3836882SBrad.Beckmann@amd.com                }
3846882SBrad.Beckmann@amd.com                break;
3856882SBrad.Beckmann@amd.com
3866882SBrad.Beckmann@amd.com              case SRR:
3876882SBrad.Beckmann@amd.com                reg = regs.srr;
3886882SBrad.Beckmann@amd.com                break;
3896882SBrad.Beckmann@amd.com
3906882SBrad.Beckmann@amd.com              case MIBC:
3916882SBrad.Beckmann@amd.com                reg = regs.mibc;
3926888SBrad.Beckmann@amd.com                reg &= ~(MIBC_MIBS | MIBC_ACLR);
3936888SBrad.Beckmann@amd.com                break;
3946888SBrad.Beckmann@amd.com
3956888SBrad.Beckmann@amd.com              case VRCR:
3966888SBrad.Beckmann@amd.com                reg = regs.vrcr;
3976888SBrad.Beckmann@amd.com                break;
3986888SBrad.Beckmann@amd.com
3996888SBrad.Beckmann@amd.com              case VTCR:
4006657Snate@binkert.org                reg = regs.vtcr;
4016888SBrad.Beckmann@amd.com                break;
4026888SBrad.Beckmann@amd.com
4036888SBrad.Beckmann@amd.com              case VDR:
4046888SBrad.Beckmann@amd.com                reg = regs.vdr;
4056657Snate@binkert.org                break;
4066657Snate@binkert.org
4076657Snate@binkert.org              case CCSR:
4086657Snate@binkert.org                reg = regs.ccsr;
4096657Snate@binkert.org                break;
4106657Snate@binkert.org
4116657Snate@binkert.org              case TBICR:
4126657Snate@binkert.org                reg = regs.tbicr;
4136657Snate@binkert.org                break;
4146877Ssteve.reinhardt@amd.com
4156657Snate@binkert.org              case TBISR:
4166657Snate@binkert.org                reg = regs.tbisr;
4176657Snate@binkert.org                break;
4186657Snate@binkert.org
4196657Snate@binkert.org              case TANAR:
4206657Snate@binkert.org                reg = regs.tanar;
4216657Snate@binkert.org                break;
4226657Snate@binkert.org
4236657Snate@binkert.org              case TANLPAR:
4246657Snate@binkert.org                reg = regs.tanlpar;
4256657Snate@binkert.org                break;
4266657Snate@binkert.org
4276657Snate@binkert.org              case TANER:
4286657Snate@binkert.org                reg = regs.taner;
4296657Snate@binkert.org                break;
4306657Snate@binkert.org
4316657Snate@binkert.org              case TESR:
4326657Snate@binkert.org                reg = regs.tesr;
4336657Snate@binkert.org                break;
4346657Snate@binkert.org
4356657Snate@binkert.org              default:
4366657Snate@binkert.org                panic("reading unimplemented register: addr = %#x", daddr);
4376657Snate@binkert.org            }
4386657Snate@binkert.org
4396657Snate@binkert.org            DPRINTF(EthernetPIO, "read from %#x: data=%d data=%#x\n",
4406657Snate@binkert.org                    daddr, reg, reg);
4416657Snate@binkert.org        }
4426657Snate@binkert.org        break;
4436657Snate@binkert.org
4446657Snate@binkert.org      default:
4456657Snate@binkert.org        panic("accessing register with invalid size: addr=%#x, size=%d",
4466657Snate@binkert.org              daddr, req->size);
4476657Snate@binkert.org    }
4486657Snate@binkert.org
4496657Snate@binkert.org    return No_Fault;
4506657Snate@binkert.org}
4516657Snate@binkert.org
4526657Snate@binkert.orgFault
4536657Snate@binkert.orgNSGigE::write(MemReqPtr &req, const uint8_t *data)
4546657Snate@binkert.org{
4556657Snate@binkert.org    Addr daddr = req->paddr & 0xfff;
4566657Snate@binkert.org    DPRINTF(EthernetPIO, "write da=%#x pa=%#x va=%#x size=%d\n",
4576657Snate@binkert.org            daddr, req->paddr, req->vaddr, req->size);
4586657Snate@binkert.org
4596657Snate@binkert.org    if (daddr > LAST && daddr <=  RESERVED) {
4606657Snate@binkert.org        panic("Accessing reserved register");
4616657Snate@binkert.org    } else if (daddr > RESERVED && daddr <= 0x3FC) {
4626657Snate@binkert.org        WriteConfig(daddr & 0xff, req->size, *(uint32_t *)data);
4636657Snate@binkert.org        return No_Fault;
4646657Snate@binkert.org    } else if (daddr > 0x3FC)
4656657Snate@binkert.org        panic("Something is messed up!\n");
4666657Snate@binkert.org
4676657Snate@binkert.org    if (req->size == sizeof(uint32_t)) {
4686657Snate@binkert.org        uint32_t reg = *(uint32_t *)data;
4696657Snate@binkert.org        DPRINTF(EthernetPIO, "write data=%d data=%#x\n", reg, reg);
4706657Snate@binkert.org
4716657Snate@binkert.org        switch (daddr) {
4726657Snate@binkert.org          case CR:
4736657Snate@binkert.org            regs.command = reg;
4746657Snate@binkert.org            if ((reg & (CR_TXE | CR_TXD)) == (CR_TXE | CR_TXD)) {
4756657Snate@binkert.org                txHalt = true;
4766657Snate@binkert.org            } else if (reg & CR_TXE) {
4776657Snate@binkert.org                //the kernel is enabling the transmit machine
4786657Snate@binkert.org                if (txState == txIdle)
4796657Snate@binkert.org                    txKick();
4806657Snate@binkert.org            } else if (reg & CR_TXD) {
4816657Snate@binkert.org                txHalt = true;
4826657Snate@binkert.org            }
4836657Snate@binkert.org
4846657Snate@binkert.org            if ((reg & (CR_RXE | CR_RXD)) == (CR_RXE | CR_RXD)) {
4856657Snate@binkert.org                rxHalt = true;
4866657Snate@binkert.org            } else if (reg & CR_RXE) {
4876657Snate@binkert.org                if (rxState == rxIdle) {
4886657Snate@binkert.org                    rxKick();
4896657Snate@binkert.org                }
4906657Snate@binkert.org            } else if (reg & CR_RXD) {
4916657Snate@binkert.org                rxHalt = true;
4926657Snate@binkert.org            }
4936657Snate@binkert.org
4946657Snate@binkert.org            if (reg & CR_TXR)
4956657Snate@binkert.org                txReset();
4966657Snate@binkert.org
4976657Snate@binkert.org            if (reg & CR_RXR)
4986657Snate@binkert.org                rxReset();
4996657Snate@binkert.org
5006657Snate@binkert.org            if (reg & CR_SWI)
5016657Snate@binkert.org                devIntrPost(ISR_SWI);
5026657Snate@binkert.org
5036657Snate@binkert.org            if (reg & CR_RST) {
5046657Snate@binkert.org                txReset();
5056657Snate@binkert.org                rxReset();
5066657Snate@binkert.org
5076657Snate@binkert.org                regsReset();
5086657Snate@binkert.org            }
5096657Snate@binkert.org            break;
5106657Snate@binkert.org
5116657Snate@binkert.org          case CFG:
5126657Snate@binkert.org            if (reg & CFG_LNKSTS || reg & CFG_SPDSTS || reg & CFG_DUPSTS
5136657Snate@binkert.org                || reg & CFG_RESERVED || reg & CFG_T64ADDR
5146657Snate@binkert.org                || reg & CFG_PCI64_DET)
5156657Snate@binkert.org                panic("writing to read-only or reserved CFG bits!\n");
5166657Snate@binkert.org
5176657Snate@binkert.org            regs.config |= reg & ~(CFG_LNKSTS | CFG_SPDSTS | CFG_DUPSTS | CFG_RESERVED |
5186657Snate@binkert.org                                  CFG_T64ADDR | CFG_PCI64_DET);
5196657Snate@binkert.org
5206657Snate@binkert.org// all these #if 0's are because i don't THINK the kernel needs to have these implemented
5216657Snate@binkert.org// if there is a problem relating to one of these, you may need to add functionality in
5226657Snate@binkert.org#if 0
5236657Snate@binkert.org              if (reg & CFG_TBI_EN) ;
5246657Snate@binkert.org              if (reg & CFG_MODE_1000) ;
5256657Snate@binkert.org#endif
5266657Snate@binkert.org
5276657Snate@binkert.org            if (reg & CFG_AUTO_1000)
5286657Snate@binkert.org                panic("CFG_AUTO_1000 not implemented!\n");
5296657Snate@binkert.org
5306657Snate@binkert.org#if 0
5316657Snate@binkert.org            if (reg & CFG_PINT_DUPSTS || reg & CFG_PINT_LNKSTS || reg & CFG_PINT_SPDSTS) ;
5326657Snate@binkert.org            if (reg & CFG_TMRTEST) ;
5336657Snate@binkert.org            if (reg & CFG_MRM_DIS) ;
5346657Snate@binkert.org            if (reg & CFG_MWI_DIS) ;
5356657Snate@binkert.org
5366657Snate@binkert.org            if (reg & CFG_T64ADDR)
5376657Snate@binkert.org                panic("CFG_T64ADDR is read only register!\n");
5386657Snate@binkert.org
5396657Snate@binkert.org            if (reg & CFG_PCI64_DET)
5406657Snate@binkert.org                panic("CFG_PCI64_DET is read only register!\n");
5416657Snate@binkert.org
5426657Snate@binkert.org            if (reg & CFG_DATA64_EN) ;
5436657Snate@binkert.org            if (reg & CFG_M64ADDR) ;
5446657Snate@binkert.org            if (reg & CFG_PHY_RST) ;
5456657Snate@binkert.org            if (reg & CFG_PHY_DIS) ;
5466657Snate@binkert.org#endif
5476657Snate@binkert.org
5486657Snate@binkert.org            if (reg & CFG_EXTSTS_EN)
5496657Snate@binkert.org                extstsEnable = true;
5506657Snate@binkert.org            else
5516657Snate@binkert.org                extstsEnable = false;
5526657Snate@binkert.org
5536657Snate@binkert.org#if 0
5546657Snate@binkert.org              if (reg & CFG_REQALG) ;
5556657Snate@binkert.org              if (reg & CFG_SB) ;
5566657Snate@binkert.org              if (reg & CFG_POW) ;
5576657Snate@binkert.org              if (reg & CFG_EXD) ;
5586657Snate@binkert.org              if (reg & CFG_PESEL) ;
5596657Snate@binkert.org              if (reg & CFG_BROM_DIS) ;
5606657Snate@binkert.org              if (reg & CFG_EXT_125) ;
5616657Snate@binkert.org              if (reg & CFG_BEM) ;
5626657Snate@binkert.org#endif
5636657Snate@binkert.org            break;
5646657Snate@binkert.org
5656657Snate@binkert.org          case MEAR:
5666657Snate@binkert.org            regs.mear = reg;
5676657Snate@binkert.org            /* since phy is completely faked, MEAR_MD* don't matter
5686657Snate@binkert.org               and since the driver never uses MEAR_EE*, they don't matter */
5696657Snate@binkert.org#if 0
5706657Snate@binkert.org            if (reg & MEAR_EEDI) ;
5716657Snate@binkert.org            if (reg & MEAR_EEDO) ; //this one is read only
5726657Snate@binkert.org            if (reg & MEAR_EECLK) ;
5736657Snate@binkert.org            if (reg & MEAR_EESEL) ;
5746657Snate@binkert.org            if (reg & MEAR_MDIO) ;
5756657Snate@binkert.org            if (reg & MEAR_MDDIR) ;
5766657Snate@binkert.org            if (reg & MEAR_MDC) ;
5776657Snate@binkert.org#endif
5786657Snate@binkert.org            break;
5796863Sdrh5@cs.wisc.edu
5806863Sdrh5@cs.wisc.edu          case PTSCR:
5816863Sdrh5@cs.wisc.edu            regs.ptscr = reg & ~(PTSCR_RBIST_RDONLY);
5826863Sdrh5@cs.wisc.edu            /* these control BISTs for various parts of chip - we don't care or do
5836863Sdrh5@cs.wisc.edu               just fake that the BIST is done */
5846863Sdrh5@cs.wisc.edu            if (reg & PTSCR_RBIST_EN)
5856863Sdrh5@cs.wisc.edu                regs.ptscr |= PTSCR_RBIST_DONE;
5866863Sdrh5@cs.wisc.edu            if (reg & PTSCR_EEBIST_EN)
5876863Sdrh5@cs.wisc.edu                regs.ptscr &= ~PTSCR_EEBIST_EN;
5886863Sdrh5@cs.wisc.edu            if (reg & PTSCR_EELOAD_EN)
5896863Sdrh5@cs.wisc.edu                regs.ptscr &= ~PTSCR_EELOAD_EN;
5906657Snate@binkert.org            break;
5916657Snate@binkert.org
5926657Snate@binkert.org          case ISR: /* writing to the ISR has no effect */
5936657Snate@binkert.org            panic("ISR is a read only register!\n");
5946657Snate@binkert.org
5956657Snate@binkert.org          case IMR:
5966657Snate@binkert.org            regs.imr = reg;
5976657Snate@binkert.org            devIntrChangeMask();
5986657Snate@binkert.org            break;
5996657Snate@binkert.org
6006902SBrad.Beckmann@amd.com          case IER:
6016902SBrad.Beckmann@amd.com            regs.ier = reg;
6026902SBrad.Beckmann@amd.com            break;
6036902SBrad.Beckmann@amd.com
6046902SBrad.Beckmann@amd.com          case IHR:
6056902SBrad.Beckmann@amd.com            regs.ihr = reg;
6066902SBrad.Beckmann@amd.com            /* not going to implement real interrupt holdoff */
6076902SBrad.Beckmann@amd.com            break;
6086902SBrad.Beckmann@amd.com
6096902SBrad.Beckmann@amd.com          case TXDP:
6106902SBrad.Beckmann@amd.com            regs.txdp = (reg & 0xFFFFFFFC);
6116902SBrad.Beckmann@amd.com            assert(txState == txIdle);
6126902SBrad.Beckmann@amd.com            CTDD = false;
6136902SBrad.Beckmann@amd.com            break;
6146902SBrad.Beckmann@amd.com
6156902SBrad.Beckmann@amd.com          case TXDP_HI:
6166902SBrad.Beckmann@amd.com            regs.txdp_hi = reg;
6176902SBrad.Beckmann@amd.com            break;
6186902SBrad.Beckmann@amd.com
6196902SBrad.Beckmann@amd.com          case TXCFG:
6206902SBrad.Beckmann@amd.com            regs.txcfg = reg;
6216902SBrad.Beckmann@amd.com#if 0
6226902SBrad.Beckmann@amd.com            if (reg & TXCFG_CSI) ;
6236902SBrad.Beckmann@amd.com            if (reg & TXCFG_HBI) ;
6246902SBrad.Beckmann@amd.com            if (reg & TXCFG_MLB) ;
6256902SBrad.Beckmann@amd.com            if (reg & TXCFG_ATP) ;
6266902SBrad.Beckmann@amd.com            if (reg & TXCFG_ECRETRY) ;  /* this could easily be implemented, but
6276902SBrad.Beckmann@amd.com                                           considering the network is just a fake
6286902SBrad.Beckmann@amd.com                                           pipe, wouldn't make sense to do this */
6296902SBrad.Beckmann@amd.com
6306902SBrad.Beckmann@amd.com            if (reg & TXCFG_BRST_DIS) ;
6316902SBrad.Beckmann@amd.com#endif
6326657Snate@binkert.org
6336657Snate@binkert.org
6346657Snate@binkert.org            /* we handle our own DMA, ignore the kernel's exhortations */
6356657Snate@binkert.org            if (reg & TXCFG_MXDMA) ;
6366657Snate@binkert.org
6376657Snate@binkert.org            break;
6386657Snate@binkert.org
6396657Snate@binkert.org          case GPIOR:
6406657Snate@binkert.org            regs.gpior = reg;
6416657Snate@binkert.org            /* these just control general purpose i/o pins, don't matter */
6426657Snate@binkert.org            break;
6436657Snate@binkert.org
6446657Snate@binkert.org          case RXDP:
6456657Snate@binkert.org            regs.rxdp = reg;
6466657Snate@binkert.org            break;
6476657Snate@binkert.org
6486657Snate@binkert.org          case RXDP_HI:
6496657Snate@binkert.org            regs.rxdp_hi = reg;
6506657Snate@binkert.org            break;
6516657Snate@binkert.org
6526657Snate@binkert.org          case RXCFG:
6536999Snate@binkert.org            regs.rxcfg = reg;
6546657Snate@binkert.org#if 0
6556657Snate@binkert.org            if (reg & RXCFG_AEP) ;
6566657Snate@binkert.org            if (reg & RXCFG_ARP) ;
6576657Snate@binkert.org            if (reg & RXCFG_STRIPCRC) ;
6586657Snate@binkert.org            if (reg & RXCFG_RX_RD) ;
6596657Snate@binkert.org            if (reg & RXCFG_ALP) ;
6606657Snate@binkert.org            if (reg & RXCFG_AIRL) ;
6616657Snate@binkert.org#endif
6626657Snate@binkert.org
6636657Snate@binkert.org            /* we handle our own DMA, ignore what kernel says about it */
6646657Snate@binkert.org            if (reg & RXCFG_MXDMA) ;
6656657Snate@binkert.org
6666657Snate@binkert.org#if 0
6676657Snate@binkert.org            if (reg & (RXCFG_DRTH | RXCFG_DRTH0)) ;
6686657Snate@binkert.org#endif
6696657Snate@binkert.org            break;
6706657Snate@binkert.org
6716657Snate@binkert.org          case PQCR:
6726657Snate@binkert.org            /* there is no priority queueing used in the linux 2.6 driver */
6736657Snate@binkert.org            regs.pqcr = reg;
6746657Snate@binkert.org            break;
6756657Snate@binkert.org
6766657Snate@binkert.org          case WCSR:
6776657Snate@binkert.org            /* not going to implement wake on LAN */
6786657Snate@binkert.org            regs.wcsr = reg;
6796657Snate@binkert.org            break;
6806657Snate@binkert.org
6816657Snate@binkert.org          case PCR:
6826657Snate@binkert.org            /* not going to implement pause control */
6836657Snate@binkert.org            regs.pcr = reg;
6846657Snate@binkert.org            break;
6856657Snate@binkert.org
6866657Snate@binkert.org          case RFCR:
6876657Snate@binkert.org            regs.rfcr = reg;
6886657Snate@binkert.org
6896657Snate@binkert.org            rxFilterEnable = (reg & RFCR_RFEN) ? true : false;
6906657Snate@binkert.org
6916657Snate@binkert.org            acceptBroadcast = (reg & RFCR_AAB) ? true : false;
6926657Snate@binkert.org
6936657Snate@binkert.org            acceptMulticast = (reg & RFCR_AAM) ? true : false;
6946657Snate@binkert.org
6956657Snate@binkert.org            acceptUnicast = (reg & RFCR_AAU) ? true : false;
6966657Snate@binkert.org
6976657Snate@binkert.org            acceptPerfect = (reg & RFCR_APM) ? true : false;
6986657Snate@binkert.org
6996657Snate@binkert.org            acceptArp = (reg & RFCR_AARP) ? true : false;
7006657Snate@binkert.org
7016657Snate@binkert.org            if (reg & RFCR_APAT) ;
7026657Snate@binkert.org//                panic("RFCR_APAT not implemented!\n");
7036657Snate@binkert.org
7046657Snate@binkert.org            if (reg & RFCR_MHEN || reg & RFCR_UHEN)
7056657Snate@binkert.org                panic("hash filtering not implemented!\n");
7066657Snate@binkert.org
7076657Snate@binkert.org            if (reg & RFCR_ULM)
7086999Snate@binkert.org                panic("RFCR_ULM not implemented!\n");
7096657Snate@binkert.org
7106657Snate@binkert.org            break;
7116657Snate@binkert.org
7126657Snate@binkert.org          case RFDR:
7136657Snate@binkert.org            panic("the driver never writes to RFDR, something is wrong!\n");
7146657Snate@binkert.org
7156657Snate@binkert.org          case BRAR:
7166657Snate@binkert.org            panic("the driver never uses BRAR, something is wrong!\n");
7176657Snate@binkert.org
7186657Snate@binkert.org          case BRDR:
7196657Snate@binkert.org            panic("the driver never uses BRDR, something is wrong!\n");
7206657Snate@binkert.org
7216657Snate@binkert.org          case SRR:
7226657Snate@binkert.org            panic("SRR is read only register!\n");
7236657Snate@binkert.org
7246657Snate@binkert.org          case MIBC:
7256657Snate@binkert.org            panic("the driver never uses MIBC, something is wrong!\n");
7266657Snate@binkert.org
7276657Snate@binkert.org          case VRCR:
7286657Snate@binkert.org            regs.vrcr = reg;
7296657Snate@binkert.org            break;
7306657Snate@binkert.org
7316657Snate@binkert.org          case VTCR:
7326657Snate@binkert.org            regs.vtcr = reg;
7336657Snate@binkert.org            break;
7346657Snate@binkert.org
7356657Snate@binkert.org          case VDR:
7366657Snate@binkert.org            panic("the driver never uses VDR, something is wrong!\n");
7376657Snate@binkert.org            break;
7386657Snate@binkert.org
7396657Snate@binkert.org          case CCSR:
7406657Snate@binkert.org            /* not going to implement clockrun stuff */
7416657Snate@binkert.org            regs.ccsr = reg;
7426657Snate@binkert.org            break;
7436657Snate@binkert.org
7446657Snate@binkert.org          case TBICR:
7456657Snate@binkert.org            regs.tbicr = reg;
7466657Snate@binkert.org            if (reg & TBICR_MR_LOOPBACK)
7476657Snate@binkert.org                panic("TBICR_MR_LOOPBACK never used, something wrong!\n");
7486657Snate@binkert.org
7496657Snate@binkert.org            if (reg & TBICR_MR_AN_ENABLE) {
7506657Snate@binkert.org                regs.tanlpar = regs.tanar;
7516657Snate@binkert.org                regs.tbisr |= (TBISR_MR_AN_COMPLETE | TBISR_MR_LINK_STATUS);
7526657Snate@binkert.org            }
7536657Snate@binkert.org
7546657Snate@binkert.org#if 0
7556657Snate@binkert.org            if (reg & TBICR_MR_RESTART_AN) ;
7566657Snate@binkert.org#endif
7576657Snate@binkert.org
7586657Snate@binkert.org            break;
7596657Snate@binkert.org
7606657Snate@binkert.org          case TBISR:
7616657Snate@binkert.org            panic("TBISR is read only register!\n");
7626657Snate@binkert.org
7636657Snate@binkert.org          case TANAR:
7646657Snate@binkert.org            regs.tanar = reg;
7656657Snate@binkert.org            if (reg & TANAR_PS2)
7666657Snate@binkert.org                panic("this isn't used in driver, something wrong!\n");
7676657Snate@binkert.org
7686657Snate@binkert.org            if (reg & TANAR_PS1)
7696657Snate@binkert.org                panic("this isn't used in driver, something wrong!\n");
7706657Snate@binkert.org            break;
7716657Snate@binkert.org
7726657Snate@binkert.org          case TANLPAR:
7736657Snate@binkert.org            panic("this should only be written to by the fake phy!\n");
7746657Snate@binkert.org
7756657Snate@binkert.org          case TANER:
7766657Snate@binkert.org            panic("TANER is read only register!\n");
7776657Snate@binkert.org
7786657Snate@binkert.org          case TESR:
7796657Snate@binkert.org            regs.tesr = reg;
7806657Snate@binkert.org            break;
7816657Snate@binkert.org
7826657Snate@binkert.org          default:
7836657Snate@binkert.org            panic("thought i covered all the register, what is this? addr=%#x",
7846657Snate@binkert.org                  daddr);
7856657Snate@binkert.org        }
7866657Snate@binkert.org    } else
7876657Snate@binkert.org        panic("Invalid Request Size");
7886657Snate@binkert.org
7896657Snate@binkert.org    return No_Fault;
7906999Snate@binkert.org}
7916657Snate@binkert.org
7926657Snate@binkert.orgvoid
7936657Snate@binkert.orgNSGigE::devIntrPost(uint32_t interrupts)
7946657Snate@binkert.org{
7956657Snate@binkert.org    bool delay = false;
7966657Snate@binkert.org
7976657Snate@binkert.org    if (interrupts & ISR_RESERVE)
7986657Snate@binkert.org        panic("Cannot set a reserved interrupt");
7996657Snate@binkert.org
8006657Snate@binkert.org    if (interrupts & ISR_TXRCMP)
8016657Snate@binkert.org        regs.isr |= ISR_TXRCMP;
8026657Snate@binkert.org
8036657Snate@binkert.org    if (interrupts & ISR_RXRCMP)
8046657Snate@binkert.org        regs.isr |= ISR_RXRCMP;
8056657Snate@binkert.org
8066657Snate@binkert.org//ISR_DPERR  not implemented
8076657Snate@binkert.org//ISR_SSERR not implemented
8086657Snate@binkert.org//ISR_RMABT not implemented
8096657Snate@binkert.org//ISR_RXSOVR not implemented
8106657Snate@binkert.org//ISR_HIBINT not implemented
8116657Snate@binkert.org//ISR_PHY not implemented
8126657Snate@binkert.org//ISR_PME not implemented
8136657Snate@binkert.org
8146657Snate@binkert.org    if (interrupts & ISR_SWI)
8156657Snate@binkert.org        regs.isr |= ISR_SWI;
8166657Snate@binkert.org
8176657Snate@binkert.org//ISR_MIB not implemented
8186657Snate@binkert.org//ISR_TXURN not implemented
8196657Snate@binkert.org
8206657Snate@binkert.org    if (interrupts & ISR_TXIDLE)
8216657Snate@binkert.org        regs.isr |= ISR_TXIDLE;
8226657Snate@binkert.org
8236657Snate@binkert.org    if (interrupts & ISR_TXERR)
8246657Snate@binkert.org        regs.isr |= ISR_TXERR;
8256657Snate@binkert.org
8266657Snate@binkert.org    if (interrupts & ISR_TXDESC)
8276657Snate@binkert.org        regs.isr |= ISR_TXDESC;
8286657Snate@binkert.org
8296657Snate@binkert.org    if (interrupts & ISR_TXOK) {
8306657Snate@binkert.org        regs.isr |= ISR_TXOK;
8316657Snate@binkert.org        delay = true;
8326657Snate@binkert.org    }
8336657Snate@binkert.org
8346657Snate@binkert.org    if (interrupts & ISR_RXORN)
8356657Snate@binkert.org        regs.isr |= ISR_RXORN;
8366657Snate@binkert.org
8376657Snate@binkert.org    if (interrupts & ISR_RXIDLE)
8386657Snate@binkert.org        regs.isr |= ISR_RXIDLE;
8396657Snate@binkert.org
8406657Snate@binkert.org//ISR_RXEARLY not implemented
8416657Snate@binkert.org
8426657Snate@binkert.org    if (interrupts & ISR_RXERR)
8436657Snate@binkert.org        regs.isr |= ISR_RXERR;
8446657Snate@binkert.org
8456657Snate@binkert.org    if (interrupts & ISR_RXDESC)
8466657Snate@binkert.org        regs.isr |= ISR_RXDESC;
8476657Snate@binkert.org
8486657Snate@binkert.org    if (interrupts & ISR_RXOK) {
8496657Snate@binkert.org        delay = true;
8506657Snate@binkert.org        regs.isr |= ISR_RXOK;
8516657Snate@binkert.org    }
8526657Snate@binkert.org
8536657Snate@binkert.org    if ((regs.isr & regs.imr)) {
8546657Snate@binkert.org        Tick when = curTick;
8556657Snate@binkert.org        if (delay)
8566657Snate@binkert.org            when += intrDelay;
8576657Snate@binkert.org        cpuIntrPost(when);
8586657Snate@binkert.org    }
8596657Snate@binkert.org
8606657Snate@binkert.org    DPRINTF(Ethernet, "interrupt posted intr=%#x isr=%#x imr=%#x\n",
8616657Snate@binkert.org            interrupts, regs.isr, regs.imr);
8626657Snate@binkert.org}
8636657Snate@binkert.org
8646657Snate@binkert.orgvoid
8656999Snate@binkert.orgNSGigE::devIntrClear(uint32_t interrupts)
8666657Snate@binkert.org{
8676657Snate@binkert.org    if (interrupts & ISR_RESERVE)
8686657Snate@binkert.org        panic("Cannot clear a reserved interrupt");
8696657Snate@binkert.org
8706657Snate@binkert.org    if (interrupts & ISR_TXRCMP)
8716657Snate@binkert.org        regs.isr &= ~ISR_TXRCMP;
8726657Snate@binkert.org
8736657Snate@binkert.org    if (interrupts & ISR_RXRCMP)
8746657Snate@binkert.org        regs.isr &= ~ISR_RXRCMP;
8757002Snate@binkert.org
8767002Snate@binkert.org//ISR_DPERR  not implemented
8776657Snate@binkert.org//ISR_SSERR not implemented
8786657Snate@binkert.org//ISR_RMABT not implemented
8796657Snate@binkert.org//ISR_RXSOVR not implemented
8806657Snate@binkert.org//ISR_HIBINT not implemented
8816657Snate@binkert.org//ISR_PHY not implemented
8826657Snate@binkert.org//ISR_PME not implemented
8836657Snate@binkert.org
8846657Snate@binkert.org    if (interrupts & ISR_SWI)
8856657Snate@binkert.org        regs.isr &= ~ISR_SWI;
8866657Snate@binkert.org
8877002Snate@binkert.org//ISR_MIB not implemented
8886657Snate@binkert.org//ISR_TXURN not implemented
8896657Snate@binkert.org
8906657Snate@binkert.org    if (interrupts & ISR_TXIDLE)
8916657Snate@binkert.org        regs.isr &= ~ISR_TXIDLE;
8926657Snate@binkert.org
8936657Snate@binkert.org    if (interrupts & ISR_TXERR)
8946657Snate@binkert.org        regs.isr &= ~ISR_TXERR;
8956657Snate@binkert.org
8966657Snate@binkert.org    if (interrupts & ISR_TXDESC)
8976657Snate@binkert.org        regs.isr &= ~ISR_TXDESC;
8986657Snate@binkert.org
8996657Snate@binkert.org    if (interrupts & ISR_TXOK)
9006657Snate@binkert.org        regs.isr &= ~ISR_TXOK;
9016657Snate@binkert.org
9026999Snate@binkert.org    if (interrupts & ISR_RXORN)
9036657Snate@binkert.org        regs.isr &= ~ISR_RXORN;
9046657Snate@binkert.org
9056657Snate@binkert.org    if (interrupts & ISR_RXIDLE)
9066657Snate@binkert.org        regs.isr &= ~ISR_RXIDLE;
9076657Snate@binkert.org
9086657Snate@binkert.org//ISR_RXEARLY not implemented
9096657Snate@binkert.org
9106657Snate@binkert.org    if (interrupts & ISR_RXERR)
9116657Snate@binkert.org        regs.isr &= ~ISR_RXERR;
9126657Snate@binkert.org
9136657Snate@binkert.org    if (interrupts & ISR_RXDESC)
9146657Snate@binkert.org        regs.isr &= ~ISR_RXDESC;
9156657Snate@binkert.org
9166657Snate@binkert.org    if (interrupts & ISR_RXOK)
9176657Snate@binkert.org        regs.isr &= ~ISR_RXOK;
9186657Snate@binkert.org
9196657Snate@binkert.org    if (!(regs.isr & regs.imr))
9206657Snate@binkert.org        cpuIntrClear();
9216657Snate@binkert.org
9226657Snate@binkert.org    DPRINTF(Ethernet, "interrupt cleared intr=%x isr=%x imr=%x\n",
9236657Snate@binkert.org            interrupts, regs.isr, regs.imr);
9246657Snate@binkert.org}
9256657Snate@binkert.org
9266657Snate@binkert.orgvoid
9276657Snate@binkert.orgNSGigE::devIntrChangeMask()
9286657Snate@binkert.org{
9296657Snate@binkert.org    DPRINTF(Ethernet, "interrupt mask changed\n");
9306657Snate@binkert.org
9316657Snate@binkert.org    if (regs.isr & regs.imr)
9326657Snate@binkert.org        cpuIntrPost(curTick);
9336657Snate@binkert.org    else
9346657Snate@binkert.org        cpuIntrClear();
9356657Snate@binkert.org}
9366657Snate@binkert.org
9376657Snate@binkert.orgvoid
9386657Snate@binkert.orgNSGigE::cpuIntrPost(Tick when)
9396657Snate@binkert.org{
9406657Snate@binkert.org    if (when > intrTick && intrTick != 0)
9416657Snate@binkert.org        return;
9426657Snate@binkert.org
9436657Snate@binkert.org    intrTick = when;
9446657Snate@binkert.org
9456657Snate@binkert.org    if (intrEvent) {
9466657Snate@binkert.org        intrEvent->squash();
9476657Snate@binkert.org        intrEvent = 0;
9486657Snate@binkert.org    }
9497002Snate@binkert.org
9506657Snate@binkert.org    if (when < curTick) {
9517002Snate@binkert.org        cpuInterrupt();
9527002Snate@binkert.org    } else {
9536657Snate@binkert.org        intrEvent = new IntrEvent(this, true);
9546657Snate@binkert.org        intrEvent->schedule(intrTick);
9556657Snate@binkert.org    }
9566657Snate@binkert.org}
9576657Snate@binkert.org
9586657Snate@binkert.orgvoid
9596657Snate@binkert.orgNSGigE::cpuInterrupt()
9606657Snate@binkert.org{
9616657Snate@binkert.org    // Don't send an interrupt if there's already one
9626657Snate@binkert.org    if (cpuPendingIntr)
9636657Snate@binkert.org        return;
9646657Snate@binkert.org
9656657Snate@binkert.org    // Don't send an interrupt if it's supposed to be delayed
9666657Snate@binkert.org    if (intrTick > curTick)
9676657Snate@binkert.org        return;
9686657Snate@binkert.org
9696657Snate@binkert.org    // Whether or not there's a pending interrupt, we don't care about
9706657Snate@binkert.org    // it anymore
9716657Snate@binkert.org    intrEvent = 0;
9726657Snate@binkert.org    intrTick = 0;
9736657Snate@binkert.org
9746657Snate@binkert.org    // Send interrupt
9756657Snate@binkert.org    cpuPendingIntr = true;
9766657Snate@binkert.org    /** @todo rework the intctrl to be tsunami ok */
9776657Snate@binkert.org    //intctrl->post(TheISA::INTLEVEL_IRQ1, TheISA::INTINDEX_ETHERNET);
9786657Snate@binkert.org    tsunami->cchip->postDRIR(configData->config.hdr.pci0.interruptLine);
9796657Snate@binkert.org}
9806657Snate@binkert.org
9816657Snate@binkert.orgvoid
9826657Snate@binkert.orgNSGigE::cpuIntrClear()
9836999Snate@binkert.org{
9846657Snate@binkert.org    if (cpuPendingIntr) {
9856657Snate@binkert.org        cpuPendingIntr = false;
9866657Snate@binkert.org        /** @todo rework the intctrl to be tsunami ok */
9876657Snate@binkert.org        //intctrl->clear(TheISA::INTLEVEL_IRQ1, TheISA::INTINDEX_ETHERNET);
9886657Snate@binkert.org        tsunami->cchip->clearDRIR(configData->config.hdr.pci0.interruptLine);
9896657Snate@binkert.org    }
9906657Snate@binkert.org}
9916657Snate@binkert.org
9926657Snate@binkert.orgbool
9936657Snate@binkert.orgNSGigE::cpuIntrPending() const
9946657Snate@binkert.org{ return cpuPendingIntr; }
9956657Snate@binkert.org
9966657Snate@binkert.orgvoid
9976657Snate@binkert.orgNSGigE::txReset()
9986657Snate@binkert.org{
9996657Snate@binkert.org
10006657Snate@binkert.org    DPRINTF(Ethernet, "transmit reset\n");
10016657Snate@binkert.org
10026657Snate@binkert.org    CTDD = false;
10036657Snate@binkert.org    txFifoCnt = 0;
10046657Snate@binkert.org    txFifoAvail = MAX_TX_FIFO_SIZE;
10056657Snate@binkert.org    txHalt = false;
10066657Snate@binkert.org    txFragPtr = 0;
10076657Snate@binkert.org    assert(txDescCnt == 0);
10086657Snate@binkert.org    txFifo.clear();
10096657Snate@binkert.org    regs.command &= ~CR_TXE;
10106657Snate@binkert.org    txState = txIdle;
10116657Snate@binkert.org    assert(txDmaState == dmaIdle);
10126657Snate@binkert.org}
10136657Snate@binkert.org
10146999Snate@binkert.orgvoid
10156657Snate@binkert.orgNSGigE::rxReset()
10166657Snate@binkert.org{
10176657Snate@binkert.org    DPRINTF(Ethernet, "receive reset\n");
10186657Snate@binkert.org
10196657Snate@binkert.org    CRDD = false;
10206657Snate@binkert.org    assert(rxPktBytes == 0);
10216657Snate@binkert.org    rxFifoCnt = 0;
10226657Snate@binkert.org    rxHalt = false;
10236657Snate@binkert.org    rxFragPtr = 0;
10246657Snate@binkert.org    assert(rxDescCnt == 0);
10256657Snate@binkert.org    assert(rxDmaState == dmaIdle);
10266657Snate@binkert.org    rxFifo.clear();
10276657Snate@binkert.org    regs.command &= ~CR_RXE;
10286657Snate@binkert.org    rxState = rxIdle;
10296657Snate@binkert.org}
10306657Snate@binkert.org
10316657Snate@binkert.orgvoid
10326657Snate@binkert.orgNSGigE::rxDmaReadCopy()
10336657Snate@binkert.org{
10346657Snate@binkert.org    assert(rxDmaState == dmaReading);
10356657Snate@binkert.org
10366657Snate@binkert.org    memcpy(rxDmaData, physmem->dma_addr(rxDmaAddr, rxDmaLen), rxDmaLen);
10376657Snate@binkert.org    rxDmaState = dmaIdle;
10386657Snate@binkert.org
10396657Snate@binkert.org    DPRINTF(EthernetDMA, "rx dma read  paddr=%#x len=%d\n",
10406657Snate@binkert.org            rxDmaAddr, rxDmaLen);
10416657Snate@binkert.org    DDUMP(EthernetDMA, rxDmaData, rxDmaLen);
10426657Snate@binkert.org}
10436657Snate@binkert.org
10446657Snate@binkert.orgbool
10456657Snate@binkert.orgNSGigE::doRxDmaRead()
10466657Snate@binkert.org{
10476657Snate@binkert.org    assert(rxDmaState == dmaIdle || rxDmaState == dmaReadWaiting);
10486657Snate@binkert.org    rxDmaState = dmaReading;
10496657Snate@binkert.org
10506657Snate@binkert.org    if (dmaInterface && !rxDmaFree) {
10516657Snate@binkert.org        if (dmaInterface->busy())
10526657Snate@binkert.org            rxDmaState = dmaReadWaiting;
10536657Snate@binkert.org        else
10546657Snate@binkert.org            dmaInterface->doDMA(Read, rxDmaAddr, rxDmaLen, curTick,
10556657Snate@binkert.org                                &rxDmaReadEvent);
10566657Snate@binkert.org        return true;
10576657Snate@binkert.org    }
10586657Snate@binkert.org
10596657Snate@binkert.org    if (dmaReadDelay == 0 && dmaReadFactor == 0) {
10606657Snate@binkert.org        rxDmaReadCopy();
10616657Snate@binkert.org        return false;
10626657Snate@binkert.org    }
10636657Snate@binkert.org
10646657Snate@binkert.org    Tick factor = ((rxDmaLen + ULL(63)) >> ULL(6)) * dmaReadFactor;
10656657Snate@binkert.org    Tick start = curTick + dmaReadDelay + factor;
10666657Snate@binkert.org    rxDmaReadEvent.schedule(start);
10676657Snate@binkert.org    return true;
10686657Snate@binkert.org}
10696657Snate@binkert.org
10706657Snate@binkert.orgvoid
10716657Snate@binkert.orgNSGigE::rxDmaReadDone()
10726657Snate@binkert.org{
10736657Snate@binkert.org    assert(rxDmaState == dmaReading);
10746657Snate@binkert.org    rxDmaReadCopy();
10756657Snate@binkert.org
10766657Snate@binkert.org    // If the transmit state machine has a pending DMA, let it go first
10776657Snate@binkert.org    if (txDmaState == dmaReadWaiting || txDmaState == dmaWriteWaiting)
10786657Snate@binkert.org        txKick();
10796657Snate@binkert.org
10806657Snate@binkert.org    rxKick();
10816657Snate@binkert.org}
10826657Snate@binkert.org
10836657Snate@binkert.orgvoid
10846657Snate@binkert.orgNSGigE::rxDmaWriteCopy()
10856657Snate@binkert.org{
10866657Snate@binkert.org    assert(rxDmaState == dmaWriting);
10876657Snate@binkert.org
10886657Snate@binkert.org    memcpy(physmem->dma_addr(rxDmaAddr, rxDmaLen), rxDmaData, rxDmaLen);
10896657Snate@binkert.org    rxDmaState = dmaIdle;
10906657Snate@binkert.org
10916657Snate@binkert.org    DPRINTF(EthernetDMA, "rx dma write paddr=%#x len=%d\n",
10926657Snate@binkert.org            rxDmaAddr, rxDmaLen);
10936657Snate@binkert.org    DDUMP(EthernetDMA, rxDmaData, rxDmaLen);
10946657Snate@binkert.org}
10956657Snate@binkert.org
10966657Snate@binkert.orgbool
10976657Snate@binkert.orgNSGigE::doRxDmaWrite()
10986657Snate@binkert.org{
10996657Snate@binkert.org    assert(rxDmaState == dmaIdle || rxDmaState == dmaWriteWaiting);
11006657Snate@binkert.org    rxDmaState = dmaWriting;
11016657Snate@binkert.org
11026657Snate@binkert.org    if (dmaInterface && !rxDmaFree) {
11036657Snate@binkert.org        if (dmaInterface->busy())
11046657Snate@binkert.org            rxDmaState = dmaWriteWaiting;
11056657Snate@binkert.org        else
11066657Snate@binkert.org            dmaInterface->doDMA(WriteInvalidate, rxDmaAddr, rxDmaLen, curTick,
11076657Snate@binkert.org                                &rxDmaWriteEvent);
11086657Snate@binkert.org        return true;
11096657Snate@binkert.org    }
11106657Snate@binkert.org
11116657Snate@binkert.org    if (dmaWriteDelay == 0 && dmaWriteFactor == 0) {
11126657Snate@binkert.org        rxDmaWriteCopy();
11136657Snate@binkert.org        return false;
11146657Snate@binkert.org    }
11156657Snate@binkert.org
11166657Snate@binkert.org    Tick factor = ((rxDmaLen + ULL(63)) >> ULL(6)) * dmaWriteFactor;
11176657Snate@binkert.org    Tick start = curTick + dmaWriteDelay + factor;
11186657Snate@binkert.org    rxDmaWriteEvent.schedule(start);
11196657Snate@binkert.org    return true;
11206657Snate@binkert.org}
11216657Snate@binkert.org
11226657Snate@binkert.orgvoid
11236657Snate@binkert.orgNSGigE::rxDmaWriteDone()
11246657Snate@binkert.org{
11256657Snate@binkert.org    assert(rxDmaState == dmaWriting);
11266657Snate@binkert.org    rxDmaWriteCopy();
11276657Snate@binkert.org
11286657Snate@binkert.org    // If the transmit state machine has a pending DMA, let it go first
11296657Snate@binkert.org    if (txDmaState == dmaReadWaiting || txDmaState == dmaWriteWaiting)
11306657Snate@binkert.org        txKick();
11316657Snate@binkert.org
11326657Snate@binkert.org    rxKick();
11336657Snate@binkert.org}
11346657Snate@binkert.org
11356657Snate@binkert.orgvoid
11366657Snate@binkert.orgNSGigE::rxKick()
11376657Snate@binkert.org{
11386657Snate@binkert.org    DPRINTF(Ethernet, "receive kick state=%s (rxBuf.size=%d)\n",
11396657Snate@binkert.org            NsRxStateStrings[rxState], rxFifo.size());
11406657Snate@binkert.org
11416657Snate@binkert.org    if (rxKickTick > curTick) {
11426657Snate@binkert.org        DPRINTF(Ethernet, "receive kick exiting, can't run till %d\n",
11436657Snate@binkert.org                rxKickTick);
11446657Snate@binkert.org        return;
11456657Snate@binkert.org    }
11466657Snate@binkert.org
11476657Snate@binkert.org  next:
11486657Snate@binkert.org    switch(rxDmaState) {
11496657Snate@binkert.org      case dmaReadWaiting:
11506657Snate@binkert.org        if (doRxDmaRead())
11516657Snate@binkert.org            goto exit;
11526657Snate@binkert.org        break;
11536657Snate@binkert.org      case dmaWriteWaiting:
1154        if (doRxDmaWrite())
1155            goto exit;
1156        break;
1157      default:
1158        break;
1159    }
1160
1161    // see state machine from spec for details
1162    // the way this works is, if you finish work on one state and can go directly to
1163    // another, you do that through jumping to the label "next".  however, if you have
1164    // intermediate work, like DMA so that you can't go to the next state yet, you go to
1165    // exit and exit the loop.  however, when the DMA is done it will trigger an
1166    // event and come back to this loop.
1167    switch (rxState) {
1168      case rxIdle:
1169        if (!regs.command & CR_RXE) {
1170            DPRINTF(Ethernet, "Receive Disabled! Nothing to do.\n");
1171            goto exit;
1172        }
1173
1174        if (CRDD) {
1175            rxState = rxDescRefr;
1176
1177            rxDmaAddr = regs.rxdp & 0x3fffffff;
1178            rxDmaData = &rxDescCache + offsetof(ns_desc, link);
1179            rxDmaLen = sizeof(rxDescCache.link);
1180            rxDmaFree = dmaDescFree;
1181
1182            if (doRxDmaRead())
1183                goto exit;
1184        } else {
1185            rxState = rxDescRead;
1186
1187            rxDmaAddr = regs.rxdp & 0x3fffffff;
1188            rxDmaData = &rxDescCache;
1189            rxDmaLen = sizeof(ns_desc);
1190            rxDmaFree = dmaDescFree;
1191
1192            if (doRxDmaRead())
1193                goto exit;
1194        }
1195        break;
1196
1197      case rxDescRefr:
1198        if (rxDmaState != dmaIdle)
1199            goto exit;
1200
1201        rxState = rxAdvance;
1202        break;
1203
1204     case rxDescRead:
1205        if (rxDmaState != dmaIdle)
1206            goto exit;
1207
1208        DPRINTF(Ethernet,
1209                "rxDescCache:\n\tlink=%#x\n\tbufptr=%#x\n\tcmdsts=%#x\n\textsts=%#x\n"
1210                ,rxDescCache.link, rxDescCache.bufptr, rxDescCache.cmdsts,
1211                rxDescCache.extsts);
1212
1213        if (rxDescCache.cmdsts & CMDSTS_OWN) {
1214            rxState = rxIdle;
1215        } else {
1216            rxState = rxFifoBlock;
1217            rxFragPtr = rxDescCache.bufptr;
1218            rxDescCnt = rxDescCache.cmdsts & CMDSTS_LEN_MASK;
1219        }
1220        break;
1221
1222      case rxFifoBlock:
1223        if (!rxPacket) {
1224            /**
1225             * @todo in reality, we should be able to start processing
1226             * the packet as it arrives, and not have to wait for the
1227             * full packet ot be in the receive fifo.
1228             */
1229            if (rxFifo.empty())
1230                goto exit;
1231
1232            // If we don't have a packet, grab a new one from the fifo.
1233            rxPacket = rxFifo.front();
1234            rxPktBytes = rxPacket->length;
1235            rxPacketBufPtr = rxPacket->data;
1236
1237            // sanity check - i think the driver behaves like this
1238            assert(rxDescCnt >= rxPktBytes);
1239
1240            // Must clear the value before popping to decrement the
1241            // reference count
1242            rxFifo.front() = NULL;
1243            rxFifo.pop_front();
1244        }
1245
1246
1247        // dont' need the && rxDescCnt > 0 if driver sanity check above holds
1248        if (rxPktBytes > 0) {
1249            rxState = rxFragWrite;
1250            // don't need min<>(rxPktBytes,rxDescCnt) if above sanity check holds
1251            rxXferLen = rxPktBytes;
1252
1253            rxDmaAddr = rxFragPtr & 0x3fffffff;
1254            rxDmaData = rxPacketBufPtr;
1255            rxDmaLen = rxXferLen;
1256            rxDmaFree = dmaDataFree;
1257
1258            if (doRxDmaWrite())
1259                goto exit;
1260
1261        } else {
1262            rxState = rxDescWrite;
1263
1264            //if (rxPktBytes == 0) {  /* packet is done */
1265            assert(rxPktBytes == 0);
1266
1267            rxDescCache.cmdsts |= CMDSTS_OWN;
1268            rxDescCache.cmdsts &= ~CMDSTS_MORE;
1269            rxDescCache.cmdsts |= CMDSTS_OK;
1270            rxDescCache.cmdsts &= 0xffff0000;
1271            rxDescCache.cmdsts += rxPacket->length;   //i.e. set CMDSTS_SIZE
1272
1273#if 0
1274            /* all the driver uses these are for its own stats keeping
1275               which we don't care about, aren't necessary for functionality
1276               and doing this would just slow us down.  if they end up using
1277               this in a later version for functional purposes, just undef
1278            */
1279            if (rxFilterEnable) {
1280                rxDescCache.cmdsts &= ~CMDSTS_DEST_MASK;
1281                if (rxFifo.front()->IsUnicast())
1282                    rxDescCache.cmdsts |= CMDSTS_DEST_SELF;
1283                if (rxFifo.front()->IsMulticast())
1284                    rxDescCache.cmdsts |= CMDSTS_DEST_MULTI;
1285                if (rxFifo.front()->IsBroadcast())
1286                    rxDescCache.cmdsts |= CMDSTS_DEST_MASK;
1287            }
1288#endif
1289
1290            eth_header *eth = (eth_header *) rxPacket->data;
1291            // eth->type 0x800 indicated that it's an ip packet.
1292            if (eth->type == 0x800 && extstsEnable) {
1293                rxDescCache.extsts |= EXTSTS_IPPKT;
1294                if (!ipChecksum(rxPacket, false))
1295                    rxDescCache.extsts |= EXTSTS_IPERR;
1296                ip_header *ip = rxFifo.front()->getIpHdr();
1297
1298                if (ip->protocol == 6) {
1299                    rxDescCache.extsts |= EXTSTS_TCPPKT;
1300                    if (!tcpChecksum(rxPacket, false))
1301                        rxDescCache.extsts |= EXTSTS_TCPERR;
1302                } else if (ip->protocol == 17) {
1303                    rxDescCache.extsts |= EXTSTS_UDPPKT;
1304                    if (!udpChecksum(rxPacket, false))
1305                        rxDescCache.extsts |= EXTSTS_UDPERR;
1306                }
1307            }
1308
1309            rxFifoCnt -= rxPacket->length;
1310            rxPacket = 0;
1311
1312            /* the driver seems to always receive into desc buffers
1313               of size 1514, so you never have a pkt that is split
1314               into multiple descriptors on the receive side, so
1315               i don't implement that case, hence the assert above.
1316            */
1317
1318            DPRINTF(Ethernet, "rxDesc writeback:\n\tcmdsts=%#x\n\textsts=%#x\n",
1319                    rxDescCache.cmdsts, rxDescCache.extsts);
1320
1321            rxDmaAddr = (regs.rxdp + offsetof(ns_desc, cmdsts)) & 0x3fffffff;
1322            rxDmaData = &(rxDescCache.cmdsts);
1323            rxDmaLen = sizeof(rxDescCache.cmdsts) + sizeof(rxDescCache.extsts);
1324            rxDmaFree = dmaDescFree;
1325
1326            if (doRxDmaWrite())
1327                goto exit;
1328        }
1329        break;
1330
1331      case rxFragWrite:
1332        if (rxDmaState != dmaIdle)
1333            goto exit;
1334
1335        rxPacketBufPtr += rxXferLen;
1336        rxFragPtr += rxXferLen;
1337        rxPktBytes -= rxXferLen;
1338
1339        rxState = rxFifoBlock;
1340        break;
1341
1342      case rxDescWrite:
1343        if (rxDmaState != dmaIdle)
1344            goto exit;
1345
1346        assert(rxDescCache.cmdsts & CMDSTS_OWN);
1347
1348        assert(rxPacket == 0);
1349        devIntrPost(ISR_RXOK);
1350
1351        if (rxDescCache.cmdsts & CMDSTS_INTR)
1352            devIntrPost(ISR_RXDESC);
1353
1354        if (rxHalt) {
1355            rxState = rxIdle;
1356            rxHalt = false;
1357        } else
1358            rxState = rxAdvance;
1359        break;
1360
1361      case rxAdvance:
1362        if (rxDescCache.link == 0) {
1363            rxState = rxIdle;
1364            return;
1365        } else {
1366            rxState = rxDescRead;
1367            regs.rxdp = rxDescCache.link;
1368            CRDD = false;
1369
1370            rxDmaAddr = regs.rxdp & 0x3fffffff;
1371            rxDmaData = &rxDescCache;
1372            rxDmaLen = sizeof(ns_desc);
1373            rxDmaFree = dmaDescFree;
1374
1375            if (doRxDmaRead())
1376                goto exit;
1377        }
1378        break;
1379
1380      default:
1381        panic("Invalid rxState!");
1382    }
1383
1384
1385    DPRINTF(Ethernet, "entering next rx state = %s\n",
1386            NsRxStateStrings[rxState]);
1387
1388    if (rxState == rxIdle) {
1389        regs.command &= ~CR_RXE;
1390        devIntrPost(ISR_RXIDLE);
1391        return;
1392    }
1393
1394    goto next;
1395
1396  exit:
1397    /**
1398     * @todo do we want to schedule a future kick?
1399     */
1400    DPRINTF(Ethernet, "rx state machine exited state=%s\n",
1401            NsRxStateStrings[rxState]);
1402}
1403
1404void
1405NSGigE::transmit()
1406{
1407    if (txFifo.empty()) {
1408        DPRINTF(Ethernet, "nothing to transmit\n");
1409        return;
1410    }
1411
1412   if (interface->sendPacket(txFifo.front())) {
1413        DPRINTF(Ethernet, "transmit packet\n");
1414        DDUMP(Ethernet, txFifo.front()->data, txFifo.front()->length);
1415        txBytes += txFifo.front()->length;
1416        txPackets++;
1417
1418        txFifoCnt -= (txFifo.front()->length - txPktXmitted);
1419        txPktXmitted = 0;
1420        txFifo.front() = NULL;
1421        txFifo.pop_front();
1422
1423        /* normally do a writeback of the descriptor here, and ONLY after that is
1424           done, send this interrupt.  but since our stuff never actually fails,
1425           just do this interrupt here, otherwise the code has to stray from this
1426           nice format.  besides, it's functionally the same.
1427        */
1428        devIntrPost(ISR_TXOK);
1429   }
1430
1431   if (!txFifo.empty() && !txEvent.scheduled()) {
1432       DPRINTF(Ethernet, "reschedule transmit\n");
1433       txEvent.schedule(curTick + 1000);
1434   }
1435}
1436
1437void
1438NSGigE::txDmaReadCopy()
1439{
1440    assert(txDmaState == dmaReading);
1441
1442    memcpy(txDmaData, physmem->dma_addr(txDmaAddr, txDmaLen), txDmaLen);
1443    txDmaState = dmaIdle;
1444
1445    DPRINTF(EthernetDMA, "tx dma read  paddr=%#x len=%d\n",
1446            txDmaAddr, txDmaLen);
1447    DDUMP(EthernetDMA, txDmaData, txDmaLen);
1448}
1449
1450bool
1451NSGigE::doTxDmaRead()
1452{
1453    assert(txDmaState == dmaIdle || txDmaState == dmaReadWaiting);
1454    txDmaState = dmaReading;
1455
1456    if (dmaInterface && !txDmaFree) {
1457        if (dmaInterface->busy())
1458            txDmaState = dmaReadWaiting;
1459        else
1460            dmaInterface->doDMA(Read, txDmaAddr, txDmaLen, curTick,
1461                                &txDmaReadEvent);
1462        return true;
1463    }
1464
1465    if (dmaReadDelay == 0 && dmaReadFactor == 0.0) {
1466        txDmaReadCopy();
1467        return false;
1468    }
1469
1470    Tick factor = ((txDmaLen + ULL(63)) >> ULL(6)) * dmaReadFactor;
1471    Tick start = curTick + dmaReadDelay + factor;
1472    txDmaReadEvent.schedule(start);
1473    return true;
1474}
1475
1476void
1477NSGigE::txDmaReadDone()
1478{
1479    assert(txDmaState == dmaReading);
1480    txDmaReadCopy();
1481
1482    // If the receive state machine  has a pending DMA, let it go first
1483    if (rxDmaState == dmaReadWaiting || rxDmaState == dmaWriteWaiting)
1484        rxKick();
1485
1486    txKick();
1487}
1488
1489void
1490NSGigE::txDmaWriteCopy()
1491{
1492    assert(txDmaState == dmaWriting);
1493
1494    memcpy(physmem->dma_addr(txDmaAddr, txDmaLen), txDmaData, txDmaLen);
1495    txDmaState = dmaIdle;
1496
1497    DPRINTF(EthernetDMA, "tx dma write paddr=%#x len=%d\n",
1498            txDmaAddr, txDmaLen);
1499    DDUMP(EthernetDMA, txDmaData, txDmaLen);
1500}
1501
1502bool
1503NSGigE::doTxDmaWrite()
1504{
1505    assert(txDmaState == dmaIdle || txDmaState == dmaWriteWaiting);
1506    txDmaState = dmaWriting;
1507
1508    if (dmaInterface && !txDmaFree) {
1509        if (dmaInterface->busy())
1510            txDmaState = dmaWriteWaiting;
1511        else
1512            dmaInterface->doDMA(WriteInvalidate, txDmaAddr, txDmaLen, curTick,
1513                                &txDmaWriteEvent);
1514        return true;
1515    }
1516
1517    if (dmaWriteDelay == 0 && dmaWriteFactor == 0.0) {
1518        txDmaWriteCopy();
1519        return false;
1520    }
1521
1522    Tick factor = ((txDmaLen + ULL(63)) >> ULL(6)) * dmaWriteFactor;
1523    Tick start = curTick + dmaWriteDelay + factor;
1524    txDmaWriteEvent.schedule(start);
1525    return true;
1526}
1527
1528void
1529NSGigE::txDmaWriteDone()
1530{
1531    assert(txDmaState == dmaWriting);
1532    txDmaWriteCopy();
1533
1534    // If the receive state machine  has a pending DMA, let it go first
1535    if (rxDmaState == dmaReadWaiting || rxDmaState == dmaWriteWaiting)
1536        rxKick();
1537
1538    txKick();
1539}
1540
1541void
1542NSGigE::txKick()
1543{
1544    DPRINTF(Ethernet, "transmit kick state=%s\n", NsTxStateStrings[txState]);
1545
1546    if (rxKickTick > curTick) {
1547        DPRINTF(Ethernet, "receive kick exiting, can't run till %d\n",
1548                rxKickTick);
1549
1550        return;
1551    }
1552
1553  next:
1554    switch(txDmaState) {
1555      case dmaReadWaiting:
1556        if (doTxDmaRead())
1557            goto exit;
1558        break;
1559      case dmaWriteWaiting:
1560        if (doTxDmaWrite())
1561            goto exit;
1562        break;
1563      default:
1564        break;
1565    }
1566
1567    switch (txState) {
1568      case txIdle:
1569        if (!regs.command & CR_TXE) {
1570            DPRINTF(Ethernet, "Transmit disabled.  Nothing to do.\n");
1571            goto exit;
1572        }
1573
1574        if (CTDD) {
1575            txState = txDescRefr;
1576
1577            txDmaAddr = regs.txdp & 0x3fffffff;
1578            txDmaData = &txDescCache + offsetof(ns_desc, link);
1579            txDmaLen = sizeof(txDescCache.link);
1580            txDmaFree = dmaDescFree;
1581
1582            if (doTxDmaRead())
1583                goto exit;
1584
1585        } else {
1586            txState = txDescRead;
1587
1588            txDmaAddr = regs.txdp & 0x3fffffff;
1589            txDmaData = &txDescCache;
1590            txDmaLen = sizeof(ns_desc);
1591            txDmaFree = dmaDescFree;
1592
1593            if (doTxDmaRead())
1594                goto exit;
1595        }
1596        break;
1597
1598      case txDescRefr:
1599        if (txDmaState != dmaIdle)
1600            goto exit;
1601
1602        txState = txAdvance;
1603        break;
1604
1605      case txDescRead:
1606        if (txDmaState != dmaIdle)
1607            goto exit;
1608
1609        DPRINTF(Ethernet,
1610                "txDescCache data:\n\tlink=%#x\n\tbufptr=%#x\n\tcmdsts=%#x\n\textsts=%#x\n"
1611                ,txDescCache.link, txDescCache.bufptr, txDescCache.cmdsts,
1612                txDescCache.extsts);
1613
1614        if (txDescCache.cmdsts & CMDSTS_OWN) {
1615            txState = txFifoBlock;
1616            txFragPtr = txDescCache.bufptr;
1617            txDescCnt = txDescCache.cmdsts & CMDSTS_LEN_MASK;
1618        } else {
1619            txState = txIdle;
1620        }
1621        break;
1622
1623      case txFifoBlock:
1624        if (!txPacket) {
1625            DPRINTF(Ethernet, "starting the tx of a new packet\n");
1626            txPacket = new EtherPacket;
1627            txPacket->data = new uint8_t[16384];
1628            txPacketBufPtr = txPacket->data;
1629        }
1630
1631        if (txDescCnt == 0) {
1632            DPRINTF(Ethernet, "the txDescCnt == 0, done with descriptor\n");
1633            if (txDescCache.cmdsts & CMDSTS_MORE) {
1634                DPRINTF(Ethernet, "there are more descriptors to come\n");
1635                txState = txDescWrite;
1636
1637                txDescCache.cmdsts &= ~CMDSTS_OWN;
1638
1639                txDmaAddr = (regs.txdp + offsetof(ns_desc, cmdsts)) & 0x3fffffff;
1640                txDmaData = &(txDescCache.cmdsts);
1641                txDmaLen = sizeof(txDescCache.cmdsts);
1642                txDmaFree = dmaDescFree;
1643
1644                if (doTxDmaWrite())
1645                    goto exit;
1646
1647            } else { /* this packet is totally done */
1648                DPRINTF(Ethernet, "This packet is done, let's wrap it up\n");
1649                /* deal with the the packet that just finished */
1650                if ((regs.vtcr & VTCR_PPCHK) && extstsEnable) {
1651                    if (txDescCache.extsts & EXTSTS_UDPPKT) {
1652                        udpChecksum(txPacket, true);
1653                    } else if (txDescCache.extsts & EXTSTS_TCPPKT) {
1654                        tcpChecksum(txPacket, true);
1655                    } else if (txDescCache.extsts & EXTSTS_IPPKT) {
1656                        ipChecksum(txPacket, true);
1657                    }
1658                }
1659
1660                txPacket->length = txPacketBufPtr - txPacket->data;
1661                /* this is just because the receive can't handle a packet bigger
1662                   want to make sure */
1663                assert(txPacket->length <= 1514);
1664                txFifo.push_back(txPacket);
1665
1666
1667                /* this following section is not to spec, but functionally shouldn't
1668                   be any different.  normally, the chip will wait til the transmit has
1669                   occurred before writing back the descriptor because it has to wait
1670                   to see that it was successfully transmitted to decide whether to set
1671                   CMDSTS_OK or not.  however, in the simulator since it is always
1672                   successfully transmitted, and writing it exactly to spec would
1673                   complicate the code, we just do it here
1674                */
1675                txDescCache.cmdsts &= ~CMDSTS_OWN;
1676                txDescCache.cmdsts |= CMDSTS_OK;
1677
1678                DPRINTF(Ethernet,
1679                        "txDesc writeback:\n\tcmdsts=%#x\n\textsts=%#x\n",
1680                        txDescCache.cmdsts, txDescCache.extsts);
1681
1682                txDmaAddr = (regs.txdp + offsetof(ns_desc, cmdsts)) & 0x3fffffff;
1683                txDmaData = &(txDescCache.cmdsts);
1684                txDmaLen = sizeof(txDescCache.cmdsts) + sizeof(txDescCache.extsts);
1685                txDmaFree = dmaDescFree;
1686
1687                if (doTxDmaWrite())
1688                    goto exit;
1689
1690                txPacket = 0;
1691                transmit();
1692
1693                if (txHalt) {
1694                    txState = txIdle;
1695                    txHalt = false;
1696                } else
1697                    txState = txAdvance;
1698            }
1699        } else {
1700            DPRINTF(Ethernet, "this descriptor isn't done yet\n");
1701            /* the fill thresh is in units of 32 bytes, shift right by 8 to get the
1702               value, shift left by 5 to get the real number of bytes */
1703            if (txFifoAvail < ((regs.txcfg & TXCFG_FLTH_MASK) >> 3)) {
1704                DPRINTF(Ethernet, "txFifoAvail=%d, regs.txcfg & TXCFG_FLTH_MASK = %#x\n",
1705                        txFifoAvail, regs.txcfg & TXCFG_FLTH_MASK);
1706                goto exit;
1707            }
1708
1709            txState = txFragRead;
1710
1711            /* The number of bytes transferred is either whatever is left
1712               in the descriptor (txDescCnt), or if there is not enough
1713               room in the fifo, just whatever room is left in the fifo
1714            */
1715            txXferLen = min<uint32_t>(txDescCnt, txFifoAvail);
1716
1717            txDmaAddr = txFragPtr & 0x3fffffff;
1718            txDmaData = txPacketBufPtr;
1719            txDmaLen = txXferLen;
1720            txDmaFree = dmaDataFree;
1721
1722            if (doTxDmaRead())
1723                goto exit;
1724        }
1725        break;
1726
1727      case txFragRead:
1728        if (txDmaState != dmaIdle)
1729            goto exit;
1730
1731        txPacketBufPtr += txXferLen;
1732        txFragPtr += txXferLen;
1733        txFifoCnt += txXferLen;
1734        txDescCnt -= txXferLen;
1735
1736        txState = txFifoBlock;
1737        break;
1738
1739      case txDescWrite:
1740        if (txDmaState != dmaIdle)
1741            goto exit;
1742
1743        if (txFifoCnt >= ((regs.txcfg & TXCFG_DRTH_MASK) << 5)) {
1744            if (txFifo.empty()) {
1745                uint32_t xmitted = (uint32_t) (txPacketBufPtr - txPacket->data - txPktXmitted);
1746                txFifoCnt -= xmitted;
1747                txPktXmitted += xmitted;
1748            } else {
1749                transmit();
1750            }
1751        }
1752
1753        if (txDescCache.cmdsts & CMDSTS_INTR) {
1754            devIntrPost(ISR_TXDESC);
1755        }
1756
1757        txState = txAdvance;
1758        break;
1759
1760      case txAdvance:
1761        if (txDescCache.link == 0) {
1762            txState = txIdle;
1763        } else {
1764            txState = txDescRead;
1765            regs.txdp = txDescCache.link;
1766            CTDD = false;
1767
1768            txDmaAddr = txDescCache.link & 0x3fffffff;
1769            txDmaData = &txDescCache;
1770            txDmaLen = sizeof(ns_desc);
1771            txDmaFree = dmaDescFree;
1772
1773            if (doTxDmaRead())
1774                goto exit;
1775        }
1776        break;
1777
1778      default:
1779        panic("invalid state");
1780    }
1781
1782    DPRINTF(Ethernet, "entering next tx state=%s\n",
1783            NsTxStateStrings[txState]);
1784
1785    if (txState == txIdle) {
1786        regs.command &= ~CR_TXE;
1787        devIntrPost(ISR_TXIDLE);
1788        return;
1789    }
1790
1791    goto next;
1792
1793  exit:
1794    /**
1795     * @todo do we want to schedule a future kick?
1796     */
1797    DPRINTF(Ethernet, "tx state machine exited state=%s\n",
1798            NsTxStateStrings[txState]);
1799}
1800
1801void
1802NSGigE::transferDone()
1803{
1804    if (txFifo.empty())
1805        return;
1806
1807    DPRINTF(Ethernet, "schedule transmit\n");
1808
1809    if (txEvent.scheduled())
1810        txEvent.reschedule(curTick + 1);
1811    else
1812        txEvent.schedule(curTick + 1);
1813}
1814
1815bool
1816NSGigE::rxFilter(PacketPtr packet)
1817{
1818    bool drop = true;
1819    string type;
1820
1821    if (packet->IsUnicast()) {
1822        type = "unicast";
1823
1824        // If we're accepting all unicast addresses
1825        if (acceptUnicast)
1826            drop = false;
1827
1828        // If we make a perfect match
1829        if ((acceptPerfect)
1830            && (memcmp(rom.perfectMatch, packet->data, sizeof(rom.perfectMatch)) == 0))
1831            drop = false;
1832
1833        eth_header *eth = (eth_header *) packet->data;
1834        if ((acceptArp) && (eth->type == 0x806))
1835            drop = false;
1836
1837    } else if (packet->IsBroadcast()) {
1838        type = "broadcast";
1839
1840        // if we're accepting broadcasts
1841        if (acceptBroadcast)
1842            drop = false;
1843
1844    } else if (packet->IsMulticast()) {
1845        type = "multicast";
1846
1847        // if we're accepting all multicasts
1848        if (acceptMulticast)
1849            drop = false;
1850
1851    } else {
1852        type = "unknown";
1853
1854        // oh well, punt on this one
1855    }
1856
1857    if (drop) {
1858        DPRINTF(Ethernet, "rxFilter drop\n");
1859        DDUMP(EthernetData, packet->data, packet->length);
1860    }
1861
1862    return drop;
1863}
1864
1865bool
1866NSGigE::recvPacket(PacketPtr packet)
1867{
1868    rxBytes += packet->length;
1869    rxPackets++;
1870
1871    if (rxState == rxIdle) {
1872        DPRINTF(Ethernet, "receive disabled...packet dropped\n");
1873        interface->recvDone();
1874        return true;
1875    }
1876
1877    if (rxFilterEnable && rxFilter(packet)) {
1878        DPRINTF(Ethernet, "packet filtered...dropped\n");
1879        interface->recvDone();
1880        return true;
1881    }
1882
1883    if (rxFifoCnt + packet->length >= MAX_RX_FIFO_SIZE) {
1884        DPRINTF(Ethernet,
1885                "packet will not fit in receive buffer...packet dropped\n");
1886        devIntrPost(ISR_RXORN);
1887        return false;
1888    }
1889
1890    rxFifo.push_back(packet);
1891    rxFifoCnt += packet->length;
1892    interface->recvDone();
1893
1894    rxKick();
1895    return true;
1896}
1897
1898/**
1899 * does a udp checksum.  if gen is true, then it generates it and puts it in the right place
1900 * else, it just checks what it calculates against the value in the header in packet
1901 */
1902bool
1903NSGigE::udpChecksum(PacketPtr packet, bool gen)
1904{
1905    udp_header *hdr = (udp_header *)  packet->getTransportHdr();
1906
1907    ip_header *ip = packet->getIpHdr();
1908
1909    pseudo_header *pseudo = new pseudo_header;
1910
1911    pseudo->src_ip_addr = ip->src_ip_addr;
1912    pseudo->dest_ip_addr = ip->dest_ip_addr;
1913    pseudo->protocol = ip->protocol;
1914    pseudo->len = hdr->len;
1915
1916    uint16_t cksum = checksumCalc((uint16_t *) pseudo, (uint16_t *) hdr,
1917                                  (uint32_t) hdr->len);
1918
1919    delete pseudo;
1920    if (gen)
1921        hdr->chksum = cksum;
1922    else
1923        if (cksum != 0)
1924            return false;
1925
1926    return true;
1927}
1928
1929bool
1930NSGigE::tcpChecksum(PacketPtr packet, bool gen)
1931{
1932    tcp_header *hdr = (tcp_header *) packet->getTransportHdr();
1933
1934    ip_header *ip = packet->getIpHdr();
1935
1936    pseudo_header *pseudo = new pseudo_header;
1937
1938    pseudo->src_ip_addr = ip->src_ip_addr;
1939    pseudo->dest_ip_addr = ip->dest_ip_addr;
1940    pseudo->protocol = ip->protocol;
1941    pseudo->len = ip->dgram_len - (ip->vers_len & 0xf);
1942
1943    uint16_t cksum = checksumCalc((uint16_t *) pseudo, (uint16_t *) hdr,
1944                                  (uint32_t) pseudo->len);
1945
1946    delete pseudo;
1947    if (gen)
1948        hdr->chksum = cksum;
1949    else
1950        if (cksum != 0)
1951            return false;
1952
1953    return true;
1954}
1955
1956bool
1957NSGigE::ipChecksum(PacketPtr packet, bool gen)
1958{
1959    ip_header *hdr = packet->getIpHdr();
1960
1961    uint16_t cksum = checksumCalc(NULL, (uint16_t *) hdr, (hdr->vers_len & 0xf));
1962
1963    if (gen)
1964        hdr->hdr_chksum = cksum;
1965    else
1966        if (cksum != 0)
1967            return false;
1968
1969    return true;
1970}
1971
1972uint16_t
1973NSGigE::checksumCalc(uint16_t *pseudo, uint16_t *buf, uint32_t len)
1974{
1975    uint32_t sum = 0;
1976
1977    uint16_t last_pad = 0;
1978    if (len & 1) {
1979        last_pad = buf[len/2] & 0xff;
1980        len--;
1981        sum += last_pad;
1982    }
1983
1984    if (pseudo) {
1985        sum = pseudo[0] + pseudo[1] + pseudo[2] +
1986            pseudo[3] + pseudo[4] + pseudo[5];
1987    }
1988
1989    for (int i=0; i < (len/2); ++i) {
1990        sum += buf[i];
1991    }
1992
1993    while (sum >> 16)
1994        sum = (sum >> 16) + (sum & 0xffff);
1995
1996    return ~sum;
1997}
1998
1999//=====================================================================
2000//
2001//
2002void
2003NSGigE::serialize(ostream &os)
2004{
2005    /*
2006     * Finalize any DMA events now.
2007     */
2008    if (rxDmaReadEvent.scheduled())
2009        rxDmaReadCopy();
2010    if (rxDmaWriteEvent.scheduled())
2011        rxDmaWriteCopy();
2012    if (txDmaReadEvent.scheduled())
2013        txDmaReadCopy();
2014    if (txDmaWriteEvent.scheduled())
2015        txDmaWriteCopy();
2016
2017    /*
2018     * Serialize the device registers
2019     */
2020    SERIALIZE_SCALAR(regs.command);
2021    SERIALIZE_SCALAR(regs.config);
2022    SERIALIZE_SCALAR(regs.mear);
2023    SERIALIZE_SCALAR(regs.ptscr);
2024    SERIALIZE_SCALAR(regs.isr);
2025    SERIALIZE_SCALAR(regs.imr);
2026    SERIALIZE_SCALAR(regs.ier);
2027    SERIALIZE_SCALAR(regs.ihr);
2028    SERIALIZE_SCALAR(regs.txdp);
2029    SERIALIZE_SCALAR(regs.txdp_hi);
2030    SERIALIZE_SCALAR(regs.txcfg);
2031    SERIALIZE_SCALAR(regs.gpior);
2032    SERIALIZE_SCALAR(regs.rxdp);
2033    SERIALIZE_SCALAR(regs.rxdp_hi);
2034    SERIALIZE_SCALAR(regs.rxcfg);
2035    SERIALIZE_SCALAR(regs.pqcr);
2036    SERIALIZE_SCALAR(regs.wcsr);
2037    SERIALIZE_SCALAR(regs.pcr);
2038    SERIALIZE_SCALAR(regs.rfcr);
2039    SERIALIZE_SCALAR(regs.rfdr);
2040    SERIALIZE_SCALAR(regs.srr);
2041    SERIALIZE_SCALAR(regs.mibc);
2042    SERIALIZE_SCALAR(regs.vrcr);
2043    SERIALIZE_SCALAR(regs.vtcr);
2044    SERIALIZE_SCALAR(regs.vdr);
2045    SERIALIZE_SCALAR(regs.ccsr);
2046    SERIALIZE_SCALAR(regs.tbicr);
2047    SERIALIZE_SCALAR(regs.tbisr);
2048    SERIALIZE_SCALAR(regs.tanar);
2049    SERIALIZE_SCALAR(regs.tanlpar);
2050    SERIALIZE_SCALAR(regs.taner);
2051    SERIALIZE_SCALAR(regs.tesr);
2052
2053    SERIALIZE_ARRAY(rom.perfectMatch, EADDR_LEN);
2054
2055    /*
2056     * Serialize the various helper variables
2057     */
2058    uint32_t txPktBufPtr = (uint32_t) txPacketBufPtr;
2059    SERIALIZE_SCALAR(txPktBufPtr);
2060    uint32_t rxPktBufPtr = (uint32_t) rxPktBufPtr;
2061    SERIALIZE_SCALAR(rxPktBufPtr);
2062    SERIALIZE_SCALAR(txXferLen);
2063    SERIALIZE_SCALAR(rxXferLen);
2064    SERIALIZE_SCALAR(txPktXmitted);
2065
2066    bool txPacketExists = txPacket;
2067    SERIALIZE_SCALAR(txPacketExists);
2068    bool rxPacketExists = rxPacket;
2069    SERIALIZE_SCALAR(rxPacketExists);
2070
2071    /*
2072     * Serialize DescCaches
2073     */
2074    SERIALIZE_SCALAR(txDescCache.link);
2075    SERIALIZE_SCALAR(txDescCache.bufptr);
2076    SERIALIZE_SCALAR(txDescCache.cmdsts);
2077    SERIALIZE_SCALAR(txDescCache.extsts);
2078    SERIALIZE_SCALAR(rxDescCache.link);
2079    SERIALIZE_SCALAR(rxDescCache.bufptr);
2080    SERIALIZE_SCALAR(rxDescCache.cmdsts);
2081    SERIALIZE_SCALAR(rxDescCache.extsts);
2082
2083    /*
2084     * Serialize tx state machine
2085     */
2086    int txNumPkts = txFifo.size();
2087    SERIALIZE_SCALAR(txNumPkts);
2088    int txState = this->txState;
2089    SERIALIZE_SCALAR(txState);
2090    SERIALIZE_SCALAR(CTDD);
2091    SERIALIZE_SCALAR(txFifoCnt);
2092    SERIALIZE_SCALAR(txFifoAvail);
2093    SERIALIZE_SCALAR(txHalt);
2094    SERIALIZE_SCALAR(txFragPtr);
2095    SERIALIZE_SCALAR(txDescCnt);
2096    int txDmaState = this->txDmaState;
2097    SERIALIZE_SCALAR(txDmaState);
2098
2099    /*
2100     * Serialize rx state machine
2101     */
2102    int rxNumPkts = rxFifo.size();
2103    SERIALIZE_SCALAR(rxNumPkts);
2104    int rxState = this->rxState;
2105    SERIALIZE_SCALAR(rxState);
2106    SERIALIZE_SCALAR(CRDD);
2107    SERIALIZE_SCALAR(rxPktBytes);
2108    SERIALIZE_SCALAR(rxFifoCnt);
2109    SERIALIZE_SCALAR(rxHalt);
2110    SERIALIZE_SCALAR(rxDescCnt);
2111    int rxDmaState = this->rxDmaState;
2112    SERIALIZE_SCALAR(rxDmaState);
2113
2114    SERIALIZE_SCALAR(extstsEnable);
2115
2116   /*
2117     * If there's a pending transmit, store the time so we can
2118     * reschedule it later
2119     */
2120    Tick transmitTick = txEvent.scheduled() ? txEvent.when() - curTick : 0;
2121    SERIALIZE_SCALAR(transmitTick);
2122
2123    /*
2124     * Keep track of pending interrupt status.
2125     */
2126    SERIALIZE_SCALAR(intrTick);
2127    SERIALIZE_SCALAR(cpuPendingIntr);
2128    Tick intrEventTick = 0;
2129    if (intrEvent)
2130        intrEventTick = intrEvent->when();
2131    SERIALIZE_SCALAR(intrEventTick);
2132
2133    int i = 0;
2134    for (pktiter_t p = rxFifo.begin(); p != rxFifo.end(); ++p) {
2135        nameOut(os, csprintf("%s.rxFifo%d", name(), i++));
2136        (*p)->serialize(os);
2137    }
2138    if (rxPacketExists) {
2139        nameOut(os, csprintf("%s.rxPacket", name()));
2140        rxPacket->serialize(os);
2141    }
2142    i = 0;
2143    for (pktiter_t p = txFifo.begin(); p != txFifo.end(); ++p) {
2144        nameOut(os, csprintf("%s.txFifo%d", name(), i++));
2145        (*p)->serialize(os);
2146    }
2147    if (txPacketExists) {
2148        nameOut(os, csprintf("%s.txPacket", name()));
2149        txPacket->serialize(os);
2150    }
2151}
2152
2153void
2154NSGigE::unserialize(Checkpoint *cp, const std::string &section)
2155{
2156    UNSERIALIZE_SCALAR(regs.command);
2157    UNSERIALIZE_SCALAR(regs.config);
2158    UNSERIALIZE_SCALAR(regs.mear);
2159    UNSERIALIZE_SCALAR(regs.ptscr);
2160    UNSERIALIZE_SCALAR(regs.isr);
2161    UNSERIALIZE_SCALAR(regs.imr);
2162    UNSERIALIZE_SCALAR(regs.ier);
2163    UNSERIALIZE_SCALAR(regs.ihr);
2164    UNSERIALIZE_SCALAR(regs.txdp);
2165    UNSERIALIZE_SCALAR(regs.txdp_hi);
2166    UNSERIALIZE_SCALAR(regs.txcfg);
2167    UNSERIALIZE_SCALAR(regs.gpior);
2168    UNSERIALIZE_SCALAR(regs.rxdp);
2169    UNSERIALIZE_SCALAR(regs.rxdp_hi);
2170    UNSERIALIZE_SCALAR(regs.rxcfg);
2171    UNSERIALIZE_SCALAR(regs.pqcr);
2172    UNSERIALIZE_SCALAR(regs.wcsr);
2173    UNSERIALIZE_SCALAR(regs.pcr);
2174    UNSERIALIZE_SCALAR(regs.rfcr);
2175    UNSERIALIZE_SCALAR(regs.rfdr);
2176    UNSERIALIZE_SCALAR(regs.srr);
2177    UNSERIALIZE_SCALAR(regs.mibc);
2178    UNSERIALIZE_SCALAR(regs.vrcr);
2179    UNSERIALIZE_SCALAR(regs.vtcr);
2180    UNSERIALIZE_SCALAR(regs.vdr);
2181    UNSERIALIZE_SCALAR(regs.ccsr);
2182    UNSERIALIZE_SCALAR(regs.tbicr);
2183    UNSERIALIZE_SCALAR(regs.tbisr);
2184    UNSERIALIZE_SCALAR(regs.tanar);
2185    UNSERIALIZE_SCALAR(regs.tanlpar);
2186    UNSERIALIZE_SCALAR(regs.taner);
2187    UNSERIALIZE_SCALAR(regs.tesr);
2188
2189    UNSERIALIZE_ARRAY(rom.perfectMatch, EADDR_LEN);
2190
2191    /*
2192     * unserialize the various helper variables
2193     */
2194    uint32_t txPktBufPtr;
2195    UNSERIALIZE_SCALAR(txPktBufPtr);
2196    txPacketBufPtr = (uint8_t *) txPktBufPtr;
2197    uint32_t rxPktBufPtr;
2198    UNSERIALIZE_SCALAR(rxPktBufPtr);
2199    rxPacketBufPtr = (uint8_t *) rxPktBufPtr;
2200    UNSERIALIZE_SCALAR(txXferLen);
2201    UNSERIALIZE_SCALAR(rxXferLen);
2202    UNSERIALIZE_SCALAR(txPktXmitted);
2203
2204    bool txPacketExists;
2205    UNSERIALIZE_SCALAR(txPacketExists);
2206    bool rxPacketExists;
2207    UNSERIALIZE_SCALAR(rxPacketExists);
2208
2209    /*
2210     * Unserialize DescCaches
2211     */
2212    UNSERIALIZE_SCALAR(txDescCache.link);
2213    UNSERIALIZE_SCALAR(txDescCache.bufptr);
2214    UNSERIALIZE_SCALAR(txDescCache.cmdsts);
2215    UNSERIALIZE_SCALAR(txDescCache.extsts);
2216    UNSERIALIZE_SCALAR(rxDescCache.link);
2217    UNSERIALIZE_SCALAR(rxDescCache.bufptr);
2218    UNSERIALIZE_SCALAR(rxDescCache.cmdsts);
2219    UNSERIALIZE_SCALAR(rxDescCache.extsts);
2220
2221    /*
2222     * unserialize tx state machine
2223     */
2224    int txNumPkts;
2225    UNSERIALIZE_SCALAR(txNumPkts);
2226    int txState;
2227    UNSERIALIZE_SCALAR(txState);
2228    this->txState = (TxState) txState;
2229    UNSERIALIZE_SCALAR(CTDD);
2230    UNSERIALIZE_SCALAR(txFifoCnt);
2231    UNSERIALIZE_SCALAR(txFifoAvail);
2232    UNSERIALIZE_SCALAR(txHalt);
2233    UNSERIALIZE_SCALAR(txFragPtr);
2234    UNSERIALIZE_SCALAR(txDescCnt);
2235    int txDmaState;
2236    UNSERIALIZE_SCALAR(txDmaState);
2237    this->txDmaState = (DmaState) txDmaState;
2238
2239    /*
2240     * unserialize rx state machine
2241     */
2242    int rxNumPkts;
2243    UNSERIALIZE_SCALAR(rxNumPkts);
2244    int rxState;
2245    UNSERIALIZE_SCALAR(rxState);
2246    this->rxState = (RxState) rxState;
2247    UNSERIALIZE_SCALAR(CRDD);
2248    UNSERIALIZE_SCALAR(rxPktBytes);
2249    UNSERIALIZE_SCALAR(rxFifoCnt);
2250    UNSERIALIZE_SCALAR(rxHalt);
2251    UNSERIALIZE_SCALAR(rxDescCnt);
2252    int rxDmaState;
2253    UNSERIALIZE_SCALAR(rxDmaState);
2254    this->rxDmaState = (DmaState) rxDmaState;
2255
2256    UNSERIALIZE_SCALAR(extstsEnable);
2257
2258     /*
2259     * If there's a pending transmit, store the time so we can
2260     * reschedule it later
2261     */
2262    Tick transmitTick;
2263    UNSERIALIZE_SCALAR(transmitTick);
2264    if (transmitTick)
2265        txEvent.schedule(curTick + transmitTick);
2266
2267    /*
2268     * Keep track of pending interrupt status.
2269     */
2270    UNSERIALIZE_SCALAR(intrTick);
2271    UNSERIALIZE_SCALAR(cpuPendingIntr);
2272    Tick intrEventTick;
2273    UNSERIALIZE_SCALAR(intrEventTick);
2274    if (intrEventTick) {
2275        intrEvent = new IntrEvent(this, true);
2276        intrEvent->schedule(intrEventTick);
2277    }
2278
2279    for (int i = 0; i < rxNumPkts; ++i) {
2280        PacketPtr p = new EtherPacket;
2281        p->unserialize(cp, csprintf("%s.rxFifo%d", section, i));
2282        rxFifo.push_back(p);
2283    }
2284    rxPacket = NULL;
2285    if (rxPacketExists) {
2286        rxPacket = new EtherPacket;
2287        rxPacket->unserialize(cp, csprintf("%s.rxPacket", section));
2288    }
2289    for (int i = 0; i < txNumPkts; ++i) {
2290        PacketPtr p = new EtherPacket;
2291        p->unserialize(cp, csprintf("%s.rxFifo%d", section, i));
2292        txFifo.push_back(p);
2293    }
2294    if (txPacketExists) {
2295        txPacket = new EtherPacket;
2296        txPacket->unserialize(cp, csprintf("%s.txPacket", section));
2297    }
2298}
2299
2300
2301Tick
2302NSGigE::cacheAccess(MemReqPtr &req)
2303{
2304    DPRINTF(EthernetPIO, "timing access to paddr=%#x (daddr=%#x)\n",
2305            req->paddr, req->paddr - addr);
2306    return curTick + pioLatency;
2307}
2308//=====================================================================
2309
2310
2311BEGIN_DECLARE_SIM_OBJECT_PARAMS(NSGigEInt)
2312
2313    SimObjectParam<EtherInt *> peer;
2314    SimObjectParam<NSGigE *> device;
2315
2316END_DECLARE_SIM_OBJECT_PARAMS(NSGigEInt)
2317
2318BEGIN_INIT_SIM_OBJECT_PARAMS(NSGigEInt)
2319
2320    INIT_PARAM_DFLT(peer, "peer interface", NULL),
2321    INIT_PARAM(device, "Ethernet device of this interface")
2322
2323END_INIT_SIM_OBJECT_PARAMS(NSGigEInt)
2324
2325CREATE_SIM_OBJECT(NSGigEInt)
2326{
2327    NSGigEInt *dev_int = new NSGigEInt(getInstanceName(), device);
2328
2329    EtherInt *p = (EtherInt *)peer;
2330    if (p) {
2331        dev_int->setPeer(p);
2332        p->setPeer(dev_int);
2333    }
2334
2335    return dev_int;
2336}
2337
2338REGISTER_SIM_OBJECT("NSGigEInt", NSGigEInt)
2339
2340
2341BEGIN_DECLARE_SIM_OBJECT_PARAMS(NSGigE)
2342
2343    Param<Tick> tx_delay;
2344    Param<Tick> rx_delay;
2345    SimObjectParam<IntrControl *> intr_ctrl;
2346    Param<Tick> intr_delay;
2347    SimObjectParam<MemoryController *> mmu;
2348    SimObjectParam<PhysicalMemory *> physmem;
2349    Param<Addr> addr;
2350    Param<bool> rx_filter;
2351    Param<string> hardware_address;
2352    SimObjectParam<Bus*> header_bus;
2353    SimObjectParam<Bus*> payload_bus;
2354    SimObjectParam<HierParams *> hier;
2355    Param<Tick> pio_latency;
2356    Param<bool> dma_desc_free;
2357    Param<bool> dma_data_free;
2358    Param<Tick> dma_read_delay;
2359    Param<Tick> dma_write_delay;
2360    Param<Tick> dma_read_factor;
2361    Param<Tick> dma_write_factor;
2362    SimObjectParam<PciConfigAll *> configspace;
2363    SimObjectParam<PciConfigData *> configdata;
2364    SimObjectParam<Tsunami *> tsunami;
2365    Param<uint32_t> pci_bus;
2366    Param<uint32_t> pci_dev;
2367    Param<uint32_t> pci_func;
2368
2369END_DECLARE_SIM_OBJECT_PARAMS(NSGigE)
2370
2371BEGIN_INIT_SIM_OBJECT_PARAMS(NSGigE)
2372
2373    INIT_PARAM_DFLT(tx_delay, "Transmit Delay", 1000),
2374    INIT_PARAM_DFLT(rx_delay, "Receive Delay", 1000),
2375    INIT_PARAM(intr_ctrl, "Interrupt Controller"),
2376    INIT_PARAM_DFLT(intr_delay, "Interrupt Delay in microseconds", 0),
2377    INIT_PARAM(mmu, "Memory Controller"),
2378    INIT_PARAM(physmem, "Physical Memory"),
2379    INIT_PARAM(addr, "Device Address"),
2380    INIT_PARAM_DFLT(rx_filter, "Enable Receive Filter", true),
2381    INIT_PARAM_DFLT(hardware_address, "Ethernet Hardware Address",
2382                    "00:99:00:00:00:01"),
2383    INIT_PARAM_DFLT(header_bus, "The IO Bus to attach to for headers", NULL),
2384    INIT_PARAM_DFLT(payload_bus, "The IO Bus to attach to for payload", NULL),
2385    INIT_PARAM_DFLT(hier, "Hierarchy global variables", &defaultHierParams),
2386    INIT_PARAM_DFLT(pio_latency, "Programmed IO latency", 1000),
2387    INIT_PARAM_DFLT(dma_desc_free, "DMA of Descriptors is free", false),
2388    INIT_PARAM_DFLT(dma_data_free, "DMA of Data is free", false),
2389    INIT_PARAM_DFLT(dma_read_delay, "fixed delay for dma reads", 0),
2390    INIT_PARAM_DFLT(dma_write_delay, "fixed delay for dma writes", 0),
2391    INIT_PARAM_DFLT(dma_read_factor, "multiplier for dma reads", 0),
2392    INIT_PARAM_DFLT(dma_write_factor, "multiplier for dma writes", 0),
2393    INIT_PARAM(configspace, "PCI Configspace"),
2394    INIT_PARAM(configdata, "PCI Config data"),
2395    INIT_PARAM(tsunami, "Tsunami"),
2396    INIT_PARAM(pci_bus, "PCI bus"),
2397    INIT_PARAM(pci_dev, "PCI device number"),
2398    INIT_PARAM(pci_func, "PCI function code")
2399
2400END_INIT_SIM_OBJECT_PARAMS(NSGigE)
2401
2402
2403CREATE_SIM_OBJECT(NSGigE)
2404{
2405    int eaddr[6];
2406    sscanf(((string)hardware_address).c_str(), "%x:%x:%x:%x:%x:%x",
2407           &eaddr[0], &eaddr[1], &eaddr[2], &eaddr[3], &eaddr[4], &eaddr[5]);
2408
2409    return new NSGigE(getInstanceName(), intr_ctrl, intr_delay,
2410                        physmem, tx_delay, rx_delay, mmu, hier, header_bus,
2411                        payload_bus, pio_latency, dma_desc_free, dma_data_free,
2412                        dma_read_delay, dma_write_delay, dma_read_factor,
2413                        dma_write_factor, configspace, configdata,
2414                        tsunami, pci_bus, pci_dev, pci_func, rx_filter, eaddr,
2415                        addr);
2416}
2417
2418REGISTER_SIM_OBJECT("NSGigE", NSGigE)
2419