ns_gige.cc revision 854
16657Snate@binkert.org/*
26657Snate@binkert.org * Copyright (c) 2003 The Regents of The University of Michigan
310972Sdavid.hashe@amd.com * 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 */
286657Snate@binkert.org
296999Snate@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>
348189SLisa.Hsu@amd.com#include <deque>
356657Snate@binkert.org#include <string>
369499Snilay@cs.wisc.edu
379499Snilay@cs.wisc.edu#include "base/inet.hh"
389364Snilay@cs.wisc.edu#include "cpu/exec_context.hh"
397055Snate@binkert.org#include "cpu/intr_control.hh"
406882SBrad.Beckmann@amd.com#include "dev/dma.hh"
416882SBrad.Beckmann@amd.com#include "dev/ns_gige.hh"
428191SLisa.Hsu@amd.com#include "dev/etherlink.hh"
436882SBrad.Beckmann@amd.com#include "mem/bus/bus.hh"
446882SBrad.Beckmann@amd.com#include "mem/bus/dma_interface.hh"
459102SNuwan.Jayasena@amd.com#include "mem/bus/pio_interface.hh"
4611084Snilay@cs.wisc.edu#include "mem/bus/pio_interface_impl.hh"
479366Snilay@cs.wisc.edu#include "mem/functional_mem/memory_control.hh"
489499Snilay@cs.wisc.edu#include "mem/functional_mem/physical_memory.hh"
499499Snilay@cs.wisc.edu#include "sim/builder.hh"
509499Snilay@cs.wisc.edu#include "sim/host.hh"
516882SBrad.Beckmann@amd.com#include "sim/sim_stats.hh"
526657Snate@binkert.org#include "targetarch/vtophys.hh"
536657Snate@binkert.org#include "dev/pciconfigall.hh"
546657Snate@binkert.org#include "dev/tsunami_cchip.hh"
556657Snate@binkert.org
5610311Snilay@cs.wisc.educonst char *NsRxStateStrings[] =
5710311Snilay@cs.wisc.edu{
5810311Snilay@cs.wisc.edu    "rxIdle",
5910311Snilay@cs.wisc.edu    "rxDescRefr",
606657Snate@binkert.org    "rxDescRead",
6110311Snilay@cs.wisc.edu    "rxFifoBlock",
629366Snilay@cs.wisc.edu    "rxFragWrite",
637839Snilay@cs.wisc.edu    "rxDescWrite",
646657Snate@binkert.org    "rxAdvance"
656882SBrad.Beckmann@amd.com};
6610308Snilay@cs.wisc.edu
6710308Snilay@cs.wisc.educonst char *NsTxStateStrings[] =
686882SBrad.Beckmann@amd.com{
6910308Snilay@cs.wisc.edu    "txIdle",
7010308Snilay@cs.wisc.edu    "txDescRefr",
7110308Snilay@cs.wisc.edu    "txDescRead",
7210308Snilay@cs.wisc.edu    "txFifoBlock",
7310308Snilay@cs.wisc.edu    "txFragRead",
749366Snilay@cs.wisc.edu    "txDescWrite",
759366Snilay@cs.wisc.edu    "txAdvance"
766657Snate@binkert.org};
776657Snate@binkert.org
786657Snate@binkert.orgconst char *NsDmaState[] =
796657Snate@binkert.org{
809104Shestness@cs.utexas.edu    "dmaIdle",
816657Snate@binkert.org    "dmaReading",
826657Snate@binkert.org    "dmaWriting",
836657Snate@binkert.org    "dmaReadWaiting",
8410311Snilay@cs.wisc.edu    "dmaWriteWaiting"
8510311Snilay@cs.wisc.edu};
8610311Snilay@cs.wisc.edu
8710311Snilay@cs.wisc.eduusing namespace std;
886657Snate@binkert.org
897839Snilay@cs.wisc.edu///////////////////////////////////////////////////////////////////////
907839Snilay@cs.wisc.edu//
9110972Sdavid.hashe@amd.com// EtherDev PCI Device
9210972Sdavid.hashe@amd.com//
9310972Sdavid.hashe@amd.comEtherDev::EtherDev(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),
1126779SBrad.Beckmann@amd.com      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) {
12210972Sdavid.hashe@amd.com        pioInterface = newPioInterface(name, hier, header_bus, this,
12310972Sdavid.hashe@amd.com                                       &EtherDev::cacheAccess);
12410972Sdavid.hashe@amd.com        pioInterface->addAddrRange(addr, addr + size - 1);
1259104Shestness@cs.utexas.edu        if (payload_bus)
1269104Shestness@cs.utexas.edu            dmaInterface = new DMAInterface<Bus>(name + ".dma",
1279104Shestness@cs.utexas.edu                                                 header_bus, payload_bus, 1);
1289104Shestness@cs.utexas.edu        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                                       &EtherDev::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
1416657Snate@binkert.org    intrDelay = US2Ticks(intr_delay);
14210307Snilay@cs.wisc.edu    dmaReadDelay = dma_read_delay;
1436657Snate@binkert.org    dmaWriteDelay = dma_write_delay;
1446657Snate@binkert.org    dmaReadFactor = dma_read_factor;
1457839Snilay@cs.wisc.edu    dmaWriteFactor = dma_write_factor;
1467839Snilay@cs.wisc.edu
1477839Snilay@cs.wisc.edu    memset(&regs, 0, sizeof(regs));
1487839Snilay@cs.wisc.edu    regsReset();
1497839Snilay@cs.wisc.edu    rom.perfectMatch[0] = eaddr[0];
1507839Snilay@cs.wisc.edu    rom.perfectMatch[1] = eaddr[1];
1517839Snilay@cs.wisc.edu    rom.perfectMatch[2] = eaddr[2];
1527839Snilay@cs.wisc.edu    rom.perfectMatch[3] = eaddr[3];
1537839Snilay@cs.wisc.edu    rom.perfectMatch[4] = eaddr[4];
1547839Snilay@cs.wisc.edu    rom.perfectMatch[5] = eaddr[5];
15510968Sdavid.hashe@amd.com}
15610968Sdavid.hashe@amd.com
15710968Sdavid.hashe@amd.comEtherDev::~EtherDev()
15810968Sdavid.hashe@amd.com{}
15910968Sdavid.hashe@amd.com
16010968Sdavid.hashe@amd.comvoid
16110968Sdavid.hashe@amd.comEtherDev::regStats()
1627839Snilay@cs.wisc.edu{
1636657Snate@binkert.org    txBytes
1646657Snate@binkert.org        .name(name() + ".txBytes")
1656657Snate@binkert.org        .desc("Bytes Transmitted")
1666657Snate@binkert.org        .prereq(txBytes)
1676657Snate@binkert.org        ;
1686657Snate@binkert.org
1696657Snate@binkert.org    rxBytes
1706657Snate@binkert.org        .name(name() + ".rxBytes")
1716657Snate@binkert.org        .desc("Bytes Received")
1726657Snate@binkert.org        .prereq(rxBytes)
1736657Snate@binkert.org        ;
1746657Snate@binkert.org
1756657Snate@binkert.org    txPackets
1766657Snate@binkert.org        .name(name() + ".txPackets")
1776657Snate@binkert.org        .desc("Number of Packets Transmitted")
1786657Snate@binkert.org        .prereq(txBytes)
1796657Snate@binkert.org        ;
1806657Snate@binkert.org
1816657Snate@binkert.org    rxPackets
1826657Snate@binkert.org        .name(name() + ".rxPackets")
1836657Snate@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        ;
19310963Sdavid.hashe@amd.com
19410963Sdavid.hashe@amd.com    rxBandwidth
19510963Sdavid.hashe@amd.com        .name(name() + ".rxBandwidth")
19610963Sdavid.hashe@amd.com        .desc("Receive Bandwidth (bits/s)")
19710963Sdavid.hashe@amd.com        .precision(0)
19810963Sdavid.hashe@amd.com        .prereq(rxBytes)
19911095Snilay@cs.wisc.edu        ;
20010963Sdavid.hashe@amd.com
20110963Sdavid.hashe@amd.com    txPacketRate
20210963Sdavid.hashe@amd.com        .name(name() + ".txPPS")
20310963Sdavid.hashe@amd.com        .desc("Packet Tranmission Rate (packets/s)")
20410963Sdavid.hashe@amd.com        .precision(0)
20510963Sdavid.hashe@amd.com        .prereq(txBytes)
20610963Sdavid.hashe@amd.com        ;
20710963Sdavid.hashe@amd.com
2089219Spower.jg@gmail.com    rxPacketRate
2096877Ssteve.reinhardt@amd.com        .name(name() + ".rxPPS")
2106657Snate@binkert.org        .desc("Packet Reception Rate (packets/s)")
2119219Spower.jg@gmail.com        .precision(0)
2126657Snate@binkert.org        .prereq(rxBytes)
2139219Spower.jg@gmail.com        ;
2146657Snate@binkert.org
2156877Ssteve.reinhardt@amd.com    txBandwidth = txBytes * Statistics::constant(8) / simSeconds;
2166999Snate@binkert.org    rxBandwidth = rxBytes * Statistics::constant(8) / simSeconds;
2176877Ssteve.reinhardt@amd.com    txPacketRate = txPackets / simSeconds;
21810308Snilay@cs.wisc.edu    rxPacketRate = rxPackets / simSeconds;
2196877Ssteve.reinhardt@amd.com}
2206877Ssteve.reinhardt@amd.com
22110308Snilay@cs.wisc.eduvoid
2226877Ssteve.reinhardt@amd.comEtherDev::ReadConfig(int offset, int size, uint8_t *data)
2236877Ssteve.reinhardt@amd.com{
2246877Ssteve.reinhardt@amd.com    if (offset < PCI_DEVICE_SPECIFIC)
2256877Ssteve.reinhardt@amd.com        PciDev::ReadConfig(offset, size, data);
2266877Ssteve.reinhardt@amd.com    else {
2276877Ssteve.reinhardt@amd.com        panic("need to do this\n");
2286877Ssteve.reinhardt@amd.com    }
2299338SAndreas.Sandberg@arm.com}
2306877Ssteve.reinhardt@amd.com
2316877Ssteve.reinhardt@amd.comvoid
2326877Ssteve.reinhardt@amd.comEtherDev::WriteConfig(int offset, int size, uint32_t data)
2336877Ssteve.reinhardt@amd.com{
23410308Snilay@cs.wisc.edu    if (offset < PCI_DEVICE_SPECIFIC)
23510308Snilay@cs.wisc.edu        PciDev::WriteConfig(offset, size, data);
23610308Snilay@cs.wisc.edu    else
23710308Snilay@cs.wisc.edu        panic("Need to do that\n");
23811084Snilay@cs.wisc.edu}
2396882SBrad.Beckmann@amd.com
24010308Snilay@cs.wisc.eduFault
24110308Snilay@cs.wisc.eduEtherDev::read(MemReqPtr &req, uint8_t *data)
2426882SBrad.Beckmann@amd.com{
2436882SBrad.Beckmann@amd.com    Addr daddr = req->paddr & 0xfff;
2446882SBrad.Beckmann@amd.com    DPRINTF(EthernetPIO, "read  da=%#x pa=%#x va=%#x size=%d\n",
2456882SBrad.Beckmann@amd.com            daddr, req->paddr, req->vaddr, req->size);
24611021Sjthestness@gmail.com
2476877Ssteve.reinhardt@amd.com    if (daddr > LAST && daddr <=  RESERVED) {
2486877Ssteve.reinhardt@amd.com        panic("Accessing reserved register");
24910917Sbrandon.potter@amd.com    } else if (daddr > RESERVED && daddr <= 0x3FC) {
2506877Ssteve.reinhardt@amd.com        ReadConfig(daddr & 0xff, req->size, data);
2516657Snate@binkert.org        return No_Fault;
2526657Snate@binkert.org    } else if (daddr >= MIB_START && daddr <= MIB_END) {
2536999Snate@binkert.org        // don't implement all the MIB's.  hopefully the kernel
2546657Snate@binkert.org        // doesn't actually DEPEND upon their values
2556657Snate@binkert.org        uint32_t &reg = *(uint32_t *) data;
2566657Snate@binkert.org        reg = 0;
2576657Snate@binkert.org        return No_Fault;
2587007Snate@binkert.org    } else if (daddr > 0x3FC)
2596657Snate@binkert.org        panic("Something is messed up!\n");
2606657Snate@binkert.org
2616657Snate@binkert.org    switch (req->size) {
2626657Snate@binkert.org      case sizeof(uint32_t):
2636657Snate@binkert.org        {
2647007Snate@binkert.org            uint32_t &reg = *(uint32_t *)data;
2657007Snate@binkert.org
2666657Snate@binkert.org            switch (daddr) {
2677002Snate@binkert.org              case CR:
2687002Snate@binkert.org                reg = regs.command;
2697002Snate@binkert.org                reg &= ~(CR_RXD | CR_TXD | CR_TXR | CR_RXR);
2707002Snate@binkert.org                break;
2716657Snate@binkert.org
2726657Snate@binkert.org              case CFG:
2738229Snate@binkert.org                reg = regs.config;
2748229Snate@binkert.org                break;
2758229Snate@binkert.org
27610972Sdavid.hashe@amd.com              case MEAR:
2776657Snate@binkert.org                reg = regs.mear;
2786657Snate@binkert.org                break;
2796657Snate@binkert.org
2806657Snate@binkert.org              case PTSCR:
2816793SBrad.Beckmann@amd.com                reg = regs.ptscr;
2826657Snate@binkert.org                break;
28310311Snilay@cs.wisc.edu
2846657Snate@binkert.org              case ISR:
2856657Snate@binkert.org                reg = regs.isr;
2866657Snate@binkert.org                regs.isr = 0;
2877002Snate@binkert.org                break;
2886657Snate@binkert.org
2897007Snate@binkert.org              case IMR:
2907007Snate@binkert.org                reg = regs.imr;
2919271Snilay@cs.wisc.edu                break;
2926877Ssteve.reinhardt@amd.com
2936877Ssteve.reinhardt@amd.com              case IER:
2946657Snate@binkert.org                reg = regs.ier;
2956877Ssteve.reinhardt@amd.com                break;
29610311Snilay@cs.wisc.edu
29711084Snilay@cs.wisc.edu              case IHR:
29811084Snilay@cs.wisc.edu                reg = regs.ihr;
29911021Sjthestness@gmail.com                break;
3009745Snilay@cs.wisc.edu
3017002Snate@binkert.org              case TXDP:
3026657Snate@binkert.org                reg = regs.txdp;
30310012Snilay@cs.wisc.edu                break;
3049745Snilay@cs.wisc.edu
3059745Snilay@cs.wisc.edu              case TXDP_HI:
3069745Snilay@cs.wisc.edu                reg = regs.txdp_hi;
3078683Snilay@cs.wisc.edu                break;
3088683Snilay@cs.wisc.edu
3097007Snate@binkert.org              case TXCFG:
31010524Snilay@cs.wisc.edu                reg = regs.txcfg;
3119302Snilay@cs.wisc.edu                break;
3129745Snilay@cs.wisc.edu
3139745Snilay@cs.wisc.edu              case GPIOR:
31411061Snilay@cs.wisc.edu                reg = regs.gpior;
3159745Snilay@cs.wisc.edu                break;
31611061Snilay@cs.wisc.edu
3179745Snilay@cs.wisc.edu              case RXDP:
3186657Snate@binkert.org                reg = regs.rxdp;
3196657Snate@binkert.org                break;
3206657Snate@binkert.org
3216657Snate@binkert.org              case RXDP_HI:
3226657Snate@binkert.org                reg = regs.rxdp_hi;
3236657Snate@binkert.org                break;
3246882SBrad.Beckmann@amd.com
3256882SBrad.Beckmann@amd.com              case RXCFG:
3266882SBrad.Beckmann@amd.com                reg = regs.rxcfg;
3276882SBrad.Beckmann@amd.com                break;
3286657Snate@binkert.org
3296657Snate@binkert.org              case PQCR:
3307007Snate@binkert.org                reg = regs.pqcr;
3317839Snilay@cs.wisc.edu                break;
3327839Snilay@cs.wisc.edu
3337839Snilay@cs.wisc.edu              case WCSR:
3347839Snilay@cs.wisc.edu                reg = regs.wcsr;
3357839Snilay@cs.wisc.edu                break;
3367839Snilay@cs.wisc.edu
3377839Snilay@cs.wisc.edu              case PCR:
3387839Snilay@cs.wisc.edu                reg = regs.pcr;
3397839Snilay@cs.wisc.edu                break;
3407839Snilay@cs.wisc.edu
3417839Snilay@cs.wisc.edu              case RFCR:
3427839Snilay@cs.wisc.edu                reg = regs.rfcr;
34311025Snilay@cs.wisc.edu                break;
3447007Snate@binkert.org
3457007Snate@binkert.org              case RFDR:
3467007Snate@binkert.org                DPRINTF(Ethernet, "reading from RFDR\n");
3477007Snate@binkert.org                switch (regs.rfcr & RFCR_RFADDR) {
3487839Snilay@cs.wisc.edu                  case 0x000:
3497839Snilay@cs.wisc.edu                    reg = rom.perfectMatch[1];
3507839Snilay@cs.wisc.edu                    reg = reg << 8;
3517839Snilay@cs.wisc.edu                    reg += rom.perfectMatch[0];
3527839Snilay@cs.wisc.edu                    break;
3537839Snilay@cs.wisc.edu                  case 0x002:
3547839Snilay@cs.wisc.edu                    reg = rom.perfectMatch[3] << 8;
3557839Snilay@cs.wisc.edu                    reg += rom.perfectMatch[2];
3567839Snilay@cs.wisc.edu                    break;
3577839Snilay@cs.wisc.edu                  case 0x004:
3587839Snilay@cs.wisc.edu                    reg = rom.perfectMatch[5] << 8;
3597839Snilay@cs.wisc.edu                    reg += rom.perfectMatch[4];
36011025Snilay@cs.wisc.edu                    break;
3617007Snate@binkert.org                  default:
3629745Snilay@cs.wisc.edu                    panic("reading from RFDR for something for other than PMATCH!\n");
3639745Snilay@cs.wisc.edu                    //didn't implement other RFDR functionality b/c driver didn't use
3649745Snilay@cs.wisc.edu                }
3659745Snilay@cs.wisc.edu                break;
3669745Snilay@cs.wisc.edu
3679745Snilay@cs.wisc.edu              case SRR:
3686657Snate@binkert.org                reg = regs.srr;
3697007Snate@binkert.org                break;
3706657Snate@binkert.org
3716657Snate@binkert.org              case MIBC:
3726657Snate@binkert.org                reg = regs.mibc;
3736657Snate@binkert.org                reg &= ~(MIBC_MIBS | MIBC_ACLR);
3746657Snate@binkert.org                break;
3756657Snate@binkert.org
3766657Snate@binkert.org              case VRCR:
3776657Snate@binkert.org                reg = regs.vrcr;
3787839Snilay@cs.wisc.edu                break;
3797839Snilay@cs.wisc.edu
3807839Snilay@cs.wisc.edu              case VTCR:
3817839Snilay@cs.wisc.edu                reg = regs.vtcr;
3827839Snilay@cs.wisc.edu                break;
3837839Snilay@cs.wisc.edu
3847839Snilay@cs.wisc.edu              case VDR:
3857839Snilay@cs.wisc.edu                reg = regs.vdr;
3867839Snilay@cs.wisc.edu                break;
3877839Snilay@cs.wisc.edu
3887839Snilay@cs.wisc.edu              case CCSR:
3897839Snilay@cs.wisc.edu                reg = regs.ccsr;
3907839Snilay@cs.wisc.edu                break;
3917839Snilay@cs.wisc.edu
3927839Snilay@cs.wisc.edu              case TBICR:
3937839Snilay@cs.wisc.edu                reg = regs.tbicr;
39410121Snilay@cs.wisc.edu                break;
3956657Snate@binkert.org
3966657Snate@binkert.org              case TBISR:
3976657Snate@binkert.org                reg = regs.tbisr;
3986657Snate@binkert.org                break;
3997839Snilay@cs.wisc.edu
4007839Snilay@cs.wisc.edu              case TANAR:
4017839Snilay@cs.wisc.edu                reg = regs.tanar;
40210121Snilay@cs.wisc.edu                break;
40310121Snilay@cs.wisc.edu
40411025Snilay@cs.wisc.edu              case TANLPAR:
4057839Snilay@cs.wisc.edu                reg = regs.tanlpar;
4067839Snilay@cs.wisc.edu                break;
4077839Snilay@cs.wisc.edu
40810121Snilay@cs.wisc.edu              case TANER:
40911025Snilay@cs.wisc.edu                reg = regs.taner;
4107839Snilay@cs.wisc.edu                break;
4117839Snilay@cs.wisc.edu
4127839Snilay@cs.wisc.edu              case TESR:
41310121Snilay@cs.wisc.edu                reg = regs.tesr;
41411025Snilay@cs.wisc.edu                break;
4157839Snilay@cs.wisc.edu
4167839Snilay@cs.wisc.edu              default:
4177839Snilay@cs.wisc.edu                panic("reading unimplemented register: addr = %#x", daddr);
41811025Snilay@cs.wisc.edu            }
4196657Snate@binkert.org
4206657Snate@binkert.org            DPRINTF(EthernetPIO, "read from %#x: data=%d data=%#x\n", daddr, reg, reg);
4216657Snate@binkert.org        }
4226657Snate@binkert.org        break;
4237007Snate@binkert.org
4246657Snate@binkert.org      default:
4256657Snate@binkert.org        panic("accessing register with invalid size: addr=%#x, size=%d",
4269273Snilay@cs.wisc.edu              daddr, req->size);
42710305Snilay@cs.wisc.edu    }
4286657Snate@binkert.org
4296657Snate@binkert.org    return No_Fault;
4306657Snate@binkert.org}
4317007Snate@binkert.org
4326657Snate@binkert.orgFault
4336657Snate@binkert.orgEtherDev::write(MemReqPtr &req, const uint8_t *data)
4349219Spower.jg@gmail.com{
4356657Snate@binkert.org    Addr daddr = req->paddr & 0xfff;
4366657Snate@binkert.org    DPRINTF(EthernetPIO, "write da=%#x pa=%#x va=%#x size=%d\n",
4376999Snate@binkert.org            daddr, req->paddr, req->vaddr, req->size);
4386657Snate@binkert.org
4396657Snate@binkert.org    if (daddr > LAST && daddr <=  RESERVED) {
4406657Snate@binkert.org        panic("Accessing reserved register");
4416657Snate@binkert.org    } else if (daddr > RESERVED && daddr <= 0x3FC) {
4427007Snate@binkert.org        WriteConfig(daddr & 0xff, req->size, *(uint32_t *)data);
4436657Snate@binkert.org        return No_Fault;
4446657Snate@binkert.org    } else if (daddr > 0x3FC)
4456657Snate@binkert.org        panic("Something is messed up!\n");
4466657Snate@binkert.org
4476657Snate@binkert.org    if (req->size == sizeof(uint32_t)) {
4488946Sandreas.hansson@arm.com        uint32_t reg = *(uint32_t *)data;
4498946Sandreas.hansson@arm.com        DPRINTF(EthernetPIO, "write data=%d data=%#x\n", reg, reg);
4508946Sandreas.hansson@arm.com
4517832Snate@binkert.org        switch (daddr) {
4527002Snate@binkert.org          case CR:
4537002Snate@binkert.org            regs.command = reg;
45410972Sdavid.hashe@amd.com            if ((reg & (CR_TXE | CR_TXD)) == (CR_TXE | CR_TXD)) {
4557002Snate@binkert.org                txHalt = true;
4568641Snate@binkert.org            } else if (reg & CR_TXE) {
4577056Snate@binkert.org                if (txState == txIdle)
45810972Sdavid.hashe@amd.com                    txKick();
45910972Sdavid.hashe@amd.com            } else if (reg & CR_TXD) {
46010972Sdavid.hashe@amd.com                txHalt = true;
46110972Sdavid.hashe@amd.com            }
46210972Sdavid.hashe@amd.com
4636657Snate@binkert.org            if ((reg & (CR_RXE | CR_RXD)) == (CR_RXE | CR_RXD)) {
4648229Snate@binkert.org                rxHalt = true;
4656657Snate@binkert.org            } else if (reg & CR_RXE) {
4666657Snate@binkert.org                if (rxState == rxIdle) {
46711108Sdavid.hashe@amd.com                    rxKick();
46810972Sdavid.hashe@amd.com                }
4699219Spower.jg@gmail.com            } else if (reg & CR_RXD) {
4709219Spower.jg@gmail.com                rxHalt = true;
4719219Spower.jg@gmail.com            }
4729219Spower.jg@gmail.com
4739219Spower.jg@gmail.com            if (reg & CR_TXR)
4747002Snate@binkert.org                txReset();
4757002Snate@binkert.org
4766657Snate@binkert.org            if (reg & CR_RXR)
4776657Snate@binkert.org                rxReset();
4786657Snate@binkert.org
4796657Snate@binkert.org            if (reg & CR_SWI)
4806657Snate@binkert.org                devIntrPost(ISR_SWI);
4816793SBrad.Beckmann@amd.com
4826657Snate@binkert.org            if (reg & CR_RST) {
4836657Snate@binkert.org                txReset();
4846657Snate@binkert.org                rxReset();
48510121Snilay@cs.wisc.edu
48610121Snilay@cs.wisc.edu                regsReset();
4876657Snate@binkert.org            }
4886877Ssteve.reinhardt@amd.com            break;
4896877Ssteve.reinhardt@amd.com
4906877Ssteve.reinhardt@amd.com          case CFG:
4916877Ssteve.reinhardt@amd.com            if (reg & CFG_LNKSTS || reg & CFG_SPDSTS || reg & CFG_DUPSTS
4926877Ssteve.reinhardt@amd.com                || reg & CFG_RESERVED || reg & CFG_T64ADDR
4936877Ssteve.reinhardt@amd.com                || reg & CFG_PCI64_DET)
4946657Snate@binkert.org                panic("writing to read-only or reserved CFG bits!\n");
4959745Snilay@cs.wisc.edu
4969745Snilay@cs.wisc.edu            regs.config |= reg & ~(CFG_LNKSTS | CFG_SPDSTS | CFG_DUPSTS | CFG_RESERVED |
4976657Snate@binkert.org                                  CFG_T64ADDR | CFG_PCI64_DET);
4987007Snate@binkert.org
4996657Snate@binkert.org#if 0
5009801Snilay@cs.wisc.edu              if (reg & CFG_TBI_EN) ;
5019801Snilay@cs.wisc.edu              if (reg & CFG_MODE_1000) ;
5026657Snate@binkert.org#endif
5039801Snilay@cs.wisc.edu
5049801Snilay@cs.wisc.edu            if (reg & CFG_AUTO_1000)
5059801Snilay@cs.wisc.edu                panic("CFG_AUTO_1000 not implemented!\n");
5067007Snate@binkert.org
5076657Snate@binkert.org#if 0
5086877Ssteve.reinhardt@amd.com            if (reg & CFG_PINT_DUPSTS || reg & CFG_PINT_LNKSTS || reg & CFG_PINT_SPDSTS) ;
5096877Ssteve.reinhardt@amd.com            if (reg & CFG_TMRTEST) ;
5106657Snate@binkert.org            if (reg & CFG_MRM_DIS) ;
51110078Snilay@cs.wisc.edu            if (reg & CFG_MWI_DIS) ;
51210078Snilay@cs.wisc.edu
51310121Snilay@cs.wisc.edu            if (reg & CFG_T64ADDR)
51410121Snilay@cs.wisc.edu                panic("CFG_T64ADDR is read only register!\n");
51510121Snilay@cs.wisc.edu
5166657Snate@binkert.org            if (reg & CFG_PCI64_DET)
5176657Snate@binkert.org                panic("CFG_PCI64_DET is read only register!\n");
5186882SBrad.Beckmann@amd.com
5196882SBrad.Beckmann@amd.com            if (reg & CFG_DATA64_EN) ;
5206882SBrad.Beckmann@amd.com            if (reg & CFG_M64ADDR) ;
52110121Snilay@cs.wisc.edu            if (reg & CFG_PHY_RST) ;
52210121Snilay@cs.wisc.edu            if (reg & CFG_PHY_DIS) ;
5236882SBrad.Beckmann@amd.com#endif
5246877Ssteve.reinhardt@amd.com
5256882SBrad.Beckmann@amd.com            if (reg & CFG_EXTSTS_EN)
52610308Snilay@cs.wisc.edu                extstsEnable = true;
5276882SBrad.Beckmann@amd.com            else
52810308Snilay@cs.wisc.edu                extstsEnable = false;
52910311Snilay@cs.wisc.edu
53010308Snilay@cs.wisc.edu#if 0
53110308Snilay@cs.wisc.edu              if (reg & CFG_REQALG) ;
53210917Sbrandon.potter@amd.com              if (reg & CFG_SB) ;
5339595Snilay@cs.wisc.edu              if (reg & CFG_POW) ;
5349745Snilay@cs.wisc.edu              if (reg & CFG_EXD) ;
5359745Snilay@cs.wisc.edu              if (reg & CFG_PESEL) ;
5369745Snilay@cs.wisc.edu              if (reg & CFG_BROM_DIS) ;
5379745Snilay@cs.wisc.edu              if (reg & CFG_EXT_125) ;
5389745Snilay@cs.wisc.edu              if (reg & CFG_BEM) ;
5399745Snilay@cs.wisc.edu#endif
5409745Snilay@cs.wisc.edu            break;
5419745Snilay@cs.wisc.edu
5429745Snilay@cs.wisc.edu          case MEAR:
5439745Snilay@cs.wisc.edu            regs.mear = reg;
5449595Snilay@cs.wisc.edu            /* since phy is completely faked, MEAR_MD* don't matter
5456657Snate@binkert.org               and since the driver never uses MEAR_EE*, they don't matter */
5466657Snate@binkert.org#if 0
5476657Snate@binkert.org            if (reg & MEAR_EEDI) ;
5486657Snate@binkert.org            if (reg & MEAR_EEDO) ; //this one is read only
5497007Snate@binkert.org            if (reg & MEAR_EECLK) ;
55011021Sjthestness@gmail.com            if (reg & MEAR_EESEL) ;
55110311Snilay@cs.wisc.edu            if (reg & MEAR_MDIO) ;
55210311Snilay@cs.wisc.edu            if (reg & MEAR_MDDIR) ;
55310311Snilay@cs.wisc.edu            if (reg & MEAR_MDC) ;
55410311Snilay@cs.wisc.edu#endif
55510311Snilay@cs.wisc.edu            break;
55610311Snilay@cs.wisc.edu
55710311Snilay@cs.wisc.edu          case PTSCR:
55810311Snilay@cs.wisc.edu            regs.ptscr = reg & ~(PTSCR_RBIST_RDONLY);
55910311Snilay@cs.wisc.edu            /* these control BISTs for various parts of chip - we don't care or do
56010311Snilay@cs.wisc.edu               just fake that the BIST is done */
56110311Snilay@cs.wisc.edu            if (reg & PTSCR_RBIST_EN)
56210311Snilay@cs.wisc.edu                regs.ptscr |= PTSCR_RBIST_DONE;
56310311Snilay@cs.wisc.edu            if (reg & PTSCR_EEBIST_EN)
56411084Snilay@cs.wisc.edu                regs.ptscr &= ~PTSCR_EEBIST_EN;
56510311Snilay@cs.wisc.edu            if (reg & PTSCR_EELOAD_EN)
56610311Snilay@cs.wisc.edu                regs.ptscr &= ~PTSCR_EELOAD_EN;
56711021Sjthestness@gmail.com            break;
56811021Sjthestness@gmail.com
56910311Snilay@cs.wisc.edu          case ISR: /* writing to the ISR has no effect */
57010311Snilay@cs.wisc.edu            panic("ISR is a read only register!\n");
57110311Snilay@cs.wisc.edu
57210311Snilay@cs.wisc.edu          case IMR:
57310311Snilay@cs.wisc.edu            regs.imr = reg;
57410311Snilay@cs.wisc.edu            devIntrChangeMask();
57510311Snilay@cs.wisc.edu            break;
57610311Snilay@cs.wisc.edu
57710311Snilay@cs.wisc.edu          case IER:
57810311Snilay@cs.wisc.edu            regs.ier = reg;
57910311Snilay@cs.wisc.edu            break;
58011021Sjthestness@gmail.com
58111021Sjthestness@gmail.com          case IHR:
58210311Snilay@cs.wisc.edu            regs.ihr = reg;
58310311Snilay@cs.wisc.edu            /* not going to implement real interrupt holdoff */
58410311Snilay@cs.wisc.edu            break;
58510311Snilay@cs.wisc.edu
58610311Snilay@cs.wisc.edu          case TXDP:
58710311Snilay@cs.wisc.edu            regs.txdp = (reg & 0xFFFFFFFC);
58810311Snilay@cs.wisc.edu            assert(txState == txIdle);
58910311Snilay@cs.wisc.edu            CTDD = false;
59010311Snilay@cs.wisc.edu            break;
59110311Snilay@cs.wisc.edu
5927007Snate@binkert.org          case TXDP_HI:
5936657Snate@binkert.org            regs.txdp_hi = reg;
5947007Snate@binkert.org            break;
5956657Snate@binkert.org
5966657Snate@binkert.org          case TXCFG:
5976657Snate@binkert.org            regs.txcfg = reg;
59810311Snilay@cs.wisc.edu#if 0
5996657Snate@binkert.org            if (reg & TXCFG_CSI) ;
6006657Snate@binkert.org            if (reg & TXCFG_HBI) ;
60110305Snilay@cs.wisc.edu            if (reg & TXCFG_MLB) ;
6026657Snate@binkert.org            if (reg & TXCFG_ATP) ;
6036657Snate@binkert.org            if (reg & TXCFG_ECRETRY) ;  /* this could easily be implemented, but
6046657Snate@binkert.org                                           considering the network is just a fake
6056657Snate@binkert.org                                           pipe, wouldn't make sense to do this */
6066657Snate@binkert.org
6076657Snate@binkert.org            if (reg & TXCFG_BRST_DIS) ;
6086657Snate@binkert.org#endif
6096657Snate@binkert.org
61011084Snilay@cs.wisc.edu
61111084Snilay@cs.wisc.edu            /* we handle our own DMA, ignore the kernel's exhortations */
61211084Snilay@cs.wisc.edu            if (reg & TXCFG_MXDMA) ;
61311084Snilay@cs.wisc.edu
61411084Snilay@cs.wisc.edu            break;
6156657Snate@binkert.org
61611084Snilay@cs.wisc.edu          case GPIOR:
6176657Snate@binkert.org            regs.gpior = reg;
6186657Snate@binkert.org            /* these just control general purpose i/o pins, don't matter */
6196657Snate@binkert.org            break;
6207007Snate@binkert.org
6216657Snate@binkert.org          case RXDP:
6227007Snate@binkert.org            regs.rxdp = reg;
6237007Snate@binkert.org            break;
6246657Snate@binkert.org
6259366Snilay@cs.wisc.edu          case RXDP_HI:
6269366Snilay@cs.wisc.edu            regs.rxdp_hi = reg;
6279366Snilay@cs.wisc.edu            break;
6289366Snilay@cs.wisc.edu
6297566SBrad.Beckmann@amd.com          case RXCFG:
6307672Snate@binkert.org            regs.rxcfg = reg;
6316657Snate@binkert.org#if 0
6329465Snilay@cs.wisc.edu            if (reg & RXCFG_AEP) ;
6336657Snate@binkert.org            if (reg & RXCFG_ARP) ;
6346657Snate@binkert.org            if (reg & RXCFG_STRIPCRC) ;
6356657Snate@binkert.org            if (reg & RXCFG_RX_RD) ;
6367672Snate@binkert.org            if (reg & RXCFG_ALP) ;
6376657Snate@binkert.org            if (reg & RXCFG_AIRL) ;
6386657Snate@binkert.org#endif
6396657Snate@binkert.org
6406657Snate@binkert.org            /* we handle our own DMA, ignore what kernel says about it */
6416657Snate@binkert.org            if (reg & RXCFG_MXDMA) ;
6426657Snate@binkert.org
6436657Snate@binkert.org#if 0
6446657Snate@binkert.org            if (reg & (RXCFG_DRTH | RXCFG_DRTH0)) ;
6456657Snate@binkert.org#endif
6466657Snate@binkert.org            break;
6476657Snate@binkert.org
6489745Snilay@cs.wisc.edu          case PQCR:
6496657Snate@binkert.org            /* there is no priority queueing used in the linux 2.6 driver */
6506657Snate@binkert.org            regs.pqcr = reg;
6519496Snilay@cs.wisc.edu            break;
6529496Snilay@cs.wisc.edu
65310012Snilay@cs.wisc.edu          case WCSR:
6549496Snilay@cs.wisc.edu            /* not going to implement wake on LAN */
6559496Snilay@cs.wisc.edu            regs.wcsr = reg;
6566657Snate@binkert.org            break;
65710121Snilay@cs.wisc.edu
6586657Snate@binkert.org          case PCR:
6596657Snate@binkert.org            /* not going to implement pause control */
66010305Snilay@cs.wisc.edu            regs.pcr = reg;
6616657Snate@binkert.org            break;
66211021Sjthestness@gmail.com
66311021Sjthestness@gmail.com          case RFCR:
66411021Sjthestness@gmail.com            regs.rfcr = reg;
66511021Sjthestness@gmail.com            DPRINTF(Ethernet, "Writing to RFCR, RFADDR is %#x\n", reg & RFCR_RFADDR);
66611021Sjthestness@gmail.com
6678683Snilay@cs.wisc.edu            rxFilterEnable = (reg & RFCR_RFEN) ? true : false;
6688683Snilay@cs.wisc.edu
66910308Snilay@cs.wisc.edu            acceptBroadcast = (reg & RFCR_AAB) ? true : false;
6708683Snilay@cs.wisc.edu
67110308Snilay@cs.wisc.edu            acceptMulticast = (reg & RFCR_AAM) ? true : false;
6728683Snilay@cs.wisc.edu
6736657Snate@binkert.org            acceptUnicast = (reg & RFCR_AAU) ? true : false;
6749745Snilay@cs.wisc.edu
6759745Snilay@cs.wisc.edu            acceptPerfect = (reg & RFCR_APM) ? true : false;
6769745Snilay@cs.wisc.edu
6779745Snilay@cs.wisc.edu            acceptArp = (reg & RFCR_AARP) ? true : false;
67810012Snilay@cs.wisc.edu
67910012Snilay@cs.wisc.edu            if (reg & RFCR_APAT) ;
6809745Snilay@cs.wisc.edu//                panic("RFCR_APAT not implemented!\n");
6819745Snilay@cs.wisc.edu
6829745Snilay@cs.wisc.edu            if (reg & RFCR_MHEN || reg & RFCR_UHEN)
6839745Snilay@cs.wisc.edu                panic("hash filtering not implemented!\n");
6849745Snilay@cs.wisc.edu
68510919Sbrandon.potter@amd.com            if (reg & RFCR_ULM)
68610012Snilay@cs.wisc.edu                panic("RFCR_ULM not implemented!\n");
6879745Snilay@cs.wisc.edu
6889745Snilay@cs.wisc.edu            break;
6899745Snilay@cs.wisc.edu
6909745Snilay@cs.wisc.edu          case RFDR:
6919745Snilay@cs.wisc.edu            panic("the driver never writes to RFDR, something is wrong!\n");
6929745Snilay@cs.wisc.edu
6939745Snilay@cs.wisc.edu          case BRAR:
6949745Snilay@cs.wisc.edu            panic("the driver never uses BRAR, something is wrong!\n");
6959745Snilay@cs.wisc.edu
6969745Snilay@cs.wisc.edu          case BRDR:
6979745Snilay@cs.wisc.edu            panic("the driver never uses BRDR, something is wrong!\n");
6989745Snilay@cs.wisc.edu
6999745Snilay@cs.wisc.edu          case SRR:
7009745Snilay@cs.wisc.edu            panic("SRR is read only register!\n");
7019745Snilay@cs.wisc.edu
7029745Snilay@cs.wisc.edu          case MIBC:
70310919Sbrandon.potter@amd.com            panic("the driver never uses MIBC, something is wrong!\n");
70410012Snilay@cs.wisc.edu
7059745Snilay@cs.wisc.edu          case VRCR:
7069745Snilay@cs.wisc.edu            regs.vrcr = reg;
7079745Snilay@cs.wisc.edu            break;
7089745Snilay@cs.wisc.edu
7099745Snilay@cs.wisc.edu          case VTCR:
7109745Snilay@cs.wisc.edu            regs.vtcr = reg;
7119745Snilay@cs.wisc.edu            break;
7129745Snilay@cs.wisc.edu
7139745Snilay@cs.wisc.edu          case VDR:
7149745Snilay@cs.wisc.edu            panic("the driver never uses VDR, something is wrong!\n");
7159745Snilay@cs.wisc.edu            break;
7169745Snilay@cs.wisc.edu
7179745Snilay@cs.wisc.edu          case CCSR:
7189745Snilay@cs.wisc.edu            /* not going to implement clockrun stuff */
7199745Snilay@cs.wisc.edu            regs.ccsr = reg;
7209745Snilay@cs.wisc.edu            break;
72110920Sbrandon.potter@amd.com
7229745Snilay@cs.wisc.edu          case TBICR:
72310920Sbrandon.potter@amd.com            regs.tbicr = reg;
72410920Sbrandon.potter@amd.com            if (reg & TBICR_MR_LOOPBACK)
7259745Snilay@cs.wisc.edu                panic("TBICR_MR_LOOPBACK never used, something wrong!\n");
7269745Snilay@cs.wisc.edu
7279745Snilay@cs.wisc.edu            if (reg & TBICR_MR_AN_ENABLE) {
7289745Snilay@cs.wisc.edu                regs.tanlpar = regs.tanar;
7299745Snilay@cs.wisc.edu                regs.tbisr |= (TBISR_MR_AN_COMPLETE | TBISR_MR_LINK_STATUS);
7309745Snilay@cs.wisc.edu            }
7319745Snilay@cs.wisc.edu
7329745Snilay@cs.wisc.edu#if 0
7339745Snilay@cs.wisc.edu            if (reg & TBICR_MR_RESTART_AN) ;
7349745Snilay@cs.wisc.edu#endif
7359745Snilay@cs.wisc.edu
7369745Snilay@cs.wisc.edu            break;
73710920Sbrandon.potter@amd.com
7389745Snilay@cs.wisc.edu          case TBISR:
73910920Sbrandon.potter@amd.com            panic("TBISR is read only register!\n");
74010920Sbrandon.potter@amd.com
7419745Snilay@cs.wisc.edu          case TANAR:
7429745Snilay@cs.wisc.edu            regs.tanar = reg;
7439745Snilay@cs.wisc.edu            if (reg & TANAR_PS2)
7449745Snilay@cs.wisc.edu                panic("this isn't used in driver, something wrong!\n");
7459745Snilay@cs.wisc.edu
7469745Snilay@cs.wisc.edu            if (reg & TANAR_PS1)
7479745Snilay@cs.wisc.edu                panic("this isn't used in driver, something wrong!\n");
7489745Snilay@cs.wisc.edu            break;
7499745Snilay@cs.wisc.edu
7509745Snilay@cs.wisc.edu          case TANLPAR:
7519745Snilay@cs.wisc.edu            panic("this should only be written to by the fake phy!\n");
7529745Snilay@cs.wisc.edu
7539745Snilay@cs.wisc.edu          case TANER:
7549745Snilay@cs.wisc.edu            panic("TANER is read only register!\n");
7559745Snilay@cs.wisc.edu
7569745Snilay@cs.wisc.edu          case TESR:
7579745Snilay@cs.wisc.edu            regs.tesr = reg;
7589745Snilay@cs.wisc.edu            break;
7599745Snilay@cs.wisc.edu
7609745Snilay@cs.wisc.edu          default:
7619745Snilay@cs.wisc.edu            panic("thought i covered all the register, what is this? addr=%#x",
76211061Snilay@cs.wisc.edu                  daddr);
7639745Snilay@cs.wisc.edu        }
7649745Snilay@cs.wisc.edu    } else
7659745Snilay@cs.wisc.edu        panic("Invalid Request Size");
7669745Snilay@cs.wisc.edu
7679745Snilay@cs.wisc.edu    return No_Fault;
7689745Snilay@cs.wisc.edu}
7699745Snilay@cs.wisc.edu
7709745Snilay@cs.wisc.eduvoid
7719745Snilay@cs.wisc.eduEtherDev::devIntrPost(uint32_t interrupts)
7729745Snilay@cs.wisc.edu{
7739745Snilay@cs.wisc.edu    DPRINTF(Ethernet, "interrupt posted intr=%#x isr=%#x imr=%#x\n",
77411061Snilay@cs.wisc.edu            interrupts, regs.isr, regs.imr);
7759745Snilay@cs.wisc.edu
7769745Snilay@cs.wisc.edu    bool delay = false;
7779745Snilay@cs.wisc.edu
7789745Snilay@cs.wisc.edu    if (interrupts & ISR_RESERVE)
7799745Snilay@cs.wisc.edu        panic("Cannot set a reserved interrupt");
7809745Snilay@cs.wisc.edu
7817007Snate@binkert.org    if (interrupts & ISR_TXRCMP)
7827007Snate@binkert.org        regs.isr |= ISR_TXRCMP;
7837007Snate@binkert.org
7846657Snate@binkert.org    if (interrupts & ISR_RXRCMP)
7856657Snate@binkert.org        regs.isr |= ISR_RXRCMP;
7866657Snate@binkert.org
7877007Snate@binkert.org//ISR_DPERR  not implemented
7887007Snate@binkert.org//ISR_SSERR not implemented
7897007Snate@binkert.org//ISR_RMABT not implemented
7906657Snate@binkert.org//ISR_RXSOVR not implemented
7916657Snate@binkert.org//ISR_HIBINT not implemented
7926657Snate@binkert.org//ISR_PHY not implemented
79311021Sjthestness@gmail.com//ISR_PME not implemented
79411021Sjthestness@gmail.com
79511021Sjthestness@gmail.com    if (interrupts & ISR_SWI)
79611021Sjthestness@gmail.com        regs.isr |= ISR_SWI;
79711021Sjthestness@gmail.com
79811021Sjthestness@gmail.com//ISR_MIB not implemented
7998683Snilay@cs.wisc.edu//ISR_TXURN not implemented
8008683Snilay@cs.wisc.edu
8018683Snilay@cs.wisc.edu    if (interrupts & ISR_TXIDLE)
8028683Snilay@cs.wisc.edu        regs.isr |= ISR_TXIDLE;
8038683Snilay@cs.wisc.edu
8048683Snilay@cs.wisc.edu    if (interrupts & ISR_TXERR)
8057007Snate@binkert.org        regs.isr |= ISR_TXERR;
8067007Snate@binkert.org
8077007Snate@binkert.org    if (interrupts & ISR_TXDESC)
8087007Snate@binkert.org        regs.isr |= ISR_TXDESC;
8097007Snate@binkert.org
8106657Snate@binkert.org    if (interrupts & ISR_TXOK) {
81110012Snilay@cs.wisc.edu        regs.isr |= ISR_TXOK;
8129745Snilay@cs.wisc.edu        delay = true;
8139745Snilay@cs.wisc.edu    }
8149745Snilay@cs.wisc.edu
8159745Snilay@cs.wisc.edu    if (interrupts & ISR_RXORN)
8169745Snilay@cs.wisc.edu        regs.isr |= ISR_RXORN;
8179745Snilay@cs.wisc.edu
8186902SBrad.Beckmann@amd.com    if (interrupts & ISR_RXIDLE)
8199745Snilay@cs.wisc.edu        regs.isr |= ISR_RXIDLE;
8209745Snilay@cs.wisc.edu
8219745Snilay@cs.wisc.edu//ISR_RXEARLY not implemented
8229745Snilay@cs.wisc.edu
82310012Snilay@cs.wisc.edu    if (interrupts & ISR_RXERR)
8246902SBrad.Beckmann@amd.com        regs.isr |= ISR_RXERR;
8257839Snilay@cs.wisc.edu
8267839Snilay@cs.wisc.edu    if (interrupts & ISR_RXOK) {
8277839Snilay@cs.wisc.edu        delay = true;
8287839Snilay@cs.wisc.edu        regs.isr |= ISR_RXOK;
8297839Snilay@cs.wisc.edu    }
8307839Snilay@cs.wisc.edu
8317839Snilay@cs.wisc.edu    if ((regs.isr & regs.imr)) {
8327839Snilay@cs.wisc.edu        Tick when = curTick;
8337839Snilay@cs.wisc.edu        if (delay)
8347839Snilay@cs.wisc.edu            when += intrDelay;
8357839Snilay@cs.wisc.edu        cpuIntrPost(when);
8367839Snilay@cs.wisc.edu    }
8377839Snilay@cs.wisc.edu}
8387839Snilay@cs.wisc.edu
8397839Snilay@cs.wisc.eduvoid
8407839Snilay@cs.wisc.eduEtherDev::devIntrClear(uint32_t interrupts)
8417839Snilay@cs.wisc.edu{
8427839Snilay@cs.wisc.edu    DPRINTF(Ethernet, "interrupt cleared intr=%x isr=%x imr=%x\n",
8437839Snilay@cs.wisc.edu            interrupts, regs.isr, regs.imr);
8447839Snilay@cs.wisc.edu
8457839Snilay@cs.wisc.edu    if (interrupts & ISR_RESERVE)
8467839Snilay@cs.wisc.edu        panic("Cannot clear a reserved interrupt");
8477839Snilay@cs.wisc.edu
8487839Snilay@cs.wisc.edu    if (interrupts & ISR_TXRCMP)
8497839Snilay@cs.wisc.edu        regs.isr &= ~ISR_TXRCMP;
8507839Snilay@cs.wisc.edu
8517839Snilay@cs.wisc.edu    if (interrupts & ISR_RXRCMP)
8527839Snilay@cs.wisc.edu        regs.isr &= ~ISR_RXRCMP;
8537839Snilay@cs.wisc.edu
8547839Snilay@cs.wisc.edu//ISR_DPERR  not implemented
8557839Snilay@cs.wisc.edu//ISR_SSERR not implemented
8567839Snilay@cs.wisc.edu//ISR_RMABT not implemented
8577839Snilay@cs.wisc.edu//ISR_RXSOVR not implemented
8587839Snilay@cs.wisc.edu//ISR_HIBINT not implemented
8597839Snilay@cs.wisc.edu//ISR_PHY not implemented
8607839Snilay@cs.wisc.edu//ISR_PME not implemented
8617839Snilay@cs.wisc.edu
8626902SBrad.Beckmann@amd.com    if (interrupts & ISR_SWI)
8638683Snilay@cs.wisc.edu        regs.isr &= ~ISR_SWI;
8648683Snilay@cs.wisc.edu
8658683Snilay@cs.wisc.edu//ISR_MIB not implemented
8668683Snilay@cs.wisc.edu//ISR_TXURN not implemented
8678683Snilay@cs.wisc.edu
8688683Snilay@cs.wisc.edu    if (interrupts & ISR_TXIDLE)
8698683Snilay@cs.wisc.edu        regs.isr &= ~ISR_TXIDLE;
8708683Snilay@cs.wisc.edu
8718683Snilay@cs.wisc.edu    if (interrupts & ISR_TXERR)
8728683Snilay@cs.wisc.edu        regs.isr &= ~ISR_TXERR;
8738683Snilay@cs.wisc.edu
8748683Snilay@cs.wisc.edu    if (interrupts & ISR_TXDESC)
8758683Snilay@cs.wisc.edu        regs.isr &= ~ISR_TXDESC;
8768683Snilay@cs.wisc.edu
8778683Snilay@cs.wisc.edu    if (interrupts & ISR_TXOK)
8788683Snilay@cs.wisc.edu        regs.isr &= ~ISR_TXOK;
8798683Snilay@cs.wisc.edu
8806657Snate@binkert.org    if (interrupts & ISR_RXORN)
8816657Snate@binkert.org        regs.isr &= ~ISR_RXORN;
8827839Snilay@cs.wisc.edu
8837839Snilay@cs.wisc.edu    if (interrupts & ISR_RXIDLE)
8847839Snilay@cs.wisc.edu        regs.isr &= ~ISR_RXIDLE;
8857839Snilay@cs.wisc.edu
8866657Snate@binkert.org//ISR_RXEARLY not implemented
8877839Snilay@cs.wisc.edu
8887839Snilay@cs.wisc.edu    if (interrupts & ISR_RXERR)
8897839Snilay@cs.wisc.edu        regs.isr &= ~ISR_RXERR;
89011025Snilay@cs.wisc.edu
8917839Snilay@cs.wisc.edu    if (interrupts & ISR_RXOK)
8928055Sksewell@umich.edu        regs.isr &= ~ISR_RXOK;
89310963Sdavid.hashe@amd.com
89410963Sdavid.hashe@amd.com    if (!(regs.isr & regs.imr))
89510963Sdavid.hashe@amd.com        cpuIntrClear();
89610963Sdavid.hashe@amd.com}
89710963Sdavid.hashe@amd.com
89810963Sdavid.hashe@amd.comvoid
89910963Sdavid.hashe@amd.comEtherDev::devIntrChangeMask()
9007839Snilay@cs.wisc.edu{
9016657Snate@binkert.org    DPRINTF(Ethernet, "interrupt mask changed\n");
9027839Snilay@cs.wisc.edu
9037839Snilay@cs.wisc.edu    if (regs.isr & regs.imr)
9047839Snilay@cs.wisc.edu        cpuIntrPost(curTick);
9057839Snilay@cs.wisc.edu    else
9067839Snilay@cs.wisc.edu        cpuIntrClear();
9077839Snilay@cs.wisc.edu}
9087839Snilay@cs.wisc.edu
9097839Snilay@cs.wisc.eduvoid
9107839Snilay@cs.wisc.eduEtherDev::cpuIntrPost(Tick when)
91111025Snilay@cs.wisc.edu{
9127839Snilay@cs.wisc.edu    if (when > intrTick && intrTick != 0)
9138055Sksewell@umich.edu        return;
9147839Snilay@cs.wisc.edu
9157839Snilay@cs.wisc.edu    intrTick = when;
9167839Snilay@cs.wisc.edu
9177839Snilay@cs.wisc.edu    if (intrEvent) {
9187839Snilay@cs.wisc.edu        intrEvent->squash();
9197839Snilay@cs.wisc.edu        intrEvent = 0;
9207839Snilay@cs.wisc.edu    }
9217839Snilay@cs.wisc.edu
9227839Snilay@cs.wisc.edu    if (when < curTick) {
9237839Snilay@cs.wisc.edu        cpuInterrupt();
9247839Snilay@cs.wisc.edu    } else {
9257839Snilay@cs.wisc.edu        intrEvent = new IntrEvent(this, true);
92611025Snilay@cs.wisc.edu        intrEvent->schedule(intrTick);
9277839Snilay@cs.wisc.edu    }
9288055Sksewell@umich.edu}
9297839Snilay@cs.wisc.edu
9307839Snilay@cs.wisc.eduvoid
9317839Snilay@cs.wisc.eduEtherDev::cpuInterrupt()
9327839Snilay@cs.wisc.edu{
9337839Snilay@cs.wisc.edu    // Don't send an interrupt if there's already one
9347839Snilay@cs.wisc.edu    if (cpuPendingIntr)
9357839Snilay@cs.wisc.edu        return;
9367839Snilay@cs.wisc.edu
9377839Snilay@cs.wisc.edu    // Don't send an interrupt if it's supposed to be delayed
9387839Snilay@cs.wisc.edu    if (intrTick > curTick)
9396657Snate@binkert.org        return;
9407007Snate@binkert.org
94111025Snilay@cs.wisc.edu    // Whether or not there's a pending interrupt, we don't care about
9426657Snate@binkert.org    // it anymore
9438055Sksewell@umich.edu    intrEvent = 0;
9446657Snate@binkert.org    intrTick = 0;
9456657Snate@binkert.org
9466657Snate@binkert.org    // Send interrupt
9476657Snate@binkert.org    cpuPendingIntr = true;
9488478Snilay@cs.wisc.edu    /** @todo rework the intctrl to be tsunami ok */
9498478Snilay@cs.wisc.edu    //intctrl->post(TheISA::INTLEVEL_IRQ1, TheISA::INTINDEX_ETHERNET);
9508478Snilay@cs.wisc.edu    tsunami->cchip->postDRIR(configData->config.hdr.pci0.interruptLine);
9519302Snilay@cs.wisc.edu}
9529302Snilay@cs.wisc.edu
95310524Snilay@cs.wisc.eduvoid
9549302Snilay@cs.wisc.eduEtherDev::cpuIntrClear()
9559302Snilay@cs.wisc.edu{
95610524Snilay@cs.wisc.edu    if (cpuPendingIntr) {
9579302Snilay@cs.wisc.edu        cpuPendingIntr = false;
9589302Snilay@cs.wisc.edu        /** @todo rework the intctrl to be tsunami ok */
9599302Snilay@cs.wisc.edu        //intctrl->clear(TheISA::INTLEVEL_IRQ1, TheISA::INTINDEX_ETHERNET);
9609302Snilay@cs.wisc.edu        tsunami->cchip->clearDRIR(configData->config.hdr.pci0.interruptLine);
96110305Snilay@cs.wisc.edu    }
9629302Snilay@cs.wisc.edu}
96310311Snilay@cs.wisc.edu
96410311Snilay@cs.wisc.edubool
96510311Snilay@cs.wisc.eduEtherDev::cpuIntrPending() const
96610311Snilay@cs.wisc.edu{ return cpuPendingIntr; }
96710311Snilay@cs.wisc.edu
96810311Snilay@cs.wisc.eduvoid
96910311Snilay@cs.wisc.eduEtherDev::txReset()
9709302Snilay@cs.wisc.edu{
9719302Snilay@cs.wisc.edu
9729302Snilay@cs.wisc.edu    DPRINTF(Ethernet, "transmit reset\n");
9739302Snilay@cs.wisc.edu
9749302Snilay@cs.wisc.edu    CTDD = false;
9756657Snate@binkert.org    txFifoCnt = 0;
9766657Snate@binkert.org    txFifoAvail = MAX_TX_FIFO_SIZE;
9779219Spower.jg@gmail.com    txHalt = false;
9786657Snate@binkert.org    txFragPtr = 0;
9796657Snate@binkert.org    assert(txDescCnt == 0);
9806999Snate@binkert.org    txFifo.clear();
9816657Snate@binkert.org    regs.command &= ~CR_TXE;
9826657Snate@binkert.org    txState = txIdle;
9839104Shestness@cs.utexas.edu    assert(txDmaState == dmaIdle);
9849104Shestness@cs.utexas.edu}
9859104Shestness@cs.utexas.edu
9869104Shestness@cs.utexas.eduvoid
9876657Snate@binkert.orgEtherDev::rxReset()
9886657Snate@binkert.org{
9896657Snate@binkert.org    DPRINTF(Ethernet, "receive reset\n");
9906657Snate@binkert.org
9918946Sandreas.hansson@arm.com    CRDD = false;
9928946Sandreas.hansson@arm.com    assert(rxPktBytes == 0);
9938946Sandreas.hansson@arm.com    rxFifoCnt = 0;
9947832Snate@binkert.org    rxHalt = false;
99510972Sdavid.hashe@amd.com    rxFragPtr = 0;
9967832Snate@binkert.org    assert(rxDescCnt == 0);
9977007Snate@binkert.org    assert(rxDmaState == dmaIdle);
99810972Sdavid.hashe@amd.com    rxFifo.clear();
99910972Sdavid.hashe@amd.com    regs.command &= ~CR_RXE;
100010972Sdavid.hashe@amd.com    rxState = rxIdle;
100110972Sdavid.hashe@amd.com}
100210972Sdavid.hashe@amd.com
10038229Snate@binkert.orgvoid
10048229Snate@binkert.orgEtherDev::rxDmaReadCopy()
10058229Snate@binkert.org{
100610972Sdavid.hashe@amd.com    assert(rxDmaState == dmaReading);
10079104Shestness@cs.utexas.edu
10089104Shestness@cs.utexas.edu    memcpy(rxDmaData, physmem->dma_addr(rxDmaAddr, rxDmaLen), rxDmaLen);
10099104Shestness@cs.utexas.edu    rxDmaState = dmaIdle;
10109104Shestness@cs.utexas.edu
10119104Shestness@cs.utexas.edu    DPRINTF(EthernetDMA, "rx dma read  paddr=%#x len=%d\n",
10129104Shestness@cs.utexas.edu            rxDmaAddr, rxDmaLen);
10138229Snate@binkert.org    DDUMP(EthernetDMA, rxDmaData, rxDmaLen);
101411108Sdavid.hashe@amd.com}
101510972Sdavid.hashe@amd.com
10169219Spower.jg@gmail.combool
10179219Spower.jg@gmail.comEtherDev::doRxDmaRead()
10189219Spower.jg@gmail.com{
10199219Spower.jg@gmail.com    assert(rxDmaState == dmaIdle || rxDmaState == dmaReadWaiting);
10209219Spower.jg@gmail.com    rxDmaState = dmaReading;
10219219Spower.jg@gmail.com
102210963Sdavid.hashe@amd.com    if (dmaInterface && !rxDmaFree) {
102310963Sdavid.hashe@amd.com        if (dmaInterface->busy())
10249219Spower.jg@gmail.com            rxDmaState = dmaReadWaiting;
10256657Snate@binkert.org        else
10267055Snate@binkert.org            dmaInterface->doDMA(Read, rxDmaAddr, rxDmaLen, curTick,
10277055Snate@binkert.org                                &rxDmaReadEvent);
10287007Snate@binkert.org        return true;
10297007Snate@binkert.org    }
10306657Snate@binkert.org
10316657Snate@binkert.org    if (dmaReadDelay == 0 && dmaReadFactor == 0) {
10326657Snate@binkert.org        rxDmaReadCopy();
103310963Sdavid.hashe@amd.com        return false;
103410963Sdavid.hashe@amd.com    }
10356657Snate@binkert.org
10366657Snate@binkert.org    Tick factor = ((rxDmaLen + ULL(63)) >> ULL(6)) * dmaReadFactor;
10376657Snate@binkert.org    Tick start = curTick + dmaReadDelay + factor;
10387007Snate@binkert.org    rxDmaReadEvent.schedule(start);
10399496Snilay@cs.wisc.edu    return true;
10407007Snate@binkert.org}
10417007Snate@binkert.org
10429499Snilay@cs.wisc.eduvoid
10436657Snate@binkert.orgEtherDev::rxDmaReadDone()
10446657Snate@binkert.org{
10456657Snate@binkert.org    assert(rxDmaState == dmaReading);
10466657Snate@binkert.org    rxDmaReadCopy();
10476657Snate@binkert.org
10486657Snate@binkert.org    // If the transmit state machine has a pending DMA, let it go first
10496657Snate@binkert.org    if (txDmaState == dmaReadWaiting || txDmaState == dmaWriteWaiting)
10506657Snate@binkert.org        txKick();
10516657Snate@binkert.org
10526657Snate@binkert.org    rxKick();
10536657Snate@binkert.org}
10546657Snate@binkert.org
10557567SBrad.Beckmann@amd.comvoid
10569996Snilay@cs.wisc.eduEtherDev::rxDmaWriteCopy()
10577567SBrad.Beckmann@amd.com{
10589996Snilay@cs.wisc.edu    assert(rxDmaState == dmaWriting);
105910963Sdavid.hashe@amd.com
106010963Sdavid.hashe@amd.com    memcpy(physmem->dma_addr(rxDmaAddr, rxDmaLen), rxDmaData, rxDmaLen);
106110963Sdavid.hashe@amd.com    rxDmaState = dmaIdle;
10626657Snate@binkert.org
106310963Sdavid.hashe@amd.com    DPRINTF(EthernetDMA, "rx dma write paddr=%#x len=%d\n",
106410963Sdavid.hashe@amd.com            rxDmaAddr, rxDmaLen);
106510963Sdavid.hashe@amd.com    DDUMP(EthernetDMA, rxDmaData, rxDmaLen);
106610963Sdavid.hashe@amd.com}
106710963Sdavid.hashe@amd.com
106810963Sdavid.hashe@amd.combool
106910963Sdavid.hashe@amd.comEtherDev::doRxDmaWrite()
107010963Sdavid.hashe@amd.com{
10716657Snate@binkert.org    assert(rxDmaState == dmaIdle || rxDmaState == dmaWriteWaiting);
10726657Snate@binkert.org    rxDmaState = dmaWriting;
10736657Snate@binkert.org
10746657Snate@binkert.org    if (dmaInterface && !rxDmaFree) {
10756657Snate@binkert.org        if (dmaInterface->busy())
10766657Snate@binkert.org            rxDmaState = dmaWriteWaiting;
107710963Sdavid.hashe@amd.com        else
107810963Sdavid.hashe@amd.com            dmaInterface->doDMA(WriteInvalidate, rxDmaAddr, rxDmaLen, curTick,
107910963Sdavid.hashe@amd.com                                &rxDmaWriteEvent);
108010963Sdavid.hashe@amd.com        return true;
108110963Sdavid.hashe@amd.com    }
108210963Sdavid.hashe@amd.com
108311116Santhony.gutierrez@amd.com    if (dmaWriteDelay == 0 && dmaWriteFactor == 0) {
108410963Sdavid.hashe@amd.com        rxDmaWriteCopy();
108510963Sdavid.hashe@amd.com        return false;
108610963Sdavid.hashe@amd.com    }
108710963Sdavid.hashe@amd.com
108810963Sdavid.hashe@amd.com    Tick factor = ((rxDmaLen + ULL(63)) >> ULL(6)) * dmaWriteFactor;
108910963Sdavid.hashe@amd.com    Tick start = curTick + dmaWriteDelay + factor;
109010963Sdavid.hashe@amd.com    rxDmaWriteEvent.schedule(start);
109110963Sdavid.hashe@amd.com    return true;
109210963Sdavid.hashe@amd.com}
109310963Sdavid.hashe@amd.com
109410963Sdavid.hashe@amd.comvoid
109510963Sdavid.hashe@amd.comEtherDev::rxDmaWriteDone()
10966657Snate@binkert.org{
10976657Snate@binkert.org    assert(rxDmaState == dmaWriting);
10986657Snate@binkert.org    rxDmaWriteCopy();
10996657Snate@binkert.org
11006657Snate@binkert.org    // If the transmit state machine has a pending DMA, let it go first
11016657Snate@binkert.org    if (txDmaState == dmaReadWaiting || txDmaState == dmaWriteWaiting)
11026657Snate@binkert.org        txKick();
11036657Snate@binkert.org
11046657Snate@binkert.org    rxKick();
11056999Snate@binkert.org}
11066657Snate@binkert.org
11076657Snate@binkert.orgvoid
11086657Snate@binkert.orgEtherDev::rxKick()
11096657Snate@binkert.org{
11106657Snate@binkert.org    DPRINTF(Ethernet, "receive kick state=%s (rxBuf.size=%d)\n",
11116657Snate@binkert.org            NsRxStateStrings[rxState], rxFifo.size());
11127832Snate@binkert.org
11137832Snate@binkert.org    if (rxKickTick > curTick) {
11147805Snilay@cs.wisc.edu        DPRINTF(Ethernet, "receive kick exiting, can't run till %d\n",
11157832Snate@binkert.org                rxKickTick);
11168232Snate@binkert.org        return;
11178232Snate@binkert.org    }
11188229Snate@binkert.org
11198229Snate@binkert.org  next:
11208229Snate@binkert.org    switch(rxDmaState) {
11218229Snate@binkert.org      case dmaReadWaiting:
112211108Sdavid.hashe@amd.com        if (doRxDmaRead())
11236657Snate@binkert.org            goto exit;
11246657Snate@binkert.org        break;
11256657Snate@binkert.org      case dmaWriteWaiting:
11266657Snate@binkert.org        if (doRxDmaWrite())
11276657Snate@binkert.org            goto exit;
11286657Snate@binkert.org        break;
11297007Snate@binkert.org      default:
11307007Snate@binkert.org        break;
11317839Snilay@cs.wisc.edu    }
11327839Snilay@cs.wisc.edu
11337839Snilay@cs.wisc.edu    switch (rxState) {
11347839Snilay@cs.wisc.edu      case rxIdle:
11357839Snilay@cs.wisc.edu        if (!regs.command & CR_RXE) {
11367839Snilay@cs.wisc.edu            DPRINTF(Ethernet, "Receive Disabled! Nothing to do.\n");
11377839Snilay@cs.wisc.edu            goto exit;
11387839Snilay@cs.wisc.edu        }
11397839Snilay@cs.wisc.edu
11407839Snilay@cs.wisc.edu        if (CRDD) {
114111025Snilay@cs.wisc.edu            rxState = rxDescRefr;
11426657Snate@binkert.org
11437839Snilay@cs.wisc.edu            rxDmaAddr = regs.rxdp & 0x3fffffff;
114410305Snilay@cs.wisc.edu            rxDmaData = &rxDescCache + offsetof(ns_desc, link);
114510305Snilay@cs.wisc.edu            rxDmaLen = sizeof(rxDescCache.link);
11467839Snilay@cs.wisc.edu            rxDmaFree = dmaDescFree;
11478337Snilay@cs.wisc.edu
11487839Snilay@cs.wisc.edu            if (doRxDmaRead())
11498337Snilay@cs.wisc.edu                goto exit;
11507839Snilay@cs.wisc.edu        } else {
11518337Snilay@cs.wisc.edu            rxState = rxDescRead;
11527839Snilay@cs.wisc.edu
11538337Snilay@cs.wisc.edu            rxDmaAddr = regs.rxdp & 0x3fffffff;
11547839Snilay@cs.wisc.edu            rxDmaData = &rxDescCache;
11557839Snilay@cs.wisc.edu            rxDmaLen = sizeof(ns_desc);
115610305Snilay@cs.wisc.edu            rxDmaFree = dmaDescFree;
11576657Snate@binkert.org
115810305Snilay@cs.wisc.edu            if (doRxDmaRead())
115910305Snilay@cs.wisc.edu                goto exit;
116010305Snilay@cs.wisc.edu        }
11616657Snate@binkert.org        break;
116210305Snilay@cs.wisc.edu
11637839Snilay@cs.wisc.edu      case rxDescRefr:
11647839Snilay@cs.wisc.edu        if (rxDmaState != dmaIdle)
11657839Snilay@cs.wisc.edu            goto exit;
11667839Snilay@cs.wisc.edu
11677839Snilay@cs.wisc.edu        rxState = rxAdvance;
11687839Snilay@cs.wisc.edu        break;
11697839Snilay@cs.wisc.edu
11707839Snilay@cs.wisc.edu     case rxDescRead:
11717839Snilay@cs.wisc.edu        if (rxDmaState != dmaIdle)
11726657Snate@binkert.org            goto exit;
117311049Snilay@cs.wisc.edu
117411049Snilay@cs.wisc.edu        if (rxDescCache.cmdsts & CMDSTS_OWN) {
11757839Snilay@cs.wisc.edu            rxState = rxIdle;
11766657Snate@binkert.org        } else {
117710305Snilay@cs.wisc.edu            rxState = rxFifoBlock;
117810305Snilay@cs.wisc.edu            rxFragPtr = rxDescCache.bufptr;
117910305Snilay@cs.wisc.edu            rxDescCnt = rxDescCache.cmdsts & CMDSTS_LEN_MASK;
118010305Snilay@cs.wisc.edu        }
118110305Snilay@cs.wisc.edu        break;
118211025Snilay@cs.wisc.edu
118310305Snilay@cs.wisc.edu      case rxFifoBlock:
118410305Snilay@cs.wisc.edu        if (!rxPacket) {
118510305Snilay@cs.wisc.edu            /**
118610305Snilay@cs.wisc.edu             * @todo in reality, we should be able to start processing
118710305Snilay@cs.wisc.edu             * the packet as it arrives, and not have to wait for the
118810305Snilay@cs.wisc.edu             * full packet ot be in the receive fifo.
118910305Snilay@cs.wisc.edu             */
11907839Snilay@cs.wisc.edu            if (rxFifo.empty())
11917839Snilay@cs.wisc.edu                goto exit;
11928337Snilay@cs.wisc.edu
11938341Snilay@cs.wisc.edu            // If we don't have a packet, grab a new one from the fifo.
11947839Snilay@cs.wisc.edu            rxPacket = rxFifo.front();
11958337Snilay@cs.wisc.edu            rxPktBytes = rxPacket->length;
11968341Snilay@cs.wisc.edu            rxPacketBufPtr = rxPacket->data;
11977839Snilay@cs.wisc.edu
11988337Snilay@cs.wisc.edu            // sanity check - i think the driver behaves like this
11998341Snilay@cs.wisc.edu            assert(rxDescCnt >= rxPktBytes);
12007839Snilay@cs.wisc.edu
12018337Snilay@cs.wisc.edu            // Must clear the value before popping to decrement the
12028341Snilay@cs.wisc.edu            // reference count
12037839Snilay@cs.wisc.edu            rxFifo.front() = NULL;
12047839Snilay@cs.wisc.edu            rxFifo.pop_front();
120510305Snilay@cs.wisc.edu        }
120611025Snilay@cs.wisc.edu
120710305Snilay@cs.wisc.edu
120810305Snilay@cs.wisc.edu        // dont' need the && rxDescCnt > 0 if driver sanity check above holds
120910305Snilay@cs.wisc.edu        if (rxPktBytes > 0) {
121010305Snilay@cs.wisc.edu            rxState = rxFragWrite;
121110305Snilay@cs.wisc.edu            // don't need min<>(rxPktBytes,rxDescCnt) if above sanity check holds
121210305Snilay@cs.wisc.edu            rxXferLen = rxPktBytes;
121310305Snilay@cs.wisc.edu
121411025Snilay@cs.wisc.edu            rxDmaAddr = rxFragPtr & 0x3fffffff;
121510305Snilay@cs.wisc.edu            rxDmaData = rxPacketBufPtr;
121610305Snilay@cs.wisc.edu            rxDmaLen = rxXferLen;
121710305Snilay@cs.wisc.edu            rxDmaFree = dmaDataFree;
121810305Snilay@cs.wisc.edu
121910305Snilay@cs.wisc.edu            if (doRxDmaWrite())
122010305Snilay@cs.wisc.edu                goto exit;
12216657Snate@binkert.org
122210305Snilay@cs.wisc.edu        } else {
122310305Snilay@cs.wisc.edu            rxState = rxDescWrite;
122410305Snilay@cs.wisc.edu
122510305Snilay@cs.wisc.edu            //if (rxPktBytes == 0) {  /* packet is done */
12266657Snate@binkert.org            assert(rxPktBytes == 0);
12276657Snate@binkert.org
12287007Snate@binkert.org            rxFifoCnt -= rxPacket->length;
12297007Snate@binkert.org            rxPacket = 0;
12307007Snate@binkert.org
12317007Snate@binkert.org            rxDescCache.cmdsts |= CMDSTS_OWN;
12327839Snilay@cs.wisc.edu            rxDescCache.cmdsts &= ~CMDSTS_MORE;
12337839Snilay@cs.wisc.edu            rxDescCache.cmdsts |= CMDSTS_OK;
12347839Snilay@cs.wisc.edu            rxDescCache.cmdsts += rxPacket->length;   //i.e. set CMDSTS_SIZE
12357839Snilay@cs.wisc.edu
12367839Snilay@cs.wisc.edu#if 0
12377839Snilay@cs.wisc.edu            /* all the driver uses these are for its own stats keeping
12387839Snilay@cs.wisc.edu               which we don't care about, aren't necessary for functionality
12397839Snilay@cs.wisc.edu               and doing this would just slow us down.  if they end up using
12407839Snilay@cs.wisc.edu               this in a later version for functional purposes, just undef
12417839Snilay@cs.wisc.edu            */
12427839Snilay@cs.wisc.edu            if (rxFilterEnable) {
124311025Snilay@cs.wisc.edu                rxDescCache.cmdsts &= ~CMDSTS_DEST_MASK;
12446657Snate@binkert.org                if (rxFifo.front()->IsUnicast())
12456657Snate@binkert.org                    rxDescCache.cmdsts |= CMDSTS_DEST_SELF;
12466657Snate@binkert.org                if (rxFifo.front()->IsMulticast())
12476657Snate@binkert.org                    rxDescCache.cmdsts |= CMDSTS_DEST_MULTI;
12486657Snate@binkert.org                if (rxFifo.front()->IsBroadcast())
12496657Snate@binkert.org                    rxDescCache.cmdsts |= CMDSTS_DEST_MASK;
12506657Snate@binkert.org            }
12516657Snate@binkert.org#endif
12526657Snate@binkert.org
12536657Snate@binkert.org            eth_header *eth = (eth_header *) rxPacket->data;
12546657Snate@binkert.org            if (eth->type == 0x800 && extstsEnable) {
12556999Snate@binkert.org                rxDescCache.extsts |= EXTSTS_IPPKT;
12566657Snate@binkert.org                if (!ipChecksum(rxPacket, false))
12576657Snate@binkert.org                    rxDescCache.extsts |= EXTSTS_IPERR;
125810964Sdavid.hashe@amd.com                ip_header *ip = rxFifo.front()->getIpHdr();
125910964Sdavid.hashe@amd.com
126010964Sdavid.hashe@amd.com                if (ip->protocol == 6) {
126110964Sdavid.hashe@amd.com                    rxDescCache.extsts |= EXTSTS_TCPPKT;
126210964Sdavid.hashe@amd.com                    if (!tcpChecksum(rxPacket, false))
126310964Sdavid.hashe@amd.com                        rxDescCache.extsts |= EXTSTS_TCPERR;
126410964Sdavid.hashe@amd.com                } else if (ip->protocol == 17) {
126510964Sdavid.hashe@amd.com                    rxDescCache.extsts |= EXTSTS_UDPPKT;
126610964Sdavid.hashe@amd.com                    if (!udpChecksum(rxPacket, false))
126710964Sdavid.hashe@amd.com                        rxDescCache.extsts |= EXTSTS_UDPERR;
126810964Sdavid.hashe@amd.com                }
12696657Snate@binkert.org            }
12706657Snate@binkert.org
12719104Shestness@cs.utexas.edu            /* the driver seems to always receive into desc buffers
12726657Snate@binkert.org               of size 1514, so you never have a pkt that is split
12736657Snate@binkert.org               into multiple descriptors on the receive side, so
12746657Snate@binkert.org               i don't implement that case, hence the assert above.
12756657Snate@binkert.org            */
12766657Snate@binkert.org
127710228Snilay@cs.wisc.edu            rxDmaAddr = (regs.rxdp + offsetof(ns_desc, cmdsts)) & 0x3fffffff;
127811111Snilay@cs.wisc.edu            rxDmaData = &(rxDescCache.cmdsts);
12796657Snate@binkert.org            rxDmaLen = sizeof(rxDescCache.cmdsts) + sizeof(rxDescCache.extsts);
12806657Snate@binkert.org            rxDmaFree = dmaDescFree;
12816657Snate@binkert.org
12826657Snate@binkert.org            if (doRxDmaWrite())
12839105SBrad.Beckmann@amd.com                goto exit;
12849105SBrad.Beckmann@amd.com        }
12859105SBrad.Beckmann@amd.com        break;
12869105SBrad.Beckmann@amd.com
12879105SBrad.Beckmann@amd.com      case rxFragWrite:
12889105SBrad.Beckmann@amd.com        if (rxDmaState != dmaIdle)
12899105SBrad.Beckmann@amd.com            goto exit;
12909105SBrad.Beckmann@amd.com
12916657Snate@binkert.org        rxPacketBufPtr += rxXferLen;
12926657Snate@binkert.org        rxFragPtr += rxXferLen;
12936657Snate@binkert.org        rxPktBytes -= rxXferLen;
12946657Snate@binkert.org
12956657Snate@binkert.org        rxState = rxFifoBlock;
12966657Snate@binkert.org        break;
12976657Snate@binkert.org
12989104Shestness@cs.utexas.edu      case rxDescWrite:
12999104Shestness@cs.utexas.edu        if (rxDmaState != dmaIdle)
13009104Shestness@cs.utexas.edu            goto exit;
13019104Shestness@cs.utexas.edu
13026657Snate@binkert.org        assert(rxDescCache.cmdsts & CMDSTS_OWN);
13036657Snate@binkert.org
13046657Snate@binkert.org        assert(rxPacket == 0);
13056657Snate@binkert.org        devIntrPost(ISR_RXOK);
13066657Snate@binkert.org
13076657Snate@binkert.org        if (rxDescCache.cmdsts & CMDSTS_INTR)
13086657Snate@binkert.org            devIntrPost(ISR_RXDESC);
13096657Snate@binkert.org
13106657Snate@binkert.org        if (rxHalt) {
13116657Snate@binkert.org            rxState = rxIdle;
13127839Snilay@cs.wisc.edu            rxHalt = false;
13137839Snilay@cs.wisc.edu        } else
13147839Snilay@cs.wisc.edu            rxState = rxAdvance;
13157839Snilay@cs.wisc.edu        break;
13167839Snilay@cs.wisc.edu
13177839Snilay@cs.wisc.edu      case rxAdvance:
13187839Snilay@cs.wisc.edu        if (rxDescCache.link == 0) {
13197839Snilay@cs.wisc.edu            rxState = rxIdle;
13207839Snilay@cs.wisc.edu            return;
13217839Snilay@cs.wisc.edu        } else {
13227839Snilay@cs.wisc.edu            rxState = rxDescRead;
13237839Snilay@cs.wisc.edu            regs.rxdp = rxDescCache.link;
13246657Snate@binkert.org            CRDD = false;
13256657Snate@binkert.org
13266657Snate@binkert.org            rxDmaAddr = regs.rxdp & 0x3fffffff;
13276657Snate@binkert.org            rxDmaData = &rxDescCache;
13286657Snate@binkert.org            rxDmaLen = sizeof(ns_desc);
13296657Snate@binkert.org            rxDmaFree = dmaDescFree;
13306657Snate@binkert.org
13316657Snate@binkert.org            if (doRxDmaRead())
13326657Snate@binkert.org                goto exit;
13336657Snate@binkert.org        }
13346657Snate@binkert.org        break;
13356657Snate@binkert.org
13366657Snate@binkert.org      default:
13376657Snate@binkert.org        panic("Invalid rxState!");
13386657Snate@binkert.org    }
13396657Snate@binkert.org
13406657Snate@binkert.org
134110305Snilay@cs.wisc.edu    DPRINTF(Ethernet, "entering next rx state = %s\n",
13426657Snate@binkert.org            NsRxStateStrings[rxState]);
13436657Snate@binkert.org
13446657Snate@binkert.org    if (rxState == rxIdle) {
134510962SBrad.Beckmann@amd.com        regs.command &= ~CR_RXE;
13468159SBrad.Beckmann@amd.com        devIntrPost(ISR_RXIDLE);
13479465Snilay@cs.wisc.edu        return;
13486657Snate@binkert.org    }
134910305Snilay@cs.wisc.edu
13506657Snate@binkert.org    goto next;
13516657Snate@binkert.org
13526657Snate@binkert.org  exit:
13536657Snate@binkert.org    /**
13546657Snate@binkert.org     * @todo do we want to schedule a future kick?
13556657Snate@binkert.org     */
13566657Snate@binkert.org    DPRINTF(Ethernet, "rx state machine exited state=%s\n",
13576657Snate@binkert.org            NsRxStateStrings[rxState]);
13586657Snate@binkert.org}
13597007Snate@binkert.org
13606999Snate@binkert.orgvoid
13617007Snate@binkert.orgEtherDev::transmit()
13627007Snate@binkert.org{
13637007Snate@binkert.org    if (txFifo.empty()) {
13647007Snate@binkert.org        DPRINTF(Ethernet, "nothing to transmit\n");
13657007Snate@binkert.org        return;
13667007Snate@binkert.org    }
13676657Snate@binkert.org
13686657Snate@binkert.org   if (interface->sendPacket(txFifo.front())) {
13696657Snate@binkert.org        DPRINTF(Ethernet, "transmit packet\n");
13706657Snate@binkert.org        DDUMP(Ethernet, txFifo.front()->data, txFifo.front()->length);
13716657Snate@binkert.org        txBytes += txFifo.front()->length;
13726657Snate@binkert.org        txPackets++;
13736657Snate@binkert.org
13746657Snate@binkert.org        txFifoCnt -= (txFifo.front()->length - txPktXmitted);
13756657Snate@binkert.org        txPktXmitted = 0;
13766657Snate@binkert.org        txFifo.front() = NULL;
13776657Snate@binkert.org        txFifo.pop_front();
13786657Snate@binkert.org
13796657Snate@binkert.org        /* normally do a writeback of the descriptor here, and ONLY after that is
13806657Snate@binkert.org           done, send this interrupt.  but since our stuff never actually fails,
13816657Snate@binkert.org           just do this interrupt here, otherwise the code has to stray from this
13826657Snate@binkert.org           nice format.  besides, it's functionally the same.
13836657Snate@binkert.org        */
13846657Snate@binkert.org        devIntrPost(ISR_TXOK);
13856657Snate@binkert.org   }
13866657Snate@binkert.org
13876657Snate@binkert.org   if (!txFifo.empty() && !txEvent.scheduled()) {
13886657Snate@binkert.org       DPRINTF(Ethernet, "reschedule transmit\n");
13896657Snate@binkert.org       txEvent.schedule(curTick + 1000);
13906657Snate@binkert.org   }
13916657Snate@binkert.org}
13926657Snate@binkert.org
13936657Snate@binkert.orgvoid
13946657Snate@binkert.orgEtherDev::txDmaReadCopy()
13956657Snate@binkert.org{
13966999Snate@binkert.org    assert(txDmaState == dmaReading);
13976657Snate@binkert.org
13986657Snate@binkert.org    memcpy(txDmaData, physmem->dma_addr(txDmaAddr, txDmaLen), txDmaLen);
13997007Snate@binkert.org    txDmaState = dmaIdle;
14007007Snate@binkert.org
14016657Snate@binkert.org    DPRINTF(EthernetDMA, "tx dma read  paddr=%#x len=%d\n",
14026657Snate@binkert.org            txDmaAddr, txDmaLen);
14036657Snate@binkert.org    DDUMP(EthernetDMA, txDmaData, txDmaLen);
14046657Snate@binkert.org}
14056657Snate@binkert.org
14066657Snate@binkert.orgbool
14076657Snate@binkert.orgEtherDev::doTxDmaRead()
14086657Snate@binkert.org{
14096657Snate@binkert.org    assert(txDmaState == dmaIdle || txDmaState == dmaReadWaiting);
14106657Snate@binkert.org    txDmaState = dmaReading;
14116657Snate@binkert.org
14126657Snate@binkert.org    if (dmaInterface && !txDmaFree) {
14136657Snate@binkert.org        if (dmaInterface->busy())
14146657Snate@binkert.org            txDmaState = dmaReadWaiting;
14156657Snate@binkert.org        else
14166657Snate@binkert.org            dmaInterface->doDMA(Read, txDmaAddr, txDmaLen, curTick,
14176657Snate@binkert.org                                &txDmaReadEvent);
14186657Snate@binkert.org        return true;
14196657Snate@binkert.org    }
14206657Snate@binkert.org
14216657Snate@binkert.org    if (dmaReadDelay == 0 && dmaReadFactor == 0.0) {
14226657Snate@binkert.org        txDmaReadCopy();
14236657Snate@binkert.org        return false;
14246657Snate@binkert.org    }
14256657Snate@binkert.org
14266657Snate@binkert.org    Tick factor = ((txDmaLen + ULL(63)) >> ULL(6)) * dmaReadFactor;
14276657Snate@binkert.org    Tick start = curTick + dmaReadDelay + factor;
14286657Snate@binkert.org    txDmaReadEvent.schedule(start);
14296657Snate@binkert.org    return true;
14306657Snate@binkert.org}
14316657Snate@binkert.org
14326657Snate@binkert.orgvoid
14336657Snate@binkert.orgEtherDev::txDmaReadDone()
14346657Snate@binkert.org{
14356657Snate@binkert.org    assert(txDmaState == dmaReading);
14366657Snate@binkert.org    txDmaReadCopy();
14376657Snate@binkert.org
14386657Snate@binkert.org    // If the receive state machine  has a pending DMA, let it go first
14396657Snate@binkert.org    if (rxDmaState == dmaReadWaiting || rxDmaState == dmaWriteWaiting)
14406657Snate@binkert.org        rxKick();
14416657Snate@binkert.org
14426657Snate@binkert.org    txKick();
14436657Snate@binkert.org}
14446657Snate@binkert.org
14456657Snate@binkert.orgvoid
14466657Snate@binkert.orgEtherDev::txDmaWriteCopy()
14476657Snate@binkert.org{
14486657Snate@binkert.org    assert(txDmaState == dmaWriting);
14496657Snate@binkert.org
14506657Snate@binkert.org    memcpy(physmem->dma_addr(txDmaAddr, txDmaLen), txDmaData, txDmaLen);
14516657Snate@binkert.org    txDmaState = dmaIdle;
14526657Snate@binkert.org
14536657Snate@binkert.org    DPRINTF(EthernetDMA, "tx dma write paddr=%#x len=%d\n",
14546657Snate@binkert.org            txDmaAddr, txDmaLen);
14556657Snate@binkert.org    DDUMP(EthernetDMA, txDmaData, txDmaLen);
14566657Snate@binkert.org}
14576657Snate@binkert.org
14586657Snate@binkert.orgbool
14596657Snate@binkert.orgEtherDev::doTxDmaWrite()
14606657Snate@binkert.org{
14616657Snate@binkert.org    assert(txDmaState == dmaIdle || txDmaState == dmaWriteWaiting);
14626657Snate@binkert.org    txDmaState = dmaWriting;
14636657Snate@binkert.org
14646657Snate@binkert.org    if (dmaInterface && !txDmaFree) {
14656657Snate@binkert.org        if (dmaInterface->busy())
14666657Snate@binkert.org            txDmaState = dmaWriteWaiting;
14676657Snate@binkert.org        else
14686657Snate@binkert.org            dmaInterface->doDMA(WriteInvalidate, txDmaAddr, txDmaLen, curTick,
14696657Snate@binkert.org                                &txDmaWriteEvent);
14706657Snate@binkert.org        return true;
14716657Snate@binkert.org    }
14726657Snate@binkert.org
14736657Snate@binkert.org    if (dmaWriteDelay == 0 && dmaWriteFactor == 0.0) {
14746657Snate@binkert.org        txDmaWriteCopy();
14756657Snate@binkert.org        return false;
14766657Snate@binkert.org    }
14776657Snate@binkert.org
14786657Snate@binkert.org    Tick factor = ((txDmaLen + ULL(63)) >> ULL(6)) * dmaWriteFactor;
14796657Snate@binkert.org    Tick start = curTick + dmaWriteDelay + factor;
14806657Snate@binkert.org    txDmaWriteEvent.schedule(start);
14816657Snate@binkert.org    return true;
14826657Snate@binkert.org}
14836657Snate@binkert.org
14846657Snate@binkert.orgvoid
14856657Snate@binkert.orgEtherDev::txDmaWriteDone()
14866657Snate@binkert.org{
14876657Snate@binkert.org    assert(txDmaState == dmaWriting);
14886657Snate@binkert.org    txDmaWriteCopy();
14897007Snate@binkert.org
14906657Snate@binkert.org    // If the receive state machine  has a pending DMA, let it go first
14916657Snate@binkert.org    if (rxDmaState == dmaReadWaiting || rxDmaState == dmaWriteWaiting)
14926657Snate@binkert.org        rxKick();
14936657Snate@binkert.org
14946657Snate@binkert.org    txKick();
14956657Snate@binkert.org}
14966657Snate@binkert.org
14977007Snate@binkert.orgvoid
14986657Snate@binkert.orgEtherDev::txKick()
14996657Snate@binkert.org{
15006657Snate@binkert.org    DPRINTF(Ethernet, "transmit kick state=%s\n", NsTxStateStrings[txState]);
15016657Snate@binkert.org
15026657Snate@binkert.org    if (rxKickTick > curTick) {
15036657Snate@binkert.org        DPRINTF(Ethernet, "receive kick exiting, can't run till %d\n",
15046657Snate@binkert.org                rxKickTick);
15056657Snate@binkert.org
15066657Snate@binkert.org        return;
15076657Snate@binkert.org    }
15086657Snate@binkert.org
15096657Snate@binkert.org  next:
15106657Snate@binkert.org    switch(txDmaState) {
15116657Snate@binkert.org      case dmaReadWaiting:
15126657Snate@binkert.org        if (doTxDmaRead())
151310917Sbrandon.potter@amd.com            goto exit;
15146657Snate@binkert.org        break;
15156657Snate@binkert.org      case dmaWriteWaiting:
15166657Snate@binkert.org        if (doTxDmaWrite())
15176657Snate@binkert.org            goto exit;
15186657Snate@binkert.org        break;
15196657Snate@binkert.org      default:
15206657Snate@binkert.org        break;
15216657Snate@binkert.org    }
15226657Snate@binkert.org
15236657Snate@binkert.org    switch (txState) {
15246657Snate@binkert.org      case txIdle:
15256657Snate@binkert.org        if (!regs.command & CR_TXE) {
15266657Snate@binkert.org            DPRINTF(Ethernet, "Transmit disabled.  Nothing to do.\n");
15276657Snate@binkert.org            goto exit;
15286657Snate@binkert.org        }
15296657Snate@binkert.org
15306657Snate@binkert.org        if (CTDD) {
15316657Snate@binkert.org            txState = txDescRefr;
15326657Snate@binkert.org
15336657Snate@binkert.org            txDmaAddr = txDescCache.link & 0x3fffffff;
15346657Snate@binkert.org            txDmaData = &txDescCache;
15356657Snate@binkert.org            txDmaLen = sizeof(txDescCache.link);
1536            txDmaFree = dmaDescFree;
1537
1538            if (doTxDmaRead())
1539                goto exit;
1540
1541        } else {
1542            txState = txDescRead;
1543
1544            txDmaAddr = regs.txdp & 0x3fffffff;
1545            txDmaData = &txDescCache + offsetof(ns_desc, link);
1546            txDmaLen = sizeof(ns_desc);
1547            txDmaFree = dmaDescFree;
1548
1549            if (doTxDmaRead())
1550                goto exit;
1551        }
1552        break;
1553
1554      case txDescRefr:
1555        if (txDmaState != dmaIdle)
1556            goto exit;
1557
1558        txState = txAdvance;
1559        break;
1560
1561      case txDescRead:
1562        if (txDmaState != dmaIdle)
1563            goto exit;
1564
1565        if (txDescCache.cmdsts & CMDSTS_OWN) {
1566            txState = txFifoBlock;
1567            txFragPtr = txDescCache.bufptr;
1568            txDescCnt = txDescCache.cmdsts & CMDSTS_LEN_MASK;
1569        } else {
1570            txState = txIdle;
1571        }
1572        break;
1573
1574      case txFifoBlock:
1575        if (!txPacket) {
1576            DPRINTF(Ethernet, "starting the tx of a new packet\n");
1577            txPacket = new EtherPacket;
1578            txPacket->data = new uint8_t[16384];
1579            txPacketBufPtr = txPacket->data;
1580        }
1581
1582        if (txDescCnt == 0) {
1583            DPRINTF(Ethernet, "the txDescCnt == 0, done with descriptor\n");
1584            if (txDescCache.cmdsts & CMDSTS_MORE) {
1585                DPRINTF(Ethernet, "there are more descriptors to come\n");
1586                txState = txDescWrite;
1587
1588                txDescCache.cmdsts &= ~CMDSTS_OWN;
1589
1590                txDmaAddr = (regs.txdp + offsetof(ns_desc, cmdsts)) & 0x3fffffff;
1591                txDmaData = &(txDescCache.cmdsts);
1592                txDmaLen = sizeof(txDescCache.cmdsts);
1593                txDmaFree = dmaDescFree;
1594
1595                if (doTxDmaWrite())
1596                    goto exit;
1597
1598            } else { /* this packet is totally done */
1599                DPRINTF(Ethernet, "This packet is done, let's wrap it up\n");
1600                /* deal with the the packet that just finished */
1601                if ((regs.vtcr & VTCR_PPCHK) && extstsEnable) {
1602                    if (txDescCache.extsts & EXTSTS_UDPPKT) {
1603                        udpChecksum(txPacket, true);
1604                    } else if (txDescCache.extsts & EXTSTS_TCPPKT) {
1605                        tcpChecksum(txPacket, true);
1606                    } else if (txDescCache.extsts & EXTSTS_IPPKT) {
1607                        ipChecksum(txPacket, true);
1608                    }
1609                }
1610
1611                txPacket->length = txPacketBufPtr - txPacket->data;
1612                /* this is just because the receive can't handle a packet bigger
1613                   want to make sure */
1614                assert(txPacket->length <= 1514);
1615                txFifo.push_back(txPacket);
1616
1617
1618                /* this following section is not to spec, but functionally shouldn't
1619                   be any different.  normally, the chip will wait til the transmit has
1620                   occurred before writing back the descriptor because it has to wait
1621                   to see that it was successfully transmitted to decide whether to set
1622                   CMDSTS_OK or not.  however, in the simulator since it is always
1623                   successfully transmitted, and writing it exactly to spec would
1624                   complicate the code, we just do it here
1625                */
1626                txDescCache.cmdsts &= ~CMDSTS_OWN;
1627                txDescCache.cmdsts |= CMDSTS_OK;
1628
1629                txDmaAddr = regs.txdp & 0x3fffffff;
1630                txDmaData = &txDescCache + offsetof(ns_desc, cmdsts);
1631                txDmaLen = sizeof(txDescCache.cmdsts) + sizeof(txDescCache.extsts);
1632                txDmaFree = dmaDescFree;
1633
1634
1635                if (doTxDmaWrite())
1636                    goto exit;
1637
1638                txPacket = 0;
1639                transmit();
1640
1641                if (txHalt) {
1642                    txState = txIdle;
1643                    txHalt = false;
1644                } else
1645                    txState = txAdvance;
1646            }
1647        } else {
1648            DPRINTF(Ethernet, "this descriptor isn't done yet\n");
1649            /* the fill thresh is in units of 32 bytes, shift right by 8 to get the
1650               value, shift left by 5 to get the real number of bytes */
1651            if (txFifoAvail < ((regs.txcfg & TXCFG_FLTH_MASK) >> 3)) {
1652                DPRINTF(Ethernet, "txFifoAvail=%d, regs.txcfg & TXCFG_FLTH_MASK = %#x\n",
1653                        txFifoAvail, regs.txcfg & TXCFG_FLTH_MASK);
1654                goto exit;
1655            }
1656
1657            txState = txFragRead;
1658
1659            /* The number of bytes transferred is either whatever is left
1660               in the descriptor (txDescCnt), or if there is not enough
1661               room in the fifo, just whatever room is left in the fifo
1662            */
1663            txXferLen = min<uint32_t>(txDescCnt, txFifoAvail);
1664
1665            txDmaAddr = txFragPtr & 0x3fffffff;
1666            txDmaData = txPacketBufPtr;
1667            txDmaLen = txXferLen;
1668            txDmaFree = dmaDataFree;
1669
1670            if (doTxDmaRead())
1671                goto exit;
1672        }
1673        break;
1674
1675      case txFragRead:
1676        if (txDmaState != dmaIdle)
1677            goto exit;
1678
1679        txPacketBufPtr += txXferLen;
1680        txFragPtr += txXferLen;
1681        txFifoCnt += txXferLen;
1682        txDescCnt -= txXferLen;
1683
1684        txState = txFifoBlock;
1685        break;
1686
1687      case txDescWrite:
1688        if (txDmaState != dmaIdle)
1689            goto exit;
1690
1691        if (txFifoCnt >= ((regs.txcfg & TXCFG_DRTH_MASK) << 5)) {
1692            if (txFifo.empty()) {
1693                uint32_t xmitted = (uint32_t) (txPacketBufPtr - txPacket->data - txPktXmitted);
1694                txFifoCnt -= xmitted;
1695                txPktXmitted += xmitted;
1696            } else {
1697                transmit();
1698            }
1699        }
1700
1701        if (txDescCache.cmdsts & CMDSTS_INTR) {
1702            devIntrPost(ISR_TXDESC);
1703        }
1704
1705        txState = txAdvance;
1706        break;
1707
1708      case txAdvance:
1709        if (txDescCache.link == 0) {
1710            txState = txIdle;
1711        } else {
1712            txState = txDescRead;
1713            regs.txdp = txDescCache.link;
1714            CTDD = false;
1715
1716            txDmaAddr = txDescCache.link & 0x3fffffff;
1717            txDmaData = &txDescCache;
1718            txDmaLen = sizeof(ns_desc);
1719            txDmaFree = dmaDescFree;
1720
1721            if (doTxDmaRead())
1722                goto exit;
1723        }
1724        break;
1725
1726      default:
1727        panic("invalid state");
1728    }
1729
1730    DPRINTF(Ethernet, "entering next tx state=%s\n",
1731            NsTxStateStrings[txState]);
1732
1733    if (txState == txIdle) {
1734        regs.command &= ~CR_TXE;
1735        devIntrPost(ISR_TXIDLE);
1736        return;
1737    }
1738
1739    goto next;
1740
1741  exit:
1742    /**
1743     * @todo do we want to schedule a future kick?
1744     */
1745    DPRINTF(Ethernet, "tx state machine exited state=%s\n",
1746            NsTxStateStrings[txState]);
1747}
1748
1749void
1750EtherDev::transferDone()
1751{
1752    if (txFifo.empty())
1753        return;
1754
1755    DPRINTF(Ethernet, "schedule transmit\n");
1756
1757    if (txEvent.scheduled())
1758        txEvent.reschedule(curTick + 1);
1759    else
1760        txEvent.schedule(curTick + 1);
1761}
1762
1763bool
1764EtherDev::rxFilter(PacketPtr packet)
1765{
1766    bool drop = true;
1767    string type;
1768
1769    if (packet->IsUnicast()) {
1770        type = "unicast";
1771
1772        // If we're accepting all unicast addresses
1773        if (acceptUnicast)
1774            drop = false;
1775
1776        // If we make a perfect match
1777        if ((acceptPerfect)
1778            && (memcmp(rom.perfectMatch, packet->data, sizeof(rom.perfectMatch)) == 0))
1779            drop = false;
1780
1781        eth_header *eth = (eth_header *) packet->data;
1782        if ((acceptArp) && (eth->type == 0x806))
1783            drop = false;
1784
1785    } else if (packet->IsBroadcast()) {
1786        type = "broadcast";
1787
1788        // if we're accepting broadcasts
1789        if (acceptBroadcast)
1790            drop = false;
1791
1792    } else if (packet->IsMulticast()) {
1793        type = "multicast";
1794
1795        // if we're accepting all multicasts
1796        if (acceptMulticast)
1797            drop = false;
1798
1799    } else {
1800        type = "unknown";
1801
1802        // oh well, punt on this one
1803    }
1804
1805    if (drop) {
1806        DPRINTF(Ethernet, "rxFilter drop\n");
1807        DDUMP(EthernetData, packet->data, packet->length);
1808    }
1809
1810    return drop;
1811}
1812
1813bool
1814EtherDev::recvPacket(PacketPtr packet)
1815{
1816    rxBytes += packet->length;
1817    rxPackets++;
1818
1819    if (rxState == rxIdle) {
1820        DPRINTF(Ethernet, "receive disabled...packet dropped\n");
1821        interface->recvDone();
1822        return true;
1823    }
1824
1825    if (rxFilterEnable && rxFilter(packet)) {
1826        DPRINTF(Ethernet, "packet filtered...dropped\n");
1827        interface->recvDone();
1828        return true;
1829    }
1830
1831    if (rxFifoCnt + packet->length >= MAX_RX_FIFO_SIZE) {
1832        DPRINTF(Ethernet,
1833                "packet will not fit in receive buffer...packet dropped\n");
1834        devIntrPost(ISR_RXORN);
1835        return false;
1836    }
1837
1838    rxFifo.push_back(packet);
1839    rxFifoCnt += packet->length;
1840    interface->recvDone();
1841
1842    rxKick();
1843    return true;
1844}
1845
1846bool
1847EtherDev::udpChecksum(PacketPtr packet, bool gen)
1848{
1849    udp_header *hdr = (udp_header *)  packet->getTransportHdr();
1850
1851    ip_header *ip = packet->getIpHdr();
1852
1853    pseudo_header *pseudo = new pseudo_header;
1854
1855    pseudo->src_ip_addr = ip->src_ip_addr;
1856    pseudo->dest_ip_addr = ip->dest_ip_addr;
1857    pseudo->protocol = ip->protocol;
1858    pseudo->len = hdr->len;
1859
1860    uint16_t cksum = checksumCalc((uint16_t *) pseudo, (uint16_t *) hdr,
1861                                  (uint32_t) hdr->len);
1862
1863    delete pseudo;
1864    if (gen)
1865        hdr->chksum = cksum;
1866    else
1867        if (cksum != 0)
1868            return false;
1869
1870    return true;
1871}
1872
1873bool
1874EtherDev::tcpChecksum(PacketPtr packet, bool gen)
1875{
1876    tcp_header *hdr = (tcp_header *) packet->getTransportHdr();
1877
1878    ip_header *ip = packet->getIpHdr();
1879
1880    pseudo_header *pseudo = new pseudo_header;
1881
1882    pseudo->src_ip_addr = ip->src_ip_addr;
1883    pseudo->dest_ip_addr = ip->dest_ip_addr;
1884    pseudo->protocol = ip->protocol;
1885    pseudo->len = ip->dgram_len - (ip->vers_len & 0xf);
1886
1887    uint16_t cksum = checksumCalc((uint16_t *) pseudo, (uint16_t *) hdr,
1888                                  (uint32_t) pseudo->len);
1889
1890    delete pseudo;
1891    if (gen)
1892        hdr->chksum = cksum;
1893    else
1894        if (cksum != 0)
1895            return false;
1896
1897    return true;
1898}
1899
1900bool
1901EtherDev::ipChecksum(PacketPtr packet, bool gen)
1902{
1903    ip_header *hdr = packet->getIpHdr();
1904
1905    uint16_t cksum = checksumCalc(NULL, (uint16_t *) hdr, (hdr->vers_len & 0xf));
1906
1907    if (gen)
1908        hdr->hdr_chksum = cksum;
1909    else
1910        if (cksum != 0)
1911            return false;
1912
1913    return true;
1914}
1915
1916uint16_t
1917EtherDev::checksumCalc(uint16_t *pseudo, uint16_t *buf, uint32_t len)
1918{
1919    uint32_t sum = 0;
1920
1921    uint16_t last_pad = 0;
1922    if (len & 1) {
1923        last_pad = buf[len/2] & 0xff;
1924        len--;
1925        sum += last_pad;
1926    }
1927
1928    if (pseudo) {
1929        sum = pseudo[0] + pseudo[1] + pseudo[2] +
1930            pseudo[3] + pseudo[4] + pseudo[5];
1931    }
1932
1933    for (int i=0; i < (len/2); ++i) {
1934        sum += buf[i];
1935    }
1936
1937    while (sum >> 16)
1938        sum = (sum >> 16) + (sum & 0xffff);
1939
1940    return ~sum;
1941}
1942
1943//=====================================================================
1944//
1945//
1946void
1947EtherDev::serialize(ostream &os)
1948{
1949    /*
1950     * Finalize any DMA events now.
1951     */
1952    if (rxDmaReadEvent.scheduled())
1953        rxDmaReadCopy();
1954    if (rxDmaWriteEvent.scheduled())
1955        rxDmaWriteCopy();
1956    if (txDmaReadEvent.scheduled())
1957        txDmaReadCopy();
1958    if (txDmaWriteEvent.scheduled())
1959        txDmaWriteCopy();
1960
1961    /*
1962     * Serialize the device registers
1963     */
1964    SERIALIZE_SCALAR(regs.command);
1965    SERIALIZE_SCALAR(regs.config);
1966    SERIALIZE_SCALAR(regs.mear);
1967    SERIALIZE_SCALAR(regs.ptscr);
1968    SERIALIZE_SCALAR(regs.isr);
1969    SERIALIZE_SCALAR(regs.imr);
1970    SERIALIZE_SCALAR(regs.ier);
1971    SERIALIZE_SCALAR(regs.ihr);
1972    SERIALIZE_SCALAR(regs.txdp);
1973    SERIALIZE_SCALAR(regs.txdp_hi);
1974    SERIALIZE_SCALAR(regs.txcfg);
1975    SERIALIZE_SCALAR(regs.gpior);
1976    SERIALIZE_SCALAR(regs.rxdp);
1977    SERIALIZE_SCALAR(regs.rxdp_hi);
1978    SERIALIZE_SCALAR(regs.rxcfg);
1979    SERIALIZE_SCALAR(regs.pqcr);
1980    SERIALIZE_SCALAR(regs.wcsr);
1981    SERIALIZE_SCALAR(regs.pcr);
1982    SERIALIZE_SCALAR(regs.rfcr);
1983    SERIALIZE_SCALAR(regs.rfdr);
1984    SERIALIZE_SCALAR(regs.srr);
1985    SERIALIZE_SCALAR(regs.mibc);
1986    SERIALIZE_SCALAR(regs.vrcr);
1987    SERIALIZE_SCALAR(regs.vtcr);
1988    SERIALIZE_SCALAR(regs.vdr);
1989    SERIALIZE_SCALAR(regs.ccsr);
1990    SERIALIZE_SCALAR(regs.tbicr);
1991    SERIALIZE_SCALAR(regs.tbisr);
1992    SERIALIZE_SCALAR(regs.tanar);
1993    SERIALIZE_SCALAR(regs.tanlpar);
1994    SERIALIZE_SCALAR(regs.taner);
1995    SERIALIZE_SCALAR(regs.tesr);
1996
1997    SERIALIZE_ARRAY(rom.perfectMatch, EADDR_LEN);
1998
1999    /*
2000     * Serialize the various helper variables
2001     */
2002    uint32_t txPktBufPtr = (uint32_t) txPacketBufPtr;
2003    SERIALIZE_SCALAR(txPktBufPtr);
2004    uint32_t rxPktBufPtr = (uint32_t) rxPktBufPtr;
2005    SERIALIZE_SCALAR(rxPktBufPtr);
2006    SERIALIZE_SCALAR(txXferLen);
2007    SERIALIZE_SCALAR(rxXferLen);
2008    SERIALIZE_SCALAR(txPktXmitted);
2009
2010    bool txPacketExists = txPacket;
2011    SERIALIZE_SCALAR(txPacketExists);
2012    bool rxPacketExists = rxPacket;
2013    SERIALIZE_SCALAR(rxPacketExists);
2014
2015    /*
2016     * Serialize DescCaches
2017     */
2018    SERIALIZE_SCALAR(txDescCache.link);
2019    SERIALIZE_SCALAR(txDescCache.bufptr);
2020    SERIALIZE_SCALAR(txDescCache.cmdsts);
2021    SERIALIZE_SCALAR(txDescCache.extsts);
2022    SERIALIZE_SCALAR(rxDescCache.link);
2023    SERIALIZE_SCALAR(rxDescCache.bufptr);
2024    SERIALIZE_SCALAR(rxDescCache.cmdsts);
2025    SERIALIZE_SCALAR(rxDescCache.extsts);
2026
2027    /*
2028     * Serialize tx state machine
2029     */
2030    int txNumPkts = txFifo.size();
2031    SERIALIZE_SCALAR(txNumPkts);
2032    int txState = this->txState;
2033    SERIALIZE_SCALAR(txState);
2034    SERIALIZE_SCALAR(CTDD);
2035    SERIALIZE_SCALAR(txFifoCnt);
2036    SERIALIZE_SCALAR(txFifoAvail);
2037    SERIALIZE_SCALAR(txHalt);
2038    SERIALIZE_SCALAR(txFragPtr);
2039    SERIALIZE_SCALAR(txDescCnt);
2040    int txDmaState = this->txDmaState;
2041    SERIALIZE_SCALAR(txDmaState);
2042
2043    /*
2044     * Serialize rx state machine
2045     */
2046    int rxNumPkts = rxFifo.size();
2047    SERIALIZE_SCALAR(rxNumPkts);
2048    int rxState = this->rxState;
2049    SERIALIZE_SCALAR(rxState);
2050    SERIALIZE_SCALAR(CRDD);
2051    SERIALIZE_SCALAR(rxPktBytes);
2052    SERIALIZE_SCALAR(rxFifoCnt);
2053    SERIALIZE_SCALAR(rxHalt);
2054    SERIALIZE_SCALAR(rxDescCnt);
2055    int rxDmaState = this->rxDmaState;
2056    SERIALIZE_SCALAR(rxDmaState);
2057
2058    SERIALIZE_SCALAR(extstsEnable);
2059
2060   /*
2061     * If there's a pending transmit, store the time so we can
2062     * reschedule it later
2063     */
2064    Tick transmitTick = txEvent.scheduled() ? txEvent.when() - curTick : 0;
2065    SERIALIZE_SCALAR(transmitTick);
2066
2067    /*
2068     * Keep track of pending interrupt status.
2069     */
2070    SERIALIZE_SCALAR(intrTick);
2071    SERIALIZE_SCALAR(cpuPendingIntr);
2072    Tick intrEventTick = 0;
2073    if (intrEvent)
2074        intrEventTick = intrEvent->when();
2075    SERIALIZE_SCALAR(intrEventTick);
2076
2077    int i = 0;
2078    for (pktiter_t p = rxFifo.begin(); p != rxFifo.end(); ++p) {
2079        nameOut(os, csprintf("%s.rxFifo%d", name(), i++));
2080        (*p)->serialize(os);
2081    }
2082    if (rxPacketExists) {
2083        nameOut(os, csprintf("%s.rxPacket", name()));
2084        rxPacket->serialize(os);
2085    }
2086    i = 0;
2087    for (pktiter_t p = txFifo.begin(); p != txFifo.end(); ++p) {
2088        nameOut(os, csprintf("%s.txFifo%d", name(), i++));
2089        (*p)->serialize(os);
2090    }
2091    if (txPacketExists) {
2092        nameOut(os, csprintf("%s.txPacket", name()));
2093        txPacket->serialize(os);
2094    }
2095}
2096
2097void
2098EtherDev::unserialize(Checkpoint *cp, const std::string &section)
2099{
2100    UNSERIALIZE_SCALAR(regs.command);
2101    UNSERIALIZE_SCALAR(regs.config);
2102    UNSERIALIZE_SCALAR(regs.mear);
2103    UNSERIALIZE_SCALAR(regs.ptscr);
2104    UNSERIALIZE_SCALAR(regs.isr);
2105    UNSERIALIZE_SCALAR(regs.imr);
2106    UNSERIALIZE_SCALAR(regs.ier);
2107    UNSERIALIZE_SCALAR(regs.ihr);
2108    UNSERIALIZE_SCALAR(regs.txdp);
2109    UNSERIALIZE_SCALAR(regs.txdp_hi);
2110    UNSERIALIZE_SCALAR(regs.txcfg);
2111    UNSERIALIZE_SCALAR(regs.gpior);
2112    UNSERIALIZE_SCALAR(regs.rxdp);
2113    UNSERIALIZE_SCALAR(regs.rxdp_hi);
2114    UNSERIALIZE_SCALAR(regs.rxcfg);
2115    UNSERIALIZE_SCALAR(regs.pqcr);
2116    UNSERIALIZE_SCALAR(regs.wcsr);
2117    UNSERIALIZE_SCALAR(regs.pcr);
2118    UNSERIALIZE_SCALAR(regs.rfcr);
2119    UNSERIALIZE_SCALAR(regs.rfdr);
2120    UNSERIALIZE_SCALAR(regs.srr);
2121    UNSERIALIZE_SCALAR(regs.mibc);
2122    UNSERIALIZE_SCALAR(regs.vrcr);
2123    UNSERIALIZE_SCALAR(regs.vtcr);
2124    UNSERIALIZE_SCALAR(regs.vdr);
2125    UNSERIALIZE_SCALAR(regs.ccsr);
2126    UNSERIALIZE_SCALAR(regs.tbicr);
2127    UNSERIALIZE_SCALAR(regs.tbisr);
2128    UNSERIALIZE_SCALAR(regs.tanar);
2129    UNSERIALIZE_SCALAR(regs.tanlpar);
2130    UNSERIALIZE_SCALAR(regs.taner);
2131    UNSERIALIZE_SCALAR(regs.tesr);
2132
2133    UNSERIALIZE_ARRAY(rom.perfectMatch, EADDR_LEN);
2134
2135    /*
2136     * unserialize the various helper variables
2137     */
2138    uint32_t txPktBufPtr;
2139    UNSERIALIZE_SCALAR(txPktBufPtr);
2140    txPacketBufPtr = (uint8_t *) txPktBufPtr;
2141    uint32_t rxPktBufPtr;
2142    UNSERIALIZE_SCALAR(rxPktBufPtr);
2143    rxPacketBufPtr = (uint8_t *) rxPktBufPtr;
2144    UNSERIALIZE_SCALAR(txXferLen);
2145    UNSERIALIZE_SCALAR(rxXferLen);
2146    UNSERIALIZE_SCALAR(txPktXmitted);
2147
2148    bool txPacketExists;
2149    UNSERIALIZE_SCALAR(txPacketExists);
2150    bool rxPacketExists;
2151    UNSERIALIZE_SCALAR(rxPacketExists);
2152
2153    /*
2154     * Unserialize DescCaches
2155     */
2156    UNSERIALIZE_SCALAR(txDescCache.link);
2157    UNSERIALIZE_SCALAR(txDescCache.bufptr);
2158    UNSERIALIZE_SCALAR(txDescCache.cmdsts);
2159    UNSERIALIZE_SCALAR(txDescCache.extsts);
2160    UNSERIALIZE_SCALAR(rxDescCache.link);
2161    UNSERIALIZE_SCALAR(rxDescCache.bufptr);
2162    UNSERIALIZE_SCALAR(rxDescCache.cmdsts);
2163    UNSERIALIZE_SCALAR(rxDescCache.extsts);
2164
2165    /*
2166     * unserialize tx state machine
2167     */
2168    int txNumPkts;
2169    UNSERIALIZE_SCALAR(txNumPkts);
2170    int txState;
2171    UNSERIALIZE_SCALAR(txState);
2172    this->txState = (TxState) txState;
2173    UNSERIALIZE_SCALAR(CTDD);
2174    UNSERIALIZE_SCALAR(txFifoCnt);
2175    UNSERIALIZE_SCALAR(txFifoAvail);
2176    UNSERIALIZE_SCALAR(txHalt);
2177    UNSERIALIZE_SCALAR(txFragPtr);
2178    UNSERIALIZE_SCALAR(txDescCnt);
2179    int txDmaState;
2180    UNSERIALIZE_SCALAR(txDmaState);
2181    this->txDmaState = (DmaState) txDmaState;
2182
2183    /*
2184     * unserialize rx state machine
2185     */
2186    int rxNumPkts;
2187    UNSERIALIZE_SCALAR(rxNumPkts);
2188    int rxState;
2189    UNSERIALIZE_SCALAR(rxState);
2190    this->rxState = (RxState) rxState;
2191    UNSERIALIZE_SCALAR(CRDD);
2192    UNSERIALIZE_SCALAR(rxPktBytes);
2193    UNSERIALIZE_SCALAR(rxFifoCnt);
2194    UNSERIALIZE_SCALAR(rxHalt);
2195    UNSERIALIZE_SCALAR(rxDescCnt);
2196    int rxDmaState;
2197    UNSERIALIZE_SCALAR(rxDmaState);
2198    this->rxDmaState = (DmaState) rxDmaState;
2199
2200    UNSERIALIZE_SCALAR(extstsEnable);
2201
2202     /*
2203     * If there's a pending transmit, store the time so we can
2204     * reschedule it later
2205     */
2206    Tick transmitTick;
2207    UNSERIALIZE_SCALAR(transmitTick);
2208    if (transmitTick)
2209        txEvent.schedule(curTick + transmitTick);
2210
2211    /*
2212     * Keep track of pending interrupt status.
2213     */
2214    UNSERIALIZE_SCALAR(intrTick);
2215    UNSERIALIZE_SCALAR(cpuPendingIntr);
2216    Tick intrEventTick;
2217    UNSERIALIZE_SCALAR(intrEventTick);
2218    if (intrEventTick) {
2219        intrEvent = new IntrEvent(this, true);
2220        intrEvent->schedule(intrEventTick);
2221    }
2222
2223    for (int i = 0; i < rxNumPkts; ++i) {
2224        PacketPtr p = new EtherPacket;
2225        p->unserialize(cp, csprintf("%s.rxFifo%d", section, i));
2226        rxFifo.push_back(p);
2227    }
2228    rxPacket = NULL;
2229    if (rxPacketExists) {
2230        rxPacket = new EtherPacket;
2231        rxPacket->unserialize(cp, csprintf("%s.rxPacket", section));
2232    }
2233    for (int i = 0; i < txNumPkts; ++i) {
2234        PacketPtr p = new EtherPacket;
2235        p->unserialize(cp, csprintf("%s.rxFifo%d", section, i));
2236        txFifo.push_back(p);
2237    }
2238    if (txPacketExists) {
2239        txPacket = new EtherPacket;
2240        txPacket->unserialize(cp, csprintf("%s.txPacket", section));
2241    }
2242}
2243
2244
2245Tick
2246EtherDev::cacheAccess(MemReqPtr &req)
2247{
2248    DPRINTF(EthernetPIO, "timing access to paddr=%#x (daddr=%#x)\n",
2249            req->paddr, req->paddr - addr);
2250    return curTick + pioLatency;
2251}
2252//=====================================================================
2253
2254
2255BEGIN_DECLARE_SIM_OBJECT_PARAMS(EtherDevInt)
2256
2257    SimObjectParam<EtherInt *> peer;
2258    SimObjectParam<EtherDev *> device;
2259
2260END_DECLARE_SIM_OBJECT_PARAMS(EtherDevInt)
2261
2262BEGIN_INIT_SIM_OBJECT_PARAMS(EtherDevInt)
2263
2264    INIT_PARAM_DFLT(peer, "peer interface", NULL),
2265    INIT_PARAM(device, "Ethernet device of this interface")
2266
2267END_INIT_SIM_OBJECT_PARAMS(EtherDevInt)
2268
2269CREATE_SIM_OBJECT(EtherDevInt)
2270{
2271    EtherDevInt *dev_int = new EtherDevInt(getInstanceName(), device);
2272
2273    EtherInt *p = (EtherInt *)peer;
2274    if (p) {
2275        dev_int->setPeer(p);
2276        p->setPeer(dev_int);
2277    }
2278
2279    return dev_int;
2280}
2281
2282REGISTER_SIM_OBJECT("EtherDevInt", EtherDevInt)
2283
2284
2285BEGIN_DECLARE_SIM_OBJECT_PARAMS(EtherDev)
2286
2287    Param<Tick> tx_delay;
2288    Param<Tick> rx_delay;
2289    SimObjectParam<IntrControl *> intr_ctrl;
2290    Param<Tick> intr_delay;
2291    SimObjectParam<MemoryController *> mmu;
2292    SimObjectParam<PhysicalMemory *> physmem;
2293    Param<Addr> addr;
2294    Param<bool> rx_filter;
2295    Param<string> hardware_address;
2296    SimObjectParam<Bus*> header_bus;
2297    SimObjectParam<Bus*> payload_bus;
2298    SimObjectParam<HierParams *> hier;
2299    Param<Tick> pio_latency;
2300    Param<bool> dma_desc_free;
2301    Param<bool> dma_data_free;
2302    Param<Tick> dma_read_delay;
2303    Param<Tick> dma_write_delay;
2304    Param<Tick> dma_read_factor;
2305    Param<Tick> dma_write_factor;
2306    SimObjectParam<PciConfigAll *> configspace;
2307    SimObjectParam<PciConfigData *> configdata;
2308    SimObjectParam<Tsunami *> tsunami;
2309    Param<uint32_t> pci_bus;
2310    Param<uint32_t> pci_dev;
2311    Param<uint32_t> pci_func;
2312
2313END_DECLARE_SIM_OBJECT_PARAMS(EtherDev)
2314
2315BEGIN_INIT_SIM_OBJECT_PARAMS(EtherDev)
2316
2317    INIT_PARAM_DFLT(tx_delay, "Transmit Delay", 1000),
2318    INIT_PARAM_DFLT(rx_delay, "Receive Delay", 1000),
2319    INIT_PARAM(intr_ctrl, "Interrupt Controller"),
2320    INIT_PARAM_DFLT(intr_delay, "Interrupt Delay in microseconds", 0),
2321    INIT_PARAM(mmu, "Memory Controller"),
2322    INIT_PARAM(physmem, "Physical Memory"),
2323    INIT_PARAM(addr, "Device Address"),
2324    INIT_PARAM_DFLT(rx_filter, "Enable Receive Filter", true),
2325    INIT_PARAM_DFLT(hardware_address, "Ethernet Hardware Address",
2326                    "00:99:00:00:00:01"),
2327    INIT_PARAM_DFLT(header_bus, "The IO Bus to attach to for headers", NULL),
2328    INIT_PARAM_DFLT(payload_bus, "The IO Bus to attach to for payload", NULL),
2329    INIT_PARAM_DFLT(hier, "Hierarchy global variables", &defaultHierParams),
2330    INIT_PARAM_DFLT(pio_latency, "Programmed IO latency", 1000),
2331    INIT_PARAM_DFLT(dma_desc_free, "DMA of Descriptors is free", false),
2332    INIT_PARAM_DFLT(dma_data_free, "DMA of Data is free", false),
2333    INIT_PARAM_DFLT(dma_read_delay, "fixed delay for dma reads", 0),
2334    INIT_PARAM_DFLT(dma_write_delay, "fixed delay for dma writes", 0),
2335    INIT_PARAM_DFLT(dma_read_factor, "multiplier for dma reads", 0),
2336    INIT_PARAM_DFLT(dma_write_factor, "multiplier for dma writes", 0),
2337    INIT_PARAM(configspace, "PCI Configspace"),
2338    INIT_PARAM(configdata, "PCI Config data"),
2339    INIT_PARAM(tsunami, "Tsunami"),
2340    INIT_PARAM(pci_bus, "PCI bus"),
2341    INIT_PARAM(pci_dev, "PCI device number"),
2342    INIT_PARAM(pci_func, "PCI function code")
2343
2344END_INIT_SIM_OBJECT_PARAMS(EtherDev)
2345
2346
2347CREATE_SIM_OBJECT(EtherDev)
2348{
2349    int eaddr[6];
2350    sscanf(((string)hardware_address).c_str(), "%x:%x:%x:%x:%x:%x",
2351           &eaddr[0], &eaddr[1], &eaddr[2], &eaddr[3], &eaddr[4], &eaddr[5]);
2352
2353    return new EtherDev(getInstanceName(), intr_ctrl, intr_delay,
2354                        physmem, tx_delay, rx_delay, mmu, hier, header_bus,
2355                        payload_bus, pio_latency, dma_desc_free, dma_data_free,
2356                        dma_read_delay, dma_write_delay, dma_read_factor,
2357                        dma_write_factor, configspace, configdata,
2358                        tsunami, pci_bus, pci_dev, pci_func, rx_filter, eaddr,
2359                        addr);
2360}
2361
2362REGISTER_SIM_OBJECT("EtherDev", EtherDev)
2363