ns_gige.cc revision 854
15331Sgblack@eecs.umich.edu/*
25331Sgblack@eecs.umich.edu * Copyright (c) 2003 The Regents of The University of Michigan
35331Sgblack@eecs.umich.edu * All rights reserved.
45331Sgblack@eecs.umich.edu *
55331Sgblack@eecs.umich.edu * Redistribution and use in source and binary forms, with or without
65331Sgblack@eecs.umich.edu * modification, are permitted provided that the following conditions are
75331Sgblack@eecs.umich.edu * met: redistributions of source code must retain the above copyright
85331Sgblack@eecs.umich.edu * notice, this list of conditions and the following disclaimer;
95331Sgblack@eecs.umich.edu * redistributions in binary form must reproduce the above copyright
105331Sgblack@eecs.umich.edu * notice, this list of conditions and the following disclaimer in the
115331Sgblack@eecs.umich.edu * documentation and/or other materials provided with the distribution;
125331Sgblack@eecs.umich.edu * neither the name of the copyright holders nor the names of its
135331Sgblack@eecs.umich.edu * contributors may be used to endorse or promote products derived from
145331Sgblack@eecs.umich.edu * this software without specific prior written permission.
155331Sgblack@eecs.umich.edu *
165331Sgblack@eecs.umich.edu * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
175331Sgblack@eecs.umich.edu * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
185331Sgblack@eecs.umich.edu * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
195331Sgblack@eecs.umich.edu * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
205331Sgblack@eecs.umich.edu * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
215331Sgblack@eecs.umich.edu * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
225331Sgblack@eecs.umich.edu * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
235331Sgblack@eecs.umich.edu * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
245331Sgblack@eecs.umich.edu * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
255331Sgblack@eecs.umich.edu * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
265331Sgblack@eecs.umich.edu * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
275331Sgblack@eecs.umich.edu */
285331Sgblack@eecs.umich.edu
295331Sgblack@eecs.umich.edu/* @file
304276Sgblack@eecs.umich.edu * Device module for modelling the National Semiconductor
314276Sgblack@eecs.umich.edu * DP83820 ethernet controller.  Does not support priority queueing
324276Sgblack@eecs.umich.edu */
334276Sgblack@eecs.umich.edu#include <cstdio>
344276Sgblack@eecs.umich.edu#include <deque>
354276Sgblack@eecs.umich.edu#include <string>
364276Sgblack@eecs.umich.edu
374276Sgblack@eecs.umich.edu#include "base/inet.hh"
384276Sgblack@eecs.umich.edu#include "cpu/exec_context.hh"
394276Sgblack@eecs.umich.edu#include "cpu/intr_control.hh"
404276Sgblack@eecs.umich.edu#include "dev/dma.hh"
414276Sgblack@eecs.umich.edu#include "dev/ns_gige.hh"
424276Sgblack@eecs.umich.edu#include "dev/etherlink.hh"
434276Sgblack@eecs.umich.edu#include "mem/bus/bus.hh"
444276Sgblack@eecs.umich.edu#include "mem/bus/dma_interface.hh"
454276Sgblack@eecs.umich.edu#include "mem/bus/pio_interface.hh"
464276Sgblack@eecs.umich.edu#include "mem/bus/pio_interface_impl.hh"
474276Sgblack@eecs.umich.edu#include "mem/functional_mem/memory_control.hh"
484276Sgblack@eecs.umich.edu#include "mem/functional_mem/physical_memory.hh"
494276Sgblack@eecs.umich.edu#include "sim/builder.hh"
504276Sgblack@eecs.umich.edu#include "sim/host.hh"
514276Sgblack@eecs.umich.edu#include "sim/sim_stats.hh"
524276Sgblack@eecs.umich.edu#include "targetarch/vtophys.hh"
534276Sgblack@eecs.umich.edu#include "dev/pciconfigall.hh"
544276Sgblack@eecs.umich.edu#include "dev/tsunami_cchip.hh"
554276Sgblack@eecs.umich.edu
564276Sgblack@eecs.umich.educonst char *NsRxStateStrings[] =
574276Sgblack@eecs.umich.edu{
584276Sgblack@eecs.umich.edu    "rxIdle",
594276Sgblack@eecs.umich.edu    "rxDescRefr",
604276Sgblack@eecs.umich.edu    "rxDescRead",
614276Sgblack@eecs.umich.edu    "rxFifoBlock",
624276Sgblack@eecs.umich.edu    "rxFragWrite",
634276Sgblack@eecs.umich.edu    "rxDescWrite",
644276Sgblack@eecs.umich.edu    "rxAdvance"
654276Sgblack@eecs.umich.edu};
664276Sgblack@eecs.umich.edu
674276Sgblack@eecs.umich.educonst char *NsTxStateStrings[] =
684276Sgblack@eecs.umich.edu{
694276Sgblack@eecs.umich.edu    "txIdle",
704276Sgblack@eecs.umich.edu    "txDescRefr",
714276Sgblack@eecs.umich.edu    "txDescRead",
724276Sgblack@eecs.umich.edu    "txFifoBlock",
734276Sgblack@eecs.umich.edu    "txFragRead",
744276Sgblack@eecs.umich.edu    "txDescWrite",
754276Sgblack@eecs.umich.edu    "txAdvance"
764276Sgblack@eecs.umich.edu};
774276Sgblack@eecs.umich.edu
784276Sgblack@eecs.umich.educonst char *NsDmaState[] =
794276Sgblack@eecs.umich.edu{
804276Sgblack@eecs.umich.edu    "dmaIdle",
814276Sgblack@eecs.umich.edu    "dmaReading",
824276Sgblack@eecs.umich.edu    "dmaWriting",
834276Sgblack@eecs.umich.edu    "dmaReadWaiting",
844276Sgblack@eecs.umich.edu    "dmaWriteWaiting"
854276Sgblack@eecs.umich.edu};
864276Sgblack@eecs.umich.edu
874276Sgblack@eecs.umich.eduusing namespace std;
884276Sgblack@eecs.umich.edu
894711Sgblack@eecs.umich.edu///////////////////////////////////////////////////////////////////////
904276Sgblack@eecs.umich.edu//
914276Sgblack@eecs.umich.edu// EtherDev PCI Device
925238Sgblack@eecs.umich.edu//
935238Sgblack@eecs.umich.eduEtherDev::EtherDev(const std::string &name, IntrControl *i, Tick intr_delay,
945238Sgblack@eecs.umich.edu             PhysicalMemory *pmem, Tick tx_delay, Tick rx_delay,
955238Sgblack@eecs.umich.edu             MemoryController *mmu, HierParams *hier, Bus *header_bus,
965937Sgblack@eecs.umich.edu             Bus *payload_bus, Tick pio_latency, bool dma_desc_free,
975902Sgblack@eecs.umich.edu             bool dma_data_free, Tick dma_read_delay, Tick dma_write_delay,
985238Sgblack@eecs.umich.edu             Tick dma_read_factor, Tick dma_write_factor, PciConfigAll *cf,
995238Sgblack@eecs.umich.edu             PciConfigData *cd, Tsunami *t, uint32_t bus, uint32_t dev,
1005238Sgblack@eecs.umich.edu             uint32_t func, bool rx_filter, const int eaddr[6], Addr addr)
1015238Sgblack@eecs.umich.edu    : PciDev(name, mmu, cf, cd, bus, dev, func), tsunami(t),
1025238Sgblack@eecs.umich.edu      addr(addr), txPacketBufPtr(NULL), rxPacketBufPtr(NULL),
1035238Sgblack@eecs.umich.edu      txXferLen(0), rxXferLen(0), txPktXmitted(0), txState(txIdle), CTDD(false),
1046611Sgblack@eecs.umich.edu      txFifoCnt(0), txFifoAvail(MAX_TX_FIFO_SIZE), txHalt(false),
1056611Sgblack@eecs.umich.edu      txFragPtr(0), txDescCnt(0), txDmaState(dmaIdle), rxState(rxIdle),
1066611Sgblack@eecs.umich.edu      CRDD(false), rxPktBytes(0), rxFifoCnt(0), rxHalt(false),
1075238Sgblack@eecs.umich.edu      rxFragPtr(0), rxDescCnt(0), rxDmaState(dmaIdle), extstsEnable(false),
1085238Sgblack@eecs.umich.edu      rxDmaReadEvent(this), rxDmaWriteEvent(this),
1095238Sgblack@eecs.umich.edu      txDmaReadEvent(this), txDmaWriteEvent(this),
1105238Sgblack@eecs.umich.edu      dmaDescFree(dma_desc_free), dmaDataFree(dma_data_free),
1115238Sgblack@eecs.umich.edu      txDelay(tx_delay), rxDelay(rx_delay), rxKickTick(0), txKickTick(0),
1125238Sgblack@eecs.umich.edu      txEvent(this), rxFilterEnable(rx_filter), acceptBroadcast(false),
1136611Sgblack@eecs.umich.edu      acceptMulticast(false), acceptUnicast(false),
1146611Sgblack@eecs.umich.edu      acceptPerfect(false), acceptArp(false),
1156611Sgblack@eecs.umich.edu      physmem(pmem), intctrl(i), intrTick(0),
1166611Sgblack@eecs.umich.edu      cpuPendingIntr(false), intrEvent(0), interface(0), pioLatency(pio_latency)
1175238Sgblack@eecs.umich.edu{
1185238Sgblack@eecs.umich.edu    mmu->add_child(this, Range<Addr>(addr, addr + size));
1195238Sgblack@eecs.umich.edu    tsunami->ethernet = this;
1205238Sgblack@eecs.umich.edu
1216611Sgblack@eecs.umich.edu    if (header_bus) {
1226611Sgblack@eecs.umich.edu        pioInterface = newPioInterface(name, hier, header_bus, this,
1236611Sgblack@eecs.umich.edu                                       &EtherDev::cacheAccess);
1246611Sgblack@eecs.umich.edu        pioInterface->addAddrRange(addr, addr + size - 1);
1256611Sgblack@eecs.umich.edu        if (payload_bus)
1266611Sgblack@eecs.umich.edu            dmaInterface = new DMAInterface<Bus>(name + ".dma",
1276611Sgblack@eecs.umich.edu                                                 header_bus, payload_bus, 1);
1286611Sgblack@eecs.umich.edu        else
1296611Sgblack@eecs.umich.edu            dmaInterface = new DMAInterface<Bus>(name + ".dma",
1306611Sgblack@eecs.umich.edu                                                 header_bus, header_bus, 1);
1316611Sgblack@eecs.umich.edu    } else if (payload_bus) {
1326611Sgblack@eecs.umich.edu        pioInterface = newPioInterface(name, hier, payload_bus, this,
1336611Sgblack@eecs.umich.edu                                       &EtherDev::cacheAccess);
1346611Sgblack@eecs.umich.edu        pioInterface->addAddrRange(addr, addr + size - 1);
1356611Sgblack@eecs.umich.edu        dmaInterface = new DMAInterface<Bus>(name + ".dma",
1366611Sgblack@eecs.umich.edu                                             payload_bus, payload_bus, 1);
1376611Sgblack@eecs.umich.edu
1386611Sgblack@eecs.umich.edu    }
1395238Sgblack@eecs.umich.edu
1405238Sgblack@eecs.umich.edu
1415238Sgblack@eecs.umich.edu    intrDelay = US2Ticks(intr_delay);
1425238Sgblack@eecs.umich.edu    dmaReadDelay = dma_read_delay;
1435238Sgblack@eecs.umich.edu    dmaWriteDelay = dma_write_delay;
1445238Sgblack@eecs.umich.edu    dmaReadFactor = dma_read_factor;
1455238Sgblack@eecs.umich.edu    dmaWriteFactor = dma_write_factor;
1465238Sgblack@eecs.umich.edu
1475238Sgblack@eecs.umich.edu    memset(&regs, 0, sizeof(regs));
1485238Sgblack@eecs.umich.edu    regsReset();
1496611Sgblack@eecs.umich.edu    rom.perfectMatch[0] = eaddr[0];
1505292Sgblack@eecs.umich.edu    rom.perfectMatch[1] = eaddr[1];
1515292Sgblack@eecs.umich.edu    rom.perfectMatch[2] = eaddr[2];
1525292Sgblack@eecs.umich.edu    rom.perfectMatch[3] = eaddr[3];
1535292Sgblack@eecs.umich.edu    rom.perfectMatch[4] = eaddr[4];
1545292Sgblack@eecs.umich.edu    rom.perfectMatch[5] = eaddr[5];
1555292Sgblack@eecs.umich.edu}
1565292Sgblack@eecs.umich.edu
1575292Sgblack@eecs.umich.eduEtherDev::~EtherDev()
1586611Sgblack@eecs.umich.edu{}
1596611Sgblack@eecs.umich.edu
1606611Sgblack@eecs.umich.eduvoid
1616611Sgblack@eecs.umich.eduEtherDev::regStats()
1626611Sgblack@eecs.umich.edu{
1636611Sgblack@eecs.umich.edu    txBytes
1646611Sgblack@eecs.umich.edu        .name(name() + ".txBytes")
1656611Sgblack@eecs.umich.edu        .desc("Bytes Transmitted")
1666611Sgblack@eecs.umich.edu        .prereq(txBytes)
1676611Sgblack@eecs.umich.edu        ;
1686611Sgblack@eecs.umich.edu
1696611Sgblack@eecs.umich.edu    rxBytes
1706611Sgblack@eecs.umich.edu        .name(name() + ".rxBytes")
1715238Sgblack@eecs.umich.edu        .desc("Bytes Received")
1725238Sgblack@eecs.umich.edu        .prereq(rxBytes)
1734276Sgblack@eecs.umich.edu        ;
1744276Sgblack@eecs.umich.edu
1755789Sgblack@eecs.umich.edu    txPackets
1765789Sgblack@eecs.umich.edu        .name(name() + ".txPackets")
1775789Sgblack@eecs.umich.edu        .desc("Number of Packets Transmitted")
1785789Sgblack@eecs.umich.edu        .prereq(txBytes)
1795789Sgblack@eecs.umich.edu        ;
1805789Sgblack@eecs.umich.edu
1815789Sgblack@eecs.umich.edu    rxPackets
1825789Sgblack@eecs.umich.edu        .name(name() + ".rxPackets")
1835789Sgblack@eecs.umich.edu        .desc("Number of Packets Received")
1845789Sgblack@eecs.umich.edu        .prereq(rxBytes)
1855789Sgblack@eecs.umich.edu        ;
1865789Sgblack@eecs.umich.edu
1875789Sgblack@eecs.umich.edu    txBandwidth
1885789Sgblack@eecs.umich.edu        .name(name() + ".txBandwidth")
1895789Sgblack@eecs.umich.edu        .desc("Transmit Bandwidth (bits/s)")
1905789Sgblack@eecs.umich.edu        .precision(0)
1915789Sgblack@eecs.umich.edu        .prereq(txBytes)
1925789Sgblack@eecs.umich.edu        ;
1935789Sgblack@eecs.umich.edu
1945789Sgblack@eecs.umich.edu    rxBandwidth
1955789Sgblack@eecs.umich.edu        .name(name() + ".rxBandwidth")
1965789Sgblack@eecs.umich.edu        .desc("Receive Bandwidth (bits/s)")
1975789Sgblack@eecs.umich.edu        .precision(0)
1985789Sgblack@eecs.umich.edu        .prereq(rxBytes)
1995789Sgblack@eecs.umich.edu        ;
2005789Sgblack@eecs.umich.edu
2015789Sgblack@eecs.umich.edu    txPacketRate
2025789Sgblack@eecs.umich.edu        .name(name() + ".txPPS")
2035789Sgblack@eecs.umich.edu        .desc("Packet Tranmission Rate (packets/s)")
2045789Sgblack@eecs.umich.edu        .precision(0)
2055789Sgblack@eecs.umich.edu        .prereq(txBytes)
2065789Sgblack@eecs.umich.edu        ;
2075789Sgblack@eecs.umich.edu
2085789Sgblack@eecs.umich.edu    rxPacketRate
2095789Sgblack@eecs.umich.edu        .name(name() + ".rxPPS")
2105789Sgblack@eecs.umich.edu        .desc("Packet Reception Rate (packets/s)")
2115789Sgblack@eecs.umich.edu        .precision(0)
2125789Sgblack@eecs.umich.edu        .prereq(rxBytes)
2135789Sgblack@eecs.umich.edu        ;
2145789Sgblack@eecs.umich.edu
2155789Sgblack@eecs.umich.edu    txBandwidth = txBytes * Statistics::constant(8) / simSeconds;
2165789Sgblack@eecs.umich.edu    rxBandwidth = rxBytes * Statistics::constant(8) / simSeconds;
2175789Sgblack@eecs.umich.edu    txPacketRate = txPackets / simSeconds;
2185789Sgblack@eecs.umich.edu    rxPacketRate = rxPackets / simSeconds;
2195789Sgblack@eecs.umich.edu}
2205789Sgblack@eecs.umich.edu
2215789Sgblack@eecs.umich.eduvoid
2225789Sgblack@eecs.umich.eduEtherDev::ReadConfig(int offset, int size, uint8_t *data)
2235789Sgblack@eecs.umich.edu{
2245789Sgblack@eecs.umich.edu    if (offset < PCI_DEVICE_SPECIFIC)
2255789Sgblack@eecs.umich.edu        PciDev::ReadConfig(offset, size, data);
2265789Sgblack@eecs.umich.edu    else {
2275789Sgblack@eecs.umich.edu        panic("need to do this\n");
2285789Sgblack@eecs.umich.edu    }
2295789Sgblack@eecs.umich.edu}
2305789Sgblack@eecs.umich.edu
2315789Sgblack@eecs.umich.eduvoid
2325789Sgblack@eecs.umich.eduEtherDev::WriteConfig(int offset, int size, uint32_t data)
2335789Sgblack@eecs.umich.edu{
2345789Sgblack@eecs.umich.edu    if (offset < PCI_DEVICE_SPECIFIC)
2355789Sgblack@eecs.umich.edu        PciDev::WriteConfig(offset, size, data);
2365789Sgblack@eecs.umich.edu    else
2375789Sgblack@eecs.umich.edu        panic("Need to do that\n");
2385789Sgblack@eecs.umich.edu}
2395789Sgblack@eecs.umich.edu
2405789Sgblack@eecs.umich.eduFault
2415789Sgblack@eecs.umich.eduEtherDev::read(MemReqPtr &req, uint8_t *data)
2425789Sgblack@eecs.umich.edu{
2435789Sgblack@eecs.umich.edu    Addr daddr = req->paddr & 0xfff;
2445789Sgblack@eecs.umich.edu    DPRINTF(EthernetPIO, "read  da=%#x pa=%#x va=%#x size=%d\n",
2455789Sgblack@eecs.umich.edu            daddr, req->paddr, req->vaddr, req->size);
2465789Sgblack@eecs.umich.edu
2475789Sgblack@eecs.umich.edu    if (daddr > LAST && daddr <=  RESERVED) {
2485789Sgblack@eecs.umich.edu        panic("Accessing reserved register");
2495789Sgblack@eecs.umich.edu    } else if (daddr > RESERVED && daddr <= 0x3FC) {
2505789Sgblack@eecs.umich.edu        ReadConfig(daddr & 0xff, req->size, data);
2515789Sgblack@eecs.umich.edu        return No_Fault;
2525789Sgblack@eecs.umich.edu    } else if (daddr >= MIB_START && daddr <= MIB_END) {
2535789Sgblack@eecs.umich.edu        // don't implement all the MIB's.  hopefully the kernel
2545789Sgblack@eecs.umich.edu        // doesn't actually DEPEND upon their values
2555789Sgblack@eecs.umich.edu        uint32_t &reg = *(uint32_t *) data;
2565789Sgblack@eecs.umich.edu        reg = 0;
2575789Sgblack@eecs.umich.edu        return No_Fault;
2585789Sgblack@eecs.umich.edu    } else if (daddr > 0x3FC)
2595789Sgblack@eecs.umich.edu        panic("Something is messed up!\n");
2605789Sgblack@eecs.umich.edu
2615789Sgblack@eecs.umich.edu    switch (req->size) {
2625789Sgblack@eecs.umich.edu      case sizeof(uint32_t):
2635789Sgblack@eecs.umich.edu        {
2645789Sgblack@eecs.umich.edu            uint32_t &reg = *(uint32_t *)data;
2654712Sgblack@eecs.umich.edu
2665907Sgblack@eecs.umich.edu            switch (daddr) {
2675907Sgblack@eecs.umich.edu              case CR:
2685907Sgblack@eecs.umich.edu                reg = regs.command;
2695907Sgblack@eecs.umich.edu                reg &= ~(CR_RXD | CR_TXD | CR_TXR | CR_RXR);
2705907Sgblack@eecs.umich.edu                break;
2715907Sgblack@eecs.umich.edu
2725907Sgblack@eecs.umich.edu              case CFG:
2734712Sgblack@eecs.umich.edu                reg = regs.config;
2745659Sgblack@eecs.umich.edu                break;
2754712Sgblack@eecs.umich.edu
2765933Sgblack@eecs.umich.edu              case MEAR:
2775908Sgblack@eecs.umich.edu                reg = regs.mear;
2785908Sgblack@eecs.umich.edu                break;
2795908Sgblack@eecs.umich.edu
2805908Sgblack@eecs.umich.edu              case PTSCR:
2815908Sgblack@eecs.umich.edu                reg = regs.ptscr;
2825908Sgblack@eecs.umich.edu                break;
2835908Sgblack@eecs.umich.edu
2845908Sgblack@eecs.umich.edu              case ISR:
2855908Sgblack@eecs.umich.edu                reg = regs.isr;
2864276Sgblack@eecs.umich.edu                regs.isr = 0;
2874276Sgblack@eecs.umich.edu                break;
2884712Sgblack@eecs.umich.edu
2894712Sgblack@eecs.umich.edu              case IMR:
2904730Sgblack@eecs.umich.edu                reg = regs.imr;
2914760Sgblack@eecs.umich.edu                break;
2924730Sgblack@eecs.umich.edu
2935920Sgblack@eecs.umich.edu              case IER:
2945422Sgblack@eecs.umich.edu                reg = regs.ier;
2956616Sgblack@eecs.umich.edu                break;
2966616Sgblack@eecs.umich.edu
2976616Sgblack@eecs.umich.edu              case IHR:
2986616Sgblack@eecs.umich.edu                reg = regs.ihr;
2996616Sgblack@eecs.umich.edu                break;
3006616Sgblack@eecs.umich.edu
3016616Sgblack@eecs.umich.edu              case TXDP:
3026616Sgblack@eecs.umich.edu                reg = regs.txdp;
3036616Sgblack@eecs.umich.edu                break;
3046616Sgblack@eecs.umich.edu
3056616Sgblack@eecs.umich.edu              case TXDP_HI:
3066616Sgblack@eecs.umich.edu                reg = regs.txdp_hi;
3076616Sgblack@eecs.umich.edu                break;
3086616Sgblack@eecs.umich.edu
3096616Sgblack@eecs.umich.edu              case TXCFG:
3106616Sgblack@eecs.umich.edu                reg = regs.txcfg;
3116616Sgblack@eecs.umich.edu                break;
3126616Sgblack@eecs.umich.edu
3136616Sgblack@eecs.umich.edu              case GPIOR:
3146616Sgblack@eecs.umich.edu                reg = regs.gpior;
3156616Sgblack@eecs.umich.edu                break;
3166616Sgblack@eecs.umich.edu
3176616Sgblack@eecs.umich.edu              case RXDP:
3186616Sgblack@eecs.umich.edu                reg = regs.rxdp;
3196616Sgblack@eecs.umich.edu                break;
3206616Sgblack@eecs.umich.edu
3216616Sgblack@eecs.umich.edu              case RXDP_HI:
3224276Sgblack@eecs.umich.edu                reg = regs.rxdp_hi;
3236576Sgblack@eecs.umich.edu                break;
3246576Sgblack@eecs.umich.edu
3256576Sgblack@eecs.umich.edu              case RXCFG:
3266576Sgblack@eecs.umich.edu                reg = regs.rxcfg;
3276576Sgblack@eecs.umich.edu                break;
3286576Sgblack@eecs.umich.edu
3296576Sgblack@eecs.umich.edu              case PQCR:
3306611Sgblack@eecs.umich.edu                reg = regs.pqcr;
3316611Sgblack@eecs.umich.edu                break;
3326576Sgblack@eecs.umich.edu
3336611Sgblack@eecs.umich.edu              case WCSR:
3346576Sgblack@eecs.umich.edu                reg = regs.wcsr;
3356611Sgblack@eecs.umich.edu                break;
3366576Sgblack@eecs.umich.edu
3376611Sgblack@eecs.umich.edu              case PCR:
3386611Sgblack@eecs.umich.edu                reg = regs.pcr;
3396576Sgblack@eecs.umich.edu                break;
3406576Sgblack@eecs.umich.edu
3415020Sgblack@eecs.umich.edu              case RFCR:
3426576Sgblack@eecs.umich.edu                reg = regs.rfcr;
3436576Sgblack@eecs.umich.edu                break;
3446600Sgblack@eecs.umich.edu
3456600Sgblack@eecs.umich.edu              case RFDR:
3466576Sgblack@eecs.umich.edu                DPRINTF(Ethernet, "reading from RFDR\n");
3476576Sgblack@eecs.umich.edu                switch (regs.rfcr & RFCR_RFADDR) {
3486576Sgblack@eecs.umich.edu                  case 0x000:
3495020Sgblack@eecs.umich.edu                    reg = rom.perfectMatch[1];
3506576Sgblack@eecs.umich.edu                    reg = reg << 8;
3516576Sgblack@eecs.umich.edu                    reg += rom.perfectMatch[0];
3526576Sgblack@eecs.umich.edu                    break;
3536576Sgblack@eecs.umich.edu                  case 0x002:
3546576Sgblack@eecs.umich.edu                    reg = rom.perfectMatch[3] << 8;
3556576Sgblack@eecs.umich.edu                    reg += rom.perfectMatch[2];
3566576Sgblack@eecs.umich.edu                    break;
3576576Sgblack@eecs.umich.edu                  case 0x004:
3586576Sgblack@eecs.umich.edu                    reg = rom.perfectMatch[5] << 8;
3596576Sgblack@eecs.umich.edu                    reg += rom.perfectMatch[4];
3606576Sgblack@eecs.umich.edu                    break;
3616576Sgblack@eecs.umich.edu                  default:
3626576Sgblack@eecs.umich.edu                    panic("reading from RFDR for something for other than PMATCH!\n");
3636576Sgblack@eecs.umich.edu                    //didn't implement other RFDR functionality b/c driver didn't use
3646576Sgblack@eecs.umich.edu                }
3656576Sgblack@eecs.umich.edu                break;
3666576Sgblack@eecs.umich.edu
3676576Sgblack@eecs.umich.edu              case SRR:
3686576Sgblack@eecs.umich.edu                reg = regs.srr;
3694760Sgblack@eecs.umich.edu                break;
3706576Sgblack@eecs.umich.edu
3716611Sgblack@eecs.umich.edu              case MIBC:
3726576Sgblack@eecs.umich.edu                reg = regs.mibc;
3736576Sgblack@eecs.umich.edu                reg &= ~(MIBC_MIBS | MIBC_ACLR);
3746576Sgblack@eecs.umich.edu                break;
3756576Sgblack@eecs.umich.edu
3766576Sgblack@eecs.umich.edu              case VRCR:
3776576Sgblack@eecs.umich.edu                reg = regs.vrcr;
3786576Sgblack@eecs.umich.edu                break;
3796576Sgblack@eecs.umich.edu
3806576Sgblack@eecs.umich.edu              case VTCR:
3816576Sgblack@eecs.umich.edu                reg = regs.vtcr;
3826576Sgblack@eecs.umich.edu                break;
3836576Sgblack@eecs.umich.edu
3846576Sgblack@eecs.umich.edu              case VDR:
3856576Sgblack@eecs.umich.edu                reg = regs.vdr;
3864760Sgblack@eecs.umich.edu                break;
3876576Sgblack@eecs.umich.edu
3886576Sgblack@eecs.umich.edu              case CCSR:
3896576Sgblack@eecs.umich.edu                reg = regs.ccsr;
3906576Sgblack@eecs.umich.edu                break;
3916576Sgblack@eecs.umich.edu
3926576Sgblack@eecs.umich.edu              case TBICR:
3936576Sgblack@eecs.umich.edu                reg = regs.tbicr;
3946576Sgblack@eecs.umich.edu                break;
3956576Sgblack@eecs.umich.edu
3966576Sgblack@eecs.umich.edu              case TBISR:
3974760Sgblack@eecs.umich.edu                reg = regs.tbisr;
3986611Sgblack@eecs.umich.edu                break;
3996611Sgblack@eecs.umich.edu
4006611Sgblack@eecs.umich.edu              case TANAR:
4016611Sgblack@eecs.umich.edu                reg = regs.tanar;
4026611Sgblack@eecs.umich.edu                break;
4036611Sgblack@eecs.umich.edu
4046611Sgblack@eecs.umich.edu              case TANLPAR:
4056611Sgblack@eecs.umich.edu                reg = regs.tanlpar;
4066611Sgblack@eecs.umich.edu                break;
4076611Sgblack@eecs.umich.edu
4086611Sgblack@eecs.umich.edu              case TANER:
4096611Sgblack@eecs.umich.edu                reg = regs.taner;
4106611Sgblack@eecs.umich.edu                break;
4116611Sgblack@eecs.umich.edu
4126611Sgblack@eecs.umich.edu              case TESR:
4136611Sgblack@eecs.umich.edu                reg = regs.tesr;
4146611Sgblack@eecs.umich.edu                break;
4156611Sgblack@eecs.umich.edu
4166611Sgblack@eecs.umich.edu              default:
4176611Sgblack@eecs.umich.edu                panic("reading unimplemented register: addr = %#x", daddr);
4186611Sgblack@eecs.umich.edu            }
4196611Sgblack@eecs.umich.edu
4206611Sgblack@eecs.umich.edu            DPRINTF(EthernetPIO, "read from %#x: data=%d data=%#x\n", daddr, reg, reg);
4216611Sgblack@eecs.umich.edu        }
4226611Sgblack@eecs.umich.edu        break;
4236611Sgblack@eecs.umich.edu
4246611Sgblack@eecs.umich.edu      default:
4256611Sgblack@eecs.umich.edu        panic("accessing register with invalid size: addr=%#x, size=%d",
4266611Sgblack@eecs.umich.edu              daddr, req->size);
4276611Sgblack@eecs.umich.edu    }
4286611Sgblack@eecs.umich.edu
4296611Sgblack@eecs.umich.edu    return No_Fault;
4306611Sgblack@eecs.umich.edu}
4316611Sgblack@eecs.umich.edu
4326611Sgblack@eecs.umich.eduFault
4336611Sgblack@eecs.umich.eduEtherDev::write(MemReqPtr &req, const uint8_t *data)
4346611Sgblack@eecs.umich.edu{
4356611Sgblack@eecs.umich.edu    Addr daddr = req->paddr & 0xfff;
4366611Sgblack@eecs.umich.edu    DPRINTF(EthernetPIO, "write da=%#x pa=%#x va=%#x size=%d\n",
4376611Sgblack@eecs.umich.edu            daddr, req->paddr, req->vaddr, req->size);
4386611Sgblack@eecs.umich.edu
4396611Sgblack@eecs.umich.edu    if (daddr > LAST && daddr <=  RESERVED) {
4405020Sgblack@eecs.umich.edu        panic("Accessing reserved register");
4414276Sgblack@eecs.umich.edu    } else if (daddr > RESERVED && daddr <= 0x3FC) {
4424276Sgblack@eecs.umich.edu        WriteConfig(daddr & 0xff, req->size, *(uint32_t *)data);
4435149Sgblack@eecs.umich.edu        return No_Fault;
4445409Sgblack@eecs.umich.edu    } else if (daddr > 0x3FC)
4455149Sgblack@eecs.umich.edu        panic("Something is messed up!\n");
4464712Sgblack@eecs.umich.edu
4475972Sgblack@eecs.umich.edu    if (req->size == sizeof(uint32_t)) {
4484712Sgblack@eecs.umich.edu        uint32_t reg = *(uint32_t *)data;
4495972Sgblack@eecs.umich.edu        DPRINTF(EthernetPIO, "write data=%d data=%#x\n", reg, reg);
4505972Sgblack@eecs.umich.edu
4515972Sgblack@eecs.umich.edu        switch (daddr) {
4524712Sgblack@eecs.umich.edu          case CR:
4534730Sgblack@eecs.umich.edu            regs.command = reg;
4544712Sgblack@eecs.umich.edu            if ((reg & (CR_TXE | CR_TXD)) == (CR_TXE | CR_TXD)) {
4554276Sgblack@eecs.umich.edu                txHalt = true;
4564276Sgblack@eecs.umich.edu            } else if (reg & CR_TXE) {
4576615Sgblack@eecs.umich.edu                if (txState == txIdle)
4586615Sgblack@eecs.umich.edu                    txKick();
4596615Sgblack@eecs.umich.edu            } else if (reg & CR_TXD) {
4606615Sgblack@eecs.umich.edu                txHalt = true;
4616615Sgblack@eecs.umich.edu            }
4626615Sgblack@eecs.umich.edu
4636611Sgblack@eecs.umich.edu            if ((reg & (CR_RXE | CR_RXD)) == (CR_RXE | CR_RXD)) {
4644276Sgblack@eecs.umich.edu                rxHalt = true;
4654760Sgblack@eecs.umich.edu            } else if (reg & CR_RXE) {
4664760Sgblack@eecs.umich.edu                if (rxState == rxIdle) {
4674760Sgblack@eecs.umich.edu                    rxKick();
4684760Sgblack@eecs.umich.edu                }
4694760Sgblack@eecs.umich.edu            } else if (reg & CR_RXD) {
4704760Sgblack@eecs.umich.edu                rxHalt = true;
4714760Sgblack@eecs.umich.edu            }
4724760Sgblack@eecs.umich.edu
4734760Sgblack@eecs.umich.edu            if (reg & CR_TXR)
4744760Sgblack@eecs.umich.edu                txReset();
4754760Sgblack@eecs.umich.edu
4764760Sgblack@eecs.umich.edu            if (reg & CR_RXR)
4774760Sgblack@eecs.umich.edu                rxReset();
4784760Sgblack@eecs.umich.edu
4794760Sgblack@eecs.umich.edu            if (reg & CR_SWI)
4804760Sgblack@eecs.umich.edu                devIntrPost(ISR_SWI);
4814760Sgblack@eecs.umich.edu
4824760Sgblack@eecs.umich.edu            if (reg & CR_RST) {
4834760Sgblack@eecs.umich.edu                txReset();
4844760Sgblack@eecs.umich.edu                rxReset();
4854760Sgblack@eecs.umich.edu
4866576Sgblack@eecs.umich.edu                regsReset();
4876576Sgblack@eecs.umich.edu            }
4886576Sgblack@eecs.umich.edu            break;
4896593Sgblack@eecs.umich.edu
4906576Sgblack@eecs.umich.edu          case CFG:
4916576Sgblack@eecs.umich.edu            if (reg & CFG_LNKSTS || reg & CFG_SPDSTS || reg & CFG_DUPSTS
4926576Sgblack@eecs.umich.edu                || reg & CFG_RESERVED || reg & CFG_T64ADDR
4936576Sgblack@eecs.umich.edu                || reg & CFG_PCI64_DET)
4946576Sgblack@eecs.umich.edu                panic("writing to read-only or reserved CFG bits!\n");
4956576Sgblack@eecs.umich.edu
4966576Sgblack@eecs.umich.edu            regs.config |= reg & ~(CFG_LNKSTS | CFG_SPDSTS | CFG_DUPSTS | CFG_RESERVED |
4976576Sgblack@eecs.umich.edu                                  CFG_T64ADDR | CFG_PCI64_DET);
4986576Sgblack@eecs.umich.edu
4996576Sgblack@eecs.umich.edu#if 0
5006576Sgblack@eecs.umich.edu              if (reg & CFG_TBI_EN) ;
5016576Sgblack@eecs.umich.edu              if (reg & CFG_MODE_1000) ;
5026576Sgblack@eecs.umich.edu#endif
5036576Sgblack@eecs.umich.edu
5046576Sgblack@eecs.umich.edu            if (reg & CFG_AUTO_1000)
5056576Sgblack@eecs.umich.edu                panic("CFG_AUTO_1000 not implemented!\n");
5066576Sgblack@eecs.umich.edu
5076593Sgblack@eecs.umich.edu#if 0
5086576Sgblack@eecs.umich.edu            if (reg & CFG_PINT_DUPSTS || reg & CFG_PINT_LNKSTS || reg & CFG_PINT_SPDSTS) ;
5096576Sgblack@eecs.umich.edu            if (reg & CFG_TMRTEST) ;
5106576Sgblack@eecs.umich.edu            if (reg & CFG_MRM_DIS) ;
5116576Sgblack@eecs.umich.edu            if (reg & CFG_MWI_DIS) ;
5126611Sgblack@eecs.umich.edu
5136576Sgblack@eecs.umich.edu            if (reg & CFG_T64ADDR)
5146576Sgblack@eecs.umich.edu                panic("CFG_T64ADDR is read only register!\n");
5155059Sgblack@eecs.umich.edu
5165059Sgblack@eecs.umich.edu            if (reg & CFG_PCI64_DET)
5176576Sgblack@eecs.umich.edu                panic("CFG_PCI64_DET is read only register!\n");
5185059Sgblack@eecs.umich.edu
5195059Sgblack@eecs.umich.edu            if (reg & CFG_DATA64_EN) ;
5205059Sgblack@eecs.umich.edu            if (reg & CFG_M64ADDR) ;
5215020Sgblack@eecs.umich.edu            if (reg & CFG_PHY_RST) ;
5226576Sgblack@eecs.umich.edu            if (reg & CFG_PHY_DIS) ;
5236576Sgblack@eecs.umich.edu#endif
5246576Sgblack@eecs.umich.edu
5256576Sgblack@eecs.umich.edu            if (reg & CFG_EXTSTS_EN)
5266576Sgblack@eecs.umich.edu                extstsEnable = true;
5276576Sgblack@eecs.umich.edu            else
5286576Sgblack@eecs.umich.edu                extstsEnable = false;
5296576Sgblack@eecs.umich.edu
5306576Sgblack@eecs.umich.edu#if 0
5316576Sgblack@eecs.umich.edu              if (reg & CFG_REQALG) ;
5326576Sgblack@eecs.umich.edu              if (reg & CFG_SB) ;
5336576Sgblack@eecs.umich.edu              if (reg & CFG_POW) ;
5346576Sgblack@eecs.umich.edu              if (reg & CFG_EXD) ;
5356576Sgblack@eecs.umich.edu              if (reg & CFG_PESEL) ;
5366576Sgblack@eecs.umich.edu              if (reg & CFG_BROM_DIS) ;
5376576Sgblack@eecs.umich.edu              if (reg & CFG_EXT_125) ;
5386576Sgblack@eecs.umich.edu              if (reg & CFG_BEM) ;
5396606Sgblack@eecs.umich.edu#endif
5406576Sgblack@eecs.umich.edu            break;
5416576Sgblack@eecs.umich.edu
5426576Sgblack@eecs.umich.edu          case MEAR:
5436576Sgblack@eecs.umich.edu            regs.mear = reg;
5446576Sgblack@eecs.umich.edu            /* since phy is completely faked, MEAR_MD* don't matter
5456576Sgblack@eecs.umich.edu               and since the driver never uses MEAR_EE*, they don't matter */
5466576Sgblack@eecs.umich.edu#if 0
5476576Sgblack@eecs.umich.edu            if (reg & MEAR_EEDI) ;
5486576Sgblack@eecs.umich.edu            if (reg & MEAR_EEDO) ; //this one is read only
5496576Sgblack@eecs.umich.edu            if (reg & MEAR_EECLK) ;
5506606Sgblack@eecs.umich.edu            if (reg & MEAR_EESEL) ;
5516576Sgblack@eecs.umich.edu            if (reg & MEAR_MDIO) ;
5526576Sgblack@eecs.umich.edu            if (reg & MEAR_MDDIR) ;
5536576Sgblack@eecs.umich.edu            if (reg & MEAR_MDC) ;
5546576Sgblack@eecs.umich.edu#endif
5556576Sgblack@eecs.umich.edu            break;
5566576Sgblack@eecs.umich.edu
5576576Sgblack@eecs.umich.edu          case PTSCR:
5586576Sgblack@eecs.umich.edu            regs.ptscr = reg & ~(PTSCR_RBIST_RDONLY);
5596576Sgblack@eecs.umich.edu            /* these control BISTs for various parts of chip - we don't care or do
5606576Sgblack@eecs.umich.edu               just fake that the BIST is done */
5616576Sgblack@eecs.umich.edu            if (reg & PTSCR_RBIST_EN)
5626576Sgblack@eecs.umich.edu                regs.ptscr |= PTSCR_RBIST_DONE;
5636576Sgblack@eecs.umich.edu            if (reg & PTSCR_EEBIST_EN)
5646576Sgblack@eecs.umich.edu                regs.ptscr &= ~PTSCR_EEBIST_EN;
5656576Sgblack@eecs.umich.edu            if (reg & PTSCR_EELOAD_EN)
5666576Sgblack@eecs.umich.edu                regs.ptscr &= ~PTSCR_EELOAD_EN;
5676576Sgblack@eecs.umich.edu            break;
5685020Sgblack@eecs.umich.edu
5696576Sgblack@eecs.umich.edu          case ISR: /* writing to the ISR has no effect */
5706576Sgblack@eecs.umich.edu            panic("ISR is a read only register!\n");
5716576Sgblack@eecs.umich.edu
5726576Sgblack@eecs.umich.edu          case IMR:
5736576Sgblack@eecs.umich.edu            regs.imr = reg;
5746576Sgblack@eecs.umich.edu            devIntrChangeMask();
5756576Sgblack@eecs.umich.edu            break;
5766576Sgblack@eecs.umich.edu
5776576Sgblack@eecs.umich.edu          case IER:
5786576Sgblack@eecs.umich.edu            regs.ier = reg;
5796576Sgblack@eecs.umich.edu            break;
5806576Sgblack@eecs.umich.edu
5816576Sgblack@eecs.umich.edu          case IHR:
5826576Sgblack@eecs.umich.edu            regs.ihr = reg;
5836576Sgblack@eecs.umich.edu            /* not going to implement real interrupt holdoff */
5846576Sgblack@eecs.umich.edu            break;
5856576Sgblack@eecs.umich.edu
5866576Sgblack@eecs.umich.edu          case TXDP:
5876576Sgblack@eecs.umich.edu            regs.txdp = (reg & 0xFFFFFFFC);
5886576Sgblack@eecs.umich.edu            assert(txState == txIdle);
5896576Sgblack@eecs.umich.edu            CTDD = false;
5906576Sgblack@eecs.umich.edu            break;
5916576Sgblack@eecs.umich.edu
5926576Sgblack@eecs.umich.edu          case TXDP_HI:
5935020Sgblack@eecs.umich.edu            regs.txdp_hi = reg;
5946576Sgblack@eecs.umich.edu            break;
5956576Sgblack@eecs.umich.edu
5966576Sgblack@eecs.umich.edu          case TXCFG:
5976576Sgblack@eecs.umich.edu            regs.txcfg = reg;
5986576Sgblack@eecs.umich.edu#if 0
5996576Sgblack@eecs.umich.edu            if (reg & TXCFG_CSI) ;
6006576Sgblack@eecs.umich.edu            if (reg & TXCFG_HBI) ;
6016576Sgblack@eecs.umich.edu            if (reg & TXCFG_MLB) ;
6026576Sgblack@eecs.umich.edu            if (reg & TXCFG_ATP) ;
6036576Sgblack@eecs.umich.edu            if (reg & TXCFG_ECRETRY) ;  /* this could easily be implemented, but
6046576Sgblack@eecs.umich.edu                                           considering the network is just a fake
6056576Sgblack@eecs.umich.edu                                           pipe, wouldn't make sense to do this */
6066576Sgblack@eecs.umich.edu
6076696Svince@csl.cornell.edu            if (reg & TXCFG_BRST_DIS) ;
6086576Sgblack@eecs.umich.edu#endif
6096576Sgblack@eecs.umich.edu
6106576Sgblack@eecs.umich.edu
6116576Sgblack@eecs.umich.edu            /* we handle our own DMA, ignore the kernel's exhortations */
6126576Sgblack@eecs.umich.edu            if (reg & TXCFG_MXDMA) ;
6136576Sgblack@eecs.umich.edu
6146576Sgblack@eecs.umich.edu            break;
6156576Sgblack@eecs.umich.edu
6166576Sgblack@eecs.umich.edu          case GPIOR:
6176576Sgblack@eecs.umich.edu            regs.gpior = reg;
6186706Svince@csl.cornell.edu            /* these just control general purpose i/o pins, don't matter */
6196696Svince@csl.cornell.edu            break;
6206576Sgblack@eecs.umich.edu
6216576Sgblack@eecs.umich.edu          case RXDP:
6225020Sgblack@eecs.umich.edu            regs.rxdp = reg;
6236584Sgblack@eecs.umich.edu            break;
6246584Sgblack@eecs.umich.edu
6256584Sgblack@eecs.umich.edu          case RXDP_HI:
6266597Sgblack@eecs.umich.edu            regs.rxdp_hi = reg;
6276611Sgblack@eecs.umich.edu            break;
6286584Sgblack@eecs.umich.edu
6296611Sgblack@eecs.umich.edu          case RXCFG:
6306611Sgblack@eecs.umich.edu            regs.rxcfg = reg;
6316611Sgblack@eecs.umich.edu#if 0
6326584Sgblack@eecs.umich.edu            if (reg & RXCFG_AEP) ;
6335238Sgblack@eecs.umich.edu            if (reg & RXCFG_ARP) ;
6346611Sgblack@eecs.umich.edu            if (reg & RXCFG_STRIPCRC) ;
6356584Sgblack@eecs.umich.edu            if (reg & RXCFG_RX_RD) ;
6366611Sgblack@eecs.umich.edu            if (reg & RXCFG_ALP) ;
6376611Sgblack@eecs.umich.edu            if (reg & RXCFG_AIRL) ;
6386611Sgblack@eecs.umich.edu#endif
6396584Sgblack@eecs.umich.edu
6405238Sgblack@eecs.umich.edu            /* we handle our own DMA, ignore what kernel says about it */
6416611Sgblack@eecs.umich.edu            if (reg & RXCFG_MXDMA) ;
6426584Sgblack@eecs.umich.edu
6436611Sgblack@eecs.umich.edu#if 0
6446611Sgblack@eecs.umich.edu            if (reg & (RXCFG_DRTH | RXCFG_DRTH0)) ;
6456584Sgblack@eecs.umich.edu#endif
6465238Sgblack@eecs.umich.edu            break;
6476584Sgblack@eecs.umich.edu
6486584Sgblack@eecs.umich.edu          case PQCR:
6496584Sgblack@eecs.umich.edu            /* there is no priority queueing used in the linux 2.6 driver */
6506584Sgblack@eecs.umich.edu            regs.pqcr = reg;
6515238Sgblack@eecs.umich.edu            break;
6526584Sgblack@eecs.umich.edu
6536584Sgblack@eecs.umich.edu          case WCSR:
6546597Sgblack@eecs.umich.edu            /* not going to implement wake on LAN */
6556584Sgblack@eecs.umich.edu            regs.wcsr = reg;
6566584Sgblack@eecs.umich.edu            break;
6576584Sgblack@eecs.umich.edu
6586584Sgblack@eecs.umich.edu          case PCR:
6596597Sgblack@eecs.umich.edu            /* not going to implement pause control */
6606611Sgblack@eecs.umich.edu            regs.pcr = reg;
6616584Sgblack@eecs.umich.edu            break;
6626611Sgblack@eecs.umich.edu
6636611Sgblack@eecs.umich.edu          case RFCR:
6646611Sgblack@eecs.umich.edu            regs.rfcr = reg;
6655238Sgblack@eecs.umich.edu            DPRINTF(Ethernet, "Writing to RFCR, RFADDR is %#x\n", reg & RFCR_RFADDR);
6666611Sgblack@eecs.umich.edu
6676584Sgblack@eecs.umich.edu            rxFilterEnable = (reg & RFCR_RFEN) ? true : false;
6686611Sgblack@eecs.umich.edu
6696611Sgblack@eecs.umich.edu            acceptBroadcast = (reg & RFCR_AAB) ? true : false;
6706611Sgblack@eecs.umich.edu
6716584Sgblack@eecs.umich.edu            acceptMulticast = (reg & RFCR_AAM) ? true : false;
6725238Sgblack@eecs.umich.edu
6736611Sgblack@eecs.umich.edu            acceptUnicast = (reg & RFCR_AAU) ? true : false;
6746584Sgblack@eecs.umich.edu
6756611Sgblack@eecs.umich.edu            acceptPerfect = (reg & RFCR_APM) ? true : false;
6766707Svince@csl.cornell.edu
6776611Sgblack@eecs.umich.edu            acceptArp = (reg & RFCR_AARP) ? true : false;
6786707Svince@csl.cornell.edu
6796584Sgblack@eecs.umich.edu            if (reg & RFCR_APAT) ;
6805238Sgblack@eecs.umich.edu//                panic("RFCR_APAT not implemented!\n");
6816584Sgblack@eecs.umich.edu
6826584Sgblack@eecs.umich.edu            if (reg & RFCR_MHEN || reg & RFCR_UHEN)
6836584Sgblack@eecs.umich.edu                panic("hash filtering not implemented!\n");
6846584Sgblack@eecs.umich.edu
6855238Sgblack@eecs.umich.edu            if (reg & RFCR_ULM)
6866584Sgblack@eecs.umich.edu                panic("RFCR_ULM not implemented!\n");
6876584Sgblack@eecs.umich.edu
6886597Sgblack@eecs.umich.edu            break;
6896584Sgblack@eecs.umich.edu
6905238Sgblack@eecs.umich.edu          case RFDR:
6916584Sgblack@eecs.umich.edu            panic("the driver never writes to RFDR, something is wrong!\n");
6925020Sgblack@eecs.umich.edu
6936584Sgblack@eecs.umich.edu          case BRAR:
6946584Sgblack@eecs.umich.edu            panic("the driver never uses BRAR, something is wrong!\n");
6956584Sgblack@eecs.umich.edu
6966611Sgblack@eecs.umich.edu          case BRDR:
6976611Sgblack@eecs.umich.edu            panic("the driver never uses BRDR, something is wrong!\n");
6986584Sgblack@eecs.umich.edu
6996584Sgblack@eecs.umich.edu          case SRR:
7006584Sgblack@eecs.umich.edu            panic("SRR is read only register!\n");
7016584Sgblack@eecs.umich.edu
7026584Sgblack@eecs.umich.edu          case MIBC:
7036584Sgblack@eecs.umich.edu            panic("the driver never uses MIBC, something is wrong!\n");
7046584Sgblack@eecs.umich.edu
7056696Svince@csl.cornell.edu          case VRCR:
7066584Sgblack@eecs.umich.edu            regs.vrcr = reg;
7076584Sgblack@eecs.umich.edu            break;
7086584Sgblack@eecs.umich.edu
7096584Sgblack@eecs.umich.edu          case VTCR:
7106705Svince@csl.cornell.edu            regs.vtcr = reg;
7116584Sgblack@eecs.umich.edu            break;
7126706Svince@csl.cornell.edu
7136696Svince@csl.cornell.edu          case VDR:
7146584Sgblack@eecs.umich.edu            panic("the driver never uses VDR, something is wrong!\n");
7156584Sgblack@eecs.umich.edu            break;
7166584Sgblack@eecs.umich.edu
7176584Sgblack@eecs.umich.edu          case CCSR:
7186584Sgblack@eecs.umich.edu            /* not going to implement clockrun stuff */
7196584Sgblack@eecs.umich.edu            regs.ccsr = reg;
7206584Sgblack@eecs.umich.edu            break;
7216584Sgblack@eecs.umich.edu
7226584Sgblack@eecs.umich.edu          case TBICR:
7235020Sgblack@eecs.umich.edu            regs.tbicr = reg;
7244727Sgblack@eecs.umich.edu            if (reg & TBICR_MR_LOOPBACK)
7254727Sgblack@eecs.umich.edu                panic("TBICR_MR_LOOPBACK never used, something wrong!\n");
7264727Sgblack@eecs.umich.edu
7274727Sgblack@eecs.umich.edu            if (reg & TBICR_MR_AN_ENABLE) {
7284727Sgblack@eecs.umich.edu                regs.tanlpar = regs.tanar;
7294727Sgblack@eecs.umich.edu                regs.tbisr |= (TBISR_MR_AN_COMPLETE | TBISR_MR_LINK_STATUS);
7304727Sgblack@eecs.umich.edu            }
7314727Sgblack@eecs.umich.edu
7324727Sgblack@eecs.umich.edu#if 0
7334727Sgblack@eecs.umich.edu            if (reg & TBICR_MR_RESTART_AN) ;
7344727Sgblack@eecs.umich.edu#endif
7354727Sgblack@eecs.umich.edu
7364727Sgblack@eecs.umich.edu            break;
7374727Sgblack@eecs.umich.edu
7384727Sgblack@eecs.umich.edu          case TBISR:
7394727Sgblack@eecs.umich.edu            panic("TBISR is read only register!\n");
7404727Sgblack@eecs.umich.edu
7414727Sgblack@eecs.umich.edu          case TANAR:
7424727Sgblack@eecs.umich.edu            regs.tanar = reg;
7434727Sgblack@eecs.umich.edu            if (reg & TANAR_PS2)
7444760Sgblack@eecs.umich.edu                panic("this isn't used in driver, something wrong!\n");
7454760Sgblack@eecs.umich.edu
7464760Sgblack@eecs.umich.edu            if (reg & TANAR_PS1)
7474760Sgblack@eecs.umich.edu                panic("this isn't used in driver, something wrong!\n");
7484760Sgblack@eecs.umich.edu            break;
7494760Sgblack@eecs.umich.edu
7504760Sgblack@eecs.umich.edu          case TANLPAR:
7514760Sgblack@eecs.umich.edu            panic("this should only be written to by the fake phy!\n");
7524760Sgblack@eecs.umich.edu
7534760Sgblack@eecs.umich.edu          case TANER:
7544760Sgblack@eecs.umich.edu            panic("TANER is read only register!\n");
7554760Sgblack@eecs.umich.edu
7564760Sgblack@eecs.umich.edu          case TESR:
7574760Sgblack@eecs.umich.edu            regs.tesr = reg;
7584760Sgblack@eecs.umich.edu            break;
7594760Sgblack@eecs.umich.edu
7604760Sgblack@eecs.umich.edu          default:
7614760Sgblack@eecs.umich.edu            panic("thought i covered all the register, what is this? addr=%#x",
7624760Sgblack@eecs.umich.edu                  daddr);
7634760Sgblack@eecs.umich.edu        }
7644276Sgblack@eecs.umich.edu    } else
7654276Sgblack@eecs.umich.edu        panic("Invalid Request Size");
7664712Sgblack@eecs.umich.edu
7674712Sgblack@eecs.umich.edu    return No_Fault;
7685659Sgblack@eecs.umich.edu}
7695659Sgblack@eecs.umich.edu
7707072Sgblack@eecs.umich.eduvoid
7717072Sgblack@eecs.umich.eduEtherDev::devIntrPost(uint32_t interrupts)
7725659Sgblack@eecs.umich.edu{
7735659Sgblack@eecs.umich.edu    DPRINTF(Ethernet, "interrupt posted intr=%#x isr=%#x imr=%#x\n",
7745659Sgblack@eecs.umich.edu            interrupts, regs.isr, regs.imr);
7755659Sgblack@eecs.umich.edu
7765659Sgblack@eecs.umich.edu    bool delay = false;
7775240Sgblack@eecs.umich.edu
7786480Sgblack@eecs.umich.edu    if (interrupts & ISR_RESERVE)
7796480Sgblack@eecs.umich.edu        panic("Cannot set a reserved interrupt");
7806611Sgblack@eecs.umich.edu
7814276Sgblack@eecs.umich.edu    if (interrupts & ISR_TXRCMP)
7824276Sgblack@eecs.umich.edu        regs.isr |= ISR_TXRCMP;
7834712Sgblack@eecs.umich.edu
7844712Sgblack@eecs.umich.edu    if (interrupts & ISR_RXRCMP)
7854712Sgblack@eecs.umich.edu        regs.isr |= ISR_RXRCMP;
7865240Sgblack@eecs.umich.edu
7875977Sgblack@eecs.umich.edu//ISR_DPERR  not implemented
7886481Sgblack@eecs.umich.edu//ISR_SSERR not implemented
7896611Sgblack@eecs.umich.edu//ISR_RMABT not implemented
7906611Sgblack@eecs.umich.edu//ISR_RXSOVR not implemented
7916611Sgblack@eecs.umich.edu//ISR_HIBINT not implemented
7926611Sgblack@eecs.umich.edu//ISR_PHY not implemented
7935923Sgblack@eecs.umich.edu//ISR_PME not implemented
7946611Sgblack@eecs.umich.edu
7956611Sgblack@eecs.umich.edu    if (interrupts & ISR_SWI)
7966611Sgblack@eecs.umich.edu        regs.isr |= ISR_SWI;
7976611Sgblack@eecs.umich.edu
7985238Sgblack@eecs.umich.edu//ISR_MIB not implemented
7995238Sgblack@eecs.umich.edu//ISR_TXURN not implemented
8006611Sgblack@eecs.umich.edu
8016611Sgblack@eecs.umich.edu    if (interrupts & ISR_TXIDLE)
8026611Sgblack@eecs.umich.edu        regs.isr |= ISR_TXIDLE;
8036611Sgblack@eecs.umich.edu
8046611Sgblack@eecs.umich.edu    if (interrupts & ISR_TXERR)
8056611Sgblack@eecs.umich.edu        regs.isr |= ISR_TXERR;
8066611Sgblack@eecs.umich.edu
8076611Sgblack@eecs.umich.edu    if (interrupts & ISR_TXDESC)
8086611Sgblack@eecs.umich.edu        regs.isr |= ISR_TXDESC;
8095238Sgblack@eecs.umich.edu
8105238Sgblack@eecs.umich.edu    if (interrupts & ISR_TXOK) {
8114724Sgblack@eecs.umich.edu        regs.isr |= ISR_TXOK;
8124276Sgblack@eecs.umich.edu        delay = true;
8136593Sgblack@eecs.umich.edu    }
8146593Sgblack@eecs.umich.edu
8156593Sgblack@eecs.umich.edu    if (interrupts & ISR_RXORN)
8166593Sgblack@eecs.umich.edu        regs.isr |= ISR_RXORN;
8176593Sgblack@eecs.umich.edu
8186593Sgblack@eecs.umich.edu    if (interrupts & ISR_RXIDLE)
8196593Sgblack@eecs.umich.edu        regs.isr |= ISR_RXIDLE;
8206593Sgblack@eecs.umich.edu
8216593Sgblack@eecs.umich.edu//ISR_RXEARLY not implemented
8226593Sgblack@eecs.umich.edu
8236593Sgblack@eecs.umich.edu    if (interrupts & ISR_RXERR)
8246593Sgblack@eecs.umich.edu        regs.isr |= ISR_RXERR;
8256593Sgblack@eecs.umich.edu
8266593Sgblack@eecs.umich.edu    if (interrupts & ISR_RXOK) {
8276593Sgblack@eecs.umich.edu        delay = true;
8286593Sgblack@eecs.umich.edu        regs.isr |= ISR_RXOK;
8296611Sgblack@eecs.umich.edu    }
8306611Sgblack@eecs.umich.edu
8316611Sgblack@eecs.umich.edu    if ((regs.isr & regs.imr)) {
8326611Sgblack@eecs.umich.edu        Tick when = curTick;
8336611Sgblack@eecs.umich.edu        if (delay)
8345240Sgblack@eecs.umich.edu            when += intrDelay;
8355240Sgblack@eecs.umich.edu        cpuIntrPost(when);
8365240Sgblack@eecs.umich.edu    }
8375240Sgblack@eecs.umich.edu}
8385240Sgblack@eecs.umich.edu
8395240Sgblack@eecs.umich.eduvoid
8405240Sgblack@eecs.umich.eduEtherDev::devIntrClear(uint32_t interrupts)
8415240Sgblack@eecs.umich.edu{
8425240Sgblack@eecs.umich.edu    DPRINTF(Ethernet, "interrupt cleared intr=%x isr=%x imr=%x\n",
8435240Sgblack@eecs.umich.edu            interrupts, regs.isr, regs.imr);
8446593Sgblack@eecs.umich.edu
8456593Sgblack@eecs.umich.edu    if (interrupts & ISR_RESERVE)
8466593Sgblack@eecs.umich.edu        panic("Cannot clear a reserved interrupt");
8476593Sgblack@eecs.umich.edu
8486593Sgblack@eecs.umich.edu    if (interrupts & ISR_TXRCMP)
8496593Sgblack@eecs.umich.edu        regs.isr &= ~ISR_TXRCMP;
8506593Sgblack@eecs.umich.edu
8516593Sgblack@eecs.umich.edu    if (interrupts & ISR_RXRCMP)
8525238Sgblack@eecs.umich.edu        regs.isr &= ~ISR_RXRCMP;
8536576Sgblack@eecs.umich.edu
8546576Sgblack@eecs.umich.edu//ISR_DPERR  not implemented
8556576Sgblack@eecs.umich.edu//ISR_SSERR not implemented
8566576Sgblack@eecs.umich.edu//ISR_RMABT not implemented
8576576Sgblack@eecs.umich.edu//ISR_RXSOVR not implemented
8586576Sgblack@eecs.umich.edu//ISR_HIBINT not implemented
8596576Sgblack@eecs.umich.edu//ISR_PHY not implemented
8606576Sgblack@eecs.umich.edu//ISR_PME not implemented
8616576Sgblack@eecs.umich.edu
8626576Sgblack@eecs.umich.edu    if (interrupts & ISR_SWI)
8636576Sgblack@eecs.umich.edu        regs.isr &= ~ISR_SWI;
8646576Sgblack@eecs.umich.edu
8656576Sgblack@eecs.umich.edu//ISR_MIB not implemented
8665238Sgblack@eecs.umich.edu//ISR_TXURN not implemented
8676576Sgblack@eecs.umich.edu
8686576Sgblack@eecs.umich.edu    if (interrupts & ISR_TXIDLE)
8695238Sgblack@eecs.umich.edu        regs.isr &= ~ISR_TXIDLE;
8706576Sgblack@eecs.umich.edu
8716576Sgblack@eecs.umich.edu    if (interrupts & ISR_TXERR)
8726576Sgblack@eecs.umich.edu        regs.isr &= ~ISR_TXERR;
8736604Sgblack@eecs.umich.edu
8746610Sgblack@eecs.umich.edu    if (interrupts & ISR_TXDESC)
8756591Sgblack@eecs.umich.edu        regs.isr &= ~ISR_TXDESC;
8766591Sgblack@eecs.umich.edu
8776597Sgblack@eecs.umich.edu    if (interrupts & ISR_TXOK)
8786576Sgblack@eecs.umich.edu        regs.isr &= ~ISR_TXOK;
8796576Sgblack@eecs.umich.edu
8806576Sgblack@eecs.umich.edu    if (interrupts & ISR_RXORN)
8816604Sgblack@eecs.umich.edu        regs.isr &= ~ISR_RXORN;
8826576Sgblack@eecs.umich.edu
8836576Sgblack@eecs.umich.edu    if (interrupts & ISR_RXIDLE)
8846576Sgblack@eecs.umich.edu        regs.isr &= ~ISR_RXIDLE;
8856576Sgblack@eecs.umich.edu
8866604Sgblack@eecs.umich.edu//ISR_RXEARLY not implemented
8876591Sgblack@eecs.umich.edu
8886591Sgblack@eecs.umich.edu    if (interrupts & ISR_RXERR)
8896597Sgblack@eecs.umich.edu        regs.isr &= ~ISR_RXERR;
8906576Sgblack@eecs.umich.edu
8916576Sgblack@eecs.umich.edu    if (interrupts & ISR_RXOK)
8926576Sgblack@eecs.umich.edu        regs.isr &= ~ISR_RXOK;
8936576Sgblack@eecs.umich.edu
8946604Sgblack@eecs.umich.edu    if (!(regs.isr & regs.imr))
8956576Sgblack@eecs.umich.edu        cpuIntrClear();
8966576Sgblack@eecs.umich.edu}
8976576Sgblack@eecs.umich.edu
8986576Sgblack@eecs.umich.eduvoid
8995238Sgblack@eecs.umich.eduEtherDev::devIntrChangeMask()
9006576Sgblack@eecs.umich.edu{
9016576Sgblack@eecs.umich.edu    DPRINTF(Ethernet, "interrupt mask changed\n");
9026576Sgblack@eecs.umich.edu
9036576Sgblack@eecs.umich.edu    if (regs.isr & regs.imr)
9045020Sgblack@eecs.umich.edu        cpuIntrPost(curTick);
9056593Sgblack@eecs.umich.edu    else
9066593Sgblack@eecs.umich.edu        cpuIntrClear();
9076593Sgblack@eecs.umich.edu}
9086593Sgblack@eecs.umich.edu
9096593Sgblack@eecs.umich.eduvoid
9106593Sgblack@eecs.umich.eduEtherDev::cpuIntrPost(Tick when)
9116593Sgblack@eecs.umich.edu{
9126593Sgblack@eecs.umich.edu    if (when > intrTick && intrTick != 0)
9136593Sgblack@eecs.umich.edu        return;
9146593Sgblack@eecs.umich.edu
9156593Sgblack@eecs.umich.edu    intrTick = when;
9166593Sgblack@eecs.umich.edu
9176593Sgblack@eecs.umich.edu    if (intrEvent) {
9186608Sgblack@eecs.umich.edu        intrEvent->squash();
9196593Sgblack@eecs.umich.edu        intrEvent = 0;
9206593Sgblack@eecs.umich.edu    }
9216593Sgblack@eecs.umich.edu
9226593Sgblack@eecs.umich.edu    if (when < curTick) {
9236593Sgblack@eecs.umich.edu        cpuInterrupt();
9246593Sgblack@eecs.umich.edu    } else {
9256593Sgblack@eecs.umich.edu        intrEvent = new IntrEvent(this, true);
9266593Sgblack@eecs.umich.edu        intrEvent->schedule(intrTick);
9276593Sgblack@eecs.umich.edu    }
9286593Sgblack@eecs.umich.edu}
9296593Sgblack@eecs.umich.edu
9306593Sgblack@eecs.umich.eduvoid
9316593Sgblack@eecs.umich.eduEtherDev::cpuInterrupt()
9326593Sgblack@eecs.umich.edu{
9336593Sgblack@eecs.umich.edu    // Don't send an interrupt if there's already one
9346593Sgblack@eecs.umich.edu    if (cpuPendingIntr)
9356607Sgblack@eecs.umich.edu        return;
9366593Sgblack@eecs.umich.edu
9376593Sgblack@eecs.umich.edu    // Don't send an interrupt if it's supposed to be delayed
9386593Sgblack@eecs.umich.edu    if (intrTick > curTick)
9395020Sgblack@eecs.umich.edu        return;
9406576Sgblack@eecs.umich.edu
9416576Sgblack@eecs.umich.edu    // Whether or not there's a pending interrupt, we don't care about
9426576Sgblack@eecs.umich.edu    // it anymore
9436580Sgblack@eecs.umich.edu    intrEvent = 0;
9446580Sgblack@eecs.umich.edu    intrTick = 0;
9456576Sgblack@eecs.umich.edu
9466576Sgblack@eecs.umich.edu    // Send interrupt
9476576Sgblack@eecs.umich.edu    cpuPendingIntr = true;
9486576Sgblack@eecs.umich.edu    /** @todo rework the intctrl to be tsunami ok */
9496576Sgblack@eecs.umich.edu    //intctrl->post(TheISA::INTLEVEL_IRQ1, TheISA::INTINDEX_ETHERNET);
9506576Sgblack@eecs.umich.edu    tsunami->cchip->postDRIR(configData->config.hdr.pci0.interruptLine);
9516576Sgblack@eecs.umich.edu}
9526576Sgblack@eecs.umich.edu
9536576Sgblack@eecs.umich.eduvoid
9546580Sgblack@eecs.umich.eduEtherDev::cpuIntrClear()
9556580Sgblack@eecs.umich.edu{
9566576Sgblack@eecs.umich.edu    if (cpuPendingIntr) {
9576576Sgblack@eecs.umich.edu        cpuPendingIntr = false;
9586576Sgblack@eecs.umich.edu        /** @todo rework the intctrl to be tsunami ok */
9596576Sgblack@eecs.umich.edu        //intctrl->clear(TheISA::INTLEVEL_IRQ1, TheISA::INTINDEX_ETHERNET);
9606576Sgblack@eecs.umich.edu        tsunami->cchip->clearDRIR(configData->config.hdr.pci0.interruptLine);
9616576Sgblack@eecs.umich.edu    }
9626576Sgblack@eecs.umich.edu}
9636576Sgblack@eecs.umich.edu
9645020Sgblack@eecs.umich.edubool
9656588Sgblack@eecs.umich.eduEtherDev::cpuIntrPending() const
9666588Sgblack@eecs.umich.edu{ return cpuPendingIntr; }
9676588Sgblack@eecs.umich.edu
9686588Sgblack@eecs.umich.eduvoid
9696588Sgblack@eecs.umich.eduEtherDev::txReset()
9706588Sgblack@eecs.umich.edu{
9716588Sgblack@eecs.umich.edu
9726588Sgblack@eecs.umich.edu    DPRINTF(Ethernet, "transmit reset\n");
9736588Sgblack@eecs.umich.edu
9746588Sgblack@eecs.umich.edu    CTDD = false;
9756588Sgblack@eecs.umich.edu    txFifoCnt = 0;
9766588Sgblack@eecs.umich.edu    txFifoAvail = MAX_TX_FIFO_SIZE;
9776588Sgblack@eecs.umich.edu    txHalt = false;
9786588Sgblack@eecs.umich.edu    txFragPtr = 0;
9796588Sgblack@eecs.umich.edu    assert(txDescCnt == 0);
9806588Sgblack@eecs.umich.edu    txFifo.clear();
9816588Sgblack@eecs.umich.edu    regs.command &= ~CR_TXE;
9826588Sgblack@eecs.umich.edu    txState = txIdle;
9836588Sgblack@eecs.umich.edu    assert(txDmaState == dmaIdle);
9846588Sgblack@eecs.umich.edu}
9856588Sgblack@eecs.umich.edu
9866588Sgblack@eecs.umich.eduvoid
9876588Sgblack@eecs.umich.eduEtherDev::rxReset()
9886588Sgblack@eecs.umich.edu{
9896588Sgblack@eecs.umich.edu    DPRINTF(Ethernet, "receive reset\n");
9906606Sgblack@eecs.umich.edu
9916588Sgblack@eecs.umich.edu    CRDD = false;
9926588Sgblack@eecs.umich.edu    assert(rxPktBytes == 0);
9936588Sgblack@eecs.umich.edu    rxFifoCnt = 0;
9946588Sgblack@eecs.umich.edu    rxHalt = false;
9956606Sgblack@eecs.umich.edu    rxFragPtr = 0;
9966588Sgblack@eecs.umich.edu    assert(rxDescCnt == 0);
9976588Sgblack@eecs.umich.edu    assert(rxDmaState == dmaIdle);
9986588Sgblack@eecs.umich.edu    rxFifo.clear();
9995022Sgblack@eecs.umich.edu    regs.command &= ~CR_RXE;
10006576Sgblack@eecs.umich.edu    rxState = rxIdle;
10016576Sgblack@eecs.umich.edu}
10026576Sgblack@eecs.umich.edu
10036580Sgblack@eecs.umich.eduvoid
10046580Sgblack@eecs.umich.eduEtherDev::rxDmaReadCopy()
10056576Sgblack@eecs.umich.edu{
10066576Sgblack@eecs.umich.edu    assert(rxDmaState == dmaReading);
10076576Sgblack@eecs.umich.edu
10086576Sgblack@eecs.umich.edu    memcpy(rxDmaData, physmem->dma_addr(rxDmaAddr, rxDmaLen), rxDmaLen);
10096576Sgblack@eecs.umich.edu    rxDmaState = dmaIdle;
10106576Sgblack@eecs.umich.edu
10116576Sgblack@eecs.umich.edu    DPRINTF(EthernetDMA, "rx dma read  paddr=%#x len=%d\n",
10126576Sgblack@eecs.umich.edu            rxDmaAddr, rxDmaLen);
10136576Sgblack@eecs.umich.edu    DDUMP(EthernetDMA, rxDmaData, rxDmaLen);
10146580Sgblack@eecs.umich.edu}
10156580Sgblack@eecs.umich.edu
10166576Sgblack@eecs.umich.edubool
10176576Sgblack@eecs.umich.eduEtherDev::doRxDmaRead()
10186576Sgblack@eecs.umich.edu{
10196576Sgblack@eecs.umich.edu    assert(rxDmaState == dmaIdle || rxDmaState == dmaReadWaiting);
10206576Sgblack@eecs.umich.edu    rxDmaState = dmaReading;
10216576Sgblack@eecs.umich.edu
10226576Sgblack@eecs.umich.edu    if (dmaInterface && !rxDmaFree) {
10236576Sgblack@eecs.umich.edu        if (dmaInterface->busy())
10245020Sgblack@eecs.umich.edu            rxDmaState = dmaReadWaiting;
10256586Sgblack@eecs.umich.edu        else
10266586Sgblack@eecs.umich.edu            dmaInterface->doDMA(Read, rxDmaAddr, rxDmaLen, curTick,
10276586Sgblack@eecs.umich.edu                                &rxDmaReadEvent);
10286586Sgblack@eecs.umich.edu        return true;
10296586Sgblack@eecs.umich.edu    }
10306586Sgblack@eecs.umich.edu
10316586Sgblack@eecs.umich.edu    if (dmaReadDelay == 0 && dmaReadFactor == 0) {
10326586Sgblack@eecs.umich.edu        rxDmaReadCopy();
10336586Sgblack@eecs.umich.edu        return false;
10346595Sgblack@eecs.umich.edu    }
10356586Sgblack@eecs.umich.edu
10366586Sgblack@eecs.umich.edu    Tick factor = ((rxDmaLen + ULL(63)) >> ULL(6)) * dmaReadFactor;
10376586Sgblack@eecs.umich.edu    Tick start = curTick + dmaReadDelay + factor;
10386586Sgblack@eecs.umich.edu    rxDmaReadEvent.schedule(start);
10396586Sgblack@eecs.umich.edu    return true;
10406586Sgblack@eecs.umich.edu}
10416586Sgblack@eecs.umich.edu
10426586Sgblack@eecs.umich.eduvoid
10436586Sgblack@eecs.umich.eduEtherDev::rxDmaReadDone()
10446586Sgblack@eecs.umich.edu{
10456595Sgblack@eecs.umich.edu    assert(rxDmaState == dmaReading);
10466586Sgblack@eecs.umich.edu    rxDmaReadCopy();
10476586Sgblack@eecs.umich.edu
10486586Sgblack@eecs.umich.edu    // If the transmit state machine has a pending DMA, let it go first
10496586Sgblack@eecs.umich.edu    if (txDmaState == dmaReadWaiting || txDmaState == dmaWriteWaiting)
10506586Sgblack@eecs.umich.edu        txKick();
10516586Sgblack@eecs.umich.edu
10526586Sgblack@eecs.umich.edu    rxKick();
10536586Sgblack@eecs.umich.edu}
10545022Sgblack@eecs.umich.edu
10556576Sgblack@eecs.umich.eduvoid
10566576Sgblack@eecs.umich.eduEtherDev::rxDmaWriteCopy()
10576576Sgblack@eecs.umich.edu{
10586580Sgblack@eecs.umich.edu    assert(rxDmaState == dmaWriting);
10596580Sgblack@eecs.umich.edu
10606580Sgblack@eecs.umich.edu    memcpy(physmem->dma_addr(rxDmaAddr, rxDmaLen), rxDmaData, rxDmaLen);
10616580Sgblack@eecs.umich.edu    rxDmaState = dmaIdle;
10626576Sgblack@eecs.umich.edu
10636576Sgblack@eecs.umich.edu    DPRINTF(EthernetDMA, "rx dma write paddr=%#x len=%d\n",
10646576Sgblack@eecs.umich.edu            rxDmaAddr, rxDmaLen);
10656576Sgblack@eecs.umich.edu    DDUMP(EthernetDMA, rxDmaData, rxDmaLen);
10666576Sgblack@eecs.umich.edu}
10676576Sgblack@eecs.umich.edu
10686576Sgblack@eecs.umich.edubool
10696580Sgblack@eecs.umich.eduEtherDev::doRxDmaWrite()
10706580Sgblack@eecs.umich.edu{
10716580Sgblack@eecs.umich.edu    assert(rxDmaState == dmaIdle || rxDmaState == dmaWriteWaiting);
10726580Sgblack@eecs.umich.edu    rxDmaState = dmaWriting;
10736576Sgblack@eecs.umich.edu
10746576Sgblack@eecs.umich.edu    if (dmaInterface && !rxDmaFree) {
10756576Sgblack@eecs.umich.edu        if (dmaInterface->busy())
10766576Sgblack@eecs.umich.edu            rxDmaState = dmaWriteWaiting;
10776576Sgblack@eecs.umich.edu        else
10786576Sgblack@eecs.umich.edu            dmaInterface->doDMA(WriteInvalidate, rxDmaAddr, rxDmaLen, curTick,
10795020Sgblack@eecs.umich.edu                                &rxDmaWriteEvent);
10804276Sgblack@eecs.umich.edu        return true;
10814276Sgblack@eecs.umich.edu    }
10824276Sgblack@eecs.umich.edu
10834276Sgblack@eecs.umich.edu    if (dmaWriteDelay == 0 && dmaWriteFactor == 0) {
10844276Sgblack@eecs.umich.edu        rxDmaWriteCopy();
10854276Sgblack@eecs.umich.edu        return false;
10864276Sgblack@eecs.umich.edu    }
1087
1088    Tick factor = ((rxDmaLen + ULL(63)) >> ULL(6)) * dmaWriteFactor;
1089    Tick start = curTick + dmaWriteDelay + factor;
1090    rxDmaWriteEvent.schedule(start);
1091    return true;
1092}
1093
1094void
1095EtherDev::rxDmaWriteDone()
1096{
1097    assert(rxDmaState == dmaWriting);
1098    rxDmaWriteCopy();
1099
1100    // If the transmit state machine has a pending DMA, let it go first
1101    if (txDmaState == dmaReadWaiting || txDmaState == dmaWriteWaiting)
1102        txKick();
1103
1104    rxKick();
1105}
1106
1107void
1108EtherDev::rxKick()
1109{
1110    DPRINTF(Ethernet, "receive kick state=%s (rxBuf.size=%d)\n",
1111            NsRxStateStrings[rxState], rxFifo.size());
1112
1113    if (rxKickTick > curTick) {
1114        DPRINTF(Ethernet, "receive kick exiting, can't run till %d\n",
1115                rxKickTick);
1116        return;
1117    }
1118
1119  next:
1120    switch(rxDmaState) {
1121      case dmaReadWaiting:
1122        if (doRxDmaRead())
1123            goto exit;
1124        break;
1125      case dmaWriteWaiting:
1126        if (doRxDmaWrite())
1127            goto exit;
1128        break;
1129      default:
1130        break;
1131    }
1132
1133    switch (rxState) {
1134      case rxIdle:
1135        if (!regs.command & CR_RXE) {
1136            DPRINTF(Ethernet, "Receive Disabled! Nothing to do.\n");
1137            goto exit;
1138        }
1139
1140        if (CRDD) {
1141            rxState = rxDescRefr;
1142
1143            rxDmaAddr = regs.rxdp & 0x3fffffff;
1144            rxDmaData = &rxDescCache + offsetof(ns_desc, link);
1145            rxDmaLen = sizeof(rxDescCache.link);
1146            rxDmaFree = dmaDescFree;
1147
1148            if (doRxDmaRead())
1149                goto exit;
1150        } else {
1151            rxState = rxDescRead;
1152
1153            rxDmaAddr = regs.rxdp & 0x3fffffff;
1154            rxDmaData = &rxDescCache;
1155            rxDmaLen = sizeof(ns_desc);
1156            rxDmaFree = dmaDescFree;
1157
1158            if (doRxDmaRead())
1159                goto exit;
1160        }
1161        break;
1162
1163      case rxDescRefr:
1164        if (rxDmaState != dmaIdle)
1165            goto exit;
1166
1167        rxState = rxAdvance;
1168        break;
1169
1170     case rxDescRead:
1171        if (rxDmaState != dmaIdle)
1172            goto exit;
1173
1174        if (rxDescCache.cmdsts & CMDSTS_OWN) {
1175            rxState = rxIdle;
1176        } else {
1177            rxState = rxFifoBlock;
1178            rxFragPtr = rxDescCache.bufptr;
1179            rxDescCnt = rxDescCache.cmdsts & CMDSTS_LEN_MASK;
1180        }
1181        break;
1182
1183      case rxFifoBlock:
1184        if (!rxPacket) {
1185            /**
1186             * @todo in reality, we should be able to start processing
1187             * the packet as it arrives, and not have to wait for the
1188             * full packet ot be in the receive fifo.
1189             */
1190            if (rxFifo.empty())
1191                goto exit;
1192
1193            // If we don't have a packet, grab a new one from the fifo.
1194            rxPacket = rxFifo.front();
1195            rxPktBytes = rxPacket->length;
1196            rxPacketBufPtr = rxPacket->data;
1197
1198            // sanity check - i think the driver behaves like this
1199            assert(rxDescCnt >= rxPktBytes);
1200
1201            // Must clear the value before popping to decrement the
1202            // reference count
1203            rxFifo.front() = NULL;
1204            rxFifo.pop_front();
1205        }
1206
1207
1208        // dont' need the && rxDescCnt > 0 if driver sanity check above holds
1209        if (rxPktBytes > 0) {
1210            rxState = rxFragWrite;
1211            // don't need min<>(rxPktBytes,rxDescCnt) if above sanity check holds
1212            rxXferLen = rxPktBytes;
1213
1214            rxDmaAddr = rxFragPtr & 0x3fffffff;
1215            rxDmaData = rxPacketBufPtr;
1216            rxDmaLen = rxXferLen;
1217            rxDmaFree = dmaDataFree;
1218
1219            if (doRxDmaWrite())
1220                goto exit;
1221
1222        } else {
1223            rxState = rxDescWrite;
1224
1225            //if (rxPktBytes == 0) {  /* packet is done */
1226            assert(rxPktBytes == 0);
1227
1228            rxFifoCnt -= rxPacket->length;
1229            rxPacket = 0;
1230
1231            rxDescCache.cmdsts |= CMDSTS_OWN;
1232            rxDescCache.cmdsts &= ~CMDSTS_MORE;
1233            rxDescCache.cmdsts |= CMDSTS_OK;
1234            rxDescCache.cmdsts += rxPacket->length;   //i.e. set CMDSTS_SIZE
1235
1236#if 0
1237            /* all the driver uses these are for its own stats keeping
1238               which we don't care about, aren't necessary for functionality
1239               and doing this would just slow us down.  if they end up using
1240               this in a later version for functional purposes, just undef
1241            */
1242            if (rxFilterEnable) {
1243                rxDescCache.cmdsts &= ~CMDSTS_DEST_MASK;
1244                if (rxFifo.front()->IsUnicast())
1245                    rxDescCache.cmdsts |= CMDSTS_DEST_SELF;
1246                if (rxFifo.front()->IsMulticast())
1247                    rxDescCache.cmdsts |= CMDSTS_DEST_MULTI;
1248                if (rxFifo.front()->IsBroadcast())
1249                    rxDescCache.cmdsts |= CMDSTS_DEST_MASK;
1250            }
1251#endif
1252
1253            eth_header *eth = (eth_header *) rxPacket->data;
1254            if (eth->type == 0x800 && extstsEnable) {
1255                rxDescCache.extsts |= EXTSTS_IPPKT;
1256                if (!ipChecksum(rxPacket, false))
1257                    rxDescCache.extsts |= EXTSTS_IPERR;
1258                ip_header *ip = rxFifo.front()->getIpHdr();
1259
1260                if (ip->protocol == 6) {
1261                    rxDescCache.extsts |= EXTSTS_TCPPKT;
1262                    if (!tcpChecksum(rxPacket, false))
1263                        rxDescCache.extsts |= EXTSTS_TCPERR;
1264                } else if (ip->protocol == 17) {
1265                    rxDescCache.extsts |= EXTSTS_UDPPKT;
1266                    if (!udpChecksum(rxPacket, false))
1267                        rxDescCache.extsts |= EXTSTS_UDPERR;
1268                }
1269            }
1270
1271            /* the driver seems to always receive into desc buffers
1272               of size 1514, so you never have a pkt that is split
1273               into multiple descriptors on the receive side, so
1274               i don't implement that case, hence the assert above.
1275            */
1276
1277            rxDmaAddr = (regs.rxdp + offsetof(ns_desc, cmdsts)) & 0x3fffffff;
1278            rxDmaData = &(rxDescCache.cmdsts);
1279            rxDmaLen = sizeof(rxDescCache.cmdsts) + sizeof(rxDescCache.extsts);
1280            rxDmaFree = dmaDescFree;
1281
1282            if (doRxDmaWrite())
1283                goto exit;
1284        }
1285        break;
1286
1287      case rxFragWrite:
1288        if (rxDmaState != dmaIdle)
1289            goto exit;
1290
1291        rxPacketBufPtr += rxXferLen;
1292        rxFragPtr += rxXferLen;
1293        rxPktBytes -= rxXferLen;
1294
1295        rxState = rxFifoBlock;
1296        break;
1297
1298      case rxDescWrite:
1299        if (rxDmaState != dmaIdle)
1300            goto exit;
1301
1302        assert(rxDescCache.cmdsts & CMDSTS_OWN);
1303
1304        assert(rxPacket == 0);
1305        devIntrPost(ISR_RXOK);
1306
1307        if (rxDescCache.cmdsts & CMDSTS_INTR)
1308            devIntrPost(ISR_RXDESC);
1309
1310        if (rxHalt) {
1311            rxState = rxIdle;
1312            rxHalt = false;
1313        } else
1314            rxState = rxAdvance;
1315        break;
1316
1317      case rxAdvance:
1318        if (rxDescCache.link == 0) {
1319            rxState = rxIdle;
1320            return;
1321        } else {
1322            rxState = rxDescRead;
1323            regs.rxdp = rxDescCache.link;
1324            CRDD = false;
1325
1326            rxDmaAddr = regs.rxdp & 0x3fffffff;
1327            rxDmaData = &rxDescCache;
1328            rxDmaLen = sizeof(ns_desc);
1329            rxDmaFree = dmaDescFree;
1330
1331            if (doRxDmaRead())
1332                goto exit;
1333        }
1334        break;
1335
1336      default:
1337        panic("Invalid rxState!");
1338    }
1339
1340
1341    DPRINTF(Ethernet, "entering next rx state = %s\n",
1342            NsRxStateStrings[rxState]);
1343
1344    if (rxState == rxIdle) {
1345        regs.command &= ~CR_RXE;
1346        devIntrPost(ISR_RXIDLE);
1347        return;
1348    }
1349
1350    goto next;
1351
1352  exit:
1353    /**
1354     * @todo do we want to schedule a future kick?
1355     */
1356    DPRINTF(Ethernet, "rx state machine exited state=%s\n",
1357            NsRxStateStrings[rxState]);
1358}
1359
1360void
1361EtherDev::transmit()
1362{
1363    if (txFifo.empty()) {
1364        DPRINTF(Ethernet, "nothing to transmit\n");
1365        return;
1366    }
1367
1368   if (interface->sendPacket(txFifo.front())) {
1369        DPRINTF(Ethernet, "transmit packet\n");
1370        DDUMP(Ethernet, txFifo.front()->data, txFifo.front()->length);
1371        txBytes += txFifo.front()->length;
1372        txPackets++;
1373
1374        txFifoCnt -= (txFifo.front()->length - txPktXmitted);
1375        txPktXmitted = 0;
1376        txFifo.front() = NULL;
1377        txFifo.pop_front();
1378
1379        /* normally do a writeback of the descriptor here, and ONLY after that is
1380           done, send this interrupt.  but since our stuff never actually fails,
1381           just do this interrupt here, otherwise the code has to stray from this
1382           nice format.  besides, it's functionally the same.
1383        */
1384        devIntrPost(ISR_TXOK);
1385   }
1386
1387   if (!txFifo.empty() && !txEvent.scheduled()) {
1388       DPRINTF(Ethernet, "reschedule transmit\n");
1389       txEvent.schedule(curTick + 1000);
1390   }
1391}
1392
1393void
1394EtherDev::txDmaReadCopy()
1395{
1396    assert(txDmaState == dmaReading);
1397
1398    memcpy(txDmaData, physmem->dma_addr(txDmaAddr, txDmaLen), txDmaLen);
1399    txDmaState = dmaIdle;
1400
1401    DPRINTF(EthernetDMA, "tx dma read  paddr=%#x len=%d\n",
1402            txDmaAddr, txDmaLen);
1403    DDUMP(EthernetDMA, txDmaData, txDmaLen);
1404}
1405
1406bool
1407EtherDev::doTxDmaRead()
1408{
1409    assert(txDmaState == dmaIdle || txDmaState == dmaReadWaiting);
1410    txDmaState = dmaReading;
1411
1412    if (dmaInterface && !txDmaFree) {
1413        if (dmaInterface->busy())
1414            txDmaState = dmaReadWaiting;
1415        else
1416            dmaInterface->doDMA(Read, txDmaAddr, txDmaLen, curTick,
1417                                &txDmaReadEvent);
1418        return true;
1419    }
1420
1421    if (dmaReadDelay == 0 && dmaReadFactor == 0.0) {
1422        txDmaReadCopy();
1423        return false;
1424    }
1425
1426    Tick factor = ((txDmaLen + ULL(63)) >> ULL(6)) * dmaReadFactor;
1427    Tick start = curTick + dmaReadDelay + factor;
1428    txDmaReadEvent.schedule(start);
1429    return true;
1430}
1431
1432void
1433EtherDev::txDmaReadDone()
1434{
1435    assert(txDmaState == dmaReading);
1436    txDmaReadCopy();
1437
1438    // If the receive state machine  has a pending DMA, let it go first
1439    if (rxDmaState == dmaReadWaiting || rxDmaState == dmaWriteWaiting)
1440        rxKick();
1441
1442    txKick();
1443}
1444
1445void
1446EtherDev::txDmaWriteCopy()
1447{
1448    assert(txDmaState == dmaWriting);
1449
1450    memcpy(physmem->dma_addr(txDmaAddr, txDmaLen), txDmaData, txDmaLen);
1451    txDmaState = dmaIdle;
1452
1453    DPRINTF(EthernetDMA, "tx dma write paddr=%#x len=%d\n",
1454            txDmaAddr, txDmaLen);
1455    DDUMP(EthernetDMA, txDmaData, txDmaLen);
1456}
1457
1458bool
1459EtherDev::doTxDmaWrite()
1460{
1461    assert(txDmaState == dmaIdle || txDmaState == dmaWriteWaiting);
1462    txDmaState = dmaWriting;
1463
1464    if (dmaInterface && !txDmaFree) {
1465        if (dmaInterface->busy())
1466            txDmaState = dmaWriteWaiting;
1467        else
1468            dmaInterface->doDMA(WriteInvalidate, txDmaAddr, txDmaLen, curTick,
1469                                &txDmaWriteEvent);
1470        return true;
1471    }
1472
1473    if (dmaWriteDelay == 0 && dmaWriteFactor == 0.0) {
1474        txDmaWriteCopy();
1475        return false;
1476    }
1477
1478    Tick factor = ((txDmaLen + ULL(63)) >> ULL(6)) * dmaWriteFactor;
1479    Tick start = curTick + dmaWriteDelay + factor;
1480    txDmaWriteEvent.schedule(start);
1481    return true;
1482}
1483
1484void
1485EtherDev::txDmaWriteDone()
1486{
1487    assert(txDmaState == dmaWriting);
1488    txDmaWriteCopy();
1489
1490    // If the receive state machine  has a pending DMA, let it go first
1491    if (rxDmaState == dmaReadWaiting || rxDmaState == dmaWriteWaiting)
1492        rxKick();
1493
1494    txKick();
1495}
1496
1497void
1498EtherDev::txKick()
1499{
1500    DPRINTF(Ethernet, "transmit kick state=%s\n", NsTxStateStrings[txState]);
1501
1502    if (rxKickTick > curTick) {
1503        DPRINTF(Ethernet, "receive kick exiting, can't run till %d\n",
1504                rxKickTick);
1505
1506        return;
1507    }
1508
1509  next:
1510    switch(txDmaState) {
1511      case dmaReadWaiting:
1512        if (doTxDmaRead())
1513            goto exit;
1514        break;
1515      case dmaWriteWaiting:
1516        if (doTxDmaWrite())
1517            goto exit;
1518        break;
1519      default:
1520        break;
1521    }
1522
1523    switch (txState) {
1524      case txIdle:
1525        if (!regs.command & CR_TXE) {
1526            DPRINTF(Ethernet, "Transmit disabled.  Nothing to do.\n");
1527            goto exit;
1528        }
1529
1530        if (CTDD) {
1531            txState = txDescRefr;
1532
1533            txDmaAddr = txDescCache.link & 0x3fffffff;
1534            txDmaData = &txDescCache;
1535            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