ns_gige.cc revision 837
12292SN/A/*
22292SN/A * Copyright (c) 2003 The Regents of The University of Michigan
32292SN/A * All rights reserved.
42292SN/A *
52292SN/A * Redistribution and use in source and binary forms, with or without
62292SN/A * modification, are permitted provided that the following conditions are
72292SN/A * met: redistributions of source code must retain the above copyright
82292SN/A * notice, this list of conditions and the following disclaimer;
92292SN/A * redistributions in binary form must reproduce the above copyright
102292SN/A * notice, this list of conditions and the following disclaimer in the
112292SN/A * documentation and/or other materials provided with the distribution;
122292SN/A * neither the name of the copyright holders nor the names of its
132292SN/A * contributors may be used to endorse or promote products derived from
142292SN/A * this software without specific prior written permission.
152292SN/A *
162292SN/A * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
172292SN/A * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
182292SN/A * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
192292SN/A * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
202292SN/A * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
212292SN/A * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
222292SN/A * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
232292SN/A * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
242292SN/A * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
252292SN/A * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
262292SN/A * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
272689Sktlim@umich.edu */
282689Sktlim@umich.edu
292689Sktlim@umich.edu/* @file
302292SN/A * Device module for modelling the National Semiconductor
312292SN/A * DP83820 ethernet controller.  Does not support priority queueing
323326Sktlim@umich.edu */
332733Sktlim@umich.edu#include <cstdio>
342733Sktlim@umich.edu#include <deque>
352907Sktlim@umich.edu#include <string>
362292SN/A
372292SN/A#include "base/inet.hh"
382722Sktlim@umich.edu#include "cpu/exec_context.hh"
392669Sktlim@umich.edu#include "cpu/intr_control.hh"
402292SN/A#include "dev/dma.hh"
412790Sktlim@umich.edu#include "dev/ns_gige.hh"
422790Sktlim@umich.edu#include "dev/etherlink.hh"
432790Sktlim@umich.edu#include "mem/functional_mem/memory_control.hh"
442790Sktlim@umich.edu#include "mem/functional_mem/physical_memory.hh"
452669Sktlim@umich.edu#include "sim/builder.hh"
462678Sktlim@umich.edu#include "sim/host.hh"
472678Sktlim@umich.edu#include "sim/sim_stats.hh"
482678Sktlim@umich.edu#include "targetarch/vtophys.hh"
492292SN/A
502678Sktlim@umich.eduusing namespace std;
512292SN/A
522292SN/A///////////////////////////////////////////////////////////////////////
532669Sktlim@umich.edu//
542292SN/A// EtherDev PCI Device
552678Sktlim@umich.edu//
562292SN/AEtherDev::EtherDev(const string &_name, DmaEngine *de, bool use_interface,
572678Sktlim@umich.edu                   IntrControl *i, MemoryController *mmu, PhysicalMemory *pmem,
582678Sktlim@umich.edu                   PCIConfigAll *cf, PciConfigData *cd, Tsunami *t, uint32_t bus,
592678Sktlim@umich.edu                   uint32_t dev, uint32_t func, bool rx_filter,
604319Sktlim@umich.edu                   const int eaddr[6], Tick tx_delay, Tick rx_delay, Addr addr,
614319Sktlim@umich.edu                   Addr mask)
624319Sktlim@umich.edu    : PciDev(_name, mmu, cf, cd, bus, dev, func), tsunami(t),
634319Sktlim@umich.edu      addr(addr), mask(mask), txPacketLen(0),
644319Sktlim@umich.edu      txPacketBufPtr(NULL), rxPacketBufPtr(NULL), rxDescBufPtr(NULL),
652678Sktlim@umich.edu      fragLen(0), rxCopied(0), txState(txIdle), CTDD(false), txFifoCnt(0),
662678Sktlim@umich.edu      txFifoAvail(MAX_TX_FIFO_SIZE), txHalt(false), txPacketFlag(false),
672292SN/A      txFragPtr(0), txDescCnt(0), rxState(rxIdle), CRDD(false),
682678Sktlim@umich.edu      rxPktBytes(0), rxFifoCnt(0), rxHalt(false), rxPacketFlag(false),
692678Sktlim@umich.edu      rxFragPtr(0), rxDescCnt(0), extstsEnable(false), maxTxBurst(0),
705336Shines@cs.fsu.edu      maxRxBurst(0), physmem(pmem),
712678Sktlim@umich.edu      rxDescDoneCB(this), rxDoneCB(this), txDescDoneCB(this), txDoneCB(this),
724873Sstever@eecs.umich.edu      dma(de), readRequest(use_interface), writeRequest(use_interface),
732678Sktlim@umich.edu      readDescRequest(use_interface), writeDescRequest(use_interface),
742292SN/A      interface(NULL), intctrl(i), txDelay(tx_delay), rxDelay(rx_delay),
752678Sktlim@umich.edu      txEvent(this), cpuPendingIntr(false), rxFilterEnable(rx_filter),
762678Sktlim@umich.edu      acceptBroadcast(false), acceptMulticast(false), acceptUnicast(false),
772678Sktlim@umich.edu      acceptPerfect(false), acceptArp(false)
782678Sktlim@umich.edu{
792678Sktlim@umich.edu    tsunami->ethernet = this;
802678Sktlim@umich.edu
812678Sktlim@umich.edu    memset(&regs, 0, sizeof(regs));
822698Sktlim@umich.edu    regsReset();
832344SN/A    regs.perfectMatch[0] = eaddr[0];
842678Sktlim@umich.edu    regs.perfectMatch[1] = eaddr[1];
852678Sktlim@umich.edu    regs.perfectMatch[2] = eaddr[2];
864986Ssaidi@eecs.umich.edu    regs.perfectMatch[3] = eaddr[3];
874986Ssaidi@eecs.umich.edu    regs.perfectMatch[4] = eaddr[4];
882678Sktlim@umich.edu    regs.perfectMatch[5] = eaddr[5];
892820Sktlim@umich.edu
902678Sktlim@umich.edu}
912678Sktlim@umich.edu
922678Sktlim@umich.eduEtherDev::~EtherDev()
932678Sktlim@umich.edu{}
942678Sktlim@umich.edu
952678Sktlim@umich.eduvoid
962678Sktlim@umich.eduEtherDev::regStats()
972678Sktlim@umich.edu{
982344SN/A    txBytes
992307SN/A        .name(name() + ".txBytes")
1002678Sktlim@umich.edu        .desc("Bytes Transmitted")
1014032Sktlim@umich.edu        .prereq(txBytes)
1022678Sktlim@umich.edu        ;
1032292SN/A
1042292SN/A    rxBytes
1052292SN/A        .name(name() + ".rxBytes")
1062292SN/A        .desc("Bytes Received")
1072678Sktlim@umich.edu        .prereq(rxBytes)
1082678Sktlim@umich.edu        ;
1092292SN/A
1102292SN/A    txPackets
1112292SN/A        .name(name() + ".txPackets")
1122292SN/A        .desc("Number of Packets Transmitted")
1132292SN/A        .prereq(txBytes)
1142292SN/A        ;
1154329Sktlim@umich.edu
1164329Sktlim@umich.edu    rxPackets
1172292SN/A        .name(name() + ".rxPackets")
1184329Sktlim@umich.edu        .desc("Number of Packets Received")
1194329Sktlim@umich.edu        .prereq(rxBytes)
1204329Sktlim@umich.edu        ;
1214329Sktlim@umich.edu
1222292SN/A    txBandwidth
1232307SN/A        .name(name() + ".txBandwidth")
1242307SN/A        .desc("Transmit Bandwidth (bits/s)")
1252907Sktlim@umich.edu        .precision(0)
1262907Sktlim@umich.edu        .prereq(txBytes)
1272292SN/A        ;
1282292SN/A
1292329SN/A    rxBandwidth
1302329SN/A        .name(name() + ".rxBandwidth")
1312329SN/A        .desc("Receive Bandwidth (bits/s)")
1322292SN/A        .precision(0)
1332292SN/A        .prereq(rxBytes)
1342292SN/A        ;
1352292SN/A
1362292SN/A    txPacketRate
1372292SN/A        .name(name() + ".txPPS")
1382292SN/A        .desc("Packet Tranmission Rate (packets/s)")
1392292SN/A        .precision(0)
1402292SN/A        .prereq(txBytes)
1412292SN/A        ;
1422292SN/A
1433492Sktlim@umich.edu    rxPacketRate
1442329SN/A        .name(name() + ".rxPPS")
1452292SN/A        .desc("Packet Reception Rate (packets/s)")
1462292SN/A        .precision(0)
1472292SN/A        .prereq(rxBytes)
1482292SN/A        ;
1492292SN/A
1502292SN/A    txBandwidth = txBytes * Statistics::constant(8) / simSeconds;
1512292SN/A    rxBandwidth = rxBytes * Statistics::constant(8) / simSeconds;
1522292SN/A    txPacketRate = txPackets / simSeconds;
1532292SN/A    rxPacketRate = rxPackets / simSeconds;
1542292SN/A}
1552292SN/A
1562292SN/Avoid
1572292SN/AEtherDev::ReadConfig(int offset, int size, uint8_t *data)
1582292SN/A{
1592292SN/A    if (offset < PCI_DEVICE_SPECIFIC)
1602292SN/A        PciDev::ReadConfig(offset, size, data);
1612292SN/A    else {
1622727Sktlim@umich.edu        panic("need to do this\n");
1632727Sktlim@umich.edu    }
1642727Sktlim@umich.edu}
1652727Sktlim@umich.edu
1662727Sktlim@umich.eduvoid
1672727Sktlim@umich.eduEtherDev::WriteConfig(int offset, int size, uint32_t data)
1682727Sktlim@umich.edu{
1692727Sktlim@umich.edu    if (offset < PCI_DEVICE_SPECIFIC)
1702727Sktlim@umich.edu        PciDev::WriteConfig(offset, size, data);
1712727Sktlim@umich.edu    else
1722727Sktlim@umich.edu        panic("Need to do that\n");
1732727Sktlim@umich.edu}
1742727Sktlim@umich.edu
1752727Sktlim@umich.eduFault
1762727Sktlim@umich.eduEtherDev::read(MemReqPtr req, uint8_t *data)
1772727Sktlim@umich.edu{
1782727Sktlim@umich.edu    DPRINTF(Ethernet, "read  va=%#x size=%d\n", req->vaddr, req->size);
1792727Sktlim@umich.edu
1802361SN/A    Addr daddr = req->paddr - addr;
1812361SN/A
1822361SN/A    if (daddr > LAST)
1832361SN/A        panic("Accessing reserved register");
1842727Sktlim@umich.edu
1852727Sktlim@umich.edu    switch (req->size) {
1862727Sktlim@umich.edu      case sizeof(uint32_t):
1872727Sktlim@umich.edu        {
1882727Sktlim@umich.edu            uint32_t &reg = *(uint32_t *)data;
1892727Sktlim@umich.edu
1902727Sktlim@umich.edu            switch (daddr) {
1912727Sktlim@umich.edu              case CR:
1922727Sktlim@umich.edu                reg = regs.command;
1932727Sktlim@umich.edu                reg &= ~(CR_RXD | CR_TXD | CR_TXR | CR_RXR);
1942727Sktlim@umich.edu                break;
1952727Sktlim@umich.edu
1962727Sktlim@umich.edu              case CFG:
1972727Sktlim@umich.edu                reg = regs.config;
1982727Sktlim@umich.edu                break;
1992727Sktlim@umich.edu
2002727Sktlim@umich.edu              case MEAR:
2012727Sktlim@umich.edu                reg = regs.mear;
2022727Sktlim@umich.edu                break;
2032727Sktlim@umich.edu
2042727Sktlim@umich.edu              case PTSCR:
2052727Sktlim@umich.edu                reg = regs.ptscr;
2062727Sktlim@umich.edu                break;
2074329Sktlim@umich.edu
2084329Sktlim@umich.edu              case ISR:
2094329Sktlim@umich.edu                reg = regs.isr;
2104329Sktlim@umich.edu                regs.isr = 0;
2114329Sktlim@umich.edu                break;
2124329Sktlim@umich.edu
2134329Sktlim@umich.edu              case IMR:
2144329Sktlim@umich.edu                reg = regs.imr;
2154329Sktlim@umich.edu                break;
2164329Sktlim@umich.edu
2174329Sktlim@umich.edu              case IER:
2184329Sktlim@umich.edu                reg = regs.ier;
2194329Sktlim@umich.edu                break;
2202292SN/A
2212292SN/A              case IHR:
2222292SN/A                reg = regs.ihr;
2232292SN/A                break;
2242292SN/A
2252292SN/A              case TXDP:
2262292SN/A                reg = regs.txdp;
2272292SN/A                break;
2282292SN/A
2292292SN/A              case TXDP_HI:
2302292SN/A                reg = regs.txdp_hi;
2312292SN/A                break;
2322292SN/A
2332292SN/A              case TXCFG:
2342307SN/A                reg = regs.txcfg;
2352307SN/A                break;
2362307SN/A
2372367SN/A              case GPIOR:
2382367SN/A                reg = regs.gpior;
2392307SN/A                break;
2402367SN/A
2412307SN/A              case RXDP:
2422329SN/A                reg = regs.rxdp;
2432307SN/A                break;
2442307SN/A
2452307SN/A              case RXDP_HI:
2462307SN/A                reg = regs.rxdp_hi;
2472307SN/A                break;
2482307SN/A
2492307SN/A              case RXCFG:
2502307SN/A                reg = regs.rxcfg;
2512307SN/A                break;
2522307SN/A
2532307SN/A              case PQCR:
2542307SN/A                reg = regs.pqcr;
2552307SN/A                break;
2562307SN/A
2572307SN/A              case WCSR:
2582329SN/A                reg = regs.wcsr;
2592307SN/A                break;
2602307SN/A
2612307SN/A              case PCR:
2622307SN/A                reg = regs.pcr;
2632307SN/A                break;
2642307SN/A
2652307SN/A              case RFCR:
2662307SN/A                reg = regs.rfcr;
2672307SN/A                break;
2682307SN/A
2692292SN/A              case RFDR:
2702292SN/A
2712329SN/A                switch (regs.rfcr & RFCR_RFADDR) {
2722329SN/A                  case 0x000:
2732292SN/A                    reg = regs.perfectMatch[1] << 8;
2742329SN/A                    reg += regs.perfectMatch[0];
2752329SN/A                    break;
2762292SN/A                  case 0x002:
2772292SN/A                    reg = regs.perfectMatch[3] << 8;
2782292SN/A                    reg += regs.perfectMatch[2];
2792292SN/A                    break;
2802292SN/A                  case 0x004:
2812329SN/A                    reg = regs.perfectMatch[5] << 8;
2822292SN/A                    reg += regs.perfectMatch[4];
2832292SN/A                    break;
2842292SN/A                  default:
2852292SN/A                    panic("reading from RFDR for something for other than PMATCH!\n");
2862292SN/A                    //didn't implement other RFDR functionality b/c driver didn't use
2872292SN/A                }
2882292SN/A                break;
2892292SN/A
2902329SN/A              case SRR:
2912329SN/A                reg = regs.srr;
2922329SN/A                break;
2932292SN/A
2942292SN/A              case MIBC:
2952292SN/A                reg = regs.mibc;
2962292SN/A                reg &= ~(MIBC_MIBS | MIBC_ACLR);
2972292SN/A                break;
2982329SN/A
2992292SN/A              case VRCR:
3002292SN/A                reg = regs.vrcr;
3012292SN/A                break;
3022292SN/A
3032292SN/A              case VTCR:
3042292SN/A                reg = regs.vtcr;
3052292SN/A                break;
3062292SN/A
3072292SN/A              case VDR:
3082292SN/A                reg = regs.vdr;
3092292SN/A                break;
3102292SN/A
3112292SN/A              case CCSR:
3122292SN/A                reg = regs.ccsr;
3132292SN/A                break;
3142292SN/A
3152292SN/A              case TBICR:
3162292SN/A                reg = regs.tbicr;
3172292SN/A                break;
3182292SN/A
3192292SN/A              case TBISR:
3202292SN/A                reg = regs.tbisr;
3212292SN/A                break;
3222292SN/A
3232329SN/A              case TANAR:
3242329SN/A                reg = regs.tanar;
3252292SN/A                break;
3262292SN/A
3272292SN/A              case TANLPAR:
3282292SN/A                reg = regs.tanlpar;
3292292SN/A                break;
3302292SN/A
3312292SN/A              case TANER:
3322292SN/A                reg = regs.taner;
3332292SN/A                break;
3342292SN/A
3352292SN/A              case TESR:
3362292SN/A                reg = regs.tesr;
3372292SN/A                break;
3382292SN/A
3392292SN/A              default:
3402292SN/A                panic("reading unimplemented register: addr = %#x", daddr);
3412292SN/A            }
3422292SN/A
3432292SN/A            DPRINTF(Ethernet, "read from %#x: data=%d data=%#x\n", daddr, reg, reg);
3442292SN/A        }
3452292SN/A        break;
3462292SN/A
3472292SN/A      default:
3482292SN/A        panic("accessing register with invalid size: addr=%#x, size=%d",
3492292SN/A              daddr, req->size);
3502292SN/A    }
3512292SN/A
3522292SN/A    return No_Fault;
3532292SN/A}
3542292SN/A
3552292SN/AFault
3562292SN/AEtherDev::write(MemReqPtr req, const uint8_t *data)
3572292SN/A{
3582292SN/A    DPRINTF(Ethernet, "write va=%#x size=%d\n", req->vaddr, req->size);
3592292SN/A
3602292SN/A    Addr daddr = req->paddr - addr;
3612292SN/A
3622292SN/A    if (daddr > LAST && daddr <= RESERVED)
3632292SN/A        panic("Accessing reserved register");
3642292SN/A
3652292SN/A    if (daddr > RESERVED)
3662292SN/A        panic("higher memory accesses not implemented!\n");
3672292SN/A
3682292SN/A    if (req->size == sizeof(uint32_t)) {
3692292SN/A        uint32_t reg = *(uint32_t *)data;
3702292SN/A        DPRINTF(Ethernet, "write data=%d data=%#x\n", reg, reg);
3712292SN/A
3722292SN/A        switch (daddr) {
3732292SN/A          case CR:
3742292SN/A            regs.command = reg;
3752292SN/A            if ((reg & (CR_TXE | CR_TXD)) == (CR_TXE | CR_TXD)) {
3762292SN/A                txHalt = true;
3772292SN/A            } else if (reg & CR_TXE) {
3782292SN/A                if (txState == txIdle)
3792292SN/A                    txKick();
3802292SN/A            } else if (reg & CR_TXD) {
3812292SN/A                txHalt = true;
3822292SN/A            }
3832292SN/A
3842292SN/A            if ((reg & (CR_RXE | CR_RXD)) == (CR_RXE | CR_RXD)) {
3852292SN/A                rxHalt = true;
3862292SN/A            } else if (reg & CR_RXE) {
3872292SN/A                if (rxState == rxIdle) {
3882292SN/A                    rxKick();
3892292SN/A                }
3902292SN/A            } else if (reg & CR_RXD) {
3912292SN/A                rxHalt = true;
3922292SN/A            }
3932292SN/A
3942292SN/A            if (reg & CR_TXR)
3952292SN/A                txReset();
3962292SN/A
3972292SN/A            if (reg & CR_RXR)
3982292SN/A                rxReset();
3992292SN/A
4002292SN/A            if (reg & CR_SWI)
4012292SN/A                devIntrPost(ISR_SWI);
4022292SN/A
4032292SN/A            if (reg & CR_RST) {
4042292SN/A                txReset();
4052292SN/A                rxReset();
4062292SN/A                regsReset();
4072292SN/A            }
4082292SN/A            break;
4092292SN/A
4102292SN/A          case CFG:
4112292SN/A            regs.config = reg;
4122292SN/A            if (reg & CFG_LNKSTS || reg & CFG_SPDSTS || reg & CFG_DUPSTS
4132292SN/A                || reg & CFG_RESERVED || reg & CFG_T64ADDR
4144032Sktlim@umich.edu                || reg & CFG_PCI64_DET)
4152292SN/A                panic("writing to read-only or reserved CFG bits!\n");
4162292SN/A
4172292SN/A#if 0
4182292SN/A              if (reg & CFG_TBI_EN) ;
4192292SN/A              if (reg & CFG_MODE_1000) ;
4202292SN/A#endif
4214032Sktlim@umich.edu
4224032Sktlim@umich.edu            if (reg & CFG_AUTO_1000)
4232669Sktlim@umich.edu                panic("CFG_AUTO_1000 not implemented!\n");
4242292SN/A
4252292SN/A#if 0
4262292SN/A            if (reg & CFG_PINT_DUPSTS || reg & CFG_PINT_LNKSTS || reg & CFG_PINT_SPDSTS) ;
4272292SN/A            if (reg & CFG_TMRTEST) ;
4282329SN/A            if (reg & CFG_MRM_DIS) ;
4292329SN/A            if (reg & CFG_MWI_DIS) ;
4302367SN/A#endif
4312367SN/A
4324032Sktlim@umich.edu            if (reg & CFG_T64ADDR)
4333731Sktlim@umich.edu                panic("CFG_T64ADDR is read only register!\n");
4342367SN/A
4352367SN/A            if (reg & CFG_PCI64_DET)
4362292SN/A                panic("CFG_PCI64_DET is read only register!\n");
4372292SN/A
4384032Sktlim@umich.edu#if 0
4394032Sktlim@umich.edu              if (reg & CFG_DATA64_EN) ;
4404032Sktlim@umich.edu              if (reg & CFG_M64ADDR) ;
4414032Sktlim@umich.edu              if (reg & CFG_PHY_RST) ;
4424032Sktlim@umich.edu              if (reg & CFG_PHY_DIS) ;
4434032Sktlim@umich.edu#endif
4444032Sktlim@umich.edu
4454032Sktlim@umich.edu            if (reg & CFG_EXTSTS_EN)
4464032Sktlim@umich.edu                extstsEnable = true;
4474032Sktlim@umich.edu            else
4484032Sktlim@umich.edu                extstsEnable = false;
4494032Sktlim@umich.edu
4504032Sktlim@umich.edu#if 0
4514032Sktlim@umich.edu              if (reg & CFG_REQALG) ;
4524032Sktlim@umich.edu              if (reg & CFG_SB) ;
4534032Sktlim@umich.edu              if (reg & CFG_POW) ;
4544032Sktlim@umich.edu              if (reg & CFG_EXD) ;
4554032Sktlim@umich.edu              if (reg & CFG_PESEL) ;
4564032Sktlim@umich.edu              if (reg & CFG_BROM_DIS) ;
4574032Sktlim@umich.edu              if (reg & CFG_EXT_125) ;
4584032Sktlim@umich.edu              if (reg & CFG_BEM) ;
4594032Sktlim@umich.edu#endif
4604032Sktlim@umich.edu            break;
4614032Sktlim@umich.edu
4624032Sktlim@umich.edu          case MEAR:
4634032Sktlim@umich.edu            regs.mear = reg;
4644032Sktlim@umich.edu            /* since phy is completely faked, MEAR_MD* don't matter
4654032Sktlim@umich.edu               and since the driver never uses MEAR_EE*, they don't matter */
4664032Sktlim@umich.edu#if 0
4674032Sktlim@umich.edu            if (reg & MEAR_EEDI) ;
4684032Sktlim@umich.edu            if (reg & MEAR_EEDO) ; //this one is read only
4694032Sktlim@umich.edu            if (reg & MEAR_EECLK) ;
4702292SN/A            if (reg & MEAR_EESEL) ;
4712292SN/A            if (reg & MEAR_MDIO) ;
4722292SN/A            if (reg & MEAR_MDDIR) ;
4732292SN/A            if (reg & MEAR_MDC) ;
4742292SN/A#endif
4752292SN/A            break;
4762292SN/A
4772292SN/A          case PTSCR:
4782292SN/A            regs.ptscr = reg;
4792292SN/A            /* these control BISTs for various parts of chip - we don't care or do */
4802292SN/A            break;
4812292SN/A
4822292SN/A          case ISR: /* writing to the ISR has no effect */
4832292SN/A            panic("ISR is a read only register!\n");
4842292SN/A
4852292SN/A          case IMR:
4862292SN/A            regs.imr = reg;
4872292SN/A            devIntrChangeMask();
4884032Sktlim@umich.edu            break;
4894032Sktlim@umich.edu
4902292SN/A          case IER:
4912292SN/A            regs.ier = reg;
4922292SN/A            break;
4932292SN/A
4942292SN/A          case IHR:
4952292SN/A            regs.ihr = reg;
4962329SN/A            /* not going to implement real interrupt holdoff */
4972292SN/A            break;
4982292SN/A
4992292SN/A          case TXDP:
5002292SN/A            regs.txdp = (reg & 0xFFFFFFFC);
5012292SN/A            assert(txState == txIdle);
5022292SN/A            CTDD = false;
5032292SN/A            break;
5042292SN/A
5052336SN/A          case TXDP_HI:
5062336SN/A            regs.txdp_hi = reg;
5072336SN/A            break;
5082329SN/A
5092292SN/A          case TXCFG:
5102329SN/A            regs.txcfg = reg;
5112292SN/A#if 0
5122292SN/A            if (reg & TXCFG_CSI) ;
5134032Sktlim@umich.edu            if (reg & TXCFG_HBI) ;
5144032Sktlim@umich.edu            if (reg & TXCFG_MLB) ;
5154032Sktlim@umich.edu            if (reg & TXCFG_ATP) ;
5164032Sktlim@umich.edu            if (reg & TXCFG_ECRETRY) ;  /* this could easily be implemented, but
5174032Sktlim@umich.edu                                           considering the network is just a fake
5182292SN/A                                           pipe, wouldn't make sense to do this */
5194032Sktlim@umich.edu
5204032Sktlim@umich.edu            if (reg & TXCFG_BRST_DIS) ;
5214032Sktlim@umich.edu#endif
5222329SN/A
5234032Sktlim@umich.edu#if 0 /* current 2.6 driver doesn't use these.  if we upgrade, may need these */
5244032Sktlim@umich.edu            if (reg & TXCFG_MXDMA1024)
5254032Sktlim@umich.edu                maxTxBurst = 1024;
5264032Sktlim@umich.edu
5274032Sktlim@umich.edu            if (reg & TXCFG_MXDMA8)
5284032Sktlim@umich.edu                maxTxBurst = 8;
5294032Sktlim@umich.edu
5304032Sktlim@umich.edu            if (reg & TXCFG_MXDMA16)
5314032Sktlim@umich.edu                maxTxBurst = 16;
5324032Sktlim@umich.edu
5334032Sktlim@umich.edu            if (reg & TXCFG_MXDMA32)
5344032Sktlim@umich.edu                maxTxBurst = 32;
5352292SN/A
5362292SN/A            if (reg & TXCFG_MXDMA64)
5374032Sktlim@umich.edu                maxTxBurst = 64;
5384032Sktlim@umich.edu
5394032Sktlim@umich.edu            if (reg & TXCFG_MXDMA128)
5402292SN/A                maxTxBurst = 128;
5412292SN/A
5424032Sktlim@umich.edu            if (reg & TXCFG_MXDMA256)
5432292SN/A                maxTxBurst = 256;
5442292SN/A#endif
5452292SN/A
5462292SN/A            if (reg & TXCFG_MXDMA512)
5472292SN/A                maxTxBurst = 512;
5482292SN/A
5492292SN/A            break;
5502292SN/A
5512292SN/A          case GPIOR:
5522292SN/A            regs.gpior = reg;
5532292SN/A            /* these just control general purpose i/o pins, don't matter */
5542292SN/A            break;
5552292SN/A
5562292SN/A          case RXCFG:
5572292SN/A            regs.rxcfg = reg;
5582292SN/A#if 0
5592292SN/A            if (reg & RXCFG_AEP) ;
5602292SN/A            if (reg & RXCFG_ARP) ;
5612292SN/A            if (reg & RXCFG_STRIPCRC) ;
5622292SN/A            if (reg & RXCFG_RX_RD) ;
5632292SN/A            if (reg & RXCFG_ALP) ;
5642292SN/A            if (reg & RXCFG_AIRL) ;
5652292SN/A#endif
5662292SN/A
5672292SN/A            if (reg & RXCFG_MXDMA512)
5682292SN/A                maxRxBurst = 512;
5692292SN/A
5702292SN/A#if 0
5712292SN/A            if (reg & (RXCFG_DRTH | RXCFG_DRTH0)) ;
5722292SN/A#endif
5732292SN/A            break;
5742292SN/A
5752292SN/A          case PQCR:
5762292SN/A            /* there is no priority queueing used in the linux 2.6 driver */
5772292SN/A            regs.pqcr = reg;
5782292SN/A            break;
5792292SN/A
5802292SN/A          case WCSR:
5812292SN/A            /* not going to implement wake on LAN */
5822292SN/A            regs.wcsr = reg;
5832292SN/A            break;
5842292SN/A
5852329SN/A          case PCR:
5862329SN/A            /* not going to implement pause control */
5872292SN/A            regs.pcr = reg;
5882292SN/A            break;
5892292SN/A
5902292SN/A          case RFCR:
5912292SN/A            regs.rfcr = reg;
5922292SN/A            rxFilterEnable = (reg & RFCR_RFEN) ? true : false;
5932292SN/A
5942292SN/A            acceptBroadcast = (reg & RFCR_AAB) ? true : false;
5952292SN/A
5962292SN/A            acceptMulticast = (reg & RFCR_AAM) ? true : false;
5972292SN/A
5982292SN/A            acceptUnicast = (reg & RFCR_AAU) ? true : false;
5992292SN/A
6002292SN/A            acceptPerfect = (reg & RFCR_APM) ? true : false;
6012292SN/A
6022292SN/A            acceptArp = (reg & RFCR_AARP) ? true : false;
6032292SN/A
6042292SN/A            if (reg & RFCR_APAT)
6052292SN/A                panic("RFCR_APAT not implemented!\n");
6062292SN/A
6072292SN/A            if (reg & RFCR_MHEN || reg & RFCR_UHEN)
6082292SN/A                panic("hash filtering not implemented!\n");
6092292SN/A
6102292SN/A            if (reg & RFCR_ULM)
6112292SN/A                panic("RFCR_ULM not implemented!\n");
6122292SN/A
6132292SN/A            break;
6142292SN/A
6152907Sktlim@umich.edu          case RFDR:
6162678Sktlim@umich.edu            panic("the driver never writes to RFDR, something is wrong!\n");
6172678Sktlim@umich.edu
6182678Sktlim@umich.edu          case BRAR:
6192678Sktlim@umich.edu            panic("the driver never uses BRAR, something is wrong!\n");
6202678Sktlim@umich.edu
6212329SN/A          case BRDR:
6222329SN/A            panic("the driver never uses BRDR, something is wrong!\n");
6232292SN/A
6242292SN/A          case SRR:
6252292SN/A            panic("SRR is read only register!\n");
6262292SN/A
6272292SN/A          case MIBC:
6282292SN/A            panic("the driver never uses MIBC, something is wrong!\n");
6292292SN/A
6302678Sktlim@umich.edu          case VRCR:
6312292SN/A            regs.vrcr = reg;
6322292SN/A            break;
6332292SN/A
6342292SN/A          case VTCR:
6352292SN/A            regs.vtcr = reg;
6362292SN/A            break;
6372292SN/A
6382292SN/A          case VDR:
6392292SN/A            panic("the driver never uses VDR, something is wrong!\n");
6402292SN/A            break;
6412292SN/A
6422669Sktlim@umich.edu          case CCSR:
6432669Sktlim@umich.edu            /* not going to implement clockrun stuff */
6442669Sktlim@umich.edu            regs.ccsr = reg;
6452292SN/A            break;
6462292SN/A
6472669Sktlim@umich.edu          case TBICR:
6482669Sktlim@umich.edu            regs.tbicr = reg;
6493772Sgblack@eecs.umich.edu            if (reg & TBICR_MR_LOOPBACK)
6504326Sgblack@eecs.umich.edu                panic("TBICR_MR_LOOPBACK never used, something wrong!\n");
6512669Sktlim@umich.edu
6524878Sstever@eecs.umich.edu            if (reg & TBICR_MR_AN_ENABLE) {
6534878Sstever@eecs.umich.edu                regs.tanlpar = regs.tanar;
6544909Sstever@eecs.umich.edu                regs.tbisr |= (TBISR_MR_AN_COMPLETE | TBISR_MR_LINK_STATUS);
6554350Sgblack@eecs.umich.edu            }
6564022Sstever@eecs.umich.edu
6572669Sktlim@umich.edu#if 0
6582292SN/A            if (reg & TBICR_MR_RESTART_AN) ;
6592678Sktlim@umich.edu#endif
6602678Sktlim@umich.edu
6612678Sktlim@umich.edu            break;
6622678Sktlim@umich.edu
6632678Sktlim@umich.edu          case TBISR:
6642678Sktlim@umich.edu            panic("TBISR is read only register!\n");
6652292SN/A
6662292SN/A          case TANAR:
6673221Sktlim@umich.edu            regs.tanar = reg;
6683797Sgblack@eecs.umich.edu            if (reg & TANAR_PS2)
6693221Sktlim@umich.edu                panic("this isn't used in driver, something wrong!\n");
6702292SN/A
6712693Sktlim@umich.edu            if (reg & TANAR_PS1)
6724350Sgblack@eecs.umich.edu                panic("this isn't used in driver, something wrong!\n");
6733326Sktlim@umich.edu            break;
6743326Sktlim@umich.edu
6753326Sktlim@umich.edu          case TANLPAR:
6763326Sktlim@umich.edu            panic("this should only be written to by the fake phy!\n");
6773326Sktlim@umich.edu
6783326Sktlim@umich.edu          case TANER:
6793326Sktlim@umich.edu            panic("TANER is read only register!\n");
6803326Sktlim@umich.edu
6813326Sktlim@umich.edu          case TESR:
6823326Sktlim@umich.edu            regs.tesr = reg;
6833326Sktlim@umich.edu            break;
6843326Sktlim@umich.edu
6853326Sktlim@umich.edu          default:
6863326Sktlim@umich.edu            panic("thought i covered all the register, what is this? addr=%#x",
6873326Sktlim@umich.edu                  daddr);
6883326Sktlim@umich.edu        }
6893326Sktlim@umich.edu    } else
6902693Sktlim@umich.edu        panic("Invalid Request Size");
6912693Sktlim@umich.edu
6922693Sktlim@umich.edu    return No_Fault;
6932693Sktlim@umich.edu}
6942693Sktlim@umich.edu
6952693Sktlim@umich.eduvoid
6962669Sktlim@umich.eduEtherDev::devIntrPost(uint32_t interrupts)
6972669Sktlim@umich.edu{
6984032Sktlim@umich.eduDPRINTF(Ethernet, "interrupt posted intr=%x isr=%x imr=%x\n",
6993221Sktlim@umich.edu    interrupts, regs.isr, regs.imr);
7003221Sktlim@umich.edu
7012678Sktlim@umich.eduif (interrupts & ISR_RESERVE)
7022727Sktlim@umich.edu    panic("Cannot set a reserved interrupt");
7032698Sktlim@umich.edu
7042698Sktlim@umich.eduif (interrupts & ISR_TXRCMP)
7053014Srdreslin@umich.edu    regs.isr |= ISR_TXRCMP;
7062669Sktlim@umich.edu
7072693Sktlim@umich.eduif (interrupts & ISR_RXRCMP)
7082292SN/A    regs.isr |= ISR_RXRCMP;
7092292SN/A
7102292SN/A//ISR_DPERR  not implemented
7112292SN/A//ISR_SSERR not implemented
7122292SN/A//ISR_RMABT not implemented
7132292SN/A//ISR_RXSOVR not implemented
7142292SN/A//ISR_HIBINT not implemented
7152292SN/A//ISR_PHY not implemented
7162292SN/A//ISR_PME not implemented
7172292SN/A
7182292SN/Aif (interrupts & ISR_SWI)
7192292SN/A    regs.isr |= ISR_SWI;
7202292SN/A
7212292SN/A//ISR_MIB not implemented
7222292SN/A//ISR_TXURN not implemented
7232292SN/A
7242292SN/A if (interrupts & ISR_TXIDLE)
7252292SN/A     regs.isr |= ISR_TXIDLE;
7262292SN/A
7272292SN/A if (interrupts & ISR_TXERR)
7282292SN/A     regs.isr |= ISR_TXERR;
7292292SN/A
7302292SN/A if (interrupts & ISR_TXDESC)
7312292SN/A     regs.isr |= ISR_TXDESC;
7322292SN/A
7332292SN/A if (interrupts & ISR_TXOK)
7342292SN/A     regs.isr |= ISR_TXOK;
7352292SN/A
7362329SN/A if (interrupts & ISR_RXORN)
7372292SN/A     regs.isr |= ISR_RXORN;
7382292SN/A
7392292SN/A if (interrupts & ISR_RXIDLE)
7402292SN/A     regs.isr |= ISR_RXIDLE;
7412292SN/A
7422292SN/A//ISR_RXEARLY not implemented
7432292SN/A
7442292SN/A if (interrupts & ISR_RXERR)
7452292SN/A     regs.isr |= ISR_RXERR;
7462292SN/A
7472292SN/A if (interrupts & ISR_RXOK)
7482292SN/A     regs.isr |= ISR_RXOK;
7492292SN/A
7502292SN/A if ((regs.isr & regs.imr))
7512292SN/A        cpuIntrPost();
7522292SN/A}
7532329SN/A
7542731Sktlim@umich.eduvoid
7552292SN/AEtherDev::devIntrClear(uint32_t interrupts)
7562292SN/A{
7572292SN/A    DPRINTF(Ethernet, "interrupt cleared intr=%x isr=%x imr=%x\n",
7582292SN/A            interrupts, regs.isr, regs.imr);
7592292SN/A
7602292SN/A    if (interrupts & ISR_RESERVE)
7612292SN/A        panic("Cannot clear a reserved interrupt");
7622727Sktlim@umich.edu
7632292SN/A    if (interrupts & ISR_TXRCMP)
7642292SN/A        regs.isr &= ~ISR_TXRCMP;
7652292SN/A
7662292SN/A    if (interrupts & ISR_RXRCMP)
7672292SN/A        regs.isr &= ~ISR_RXRCMP;
7682292SN/A
7692292SN/A//ISR_DPERR  not implemented
7702292SN/A//ISR_SSERR not implemented
7712292SN/A//ISR_RMABT not implemented
7722292SN/A//ISR_RXSOVR not implemented
7734032Sktlim@umich.edu//ISR_HIBINT not implemented
7744032Sktlim@umich.edu//ISR_PHY not implemented
7754032Sktlim@umich.edu//ISR_PME not implemented
7764032Sktlim@umich.edu
7772292SN/A    if (interrupts & ISR_SWI)
7782292SN/A        regs.isr &= ~ISR_SWI;
7792292SN/A
7802292SN/A//ISR_MIB not implemented
7812292SN/A//ISR_TXURN not implemented
7822329SN/A
7832292SN/A    if (interrupts & ISR_TXIDLE)
7842292SN/A        regs.isr &= ~ISR_TXIDLE;
7852292SN/A
7862292SN/A    if (interrupts & ISR_TXERR)
7872292SN/A        regs.isr &= ~ISR_TXERR;
7882292SN/A
7892292SN/A    if (interrupts & ISR_TXDESC)
7902292SN/A        regs.isr &= ~ISR_TXDESC;
7912292SN/A
7922329SN/A    if (interrupts & ISR_TXOK)
7932329SN/A        regs.isr &= ~ISR_TXOK;
7942292SN/A
7952292SN/A    if (interrupts & ISR_RXORN)
7962292SN/A        regs.isr &= ~ISR_RXORN;
7972292SN/A
7982292SN/A    if (interrupts & ISR_RXIDLE)
7992292SN/A        regs.isr &= ~ISR_RXIDLE;
8002292SN/A
8012329SN/A//ISR_RXEARLY not implemented
8022731Sktlim@umich.edu
8032292SN/A    if (interrupts & ISR_RXERR)
8042292SN/A        regs.isr &= ~ISR_RXERR;
8052292SN/A
8064032Sktlim@umich.edu    if (interrupts & ISR_RXOK)
8074032Sktlim@umich.edu        regs.isr &= ~ISR_RXOK;
8084032Sktlim@umich.edu
8094032Sktlim@umich.edu    if ((regs.isr & regs.imr))
8104032Sktlim@umich.edu        cpuIntrPost();
8112292SN/A
8122292SN/A    if (!(regs.isr & regs.imr))
8132292SN/A        cpuIntrClear();
8142292SN/A}
8152292SN/A
8162292SN/Avoid
8172292SN/AEtherDev::devIntrChangeMask()
8182727Sktlim@umich.edu{
8192292SN/A    DPRINTF(Ethernet, "iterrupt mask changed\n");
8202292SN/A
8212292SN/A    if (regs.isr & regs.imr)
8222292SN/A        cpuIntrPost();
8232292SN/A    else
8243349Sbinkertn@umich.edu        cpuIntrClear();
8252693Sktlim@umich.edu}
8262693Sktlim@umich.edu
8272693Sktlim@umich.eduvoid
8282693Sktlim@umich.eduEtherDev::cpuIntrPost()
8292693Sktlim@umich.edu{
8302693Sktlim@umich.edu    if (!cpuPendingIntr) {
8312693Sktlim@umich.edu        if (regs.ier) {
8322693Sktlim@umich.edu            cpuPendingIntr = true;
8332693Sktlim@umich.edu            intctrl->post(TheISA::INTLEVEL_IRQ1, TheISA::INTINDEX_ETHERNET);
8342693Sktlim@umich.edu        }
8352693Sktlim@umich.edu    }
8362693Sktlim@umich.edu}
8372693Sktlim@umich.edu
8382693Sktlim@umich.eduvoid
8392693Sktlim@umich.eduEtherDev::cpuIntrClear()
8402693Sktlim@umich.edu{
8412733Sktlim@umich.edu    if (cpuPendingIntr) {
8422693Sktlim@umich.edu        cpuPendingIntr = false;
8432732Sktlim@umich.edu        intctrl->clear(TheISA::INTLEVEL_IRQ1, TheISA::INTINDEX_ETHERNET);
8442693Sktlim@umich.edu    }
8452733Sktlim@umich.edu}
8462693Sktlim@umich.edu
8472693Sktlim@umich.edubool
8482693Sktlim@umich.eduEtherDev::cpuIntrPending() const
8492693Sktlim@umich.edu{ return cpuPendingIntr; }
8502693Sktlim@umich.edu
8512693Sktlim@umich.eduvoid
8522693Sktlim@umich.eduEtherDev::txReset()
8532678Sktlim@umich.edu{
8542678Sktlim@umich.edu
8552678Sktlim@umich.edu    DPRINTF(Ethernet, "transmit reset\n");
8562678Sktlim@umich.edu
8572678Sktlim@umich.edu    txPacketFlag = false;
8582678Sktlim@umich.edu    CTDD = false;
8592927Sktlim@umich.edu    txFifoCnt = 0;
8602678Sktlim@umich.edu    txFifoAvail = 0;
8612727Sktlim@umich.edu    txHalt = false;
8622678Sktlim@umich.edu    txFifo.clear();
8632678Sktlim@umich.edu    descAddrFifo.clear();
8642678Sktlim@umich.edu    regs.command &= ~CR_TXE;
8652678Sktlim@umich.edu    txState = txIdle;
8662678Sktlim@umich.edu}
8672678Sktlim@umich.edu
8682678Sktlim@umich.eduvoid
8692678Sktlim@umich.eduEtherDev::rxReset()
8702678Sktlim@umich.edu{
8712678Sktlim@umich.edu    DPRINTF(Ethernet, "receive reset\n");
8722678Sktlim@umich.edu
8732678Sktlim@umich.edu    rxPacketFlag = false;
8742678Sktlim@umich.edu    CRDD = false;
8752678Sktlim@umich.edu    fragLen = 0;
8762678Sktlim@umich.edu    rxFifoCnt = 0;
8772678Sktlim@umich.edu    rxHalt = false;
8782678Sktlim@umich.edu    rxFifo.clear();
8792678Sktlim@umich.edu    regs.command &= ~CR_RXE;
8802292SN/A    rxState = rxIdle;
8812292SN/A}
8822292SN/A
8832292SN/A/**
8842292SN/A * This sets up a DMA transfer to read one data segment from the rxFifo into
8852292SN/A * the buffer indicated by rxDescCache.bufptr. Assumes the value of rxFragPtr
8862292SN/A * is already correctly set.
8872292SN/A */
8883126Sktlim@umich.eduvoid
8892292SN/AEtherDev::writeOneFrag()
8902292SN/A{
8912292SN/A    /* i think there is no need for an "in use" warning here like in old */
8922292SN/A    fragLen = rxFifo.front()->length; //length of whole packet
8932292SN/A    fragLen = (fragLen < rxDescCnt) ? fragLen : rxDescCnt;
8942292SN/A
8952292SN/A    writePhys.addr = rxFragPtr;
8962292SN/A    writePhys.length = fragLen;
8972292SN/A
8982292SN/A    // Set up DMA request area
8992292SN/A    writeRequest.init(&rxDoneCB, 0, false, &writePhys, 1, fragLen,
9002292SN/A                     rxDescBufPtr, fragLen, curTick);
9012292SN/A
9022329SN/A    dma->doTransfer(&readRequest);
9032329SN/A}
9042329SN/A
9052292SN/Avoid
9062292SN/AEtherDev::rxKick()
9072292SN/A{
9082292SN/A    DPRINTF(Ethernet, "receive state machine activated!\n");
9092292SN/A
9102292SN/A    if (CRDD) {
9112292SN/A        rxState = rxDescRefr;
9122292SN/A        readOneDesc(rx, LINK_LEN);
9132292SN/A    } else {
9142292SN/A        rxState = rxDescRead;
9152316SN/A        readOneDesc(rx);
9162316SN/A    }
9172329SN/A}
9182329SN/A
9192329SN/AEtherDev::RxDescDone::RxDescDone(EtherDev *e)
9202329SN/A    : ethernet(e)
9212733Sktlim@umich.edu{
9222316SN/A}
9232732Sktlim@umich.edu
9242316SN/Astd::string
9252733Sktlim@umich.eduEtherDev::RxDescDone::name() const
9262292SN/A{
9272292SN/A    return ethernet->name() + ".rxDescDoneCB";
9282292SN/A}
9292693Sktlim@umich.edu
9302693Sktlim@umich.eduvoid
9312693Sktlim@umich.eduEtherDev::RxDescDone::process()
9322698Sktlim@umich.edu{
9334985Sktlim@umich.edu    DPRINTF(Ethernet, "receive descriptor done callback\n");
9342698Sktlim@umich.edu    ethernet->rxDescDone();
9352693Sktlim@umich.edu}
9362698Sktlim@umich.edu
9372698Sktlim@umich.eduvoid
9382699Sktlim@umich.eduEtherDev::rxDescDone()
9392693Sktlim@umich.edu{
9403014Srdreslin@umich.edu    if (rxState == rxDescRefr) {
9412693Sktlim@umich.edu        if (rxDescCache.link == 0) {
9422693Sktlim@umich.edu            rxState = rxIdle;
9432727Sktlim@umich.edu            regs.command &= ~CR_RXE;
9442907Sktlim@umich.edu            devIntrPost(ISR_RXIDLE);
9452693Sktlim@umich.edu            return;
9462693Sktlim@umich.edu        } else {
9472693Sktlim@umich.edu            rxState = rxDescRead;
9482693Sktlim@umich.edu            regs.rxdp = rxDescCache.link;
9492693Sktlim@umich.edu            CRDD = false;
9502693Sktlim@umich.edu            readOneDesc(rx);
9512693Sktlim@umich.edu        }
9522693Sktlim@umich.edu    } else if (rxState == rxDescRead) {
9532693Sktlim@umich.edu        if (rxDescCache.cmdsts & CMDSTS_OWN) {
9542693Sktlim@umich.edu            rxState = rxIdle;
9552292SN/A            regs.command &= ~CR_RXE;
9562292SN/A            devIntrPost(ISR_RXIDLE);
9572292SN/A        } else {
9582292SN/A            rxState = rxFifoBlock;
9592292SN/A            rxFragPtr = rxDescCache.bufptr;
9602292SN/A            rxDescCnt = rxDescCache.cmdsts & CMDSTS_LEN_MASK;
9612292SN/A
9622292SN/A            if (!rxFifo.empty()) {
9632292SN/A                rxState = rxFragWrite;
9642292SN/A                if (!rxPacketFlag) { // reading a new packet
9652292SN/A                    rxPacketBufPtr = rxFifo.front()->data;
9662292SN/A                    rxPacketBufPtr -= rxDescCnt;
9672292SN/A                    rxDescBufPtr = rxPacketBufPtr;
9682292SN/A                    rxCopied = 0;
9692292SN/A                } else {
9702292SN/A                    rxDescBufPtr = rxPacketBufPtr - rxDescCnt;
9712292SN/A                }
9722292SN/A                writeOneFrag();
9732292SN/A            }
9742292SN/A        }
9752292SN/A    } else if (rxState == rxDescWrite) {
9762292SN/A        devIntrPost(ISR_RXOK);
9772292SN/A
9782292SN/A        if (rxDescCache.cmdsts & CMDSTS_INTR)
9792292SN/A            devIntrPost(ISR_RXDESC);
9802292SN/A
9812292SN/A        if (rxDescCache.link == 0 || ((rxPktBytes != 0) && rxHalt)) {
9822292SN/A            rxState = rxIdle;
9832292SN/A            regs.command &= ~CR_RXE;
9842292SN/A            devIntrPost(ISR_RXIDLE);
9852329SN/A            rxHalt = false;
9862329SN/A        } else {
9872329SN/A            rxState = rxDescRead;
9882329SN/A            regs.rxdp = rxDescCache.link;
9892329SN/A            CRDD = false;
9902329SN/A            readOneDesc(rx);
9912329SN/A        }
9922329SN/A    }
9932329SN/A}
9942329SN/A
9952329SN/AEtherDev::RxDone::RxDone(EtherDev *e)
9962329SN/A    : ethernet(e)
9972329SN/A{
9982329SN/A}
9992329SN/A
10002329SN/Astd::string
10012329SN/AEtherDev::RxDone::name() const
10022329SN/A{
10032329SN/A    return ethernet->name() + ".rxDoneCB";
10042329SN/A}
10052329SN/A
10062329SN/Avoid
10072329SN/AEtherDev::RxDone::process()
10082329SN/A{
10092329SN/A    DPRINTF(Ethernet, "receive done callback\n");
10102329SN/A    ethernet->rxDone();
10112329SN/A}
10122329SN/A
10132329SN/Avoid
10142329SN/AEtherDev::rxDone()
1015{
1016    DPRINTF(Ethernet, "packet received to host memory\n");
1017
1018    if (!rxDescCache.cmdsts & CMDSTS_OWN)
1019        panic("This descriptor is already owned by the driver!\n");
1020
1021    rxState = rxFifoBlock;
1022    rxCopied += fragLen;
1023    rxFifoCnt -= fragLen;
1024
1025    if (rxDescCnt) { /* there is still data left in the descriptor */
1026        rxState = rxFragWrite;
1027        rxDescBufPtr += fragLen;
1028        writeOneFrag();
1029    } else {
1030        rxState = rxDescWrite;
1031        if (rxPktBytes == 0) {  /* packet is done */
1032            rxDescCache.cmdsts |= CMDSTS_OWN;
1033            rxDescCache.cmdsts &= ~CMDSTS_MORE;
1034            rxDescCache.cmdsts |= CMDSTS_OK;
1035            rxDescCache.cmdsts += rxCopied;   //i.e. set CMDSTS_SIZE
1036
1037            rxPacketFlag = false;
1038            if (rxFilterEnable) {
1039                rxDescCache.cmdsts &= ~CMDSTS_DEST_MASK;
1040                if (rxFifo.front()->IsUnicast())
1041                    rxDescCache.cmdsts |= CMDSTS_DEST_SELF;
1042                if (rxFifo.front()->IsMulticast())
1043                    rxDescCache.cmdsts |= CMDSTS_DEST_MULTI;
1044                if (rxFifo.front()->IsBroadcast())
1045                    rxDescCache.cmdsts |= CMDSTS_DEST_MASK;
1046            }
1047
1048            PacketPtr &pkt = rxFifo.front();
1049            eth_header *eth = (eth_header *) pkt->data;
1050            if (eth->type == 0x800 && extstsEnable) {
1051                rxDescCache.extsts |= EXTSTS_IPPKT;
1052                if (!ipChecksum(pkt, false))
1053                    rxDescCache.extsts |= EXTSTS_IPERR;
1054                ip_header *ip = rxFifo.front()->getIpHdr();
1055
1056                if (ip->protocol == 6) {
1057                    rxDescCache.extsts |= EXTSTS_TCPPKT;
1058                    if (!tcpChecksum(pkt, false))
1059                        rxDescCache.extsts |= EXTSTS_TCPERR;
1060                } else if (ip->protocol == 17) {
1061                    rxDescCache.extsts |= EXTSTS_UDPPKT;
1062                    if (!udpChecksum(pkt, false))
1063                        rxDescCache.extsts |= EXTSTS_UDPERR;
1064                }
1065            }
1066
1067            rxFifo.front() = NULL;
1068            rxFifo.pop_front();
1069        } else { /* just the descriptor is done */
1070            rxDescCache.cmdsts |= CMDSTS_OWN;
1071            rxDescCache.cmdsts |= CMDSTS_MORE;
1072        }
1073        writeDescPhys.addr = regs.rxdp + LINK_LEN + BUFPTR_LEN;
1074        writeDescPhys.length = CMDSTS_LEN;
1075
1076        writeDescRequest.init(&rxDescDoneCB, 0, true, &writeDescPhys, 1,
1077                              CMDSTS_LEN, (uint8_t *) &rxDescCache.cmdsts,
1078                              CMDSTS_LEN, curTick);
1079    }
1080}
1081
1082/**
1083 * This sets up a DMA transfer to read one descriptor into the network device.
1084 */
1085void
1086EtherDev::readOneDesc(dir_t dir, uint32_t len) {
1087    readDescPhys.addr = (dir == tx) ? regs.txdp : regs.rxdp;
1088    readDescPhys.length = len;
1089
1090    ns_desc *cache = (dir == tx) ? &txDescCache : &rxDescCache;
1091
1092    /* THIS ASSUMES THAT DESC_LEN < regs.txcfg's maxdma value,
1093       which is 512 bytes in the driver, so i'll just hard code it here */
1094    readDescRequest.init(&txDescDoneCB, 0, false, &readDescPhys, 1,
1095                         len, (uint8_t *) cache , len, curTick);
1096
1097    dma->doTransfer(&readDescRequest);
1098}
1099
1100/**
1101 * This sets up a DMA transfer to read one data segment of the descriptor in
1102 * txDescCache.  Assumes the value of txFragPtr is already correctly set
1103 */
1104void
1105EtherDev::readOneFrag()
1106{
1107    /* i think there is no need for an "in use" warning here like in old */
1108    fragLen = (txDescCnt < txFifoAvail) ? txDescCnt : txFifoAvail;
1109    readPhys.addr = txFragPtr;
1110    readPhys.length = fragLen;
1111
1112    // Set up DMA request area
1113    readRequest.init(&txDoneCB, 0, false, &readPhys, 1, fragLen,
1114                     txPacketBufPtr, fragLen, curTick);
1115
1116    dma->doTransfer(&readRequest);
1117}
1118
1119void
1120EtherDev::transmit()
1121{
1122    if (txFifo.empty()) {
1123        DPRINTF(Ethernet, "nothing to transmit\n");
1124        return;
1125    }
1126
1127   if (interface->sendPacket(txFifo.front())) {
1128        DPRINTF(Ethernet, "transmit packet\n");
1129        txBytes += txFifo.front()->length;
1130        txPackets++;
1131
1132        txFifoCnt -= txFifo.front()->length;
1133
1134        txFifo.front() = NULL;
1135        txFifo.pop_front();
1136
1137        txDescCache.cmdsts &= ~CMDSTS_OK;
1138    } else {
1139        txDescCache.cmdsts &= ~CMDSTS_ERR;
1140    }
1141
1142    txDescCache.cmdsts &= ~CMDSTS_OWN;
1143
1144    writeDescPhys.addr = descAddrFifo.front() + LINK_LEN + BUFPTR_LEN;
1145    writeDescPhys.length = CMDSTS_LEN;
1146
1147    descAddrFifo.front() = 0;
1148    descAddrFifo.pop_front();
1149
1150    writeDescRequest.init(&txDescDoneCB, 0, true, &writeDescPhys, 1,
1151                          writeDescPhys.length,
1152                          (uint8_t *) &(txDescCache.cmdsts),
1153                          writeDescPhys.length, curTick);
1154
1155    dma->doTransfer(&writeDescRequest);
1156
1157    transmit();
1158}
1159
1160void
1161EtherDev::txKick()
1162{
1163    DPRINTF(Ethernet, "transmit state machine activated\n");
1164#if 0
1165    if (DTRACE(Ethernet))
1166        txDump();
1167#endif
1168
1169    if (CTDD) {
1170        txState = txDescRefr;
1171        readOneDesc(tx, LINK_LEN);
1172    } else {
1173        txState = txDescRead;
1174        readOneDesc(tx);
1175    }
1176}
1177
1178EtherDev::TxDescDone::TxDescDone(EtherDev *e)
1179    : ethernet(e)
1180{
1181}
1182
1183std::string
1184EtherDev::TxDescDone::name() const
1185{
1186    return ethernet->name() + ".txDescDoneCB";
1187}
1188
1189void
1190EtherDev::TxDescDone::process()
1191{
1192    DPRINTF(Ethernet, "transmit descriptor done callback\n");
1193    ethernet->txDescDone();
1194
1195}
1196
1197void
1198EtherDev::txDescDone()
1199{
1200    if (txState == txFifoBlock) {
1201        if (txDescCache.cmdsts & CMDSTS_OK) {
1202            devIntrPost(ISR_TXOK);
1203        } else if (txDescCache.cmdsts & CMDSTS_ERR) {
1204            devIntrPost(ISR_TXERR);
1205        }
1206    } else if (txState == txDescRefr || txState == txDescWrite) {
1207
1208        if (txState == txDescWrite) {
1209            if (txDescCache.cmdsts & CMDSTS_INTR) {
1210                devIntrPost(ISR_TXDESC);
1211            }
1212        }
1213
1214        if (txDescCache.link == 0) {
1215            txState = txIdle;
1216            regs.command &= ~CR_TXE;
1217            devIntrPost(ISR_TXIDLE);
1218            return;
1219        } else {
1220            txState = txDescRead;
1221            regs.txdp = txDescCache.link;
1222            CTDD = false;
1223            readOneDesc(tx);
1224        }
1225    } else if (txState == txDescRead) {
1226        if (txDescCache.cmdsts & CMDSTS_OWN) {
1227            txState = txFifoBlock;
1228            txFragPtr = txDescCache.bufptr;
1229            txDescCnt = txDescCache.cmdsts & CMDSTS_LEN_MASK;
1230
1231            if (txFifoAvail >= ((regs.txcfg & TXCFG_FLTH_MASK) >> 8)) {
1232                txState = txFragRead;
1233                if (!txPacketFlag) {
1234                    txPacketFlag = true;
1235                    /* find the total length of this packet */
1236                    txPacketLen = txDescCnt;
1237                    bool more = txDescCache.cmdsts & CMDSTS_MORE;
1238                    uint8_t *addr = (uint8_t *) regs.txdp;
1239                    while (more) {
1240                        addr = physmem->dma_addr(((ns_desc *) addr)->link, sizeof(ns_desc));
1241                        /* !!!!!!mask needed? */
1242                        txPacketLen += ((ns_desc *)addr)->cmdsts & CMDSTS_LEN_MASK;
1243                        more = ((ns_desc *) addr)->cmdsts & CMDSTS_MORE;
1244                    }
1245                    PacketPtr &packet = txDoneCB.packet;
1246                    packet = new EtherPacket;
1247                    packet->length = txPacketLen;
1248                    packet->data = new uint8_t[txPacketLen];
1249                    txPacketBufPtr = packet->data;
1250                }
1251                readOneFrag();
1252            }
1253        } else {
1254            txState = txIdle;
1255            regs.command &= ~CR_TXE;
1256            devIntrPost(ISR_TXIDLE);
1257        }
1258    }
1259}
1260
1261EtherDev::TxDone::TxDone(EtherDev *e)
1262    : ethernet(e)
1263{
1264}
1265
1266std::string
1267EtherDev::TxDone::name() const
1268{
1269    return ethernet->name() + ".txDoneCB";
1270}
1271
1272
1273void
1274EtherDev::TxDone::process()
1275{
1276    DPRINTF(Ethernet, "transmit done callback\n");
1277    ethernet->txDone(packet);
1278}
1279
1280void
1281EtherDev::txDone(PacketPtr packet)
1282{
1283    DPRINTF(Ethernet, "transmit done\n");
1284
1285    if (!txDescCache.cmdsts & CMDSTS_OWN)
1286        panic("This descriptor is already owned by the driver!\n");
1287
1288    txState = txFifoBlock;
1289
1290    txPacketBufPtr += fragLen;  /* hope this ptr manipulation is right! */
1291    txDescCnt -= fragLen;
1292    txFifoCnt += fragLen;
1293
1294    if (txFifoCnt >= (regs.txcfg & TXCFG_DRTH_MASK)) {
1295        if (txFifo.empty()) {
1296            txFifoCnt -= (uint32_t) (txPacketBufPtr - packet->data);
1297        } else {
1298            transmit();
1299        }
1300    }
1301
1302    if (txDescCnt) { /* if there is still more data to go in this desc */
1303        if (txFifoAvail >= regs.txcfg & TXCFG_FLTH_MASK) {
1304            txState = txFragRead;
1305            readOneFrag();
1306        }
1307    } else { /* this descriptor is done */
1308        /* but there is more descriptors for this packet */
1309        if (txDescCache.cmdsts & CMDSTS_MORE) {
1310            txState = txDescWrite;
1311            txDescCache.cmdsts &= ~CMDSTS_OWN;
1312            writeDescPhys.addr = regs.txdp + LINK_LEN + BUFPTR_LEN;
1313            writeDescPhys.length = CMDSTS_LEN;
1314
1315            writeDescRequest.init(&txDescDoneCB, 0, true, &writeDescPhys, 1,
1316                                  writeDescPhys.length,
1317                                  (uint8_t*) &txDescCache.cmdsts,
1318                                  writeDescPhys.length, curTick);
1319        } else { /* this packet is totally done */
1320            /* deal with the the packet that just finished */
1321            if (regs.vtcr & VTCR_PPCHK && extstsEnable) {
1322                if (txDescCache.extsts & EXTSTS_UDPPKT) {
1323                    udpChecksum(packet, true);
1324                } else if (txDescCache.extsts & EXTSTS_TCPPKT) {
1325                    tcpChecksum(packet, true);
1326                } else if (txDescCache.extsts & EXTSTS_IPPKT) {
1327                    ipChecksum(packet, true);
1328                }
1329            }
1330
1331            txFifo.push_back(packet);
1332            transmit();
1333            txPacketFlag = false;
1334            descAddrFifo.push_back(regs.txdp);
1335
1336            /* if there is not another descriptor ready for reading, go idle */
1337            if (txDescCache.link == 0 || txHalt) {
1338                txState = txIdle;
1339                devIntrPost(ISR_TXIDLE);
1340                txHalt = false;
1341            } else { /* else go read next descriptor */
1342                txState = txDescRead;
1343                regs.txdp = txDescCache.link;
1344                CTDD = false;
1345                readOneDesc(tx);
1346            }
1347        }
1348    }
1349}
1350
1351void
1352EtherDev::transferDone()
1353{
1354    if (txFifo.empty())
1355        return;
1356
1357    DPRINTF(Ethernet, "schedule transmit\n");
1358
1359    if (txEvent.scheduled())
1360        txEvent.reschedule(curTick + 1);
1361    else
1362        txEvent.schedule(curTick + 1);
1363}
1364
1365void
1366EtherDev::txDump() const
1367{
1368#if 0
1369    int i = tx_ptr;
1370    for (int loop = 0; loop < tx_ring_len; loop++) {
1371        es_desc *desc = &tx_ring[i];
1372
1373        if (desc->addr)
1374            cprintf("desc[%d]: addr=%#x, len=%d, flags=%#x\n",
1375                    i, desc->addr, desc->length, desc->flags);
1376
1377        if (++i >= tx_ring_len)
1378            i = 0;
1379    }
1380#endif
1381}
1382
1383void
1384EtherDev::rxDump() const
1385{
1386#if 0
1387    int i = rx_ptr;
1388    for (int loop = 0; loop < rx_ring_len; loop++) {
1389        es_desc *desc = &rx_ring[i];
1390
1391        if (desc->addr)
1392            cprintf("desc[%d]: addr=%#x, len=%d, flags=%#x\n",
1393                    i, desc->addr, desc->length, desc->flags);
1394
1395        if (++i >= rx_ring_len)
1396            i = 0;
1397    }
1398#endif
1399}
1400
1401bool
1402EtherDev::rxFilter(PacketPtr packet)
1403{
1404    bool drop = true;
1405    string type;
1406
1407    if (packet->IsUnicast()) {
1408        type = "unicast";
1409
1410        // If we're accepting all unicast addresses
1411        if (acceptUnicast)
1412            drop = false;
1413
1414        // If we make a perfect match
1415        if ((acceptPerfect)
1416            && (memcmp(regs.perfectMatch, packet->data, sizeof(regs.perfectMatch)) == 0))
1417            drop = false;
1418
1419        eth_header *eth = (eth_header *) packet->data;
1420        if ((acceptArp) && (eth->type == 0x806))
1421            drop = false;
1422
1423    } else if (packet->IsBroadcast()) {
1424        type = "broadcast";
1425
1426        // if we're accepting broadcasts
1427        if (acceptBroadcast)
1428            drop = false;
1429
1430    } else if (packet->IsMulticast()) {
1431        type = "multicast";
1432
1433        // if we're accepting all multicasts
1434        if (acceptMulticast)
1435            drop = false;
1436
1437    } else {
1438        type = "unknown";
1439
1440        // oh well, punt on this one
1441    }
1442
1443    if (drop) {
1444        DPRINTF(Ethernet, "rxFilter drop\n");
1445        DDUMP(EthernetData, packet->data, packet->length);
1446    }
1447
1448    return drop;
1449}
1450
1451bool
1452EtherDev::recvPacket(PacketPtr packet)
1453{
1454    rxBytes += packet->length;
1455    rxPackets++;
1456
1457    if (rxState == rxIdle) {
1458        DPRINTF(Ethernet, "receive disabled...packet dropped\n");
1459        interface->recvDone();
1460        return true;
1461    }
1462
1463    if (rxFilterEnable && rxFilter(packet)) {
1464        DPRINTF(Ethernet, "packet filtered...dropped\n");
1465        interface->recvDone();
1466        return true;
1467    }
1468
1469    if (rxFifoCnt + packet->length >= MAX_RX_FIFO_SIZE) {
1470        DPRINTF(Ethernet,
1471                "packet will not fit in receive buffer...packet dropped\n");
1472        devIntrPost(ISR_RXORN);
1473        return false;
1474    }
1475
1476    rxFifo.push_back(packet);
1477    rxPktBytes = packet->length;
1478    rxFifoCnt += packet->length;
1479    interface->recvDone();
1480
1481    return true;
1482}
1483
1484bool
1485EtherDev::udpChecksum(PacketPtr packet, bool gen)
1486{
1487    udp_header *hdr = (udp_header *)  packet->getTransportHdr();
1488
1489    ip_header *ip = packet->getIpHdr();
1490
1491    pseudo_header *pseudo = new pseudo_header;
1492
1493    pseudo->src_ip_addr = ip->src_ip_addr;
1494    pseudo->dest_ip_addr = ip->dest_ip_addr;
1495    pseudo->protocol = ip->protocol;
1496    pseudo->len = hdr->len;
1497
1498    uint16_t cksum = checksumCalc((uint16_t *) pseudo, (uint16_t *) hdr,
1499                                  (uint32_t) hdr->len);
1500
1501    delete pseudo;
1502    if (gen)
1503        hdr->chksum = cksum;
1504    else
1505        if (cksum != 0)
1506            return false;
1507
1508    return true;
1509}
1510
1511bool
1512EtherDev::tcpChecksum(PacketPtr packet, bool gen)
1513{
1514    tcp_header *hdr = (tcp_header *) packet->getTransportHdr();
1515
1516    ip_header *ip = packet->getIpHdr();
1517
1518    pseudo_header *pseudo = new pseudo_header;
1519
1520    pseudo->src_ip_addr = ip->src_ip_addr;
1521    pseudo->dest_ip_addr = ip->dest_ip_addr;
1522    pseudo->protocol = ip->protocol;
1523    pseudo->len = ip->dgram_len - (ip->vers_len & 0xf);
1524
1525    uint16_t cksum = checksumCalc((uint16_t *) pseudo, (uint16_t *) hdr,
1526                                  (uint32_t) pseudo->len);
1527
1528    delete pseudo;
1529    if (gen)
1530        hdr->chksum = cksum;
1531    else
1532        if (cksum != 0)
1533            return false;
1534
1535    return true;
1536}
1537
1538bool
1539EtherDev::ipChecksum(PacketPtr packet, bool gen)
1540{
1541    ip_header *hdr = packet->getIpHdr();
1542
1543    uint16_t cksum = checksumCalc(NULL, (uint16_t *) hdr, (hdr->vers_len & 0xf));
1544
1545    if (gen)
1546        hdr->hdr_chksum = cksum;
1547    else
1548        if (cksum != 0)
1549            return false;
1550
1551    return true;
1552}
1553
1554uint16_t
1555EtherDev::checksumCalc(uint16_t *pseudo, uint16_t *buf, uint32_t len)
1556{
1557    uint32_t sum = 0;
1558
1559    uint16_t last_pad = 0;
1560    if (len & 1) {
1561        last_pad = buf[len/2] & 0xff;
1562        len--;
1563        sum += last_pad;
1564    }
1565
1566    if (pseudo) {
1567        sum = pseudo[0] + pseudo[1] + pseudo[2] +
1568            pseudo[3] + pseudo[4] + pseudo[5];
1569    }
1570
1571    for (int i=0; i < (len/2); ++i) {
1572        sum += buf[i];
1573    }
1574
1575    while (sum >> 16)
1576        sum = (sum >> 16) + (sum & 0xffff);
1577
1578    return ~sum;
1579}
1580
1581//=====================================================================
1582//
1583//
1584void
1585dp_regs::serialize(ostream &os)
1586{
1587    SERIALIZE_SCALAR(command);
1588    SERIALIZE_SCALAR(config);
1589    SERIALIZE_SCALAR(isr);
1590    SERIALIZE_SCALAR(imr);
1591}
1592
1593void
1594dp_regs::unserialize(Checkpoint *cp, const std::string &section)
1595{
1596    UNSERIALIZE_SCALAR(command);
1597    UNSERIALIZE_SCALAR(config);
1598    UNSERIALIZE_SCALAR(isr);
1599    UNSERIALIZE_SCALAR(imr);
1600#if 0
1601    UNSERIALIZE_SCALAR(tx_ring);
1602    UNSERIALIZE_SCALAR(rx_ring);
1603    UNSERIALIZE_SCALAR(tx_ring_len);
1604    UNSERIALIZE_SCALAR(rx_ring_len);
1605    UNSERIALIZE_SCALAR(rom_addr);
1606    UNSERIALIZE_SCALAR(rom_data);
1607    UNSERIALIZE_SCALAR(rxfilt_ctl);
1608    UNSERIALIZE_SCALAR(rxfilt_data);
1609
1610    UNSERIALIZE_ARRAY(perfect,EADDR_LEN);
1611    UNSERIALIZE_ARRAY(hash_table,ES_HASH_SIZE);
1612
1613    UNSERIALIZE_SCALAR(tx_ring_ptr);
1614    UNSERIALIZE_SCALAR(rx_ring_ptr);
1615#endif
1616}
1617
1618//---------------------------------------
1619
1620void
1621EtherPacket::serialize(ostream &os)
1622{
1623    SERIALIZE_SCALAR(length);
1624    SERIALIZE_ARRAY(data, length);
1625}
1626
1627void
1628EtherPacket::unserialize(Checkpoint *cp, const std::string &section)
1629{
1630    UNSERIALIZE_SCALAR(length);
1631    data = new uint8_t[length];
1632    UNSERIALIZE_ARRAY(data, length);
1633}
1634
1635//---------------------------------------
1636
1637void
1638EtherDev::serialize(ostream &os)
1639{
1640
1641#if 0
1642    regs.serialize(os);
1643
1644    // tx_ring & rx_ring are contained in the physmem...
1645    SERIALIZE_SCALAR(cpuPendingIntr);
1646    SERIALIZE_SCALAR(tx_ptr);
1647    SERIALIZE_SCALAR(rx_ptr);
1648
1649    SERIALIZE_SCALAR(rxDoneCB.ptr);
1650    SERIALIZE_SCALAR(rxDoneCB.ignore);
1651
1652    SERIALIZE_SCALAR(txDoneCB.ptr);
1653    SERIALIZE_SCALAR(txDoneCB.ignore);
1654
1655    for (int i=0; i<ES_MAX_DMA_SEGS; ++i) {
1656        paramOut(os, csprintf("readPhys%d.addr",i),   readPhys[i].addr);
1657        paramOut(os, csprintf("readPhys%d.length",i), readPhys[i].length);
1658        paramOut(os, csprintf("writePhys%d.addr",i),   writePhys[i].addr);
1659        paramOut(os, csprintf("writePhys%d.length",i), writePhys[i].length);
1660    }
1661
1662    SERIALIZE_SCALAR(txEnable);
1663    SERIALIZE_SCALAR(rxEnable);
1664    SERIALIZE_SCALAR(txDelay);
1665    SERIALIZE_SCALAR(rxDelay);
1666
1667    SERIALIZE_SCALAR(txbuf_len);
1668
1669    //Calculate the number here, actually dump them at end
1670    int numTxPkts=0;
1671    for (pktiter_t p=txbuf.begin(); p!=txbuf.end(); ++p) {
1672        numTxPkts++;
1673    }
1674    SERIALIZE_SCALAR(numTxPkts);
1675
1676    SERIALIZE_SCALAR(rxbuf_len);
1677    int numRxPkts=0;
1678    for (pktiter_t p=rxbuf.begin(); p!=rxbuf.end(); ++p) {
1679        numRxPkts++;
1680    }
1681    SERIALIZE_SCALAR(numRxPkts);
1682
1683    // output whether the tx and rx packets exist
1684    bool txPacketExists = false;
1685    if (txDoneCB.packet)
1686        txPacketExists = true;
1687    SERIALIZE_SCALAR(txPacketExists);
1688
1689    bool rxPacketExists = false;
1690    if (rxPacket)
1691        rxPacketExists = true;
1692    SERIALIZE_SCALAR(rxPacketExists);
1693
1694    // output the names (unique by pointer) of the read and write requests
1695    paramOut(os, csprintf("readReqName"), readRequest.name());
1696    paramOut(os, csprintf("writeReqName"), writeRequest.name());
1697
1698    // Serialize txPacket, because its data is needed for readRequest
1699    if (txPacketExists) {
1700        nameOut(os, csprintf("%s.txPacket", name()));
1701        txDoneCB.packet->serialize(os);
1702    }
1703
1704    // Serialize rxPacket, because its data is needed for writeRequest
1705    if (rxPacketExists) {
1706        nameOut(os, csprintf("%s.rxPacket", name()));
1707        rxPacket->serialize(os);
1708    }
1709
1710    // create a section for the readRequest
1711    nameOut(os, readRequest.name());
1712    paramOut(os, csprintf("parent"), name());
1713    paramOut(os, csprintf("id"), 0);
1714    readRequest.serialize(os);
1715
1716    // create a section for the writeRequest
1717    nameOut(os, writeRequest.name());
1718    paramOut(os, csprintf("parent"), name());
1719    paramOut(os, csprintf("id"), 1);
1720    writeRequest.serialize(os);
1721
1722    //Redo the buffers, this time outputing them to the file
1723    numTxPkts = 0;
1724    for (pktiter_t p=txbuf.begin(); p!=txbuf.end(); ++p) {
1725        nameOut(os, csprintf("%s.txbuf%d", name(),numTxPkts++));
1726        (*p)->serialize(os);
1727    }
1728
1729    numRxPkts = 0;
1730    for (pktiter_t p=rxbuf.begin(); p!=rxbuf.end(); ++p) {
1731        nameOut(os, csprintf("%s.rxbuf%d", name(),numRxPkts++));
1732        (*p)->serialize(os);
1733    }
1734#endif
1735}
1736
1737void
1738EtherDev::unserialize(Checkpoint *cp, const std::string &section)
1739{
1740#if 0
1741    regs.unserialize(cp, section);
1742
1743    UNSERIALIZE_SCALAR(cpuPendingIntr);
1744
1745    // initialize the tx_ring
1746    txReset();
1747
1748    // initialize the rx_ring
1749    rxReset();
1750
1751    UNSERIALIZE_SCALAR(tx_ptr);
1752    UNSERIALIZE_SCALAR(rx_ptr);
1753
1754    PacketPtr p;
1755    UNSERIALIZE_SCALAR(txbuf_len);
1756    int numTxPkts;
1757    UNSERIALIZE_SCALAR(numTxPkts);
1758    for (int i=0; i<numTxPkts; ++i) {
1759        p = new EtherPacket;
1760        p->unserialize(cp, csprintf("%s.txbuf%d", section, i));
1761        txbuf.push_back(p);
1762    }
1763
1764    UNSERIALIZE_SCALAR(rxbuf_len);
1765    int numRxPkts;
1766    UNSERIALIZE_SCALAR(numRxPkts);
1767    for (int i=0; i<numRxPkts; ++i) {
1768        p = new EtherPacket;
1769        p->unserialize(cp, csprintf("%s.rxbuf%d", section, i));
1770        rxbuf.push_back(p);
1771    }
1772
1773    UNSERIALIZE_SCALAR(rxDoneCB.ptr);
1774    UNSERIALIZE_SCALAR(rxDoneCB.ignore);
1775
1776    UNSERIALIZE_SCALAR(txDoneCB.ptr);
1777    UNSERIALIZE_SCALAR(txDoneCB.ignore);
1778
1779    for (int i=0; i<ES_MAX_DMA_SEGS; ++i) {
1780        paramIn(cp, section, csprintf("readPhys%d.addr",i),
1781                readPhys[i].addr);
1782        paramIn(cp, section, csprintf("readPhys%d.length",i),
1783                readPhys[i].length);
1784        paramIn(cp, section, csprintf("writePhys%d.addr",i),
1785                writePhys[i].addr);
1786        paramIn(cp, section, csprintf("writePhys%d.length",i),
1787                writePhys[i].length);
1788    }
1789
1790    UNSERIALIZE_SCALAR(txEnable);
1791    UNSERIALIZE_SCALAR(rxEnable);
1792    UNSERIALIZE_SCALAR(txDelay);
1793    UNSERIALIZE_SCALAR(rxDelay);
1794
1795    // Unserialize the current txPacket
1796    bool txPacketExists;
1797    UNSERIALIZE_SCALAR(txPacketExists);
1798
1799    txDoneCB.packet = NULL;
1800    if (txPacketExists) {
1801        txDoneCB.packet = new EtherPacket;
1802        txDoneCB.packet->unserialize(cp, csprintf("%s.txPacket", section));
1803    }
1804
1805    // Unserialize the current rxPacket
1806    bool rxPacketExists;
1807    UNSERIALIZE_SCALAR(rxPacketExists);
1808
1809    rxPacket = NULL;
1810    if (rxPacketExists) {
1811        rxPacket = new EtherPacket;
1812        rxPacket->unserialize(cp, csprintf("%s.rxPacket", section));
1813    }
1814
1815    std::string readReqName, writeReqName;
1816    UNSERIALIZE_SCALAR(readReqName);
1817    UNSERIALIZE_SCALAR(writeReqName);
1818
1819    // Unserialize and fixup the readRequest
1820    readRequest.unserialize(cp, readReqName);
1821    readRequest.phys = readPhys;
1822    readRequest.bufferCB = 0;
1823    readRequest.dmaDoneCB = &txDoneCB;
1824    readRequest.data = NULL;
1825
1826    if (txDoneCB.packet)
1827        readRequest.data = txDoneCB.packet->data;
1828
1829    // Unserialize and fixup the writeRequest
1830    writeRequest.unserialize(cp, writeReqName);
1831    writeRequest.phys = writePhys;
1832    writeRequest.bufferCB = 0;
1833    writeRequest.dmaDoneCB = &rxDoneCB;
1834    writeRequest.data = NULL;
1835
1836    if (rxPacket)
1837        writeRequest.data = rxPacket->data;
1838#endif
1839}
1840
1841
1842//=====================================================================
1843
1844
1845BEGIN_DECLARE_SIM_OBJECT_PARAMS(EtherDevInt)
1846
1847    SimObjectParam<EtherInt *> peer;
1848    SimObjectParam<EtherDev *> device;
1849
1850END_DECLARE_SIM_OBJECT_PARAMS(EtherDevInt)
1851
1852BEGIN_INIT_SIM_OBJECT_PARAMS(EtherDevInt)
1853
1854    INIT_PARAM_DFLT(peer, "peer interface", NULL),
1855    INIT_PARAM(device, "Ethernet device of this interface")
1856
1857END_INIT_SIM_OBJECT_PARAMS(EtherDevInt)
1858
1859CREATE_SIM_OBJECT(EtherDevInt)
1860{
1861    EtherDevInt *dev_int = new EtherDevInt(getInstanceName(), device);
1862
1863    EtherInt *p = (EtherInt *)peer;
1864    if (p) {
1865        dev_int->setPeer(p);
1866        p->setPeer(dev_int);
1867    }
1868
1869    return dev_int;
1870}
1871
1872REGISTER_SIM_OBJECT("EtherDevInt", EtherDevInt)
1873
1874
1875BEGIN_DECLARE_SIM_OBJECT_PARAMS(EtherDev)
1876
1877    Param<Tick> tx_delay;
1878    Param<Tick> rx_delay;
1879    SimObjectParam<DmaEngine *> engine;
1880    Param<bool> use_interface;
1881    SimObjectParam<IntrControl *> intr_ctrl;
1882    SimObjectParam<MemoryController *> mmu;
1883    SimObjectParam<PhysicalMemory *> physmem;
1884    Param<Addr> addr;
1885    Param<Addr> mask;
1886    Param<bool> rx_filter;
1887    Param<string> hardware_address;
1888    SimObjectParam<PCIConfigAll *> configspace;
1889    SimObjectParam<PciConfigData *> configdata;
1890    SimObjectParam<Tsunami *> tsunami;
1891    Param<uint32_t> pci_bus;
1892    Param<uint32_t> pci_dev;
1893    Param<uint32_t> pci_func;
1894
1895END_DECLARE_SIM_OBJECT_PARAMS(EtherDev)
1896
1897BEGIN_INIT_SIM_OBJECT_PARAMS(EtherDev)
1898
1899    INIT_PARAM_DFLT(tx_delay, "Transmit Delay", 1000),
1900    INIT_PARAM_DFLT(rx_delay, "Receive Delay", 1000),
1901    INIT_PARAM(engine, "DMA Engine"),
1902    INIT_PARAM_DFLT(use_interface, "Use DMA Interface", true),
1903    INIT_PARAM(intr_ctrl, "Interrupt Controller"),
1904    INIT_PARAM(mmu, "Memory Controller"),
1905    INIT_PARAM(physmem, "Physical Memory"),
1906    INIT_PARAM(addr, "Device Address"),
1907    INIT_PARAM(mask, "Address Mask"),
1908    INIT_PARAM_DFLT(rx_filter, "Enable Receive Filter", true),
1909    INIT_PARAM_DFLT(hardware_address, "Ethernet Hardware Address",
1910                    "00:99:00:00:00:01"),
1911    INIT_PARAM(configspace, "PCI Configspace"),
1912    INIT_PARAM(configdata, "PCI Config data"),
1913    INIT_PARAM(tsunami, "Tsunami"),
1914    INIT_PARAM(pci_bus, "PCI bus"),
1915    INIT_PARAM(pci_dev, "PCI device number"),
1916    INIT_PARAM(pci_func, "PCI function code")
1917
1918END_INIT_SIM_OBJECT_PARAMS(EtherDev)
1919
1920
1921CREATE_SIM_OBJECT(EtherDev)
1922{
1923    int eaddr[6];
1924    sscanf(((string)hardware_address).c_str(), "%x:%x:%x:%x:%x:%x",
1925           &eaddr[0], &eaddr[1], &eaddr[2], &eaddr[3], &eaddr[4], &eaddr[5]);
1926
1927    return new EtherDev(getInstanceName(), engine, use_interface,
1928                        intr_ctrl, mmu, physmem, configspace, configdata,
1929                        tsunami, pci_bus, pci_dev, pci_func, rx_filter, eaddr,
1930                        tx_delay, rx_delay, addr, mask);
1931}
1932
1933REGISTER_SIM_OBJECT("EtherDev", EtherDev)
1934