sinic.cc revision 1998
19814Sandreas.hansson@arm.com/*
22292SN/A * Copyright (c) 2004-2005 The Regents of The University of Michigan
310333Smitch.hayenga@arm.com * All rights reserved.
410239Sbinhpham@cs.rutgers.edu *
57597Sminkyu.jeong@arm.com * Redistribution and use in source and binary forms, with or without
67597Sminkyu.jeong@arm.com * modification, are permitted provided that the following conditions are
77597Sminkyu.jeong@arm.com * met: redistributions of source code must retain the above copyright
87597Sminkyu.jeong@arm.com * notice, this list of conditions and the following disclaimer;
97597Sminkyu.jeong@arm.com * redistributions in binary form must reproduce the above copyright
107597Sminkyu.jeong@arm.com * notice, this list of conditions and the following disclaimer in the
117597Sminkyu.jeong@arm.com * documentation and/or other materials provided with the distribution;
127597Sminkyu.jeong@arm.com * neither the name of the copyright holders nor the names of its
137597Sminkyu.jeong@arm.com * contributors may be used to endorse or promote products derived from
147597Sminkyu.jeong@arm.com * this software without specific prior written permission.
157597Sminkyu.jeong@arm.com *
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.
272292SN/A */
282292SN/A
292292SN/A#include <cstdio>
302292SN/A#include <deque>
312292SN/A#include <string>
322292SN/A
332292SN/A#include "base/inet.hh"
342292SN/A#include "cpu/exec_context.hh"
352292SN/A#include "cpu/intr_control.hh"
362292SN/A#include "dev/etherlink.hh"
372292SN/A#include "dev/sinic.hh"
382292SN/A#include "dev/pciconfigall.hh"
392292SN/A#include "mem/bus/bus.hh"
402292SN/A#include "mem/bus/dma_interface.hh"
412689Sktlim@umich.edu#include "mem/bus/pio_interface.hh"
422689Sktlim@umich.edu#include "mem/bus/pio_interface_impl.hh"
432689Sktlim@umich.edu#include "mem/functional/memory_control.hh"
442292SN/A#include "mem/functional/physical.hh"
452292SN/A#include "sim/builder.hh"
469944Smatt.horsnell@ARM.com#include "sim/debug.hh"
479944Smatt.horsnell@ARM.com#include "sim/eventq.hh"
489944Smatt.horsnell@ARM.com#include "sim/host.hh"
498591Sgblack@eecs.umich.edu#include "sim/stats.hh"
503326Sktlim@umich.edu#include "targetarch/vtophys.hh"
518229Snate@binkert.org
526658Snate@binkert.orgusing namespace Net;
538887Sgeoffrey.blake@arm.com
542907Sktlim@umich.edunamespace Sinic {
552292SN/A
568232Snate@binkert.orgconst char *RxStateStrings[] =
578232Snate@binkert.org{
588232Snate@binkert.org    "rxIdle",
599527SMatt.Horsnell@arm.com    "rxFifoBlock",
602722Sktlim@umich.edu    "rxBeginCopy",
612669Sktlim@umich.edu    "rxCopy",
622292SN/A    "rxCopyDone"
632669Sktlim@umich.edu};
642678Sktlim@umich.edu
652678Sktlim@umich.educonst char *TxStateStrings[] =
668581Ssteve.reinhardt@amd.com{
678581Ssteve.reinhardt@amd.com    "txIdle",
682292SN/A    "txFifoBlock",
692292SN/A    "txBeginCopy",
702292SN/A    "txCopy",
712669Sktlim@umich.edu    "txCopyDone"
722292SN/A};
732678Sktlim@umich.edu
742292SN/A
759444SAndreas.Sandberg@ARM.com///////////////////////////////////////////////////////////////////////
769444SAndreas.Sandberg@ARM.com//
779444SAndreas.Sandberg@ARM.com// Sinic PCI Device
784319Sktlim@umich.edu//
794319Sktlim@umich.eduBase::Base(Params *p)
804319Sktlim@umich.edu    : PciDev(p), rxEnable(false), txEnable(false), clock(p->clock),
814319Sktlim@umich.edu      intrDelay(p->intr_delay), intrTick(0), cpuIntrEnable(false),
824319Sktlim@umich.edu      cpuPendingIntr(false), intrEvent(0), interface(NULL)
832678Sktlim@umich.edu{
842678Sktlim@umich.edu}
852292SN/A
862678Sktlim@umich.eduDevice::Device(Params *p)
872678Sktlim@umich.edu    : Base(p), plat(p->plat), physmem(p->physmem),
885336Shines@cs.fsu.edu      rxFifo(p->rx_fifo_size), txFifo(p->tx_fifo_size),
892678Sktlim@umich.edu      rxKickTick(0), txKickTick(0),
904873Sstever@eecs.umich.edu      txEvent(this), rxDmaEvent(this), txDmaEvent(this),
912678Sktlim@umich.edu      dmaReadDelay(p->dma_read_delay), dmaReadFactor(p->dma_read_factor),
922292SN/A      dmaWriteDelay(p->dma_write_delay), dmaWriteFactor(p->dma_write_factor)
932678Sktlim@umich.edu{
942678Sktlim@umich.edu    reset();
952678Sktlim@umich.edu
962678Sktlim@umich.edu    if (p->pio_bus) {
972678Sktlim@umich.edu        pioInterface = newPioInterface(p->name + ".pio", p->hier, p->pio_bus,
982678Sktlim@umich.edu                                       this, &Device::cacheAccess);
997852SMatt.Horsnell@arm.com        pioLatency = p->pio_latency * p->pio_bus->clockRate;
1007852SMatt.Horsnell@arm.com    }
1012344SN/A
10210333Smitch.hayenga@arm.com    if (p->header_bus) {
10310333Smitch.hayenga@arm.com        if (p->payload_bus)
10410333Smitch.hayenga@arm.com            dmaInterface = new DMAInterface<Bus>(p->name + ".dma",
10510333Smitch.hayenga@arm.com                                                 p->header_bus,
10610333Smitch.hayenga@arm.com                                                 p->payload_bus, 1,
10710333Smitch.hayenga@arm.com                                                 p->dma_no_allocate);
10810333Smitch.hayenga@arm.com        else
10910333Smitch.hayenga@arm.com            dmaInterface = new DMAInterface<Bus>(p->name + ".dma",
11010333Smitch.hayenga@arm.com                                                 p->header_bus,
11110333Smitch.hayenga@arm.com                                                 p->header_bus, 1,
1122678Sktlim@umich.edu                                                 p->dma_no_allocate);
1136974Stjones1@inf.ed.ac.uk    } else if (p->payload_bus)
1146974Stjones1@inf.ed.ac.uk        panic("must define a header bus if defining a payload bus");
1156974Stjones1@inf.ed.ac.uk
1166974Stjones1@inf.ed.ac.uk    pioDelayWrite = p->pio_delay_write && pioInterface;
1176974Stjones1@inf.ed.ac.uk}
1186974Stjones1@inf.ed.ac.uk
1196974Stjones1@inf.ed.ac.ukDevice::~Device()
1209444SAndreas.Sandberg@ARM.com{}
12110327Smitch.hayenga@arm.com
1222678Sktlim@umich.eduvoid
1236974Stjones1@inf.ed.ac.ukDevice::regStats()
1246974Stjones1@inf.ed.ac.uk{
1256974Stjones1@inf.ed.ac.uk    rxBytes
1266974Stjones1@inf.ed.ac.uk        .name(name() + ".rxBytes")
1276974Stjones1@inf.ed.ac.uk        .desc("Bytes Received")
1286974Stjones1@inf.ed.ac.uk        .prereq(rxBytes)
1292678Sktlim@umich.edu        ;
1302678Sktlim@umich.edu
1312678Sktlim@umich.edu    rxBandwidth
1322678Sktlim@umich.edu        .name(name() + ".rxBandwidth")
1332678Sktlim@umich.edu        .desc("Receive Bandwidth (bits/s)")
1342344SN/A        .precision(0)
1352307SN/A        .prereq(rxBytes)
1366974Stjones1@inf.ed.ac.uk        ;
1376974Stjones1@inf.ed.ac.uk
1386974Stjones1@inf.ed.ac.uk    rxPackets
1396974Stjones1@inf.ed.ac.uk        .name(name() + ".rxPackets")
14010020Smatt.horsnell@ARM.com        .desc("Number of Packets Received")
14110020Smatt.horsnell@ARM.com        .prereq(rxBytes)
14210023Smatt.horsnell@ARM.com        ;
14310023Smatt.horsnell@ARM.com
1442678Sktlim@umich.edu    rxPacketRate
1454032Sktlim@umich.edu        .name(name() + ".rxPPS")
1462678Sktlim@umich.edu        .desc("Packet Reception Rate (packets/s)")
1472292SN/A        .precision(0)
1482292SN/A        .prereq(rxBytes)
1492292SN/A        ;
1502292SN/A
1518545Ssaidi@eecs.umich.edu    rxIpPackets
15210333Smitch.hayenga@arm.com        .name(name() + ".rxIpPackets")
1532292SN/A        .desc("Number of IP Packets Received")
1542292SN/A        .prereq(rxBytes)
1552292SN/A        ;
1562292SN/A
1572292SN/A    rxTcpPackets
1585529Snate@binkert.org        .name(name() + ".rxTcpPackets")
1595529Snate@binkert.org        .desc("Number of Packets Received")
1605529Snate@binkert.org        .prereq(rxBytes)
1612292SN/A        ;
1624329Sktlim@umich.edu
1634329Sktlim@umich.edu    rxUdpPackets
1644329Sktlim@umich.edu        .name(name() + ".rxUdpPackets")
1652907Sktlim@umich.edu        .desc("Number of UDP Packets Received")
1662907Sktlim@umich.edu        .prereq(rxBytes)
1672292SN/A        ;
1682292SN/A
16910175SMitch.Hayenga@ARM.com    rxIpChecksums
17010175SMitch.Hayenga@ARM.com        .name(name() + ".rxIpChecksums")
1712329SN/A        .desc("Number of rx IP Checksums done by device")
1722329SN/A        .precision(0)
1732329SN/A        .prereq(rxBytes)
1742292SN/A        ;
1759936SFaissal.Sleiman@arm.com
1769936SFaissal.Sleiman@arm.com    rxTcpChecksums
1779936SFaissal.Sleiman@arm.com        .name(name() + ".rxTcpChecksums")
1789936SFaissal.Sleiman@arm.com        .desc("Number of rx TCP Checksums done by device")
1792292SN/A        .precision(0)
1802292SN/A        .prereq(rxBytes)
1812292SN/A        ;
1828199SAli.Saidi@ARM.com
1838199SAli.Saidi@ARM.com    rxUdpChecksums
1849444SAndreas.Sandberg@ARM.com        .name(name() + ".rxUdpChecksums")
1859444SAndreas.Sandberg@ARM.com        .desc("Number of rx UDP Checksums done by device")
1869444SAndreas.Sandberg@ARM.com        .precision(0)
1879444SAndreas.Sandberg@ARM.com        .prereq(rxBytes)
1889444SAndreas.Sandberg@ARM.com        ;
1899444SAndreas.Sandberg@ARM.com
1909444SAndreas.Sandberg@ARM.com    totBandwidth
1919444SAndreas.Sandberg@ARM.com        .name(name() + ".totBandwidth")
1929444SAndreas.Sandberg@ARM.com        .desc("Total Bandwidth (bits/s)")
1939444SAndreas.Sandberg@ARM.com        .precision(0)
1949444SAndreas.Sandberg@ARM.com        .prereq(totBytes)
1959444SAndreas.Sandberg@ARM.com        ;
1968199SAli.Saidi@ARM.com
1972292SN/A    totPackets
1982292SN/A        .name(name() + ".totPackets")
1992292SN/A        .desc("Total Packets")
2002292SN/A        .precision(0)
2012292SN/A        .prereq(totBytes)
2022292SN/A        ;
2033492Sktlim@umich.edu
2042329SN/A    totBytes
2052292SN/A        .name(name() + ".totBytes")
2069444SAndreas.Sandberg@ARM.com        .desc("Total Bytes")
2079444SAndreas.Sandberg@ARM.com        .precision(0)
2089814Sandreas.hansson@arm.com        .prereq(totBytes)
2092292SN/A        ;
2102292SN/A
2112292SN/A    totPacketRate
2122292SN/A        .name(name() + ".totPPS")
2132292SN/A        .desc("Total Tranmission Rate (packets/s)")
2142292SN/A        .precision(0)
2152292SN/A        .prereq(totBytes)
2162292SN/A        ;
2172292SN/A
2188247Snate@binkert.org    txBytes
2192292SN/A        .name(name() + ".txBytes")
2202292SN/A        .desc("Bytes Transmitted")
2212292SN/A        .prereq(txBytes)
2222292SN/A        ;
2232292SN/A
2242727Sktlim@umich.edu    txBandwidth
2252727Sktlim@umich.edu        .name(name() + ".txBandwidth")
2262727Sktlim@umich.edu        .desc("Transmit Bandwidth (bits/s)")
2272727Sktlim@umich.edu        .precision(0)
2282727Sktlim@umich.edu        .prereq(txBytes)
2292727Sktlim@umich.edu        ;
2302727Sktlim@umich.edu
2312727Sktlim@umich.edu    txPackets
2322727Sktlim@umich.edu        .name(name() + ".txPackets")
2332727Sktlim@umich.edu        .desc("Number of Packets Transmitted")
2342727Sktlim@umich.edu        .prereq(txBytes)
2352727Sktlim@umich.edu        ;
2362727Sktlim@umich.edu
2372727Sktlim@umich.edu    txPacketRate
2382727Sktlim@umich.edu        .name(name() + ".txPPS")
2392727Sktlim@umich.edu        .desc("Packet Tranmission Rate (packets/s)")
2402727Sktlim@umich.edu        .precision(0)
2412727Sktlim@umich.edu        .prereq(txBytes)
2422361SN/A        ;
2432361SN/A
2442361SN/A    txIpPackets
2452361SN/A        .name(name() + ".txIpPackets")
2462727Sktlim@umich.edu        .desc("Number of IP Packets Transmitted")
2472727Sktlim@umich.edu        .prereq(txBytes)
2482727Sktlim@umich.edu        ;
2492727Sktlim@umich.edu
2502727Sktlim@umich.edu    txTcpPackets
2512727Sktlim@umich.edu        .name(name() + ".txTcpPackets")
2522727Sktlim@umich.edu        .desc("Number of TCP Packets Transmitted")
2532727Sktlim@umich.edu        .prereq(txBytes)
2542727Sktlim@umich.edu        ;
2552727Sktlim@umich.edu
2562727Sktlim@umich.edu    txUdpPackets
2572727Sktlim@umich.edu        .name(name() + ".txUdpPackets")
2582727Sktlim@umich.edu        .desc("Number of Packets Transmitted")
2592727Sktlim@umich.edu        .prereq(txBytes)
2602727Sktlim@umich.edu        ;
2612727Sktlim@umich.edu
2622727Sktlim@umich.edu    txIpChecksums
2632727Sktlim@umich.edu        .name(name() + ".txIpChecksums")
2642727Sktlim@umich.edu        .desc("Number of tx IP Checksums done by device")
2652727Sktlim@umich.edu        .precision(0)
2662727Sktlim@umich.edu        .prereq(txBytes)
2672727Sktlim@umich.edu        ;
2682727Sktlim@umich.edu
2698922Swilliam.wang@arm.com    txTcpChecksums
2704329Sktlim@umich.edu        .name(name() + ".txTcpChecksums")
2714329Sktlim@umich.edu        .desc("Number of tx TCP Checksums done by device")
2724329Sktlim@umich.edu        .precision(0)
2734329Sktlim@umich.edu        .prereq(txBytes)
2744329Sktlim@umich.edu        ;
2754329Sktlim@umich.edu
2762292SN/A    txUdpChecksums
2772292SN/A        .name(name() + ".txUdpChecksums")
2782292SN/A        .desc("Number of tx UDP Checksums done by device")
2792292SN/A        .precision(0)
2802292SN/A        .prereq(txBytes)
2812292SN/A        ;
2822292SN/A
2832292SN/A    txBandwidth = txBytes * Stats::constant(8) / simSeconds;
2842292SN/A    rxBandwidth = rxBytes * Stats::constant(8) / simSeconds;
2852292SN/A    totBandwidth = txBandwidth + rxBandwidth;
2862292SN/A    totBytes = txBytes + rxBytes;
2872292SN/A    totPackets = txPackets + rxPackets;
2882292SN/A    txPacketRate = txPackets / simSeconds;
2892292SN/A    rxPacketRate = rxPackets / simSeconds;
2909444SAndreas.Sandberg@ARM.com}
2912307SN/A
2929444SAndreas.Sandberg@ARM.com/**
2932367SN/A * This is to write to the PCI general configuration registers
2942307SN/A */
2952329SN/Avoid
2969444SAndreas.Sandberg@ARM.comDevice::writeConfig(int offset, int size, const uint8_t *data)
2972307SN/A{
2982307SN/A    switch (offset) {
2992307SN/A      case PCI0_BASE_ADDR0:
3002307SN/A        // Need to catch writes to BARs to update the PIO interface
3012307SN/A        PciDev::writeConfig(offset, size, data);
3022307SN/A        if (BARAddrs[0] != 0) {
3039444SAndreas.Sandberg@ARM.com            if (pioInterface)
3042307SN/A                pioInterface->addAddrRange(RangeSize(BARAddrs[0], BARSize[0]));
3052307SN/A
3062307SN/A            BARAddrs[0] &= EV5::PAddrUncachedMask;
3072307SN/A        }
3082292SN/A        break;
3092292SN/A
3102329SN/A      default:
3112329SN/A        PciDev::writeConfig(offset, size, data);
3122292SN/A    }
3132329SN/A}
3142329SN/A
3152292SN/Avoid
3162292SN/ADevice::prepareIO(int cpu)
3172292SN/A{
3182292SN/A    if (cpu >= writeQueue.size())
3192292SN/A        writeQueue.resize(cpu + 1);
3202329SN/A}
3212292SN/A
3222292SN/Avoid
3239936SFaissal.Sleiman@arm.comDevice::prepareRead(int cpu)
3242292SN/A{
3252292SN/A    using namespace Regs;
3262292SN/A
3272292SN/A    // update rx registers
3282292SN/A    regs.RxDone = set_RxDone_Packets(regs.RxDone, rxFifo.packets());
3292292SN/A    regs.RxWait = regs.RxDone;
3302329SN/A
3312329SN/A    // update tx regsiters
3322329SN/A    regs.TxDone = set_TxDone_Packets(regs.TxDone, txFifo.packets());
3332292SN/A    regs.TxDone = set_TxDone_Full(regs.TxDone,
3342292SN/A                                  txFifo.avail() < regs.TxMaxCopy);
3352292SN/A    regs.TxDone = set_TxDone_Low(regs.TxDone,
3362292SN/A                                 txFifo.size() < regs.TxFifoMark);
3372292SN/A    regs.TxWait = regs.TxDone;
3382329SN/A}
3392292SN/A
3409936SFaissal.Sleiman@arm.comvoid
3419936SFaissal.Sleiman@arm.comDevice::prepareWrite(int cpu)
3422292SN/A{
3432292SN/A    prepareIO(cpu);
3442292SN/A}
3452292SN/A
3462292SN/A/**
3472292SN/A * I/O read of device register
3482292SN/A */
3492292SN/AFault
3502292SN/ADevice::read(MemReqPtr &req, uint8_t *data)
3512292SN/A{
3522292SN/A    assert(config.command & PCI_CMD_MSE);
3532292SN/A    Fault fault = readBar(req, data);
3542292SN/A
3552292SN/A    if (fault == Machine_Check_Fault) {
3562292SN/A        panic("address does not map to a BAR pa=%#x va=%#x size=%d",
3572292SN/A              req->paddr, req->vaddr, req->size);
3582292SN/A
3592292SN/A        return Machine_Check_Fault;
3602292SN/A    }
3612292SN/A
3622292SN/A    return fault;
3632292SN/A}
3642292SN/A
3652329SN/AFault
3662329SN/ADevice::readBar0(MemReqPtr &req, Addr daddr, uint8_t *data)
3672292SN/A{
3687720Sgblack@eecs.umich.edu    int cpu = (req->xc->regs.ipr[TheISA::IPR_PALtemp16] >> 8) & 0xff;
3697720Sgblack@eecs.umich.edu
3702292SN/A    if (!regValid(daddr))
3712292SN/A        panic("invalid register: cpu=%d, da=%#x pa=%#x va=%#x size=%d",
3722292SN/A              cpu, daddr, req->paddr, req->vaddr, req->size);
3732292SN/A
3742292SN/A    const Regs::Info &info = regInfo(daddr);
3752292SN/A    if (!info.read)
3762292SN/A        panic("reading %s (write only): cpu=%d da=%#x pa=%#x va=%#x size=%d",
3772292SN/A              info.name, cpu, daddr, req->paddr, req->vaddr, req->size);
3782292SN/A
3792292SN/A    if (req->size != info.size)
3802292SN/A        panic("invalid size for reg %s: cpu=%d da=%#x pa=%#x va=%#x size=%d",
3812292SN/A              info.name, cpu, daddr, req->paddr, req->vaddr, req->size);
3822292SN/A
3832292SN/A    prepareRead(cpu);
3842292SN/A
3852292SN/A    uint64_t value = 0;
3862292SN/A    if (req->size == 4) {
3872292SN/A        uint32_t &reg = *(uint32_t *)data;
3882292SN/A        reg = regData32(daddr);
3892292SN/A        value = reg;
3902292SN/A    }
3912292SN/A
3922292SN/A    if (req->size == 8) {
3932292SN/A        uint64_t &reg = *(uint64_t *)data;
3947720Sgblack@eecs.umich.edu        reg = regData64(daddr);
3957720Sgblack@eecs.umich.edu        value = reg;
3962292SN/A    }
3972292SN/A
3982292SN/A    DPRINTF(EthernetPIO,
3992292SN/A            "read %s cpu=%d da=%#x pa=%#x va=%#x size=%d val=%#x\n",
4002292SN/A            info.name, cpu, daddr, req->paddr, req->vaddr, req->size, value);
4012292SN/A
4022292SN/A    // reading the interrupt status register has the side effect of
4032292SN/A    // clearing it
4042292SN/A    if (daddr == Regs::IntrStatus)
4052292SN/A        devIntrClear();
4062292SN/A
4072292SN/A    return No_Fault;
4082292SN/A}
4092292SN/A
4102292SN/A/**
4112292SN/A * IPR read of device register
4122292SN/A */
4132292SN/AFault
4142292SN/ADevice::iprRead(Addr daddr, int cpu, uint64_t &result)
4152292SN/A{
4162292SN/A    if (!regValid(daddr))
4172292SN/A        panic("invalid address: da=%#x", daddr);
4182292SN/A
4192292SN/A    const Regs::Info &info = regInfo(daddr);
42010239Sbinhpham@cs.rutgers.edu    if (!info.read)
4212292SN/A        panic("reading %s (write only): cpu=%d da=%#x", info.name, cpu, daddr);
42210239Sbinhpham@cs.rutgers.edu
42310239Sbinhpham@cs.rutgers.edu    DPRINTF(EthernetPIO, "IPR read %s: cpu=%d da=%#x\n",
42410239Sbinhpham@cs.rutgers.edu            info.name, cpu, daddr);
42510239Sbinhpham@cs.rutgers.edu
42610239Sbinhpham@cs.rutgers.edu    prepareRead(cpu);
4272292SN/A
42810239Sbinhpham@cs.rutgers.edu    if (info.size == 4)
42910239Sbinhpham@cs.rutgers.edu        result = regData32(daddr);
43010239Sbinhpham@cs.rutgers.edu
43110239Sbinhpham@cs.rutgers.edu    if (info.size == 8)
43210239Sbinhpham@cs.rutgers.edu        result = regData64(daddr);
43310239Sbinhpham@cs.rutgers.edu
43410239Sbinhpham@cs.rutgers.edu    DPRINTF(EthernetPIO, "IPR read %s: cpu=%s da=%#x val=%#x\n",
43510239Sbinhpham@cs.rutgers.edu            info.name, cpu, result);
43610239Sbinhpham@cs.rutgers.edu
43710239Sbinhpham@cs.rutgers.edu    return No_Fault;
4382292SN/A}
4392292SN/A
4408545Ssaidi@eecs.umich.edu/**
4418545Ssaidi@eecs.umich.edu * I/O write of device register
4428545Ssaidi@eecs.umich.edu */
4438545Ssaidi@eecs.umich.eduFault
44410030SAli.Saidi@ARM.comDevice::write(MemReqPtr &req, const uint8_t *data)
4458545Ssaidi@eecs.umich.edu{
4469383SAli.Saidi@ARM.com    assert(config.command & PCI_CMD_MSE);
4479383SAli.Saidi@ARM.com    Fault fault = writeBar(req, data);
4489383SAli.Saidi@ARM.com
4499383SAli.Saidi@ARM.com    if (fault == Machine_Check_Fault) {
45010030SAli.Saidi@ARM.com        panic("address does not map to a BAR pa=%#x va=%#x size=%d",
4519383SAli.Saidi@ARM.com              req->paddr, req->vaddr, req->size);
4529383SAli.Saidi@ARM.com
4539383SAli.Saidi@ARM.com        return Machine_Check_Fault;
4549383SAli.Saidi@ARM.com    }
4559383SAli.Saidi@ARM.com
4569383SAli.Saidi@ARM.com    return fault;
4579383SAli.Saidi@ARM.com}
45810030SAli.Saidi@ARM.com
45910030SAli.Saidi@ARM.comFault
46010030SAli.Saidi@ARM.comDevice::writeBar0(MemReqPtr &req, Addr daddr, const uint8_t *data)
46110030SAli.Saidi@ARM.com{
46210030SAli.Saidi@ARM.com    int cpu = (req->xc->regs.ipr[TheISA::IPR_PALtemp16] >> 8) & 0xff;
46310030SAli.Saidi@ARM.com
46410030SAli.Saidi@ARM.com    if (!regValid(daddr))
46510030SAli.Saidi@ARM.com        panic("invalid address: cpu=%d da=%#x pa=%#x va=%#x size=%d",
46610030SAli.Saidi@ARM.com              cpu, daddr, req->paddr, req->vaddr, req->size);
46710030SAli.Saidi@ARM.com
46810030SAli.Saidi@ARM.com    const Regs::Info &info = regInfo(daddr);
4698545Ssaidi@eecs.umich.edu    if (!info.write)
4708545Ssaidi@eecs.umich.edu        panic("writing %s (read only): cpu=%d da=%#x", info.name, cpu, daddr);
4718545Ssaidi@eecs.umich.edu
47210030SAli.Saidi@ARM.com    if (req->size != info.size)
4738545Ssaidi@eecs.umich.edu        panic("invalid size for %s: cpu=%d da=%#x pa=%#x va=%#x size=%d",
4748545Ssaidi@eecs.umich.edu              info.name, cpu, daddr, req->paddr, req->vaddr, req->size);
47510149Smarco.elver@ed.ac.uk
47610149Smarco.elver@ed.ac.uk    uint32_t reg32 = *(uint32_t *)data;
4778545Ssaidi@eecs.umich.edu    uint64_t reg64 = *(uint64_t *)data;
4788545Ssaidi@eecs.umich.edu    DPRINTF(EthernetPIO,
4798545Ssaidi@eecs.umich.edu            "write %s: cpu=%d val=%#x da=%#x pa=%#x va=%#x size=%d\n",
4809046SAli.Saidi@ARM.com            info.name, cpu, info.size == 4 ? reg32 : reg64, daddr,
4818545Ssaidi@eecs.umich.edu            req->paddr, req->vaddr, req->size);
4828545Ssaidi@eecs.umich.edu
4838545Ssaidi@eecs.umich.edu
4848545Ssaidi@eecs.umich.edu    if (pioDelayWrite)
4858545Ssaidi@eecs.umich.edu        writeQueue[cpu].push_back(RegWriteData(daddr, reg64));
4868545Ssaidi@eecs.umich.edu
4878545Ssaidi@eecs.umich.edu    if (!pioDelayWrite || !info.delay_write)
4888545Ssaidi@eecs.umich.edu        regWrite(daddr, cpu, data);
48910149Smarco.elver@ed.ac.uk
49010149Smarco.elver@ed.ac.uk    return No_Fault;
49110149Smarco.elver@ed.ac.uk}
49210149Smarco.elver@ed.ac.uk
49310149Smarco.elver@ed.ac.ukvoid
49410149Smarco.elver@ed.ac.ukDevice::regWrite(Addr daddr, int cpu, const uint8_t *data)
49510149Smarco.elver@ed.ac.uk{
49610149Smarco.elver@ed.ac.uk    uint32_t reg32 = *(uint32_t *)data;
4978545Ssaidi@eecs.umich.edu    uint64_t reg64 = *(uint64_t *)data;
49810030SAli.Saidi@ARM.com
4998545Ssaidi@eecs.umich.edu    switch (daddr) {
5008545Ssaidi@eecs.umich.edu      case Regs::Config:
5018545Ssaidi@eecs.umich.edu        changeConfig(reg32);
5028545Ssaidi@eecs.umich.edu        break;
50310030SAli.Saidi@ARM.com
50410030SAli.Saidi@ARM.com      case Regs::Command:
50510030SAli.Saidi@ARM.com        command(reg32);
50610030SAli.Saidi@ARM.com        break;
50710030SAli.Saidi@ARM.com
50810030SAli.Saidi@ARM.com      case Regs::IntrStatus:
50910030SAli.Saidi@ARM.com        devIntrClear(regs.IntrStatus & reg32);
51010030SAli.Saidi@ARM.com        break;
51110030SAli.Saidi@ARM.com
5128545Ssaidi@eecs.umich.edu      case Regs::IntrMask:
5138545Ssaidi@eecs.umich.edu        devIntrChangeMask(reg32);
5148545Ssaidi@eecs.umich.edu        break;
5159046SAli.Saidi@ARM.com
5168545Ssaidi@eecs.umich.edu      case Regs::RxData:
5178545Ssaidi@eecs.umich.edu        if (rxState != rxIdle)
5188545Ssaidi@eecs.umich.edu            panic("receive machine busy with another request! rxState=%s",
5198545Ssaidi@eecs.umich.edu                  RxStateStrings[rxState]);
5208545Ssaidi@eecs.umich.edu
5218545Ssaidi@eecs.umich.edu        regs.RxDone = Regs::RxDone_Busy;
5228545Ssaidi@eecs.umich.edu        regs.RxData = reg64;
5238545Ssaidi@eecs.umich.edu        if (rxEnable) {
5242292SN/A            rxState = rxFifoBlock;
5258199SAli.Saidi@ARM.com            rxKick();
5268199SAli.Saidi@ARM.com        }
5278199SAli.Saidi@ARM.com        break;
5288199SAli.Saidi@ARM.com
5298199SAli.Saidi@ARM.com      case Regs::TxData:
5308199SAli.Saidi@ARM.com        if (txState != txIdle)
5318199SAli.Saidi@ARM.com            panic("transmit machine busy with another request! txState=%s",
5328199SAli.Saidi@ARM.com                  TxStateStrings[txState]);
5338199SAli.Saidi@ARM.com
5348199SAli.Saidi@ARM.com        regs.TxDone = Regs::TxDone_Busy;
5358199SAli.Saidi@ARM.com        regs.TxData = reg64;
5368199SAli.Saidi@ARM.com        if (txEnable) {
5379046SAli.Saidi@ARM.com            txState = txFifoBlock;
5388199SAli.Saidi@ARM.com            txKick();
5398199SAli.Saidi@ARM.com        }
5408199SAli.Saidi@ARM.com        break;
5418199SAli.Saidi@ARM.com    }
5428199SAli.Saidi@ARM.com}
5438199SAli.Saidi@ARM.com
5448199SAli.Saidi@ARM.comvoid
5458199SAli.Saidi@ARM.comDevice::devIntrPost(uint32_t interrupts)
5468272SAli.Saidi@ARM.com{
5478545Ssaidi@eecs.umich.edu    if ((interrupts & Regs::Intr_Res))
5488545Ssaidi@eecs.umich.edu        panic("Cannot set a reserved interrupt");
5498545Ssaidi@eecs.umich.edu
5508545Ssaidi@eecs.umich.edu    regs.IntrStatus |= interrupts;
5519046SAli.Saidi@ARM.com
5528545Ssaidi@eecs.umich.edu    DPRINTF(EthernetIntr,
5538545Ssaidi@eecs.umich.edu            "interrupt written to intStatus: intr=%#x status=%#x mask=%#x\n",
5548545Ssaidi@eecs.umich.edu            interrupts, regs.IntrStatus, regs.IntrMask);
5558592Sgblack@eecs.umich.edu
5568592Sgblack@eecs.umich.edu    interrupts = regs.IntrStatus & regs.IntrMask;
5578545Ssaidi@eecs.umich.edu
5588199SAli.Saidi@ARM.com    // Intr_RxHigh is special, we only signal it if we've emptied the fifo
5598545Ssaidi@eecs.umich.edu    // and then filled it above the high watermark
5608199SAli.Saidi@ARM.com    if (rxEmpty)
5618591Sgblack@eecs.umich.edu        rxEmpty = false;
5628591Sgblack@eecs.umich.edu    else
5638591Sgblack@eecs.umich.edu        interrupts &= ~Regs::Intr_RxHigh;
5648591Sgblack@eecs.umich.edu
5658545Ssaidi@eecs.umich.edu    // Intr_TxLow is special, we only signal it if we've filled up the fifo
5668545Ssaidi@eecs.umich.edu    // and then dropped below the low watermark
5678199SAli.Saidi@ARM.com    if (txFull)
5688545Ssaidi@eecs.umich.edu        txFull = false;
5698545Ssaidi@eecs.umich.edu    else
5709046SAli.Saidi@ARM.com        interrupts &= ~Regs::Intr_TxLow;
5718545Ssaidi@eecs.umich.edu
5728545Ssaidi@eecs.umich.edu    if (interrupts) {
5738545Ssaidi@eecs.umich.edu        Tick when = curTick;
5748545Ssaidi@eecs.umich.edu        if ((interrupts & Regs::Intr_NoDelay) == 0)
5758545Ssaidi@eecs.umich.edu            when += intrDelay;
5768545Ssaidi@eecs.umich.edu        cpuIntrPost(when);
5778545Ssaidi@eecs.umich.edu    }
5788545Ssaidi@eecs.umich.edu}
5798545Ssaidi@eecs.umich.edu
5808545Ssaidi@eecs.umich.eduvoid
5818592Sgblack@eecs.umich.eduDevice::devIntrClear(uint32_t interrupts)
5828592Sgblack@eecs.umich.edu{
5838592Sgblack@eecs.umich.edu    if ((interrupts & Regs::Intr_Res))
5848545Ssaidi@eecs.umich.edu        panic("Cannot clear a reserved interrupt");
5858545Ssaidi@eecs.umich.edu
5868545Ssaidi@eecs.umich.edu    regs.IntrStatus &= ~interrupts;
5878545Ssaidi@eecs.umich.edu
5888591Sgblack@eecs.umich.edu    DPRINTF(EthernetIntr,
5898591Sgblack@eecs.umich.edu            "interrupt cleared from intStatus: intr=%x status=%x mask=%x\n",
5908591Sgblack@eecs.umich.edu            interrupts, regs.IntrStatus, regs.IntrMask);
5918545Ssaidi@eecs.umich.edu
5928199SAli.Saidi@ARM.com    if (!(regs.IntrStatus & regs.IntrMask))
5938199SAli.Saidi@ARM.com        cpuIntrClear();
5948199SAli.Saidi@ARM.com}
5958199SAli.Saidi@ARM.com
5968199SAli.Saidi@ARM.comvoid
5978199SAli.Saidi@ARM.comDevice::devIntrChangeMask(uint32_t newmask)
5988199SAli.Saidi@ARM.com{
5998199SAli.Saidi@ARM.com    if (regs.IntrMask == newmask)
6008199SAli.Saidi@ARM.com        return;
6018199SAli.Saidi@ARM.com
6028199SAli.Saidi@ARM.com    regs.IntrMask = newmask;
6038199SAli.Saidi@ARM.com
6042292SN/A    DPRINTF(EthernetIntr,
6052292SN/A            "interrupt mask changed: intStatus=%x intMask=%x masked=%x\n",
6064032Sktlim@umich.edu            regs.IntrStatus, regs.IntrMask, regs.IntrStatus & regs.IntrMask);
6072292SN/A
6082292SN/A    if (regs.IntrStatus & regs.IntrMask)
6092292SN/A        cpuIntrPost(curTick);
6107720Sgblack@eecs.umich.edu    else
6117944SGiacomo.Gabrielli@arm.com        cpuIntrClear();
6122292SN/A}
6134032Sktlim@umich.edu
6144032Sktlim@umich.eduvoid
6152669Sktlim@umich.eduBase::cpuIntrPost(Tick when)
6162292SN/A{
6177944SGiacomo.Gabrielli@arm.com    // If the interrupt you want to post is later than an interrupt
6187944SGiacomo.Gabrielli@arm.com    // already scheduled, just let it post in the coming one and don't
6197944SGiacomo.Gabrielli@arm.com    // schedule another.
6207944SGiacomo.Gabrielli@arm.com    // HOWEVER, must be sure that the scheduled intrTick is in the
6217597Sminkyu.jeong@arm.com    // future (this was formerly the source of a bug)
6227597Sminkyu.jeong@arm.com    /**
62310231Ssteve.reinhardt@amd.com     * @todo this warning should be removed and the intrTick code should
6242329SN/A     * be fixed.
6252329SN/A     */
6262367SN/A    assert(when >= curTick);
6272367SN/A    assert(intrTick >= curTick || intrTick == 0);
62810231Ssteve.reinhardt@amd.com    if (!cpuIntrEnable) {
6297848SAli.Saidi@ARM.com        DPRINTF(EthernetIntr, "interrupts not enabled.\n",
6307600Sminkyu.jeong@arm.com                intrTick);
6317600Sminkyu.jeong@arm.com        return;
6327600Sminkyu.jeong@arm.com    }
6334032Sktlim@umich.edu
6343731Sktlim@umich.edu    if (when > intrTick && intrTick != 0) {
6352367SN/A        DPRINTF(EthernetIntr, "don't need to schedule event...intrTick=%d\n",
6362367SN/A                intrTick);
6372292SN/A        return;
6382292SN/A    }
63910333Smitch.hayenga@arm.com
6409046SAli.Saidi@ARM.com    intrTick = when;
6414032Sktlim@umich.edu    if (intrTick < curTick) {
6424032Sktlim@umich.edu        debug_break();
6434032Sktlim@umich.edu        intrTick = curTick;
6448199SAli.Saidi@ARM.com    }
6458199SAli.Saidi@ARM.com
6462292SN/A    DPRINTF(EthernetIntr, "going to schedule an interrupt for intrTick=%d\n",
6472292SN/A            intrTick);
6482292SN/A
6492292SN/A    if (intrEvent)
6502292SN/A        intrEvent->squash();
6512292SN/A    intrEvent = new IntrEvent(this, true);
6522292SN/A    intrEvent->schedule(intrTick);
6532292SN/A}
6542292SN/A
6552292SN/Avoid
6562292SN/ABase::cpuInterrupt()
6572292SN/A{
6582292SN/A    assert(intrTick == curTick);
6592292SN/A
6602292SN/A    // Whether or not there's a pending interrupt, we don't care about
6617720Sgblack@eecs.umich.edu    // it anymore
6627720Sgblack@eecs.umich.edu    intrEvent = 0;
6632292SN/A    intrTick = 0;
6644032Sktlim@umich.edu
6654032Sktlim@umich.edu    // Don't send an interrupt if there's already one
6662292SN/A    if (cpuPendingIntr) {
6672292SN/A        DPRINTF(EthernetIntr,
6682292SN/A                "would send an interrupt now, but there's already pending\n");
6692292SN/A    } else {
6702292SN/A        // Send interrupt
6712292SN/A        cpuPendingIntr = true;
6727944SGiacomo.Gabrielli@arm.com
6737944SGiacomo.Gabrielli@arm.com        DPRINTF(EthernetIntr, "posting interrupt\n");
6747944SGiacomo.Gabrielli@arm.com        intrPost();
6757944SGiacomo.Gabrielli@arm.com    }
67610231Ssteve.reinhardt@amd.com}
6777848SAli.Saidi@ARM.com
6787848SAli.Saidi@ARM.comvoid
6792329SN/ABase::cpuIntrClear()
6807782Sminkyu.jeong@arm.com{
6817720Sgblack@eecs.umich.edu    if (!cpuPendingIntr)
6822292SN/A        return;
6832292SN/A
68410231Ssteve.reinhardt@amd.com    if (intrEvent) {
6857782Sminkyu.jeong@arm.com        intrEvent->squash();
6867782Sminkyu.jeong@arm.com        intrEvent = 0;
6877782Sminkyu.jeong@arm.com    }
6882292SN/A
6892292SN/A    intrTick = 0;
6902292SN/A
6912292SN/A    cpuPendingIntr = false;
6922336SN/A
6932336SN/A    DPRINTF(EthernetIntr, "clearing cchip interrupt\n");
6942336SN/A    intrClear();
6952329SN/A}
6962292SN/A
6972329SN/Abool
6982292SN/ABase::cpuIntrPending() const
6992292SN/A{ return cpuPendingIntr; }
7008199SAli.Saidi@ARM.com
7012292SN/Avoid
7022292SN/ADevice::changeConfig(uint32_t newconf)
7032292SN/A{
7042292SN/A    uint32_t changed = regs.Config ^ newconf;
7052292SN/A    if (!changed)
7062292SN/A        return;
7072292SN/A
7082292SN/A    regs.Config = newconf;
7092292SN/A
7107720Sgblack@eecs.umich.edu    if ((changed & Regs::Config_IntEn)) {
7117720Sgblack@eecs.umich.edu        cpuIntrEnable = regs.Config & Regs::Config_IntEn;
7122292SN/A        if (cpuIntrEnable) {
7132292SN/A            if (regs.IntrStatus & regs.IntrMask)
7142292SN/A                cpuIntrPost(curTick);
7152292SN/A        } else {
7162292SN/A            cpuIntrClear();
7172292SN/A        }
7182292SN/A    }
7192292SN/A
7202292SN/A    if ((changed & Regs::Config_TxEn)) {
7212292SN/A        txEnable = regs.Config & Regs::Config_TxEn;
7222292SN/A        if (txEnable)
7232292SN/A            txKick();
7242292SN/A    }
7252292SN/A
7262292SN/A    if ((changed & Regs::Config_RxEn)) {
7272292SN/A        rxEnable = regs.Config & Regs::Config_RxEn;
7282292SN/A        if (rxEnable)
7292292SN/A            rxKick();
7302292SN/A    }
7312292SN/A}
7322292SN/A
7332292SN/Avoid
7342292SN/ADevice::command(uint32_t command)
7352292SN/A{
7362292SN/A    if (command & Regs::Command_Reset)
7372292SN/A        reset();
7382292SN/A}
7392292SN/A
7402292SN/Avoid
7412329SN/ADevice::reset()
7422329SN/A{
7432292SN/A    using namespace Regs;
7442292SN/A
7452292SN/A    memset(&regs, 0, sizeof(regs));
7462292SN/A
7472292SN/A    regs.Config = 0;
7487720Sgblack@eecs.umich.edu    if (params()->dedicated)
7497720Sgblack@eecs.umich.edu        regs.Config |= Config_Thread;
7502292SN/A    regs.IntrMask = Intr_RxHigh | Intr_RxDMA | Intr_TxLow;
7512292SN/A    regs.RxMaxCopy = params()->rx_max_copy;
7522292SN/A    regs.TxMaxCopy = params()->tx_max_copy;
7532292SN/A    regs.RxMaxIntr = params()->rx_max_intr;
7542292SN/A    regs.RxFifoSize = params()->rx_fifo_size;
7552292SN/A    regs.TxFifoSize = params()->tx_fifo_size;
7562292SN/A    regs.RxFifoMark = params()->rx_fifo_threshold;
7572292SN/A    regs.TxFifoMark = params()->tx_fifo_threshold;
7582292SN/A    regs.HwAddr = params()->eaddr;
7592292SN/A
7602292SN/A    rxState = rxIdle;
7612292SN/A    txState = txIdle;
7622292SN/A
7636974Stjones1@inf.ed.ac.uk    rxFifo.clear();
7646974Stjones1@inf.ed.ac.uk    txFifo.clear();
7656974Stjones1@inf.ed.ac.uk    rxEmpty = false;
7666974Stjones1@inf.ed.ac.uk    txFull = false;
7676974Stjones1@inf.ed.ac.uk}
7686974Stjones1@inf.ed.ac.uk
7696974Stjones1@inf.ed.ac.ukvoid
7706974Stjones1@inf.ed.ac.ukDevice::rxDmaCopy()
7716974Stjones1@inf.ed.ac.uk{
7726974Stjones1@inf.ed.ac.uk    assert(rxState == rxCopy);
7736974Stjones1@inf.ed.ac.uk    rxState = rxCopyDone;
7746974Stjones1@inf.ed.ac.uk    physmem->dma_write(rxDmaAddr, (uint8_t *)rxDmaData, rxDmaLen);
7756974Stjones1@inf.ed.ac.uk    DPRINTF(EthernetDMA, "rx dma write paddr=%#x len=%d\n",
7766974Stjones1@inf.ed.ac.uk            rxDmaAddr, rxDmaLen);
7776974Stjones1@inf.ed.ac.uk    DDUMP(EthernetData, rxDmaData, rxDmaLen);
7786974Stjones1@inf.ed.ac.uk}
7792292SN/A
7802292SN/Avoid
7816974Stjones1@inf.ed.ac.ukDevice::rxDmaDone()
7826974Stjones1@inf.ed.ac.uk{
7836974Stjones1@inf.ed.ac.uk    rxDmaCopy();
7846974Stjones1@inf.ed.ac.uk
7856974Stjones1@inf.ed.ac.uk    // If the transmit state machine  has a pending DMA, let it go first
7866974Stjones1@inf.ed.ac.uk    if (txState == txBeginCopy)
7872292SN/A        txKick();
7882292SN/A
7892292SN/A    rxKick();
7902292SN/A}
7918727Snilay@cs.wisc.edu
7922292SN/Avoid
7932292SN/ADevice::rxKick()
79410333Smitch.hayenga@arm.com{
7952678Sktlim@umich.edu    DPRINTF(EthernetSM, "receive kick rxState=%s (rxFifo.size=%d)\n",
7962678Sktlim@umich.edu            RxStateStrings[rxState], rxFifo.size());
7972678Sktlim@umich.edu
7982678Sktlim@umich.edu    if (rxKickTick > curTick) {
7992678Sktlim@umich.edu        DPRINTF(EthernetSM, "receive kick exiting, can't run till %d\n",
8002329SN/A                rxKickTick);
8012329SN/A        return;
8022292SN/A    }
8032292SN/A
8042292SN/A  next:
8052292SN/A    switch (rxState) {
8062292SN/A      case rxIdle:
8072292SN/A        goto exit;
8082292SN/A
8092678Sktlim@umich.edu      case rxFifoBlock:
8102292SN/A        if (rxPacket) {
8112292SN/A            rxState = rxBeginCopy;
8122292SN/A            break;
8132292SN/A        }
8142292SN/A
8152292SN/A        if (rxFifo.empty()) {
8162292SN/A            DPRINTF(EthernetSM, "receive waiting for data.  Nothing to do.\n");
8172292SN/A            goto exit;
8182292SN/A        }
8192292SN/A
8202292SN/A        // Grab a new packet from the fifo.
8216974Stjones1@inf.ed.ac.uk        rxPacket = rxFifo.front();
8226974Stjones1@inf.ed.ac.uk        rxPacketBufPtr = rxPacket->data;
8236974Stjones1@inf.ed.ac.uk        rxPktBytes = rxPacket->length;
8246974Stjones1@inf.ed.ac.uk        assert(rxPktBytes);
8256974Stjones1@inf.ed.ac.uk
8262669Sktlim@umich.edu        rxDoneData = 0;
8272669Sktlim@umich.edu        /* scope for variables */ {
8282669Sktlim@umich.edu            IpPtr ip(rxPacket);
8298481Sgblack@eecs.umich.edu            if (ip) {
8308481Sgblack@eecs.umich.edu                rxDoneData |= Regs::RxDone_IpPacket;
8318481Sgblack@eecs.umich.edu                rxIpChecksums++;
8322292SN/A                if (cksum(ip) != 0) {
8332292SN/A                    DPRINTF(EthernetCksum, "Rx IP Checksum Error\n");
8342669Sktlim@umich.edu                    rxDoneData |= Regs::RxDone_IpError;
83510031SAli.Saidi@ARM.com                }
8363772Sgblack@eecs.umich.edu                TcpPtr tcp(ip);
83710031SAli.Saidi@ARM.com                UdpPtr udp(ip);
83810031SAli.Saidi@ARM.com                if (tcp) {
83910031SAli.Saidi@ARM.com                    rxDoneData |= Regs::RxDone_TcpPacket;
84010031SAli.Saidi@ARM.com                    rxTcpChecksums++;
8412669Sktlim@umich.edu                    if (cksum(tcp) != 0) {
8424878Sstever@eecs.umich.edu                        DPRINTF(EthernetCksum, "Rx TCP Checksum Error\n");
8434878Sstever@eecs.umich.edu                        rxDoneData |= Regs::RxDone_TcpError;
8446102Sgblack@eecs.umich.edu                    }
8456974Stjones1@inf.ed.ac.uk                } else if (udp) {
8466974Stjones1@inf.ed.ac.uk                    rxDoneData |= Regs::RxDone_UdpPacket;
8472292SN/A                    rxUdpChecksums++;
8482678Sktlim@umich.edu                    if (cksum(udp) != 0) {
8492678Sktlim@umich.edu                        DPRINTF(EthernetCksum, "Rx UDP Checksum Error\n");
8502678Sktlim@umich.edu                        rxDoneData |= Regs::RxDone_UdpError;
8512678Sktlim@umich.edu                    }
8526974Stjones1@inf.ed.ac.uk                }
8536974Stjones1@inf.ed.ac.uk            }
8546974Stjones1@inf.ed.ac.uk        }
8556974Stjones1@inf.ed.ac.uk        rxState = rxBeginCopy;
8568949Sandreas.hansson@arm.com        break;
8576974Stjones1@inf.ed.ac.uk
8586974Stjones1@inf.ed.ac.uk      case rxBeginCopy:
8596974Stjones1@inf.ed.ac.uk        if (dmaInterface && dmaInterface->busy())
8606974Stjones1@inf.ed.ac.uk            goto exit;
8618949Sandreas.hansson@arm.com
8628949Sandreas.hansson@arm.com        rxDmaAddr = plat->pciToDma(Regs::get_RxData_Addr(regs.RxData));
8636974Stjones1@inf.ed.ac.uk        rxDmaLen = min<int>(Regs::get_RxData_Len(regs.RxData), rxPktBytes);
8646974Stjones1@inf.ed.ac.uk        rxDmaData = rxPacketBufPtr;
8656974Stjones1@inf.ed.ac.uk        rxState = rxCopy;
8666974Stjones1@inf.ed.ac.uk
8676974Stjones1@inf.ed.ac.uk        if (dmaInterface) {
8686974Stjones1@inf.ed.ac.uk            dmaInterface->doDMA(WriteInvalidate, rxDmaAddr, rxDmaLen,
8696974Stjones1@inf.ed.ac.uk                                curTick, &rxDmaEvent, true);
8706974Stjones1@inf.ed.ac.uk            goto exit;
8716974Stjones1@inf.ed.ac.uk        }
8726974Stjones1@inf.ed.ac.uk
8736974Stjones1@inf.ed.ac.uk        if (dmaWriteDelay != 0 || dmaWriteFactor != 0) {
8746974Stjones1@inf.ed.ac.uk            Tick factor = ((rxDmaLen + ULL(63)) >> ULL(6)) * dmaWriteFactor;
8756974Stjones1@inf.ed.ac.uk            Tick start = curTick + dmaWriteDelay + factor;
8766974Stjones1@inf.ed.ac.uk            rxDmaEvent.schedule(start);
8772678Sktlim@umich.edu            goto exit;
8787720Sgblack@eecs.umich.edu        }
8792292SN/A
8807720Sgblack@eecs.umich.edu        rxDmaCopy();
8813797Sgblack@eecs.umich.edu        break;
8823221Sktlim@umich.edu
8832292SN/A      case rxCopy:
8842693Sktlim@umich.edu        DPRINTF(EthernetSM, "receive machine still copying\n");
8854350Sgblack@eecs.umich.edu        goto exit;
8866974Stjones1@inf.ed.ac.uk
8873326Sktlim@umich.edu      case rxCopyDone:
8883326Sktlim@umich.edu        regs.RxDone = rxDoneData | rxDmaLen;
8893326Sktlim@umich.edu
8909046SAli.Saidi@ARM.com        if (rxPktBytes == rxDmaLen) {
89110030SAli.Saidi@ARM.com            rxPacket = NULL;
8929046SAli.Saidi@ARM.com            rxFifo.pop();
8933326Sktlim@umich.edu        } else {
8943326Sktlim@umich.edu            regs.RxDone |= Regs::RxDone_More;
8953326Sktlim@umich.edu            rxPktBytes -= rxDmaLen;
8963326Sktlim@umich.edu            rxPacketBufPtr += rxDmaLen;
8973326Sktlim@umich.edu        }
8983326Sktlim@umich.edu
8993326Sktlim@umich.edu        regs.RxDone |= Regs::RxDone_Complete;
9007823Ssteve.reinhardt@amd.com        devIntrPost(Regs::Intr_RxDMA);
9018887Sgeoffrey.blake@arm.com        rxState = rxIdle;
9028887Sgeoffrey.blake@arm.com        break;
9038887Sgeoffrey.blake@arm.com
9048887Sgeoffrey.blake@arm.com      default:
9058887Sgeoffrey.blake@arm.com        panic("Invalid rxState!");
9068887Sgeoffrey.blake@arm.com    }
9073326Sktlim@umich.edu
9083326Sktlim@umich.edu    DPRINTF(EthernetSM, "entering next rxState=%s\n",
9093326Sktlim@umich.edu            RxStateStrings[rxState]);
9102693Sktlim@umich.edu
9112693Sktlim@umich.edu    goto next;
9122693Sktlim@umich.edu
9132693Sktlim@umich.edu  exit:
9142693Sktlim@umich.edu    /**
9152693Sktlim@umich.edu     * @todo do we want to schedule a future kick?
9168481Sgblack@eecs.umich.edu     */
9178481Sgblack@eecs.umich.edu    DPRINTF(EthernetSM, "rx state machine exited rxState=%s\n",
9188481Sgblack@eecs.umich.edu            RxStateStrings[rxState]);
9198481Sgblack@eecs.umich.edu}
9208481Sgblack@eecs.umich.edu
9218481Sgblack@eecs.umich.eduvoid
9228481Sgblack@eecs.umich.eduDevice::txDmaCopy()
9238481Sgblack@eecs.umich.edu{
9248481Sgblack@eecs.umich.edu    assert(txState == txCopy);
9258481Sgblack@eecs.umich.edu    txState = txCopyDone;
9268481Sgblack@eecs.umich.edu    physmem->dma_read((uint8_t *)txDmaData, txDmaAddr, txDmaLen);
9278481Sgblack@eecs.umich.edu    DPRINTF(EthernetDMA, "tx dma read paddr=%#x len=%d\n",
9288481Sgblack@eecs.umich.edu            txDmaAddr, txDmaLen);
9298481Sgblack@eecs.umich.edu    DDUMP(EthernetData, txDmaData, txDmaLen);
9308481Sgblack@eecs.umich.edu}
9318481Sgblack@eecs.umich.edu
9328481Sgblack@eecs.umich.eduvoid
9338481Sgblack@eecs.umich.eduDevice::txDmaDone()
9348481Sgblack@eecs.umich.edu{
9358481Sgblack@eecs.umich.edu    txDmaCopy();
9368481Sgblack@eecs.umich.edu
9374032Sktlim@umich.edu    // If the receive state machine  has a pending DMA, let it go first
9383221Sktlim@umich.edu    if (rxState == rxBeginCopy)
9393221Sktlim@umich.edu        rxKick();
9406974Stjones1@inf.ed.ac.uk
9416974Stjones1@inf.ed.ac.uk    txKick();
9428481Sgblack@eecs.umich.edu}
9436974Stjones1@inf.ed.ac.uk
9446974Stjones1@inf.ed.ac.ukvoid
9456974Stjones1@inf.ed.ac.ukDevice::transmit()
9462669Sktlim@umich.edu{
9476974Stjones1@inf.ed.ac.uk    if (txFifo.empty()) {
9486974Stjones1@inf.ed.ac.uk        DPRINTF(Ethernet, "nothing to transmit\n");
9498481Sgblack@eecs.umich.edu        return;
9506974Stjones1@inf.ed.ac.uk    }
9516974Stjones1@inf.ed.ac.uk
9526974Stjones1@inf.ed.ac.uk    uint32_t interrupts;
9536974Stjones1@inf.ed.ac.uk    PacketPtr packet = txFifo.front();
9546974Stjones1@inf.ed.ac.uk    if (!interface->sendPacket(packet)) {
9556974Stjones1@inf.ed.ac.uk        DPRINTF(Ethernet, "Packet Transmit: failed txFifo available %d\n",
9566974Stjones1@inf.ed.ac.uk                txFifo.avail());
9576974Stjones1@inf.ed.ac.uk        goto reschedule;
9586974Stjones1@inf.ed.ac.uk    }
9596974Stjones1@inf.ed.ac.uk
9606974Stjones1@inf.ed.ac.uk    txFifo.pop();
9616974Stjones1@inf.ed.ac.uk#if TRACING_ON
9626974Stjones1@inf.ed.ac.uk    if (DTRACE(Ethernet)) {
9636974Stjones1@inf.ed.ac.uk        IpPtr ip(packet);
9646974Stjones1@inf.ed.ac.uk        if (ip) {
9656974Stjones1@inf.ed.ac.uk            DPRINTF(Ethernet, "ID is %d\n", ip->id());
9666974Stjones1@inf.ed.ac.uk            TcpPtr tcp(ip);
9676974Stjones1@inf.ed.ac.uk            if (tcp) {
9686974Stjones1@inf.ed.ac.uk                DPRINTF(Ethernet, "Src Port=%d, Dest Port=%d\n",
9696974Stjones1@inf.ed.ac.uk                        tcp->sport(), tcp->dport());
9706974Stjones1@inf.ed.ac.uk            }
9716974Stjones1@inf.ed.ac.uk        }
9726974Stjones1@inf.ed.ac.uk    }
9736974Stjones1@inf.ed.ac.uk#endif
9742292SN/A
9752292SN/A    DDUMP(EthernetData, packet->data, packet->length);
9762292SN/A    txBytes += packet->length;
9772292SN/A    txPackets++;
9782292SN/A
9792292SN/A    DPRINTF(Ethernet, "Packet Transmit: successful txFifo Available %d\n",
9802292SN/A            txFifo.avail());
9812292SN/A
9822292SN/A    interrupts = Regs::Intr_TxPacket;
9832292SN/A    if (txFifo.size() < regs.TxFifoMark)
9842292SN/A        interrupts |= Regs::Intr_TxLow;
9852292SN/A    devIntrPost(interrupts);
9862292SN/A
9872292SN/A  reschedule:
9882292SN/A   if (!txFifo.empty() && !txEvent.scheduled()) {
9892292SN/A       DPRINTF(Ethernet, "reschedule transmit\n");
9902292SN/A       txEvent.schedule(curTick + retryTime);
9912292SN/A   }
9922292SN/A}
9932292SN/A
9942292SN/Avoid
9952292SN/ADevice::txKick()
9962292SN/A{
9972292SN/A    DPRINTF(EthernetSM, "transmit kick txState=%s (txFifo.size=%d)\n",
9982292SN/A            TxStateStrings[txState], txFifo.size());
9992292SN/A
10002292SN/A    if (txKickTick > curTick) {
10012292SN/A        DPRINTF(EthernetSM, "transmit kick exiting, can't run till %d\n",
10022329SN/A                txKickTick);
10032292SN/A        return;
10042292SN/A    }
10052292SN/A
10062292SN/A  next:
10072292SN/A    switch (txState) {
10087720Sgblack@eecs.umich.edu      case txIdle:
10092292SN/A        goto exit;
10107720Sgblack@eecs.umich.edu
10112292SN/A      case txFifoBlock:
10122292SN/A        if (!txPacket) {
10132292SN/A            // Grab a new packet from the fifo.
10142292SN/A            txPacket = new PacketData(16384);
10152292SN/A            txPacketBufPtr = txPacket->data;
10162292SN/A        }
10172292SN/A
10182292SN/A        if (txFifo.avail() - txPacket->length <
10192329SN/A            Regs::get_TxData_Len(regs.TxData)) {
10202731Sktlim@umich.edu            DPRINTF(EthernetSM, "transmit fifo full.  Nothing to do.\n");
10212292SN/A            goto exit;
10222292SN/A        }
10232292SN/A
10242292SN/A        txState = txBeginCopy;
10252292SN/A        break;
10262292SN/A
10272292SN/A      case txBeginCopy:
10282727Sktlim@umich.edu        if (dmaInterface && dmaInterface->busy())
10292292SN/A            goto exit;
10302292SN/A
10314032Sktlim@umich.edu        txDmaAddr = plat->pciToDma(Regs::get_TxData_Addr(regs.TxData));
10324032Sktlim@umich.edu        txDmaLen = Regs::get_TxData_Len(regs.TxData);
10334032Sktlim@umich.edu        txDmaData = txPacketBufPtr;
10344032Sktlim@umich.edu        txState = txCopy;
10352292SN/A
10362292SN/A        if (dmaInterface) {
10372292SN/A            dmaInterface->doDMA(Read, txDmaAddr, txDmaLen,
10382292SN/A                                curTick, &txDmaEvent, true);
10392292SN/A            goto exit;
10402329SN/A        }
10412292SN/A
10422292SN/A        if (dmaReadDelay != 0 || dmaReadFactor != 0) {
10432292SN/A            Tick factor = ((txDmaLen + ULL(63)) >> ULL(6)) * dmaReadFactor;
10442292SN/A            Tick start = curTick + dmaReadDelay + factor;
10457720Sgblack@eecs.umich.edu            txDmaEvent.schedule(start);
10462292SN/A            goto exit;
10477720Sgblack@eecs.umich.edu        }
10482292SN/A
10492292SN/A        txDmaCopy();
10502329SN/A        break;
10512329SN/A
10522292SN/A      case txCopy:
10532292SN/A        DPRINTF(EthernetSM, "transmit machine still copying\n");
10542292SN/A        goto exit;
10552292SN/A
10562292SN/A      case txCopyDone:
10572292SN/A        txPacket->length += txDmaLen;
10582292SN/A        if ((regs.TxData & Regs::TxData_More)) {
10592329SN/A            txPacketBufPtr += txDmaLen;
10602731Sktlim@umich.edu        } else {
10612292SN/A            assert(txPacket->length <= txFifo.avail());
10622292SN/A            if ((regs.TxData & Regs::TxData_Checksum)) {
10632292SN/A                IpPtr ip(txPacket);
10644032Sktlim@umich.edu                if (ip) {
10654032Sktlim@umich.edu                    TcpPtr tcp(ip);
10664032Sktlim@umich.edu                    if (tcp) {
10674032Sktlim@umich.edu                        tcp->sum(0);
10686974Stjones1@inf.ed.ac.uk                        tcp->sum(cksum(tcp));
10696974Stjones1@inf.ed.ac.uk                        txTcpChecksums++;
10706974Stjones1@inf.ed.ac.uk                    }
10716974Stjones1@inf.ed.ac.uk
10726974Stjones1@inf.ed.ac.uk                    UdpPtr udp(ip);
10736974Stjones1@inf.ed.ac.uk                    if (udp) {
10746974Stjones1@inf.ed.ac.uk                        udp->sum(0);
10754032Sktlim@umich.edu                        udp->sum(cksum(udp));
10762292SN/A                        txUdpChecksums++;
10772292SN/A                    }
10782292SN/A
10792292SN/A                    ip->sum(0);
10802292SN/A                    ip->sum(cksum(ip));
10812292SN/A                    txIpChecksums++;
10822292SN/A                }
10832727Sktlim@umich.edu            }
10842292SN/A            txFifo.push(txPacket);
10852292SN/A            if (txFifo.avail() < regs.TxMaxCopy) {
10862292SN/A                devIntrPost(Regs::Intr_TxFull);
10872292SN/A                txFull = true;
10882292SN/A            }
10893349Sbinkertn@umich.edu            txPacket = 0;
10902693Sktlim@umich.edu            transmit();
10912693Sktlim@umich.edu        }
10922693Sktlim@umich.edu
10932693Sktlim@umich.edu        regs.TxDone = txDmaLen | Regs::TxDone_Complete;
10942693Sktlim@umich.edu        devIntrPost(Regs::Intr_TxDMA);
10952693Sktlim@umich.edu        txState = txIdle;
10962693Sktlim@umich.edu        break;
10972693Sktlim@umich.edu
10982693Sktlim@umich.edu      default:
10992693Sktlim@umich.edu        panic("Invalid txState!");
11002693Sktlim@umich.edu    }
11012693Sktlim@umich.edu
11022693Sktlim@umich.edu    DPRINTF(EthernetSM, "entering next txState=%s\n",
11032693Sktlim@umich.edu            TxStateStrings[txState]);
11042693Sktlim@umich.edu
11052693Sktlim@umich.edu    goto next;
11068887Sgeoffrey.blake@arm.com
11072693Sktlim@umich.edu  exit:
11082732Sktlim@umich.edu    /**
11092693Sktlim@umich.edu     * @todo do we want to schedule a future kick?
11102693Sktlim@umich.edu     */
11112693Sktlim@umich.edu    DPRINTF(EthernetSM, "tx state machine exited txState=%s\n",
11128727Snilay@cs.wisc.edu            TxStateStrings[txState]);
11138727Snilay@cs.wisc.edu}
11148727Snilay@cs.wisc.edu
11158727Snilay@cs.wisc.eduvoid
11162693Sktlim@umich.eduDevice::transferDone()
11172693Sktlim@umich.edu{
11182693Sktlim@umich.edu    if (txFifo.empty()) {
11192693Sktlim@umich.edu        DPRINTF(Ethernet, "transfer complete: txFifo empty...nothing to do\n");
11202693Sktlim@umich.edu        return;
11212678Sktlim@umich.edu    }
11222678Sktlim@umich.edu
11232678Sktlim@umich.edu    DPRINTF(Ethernet, "transfer complete: data in txFifo...schedule xmit\n");
11242678Sktlim@umich.edu
11252678Sktlim@umich.edu    if (txEvent.scheduled())
11262678Sktlim@umich.edu        txEvent.reschedule(curTick + cycles(1));
11272678Sktlim@umich.edu    else
11282727Sktlim@umich.edu        txEvent.schedule(curTick + cycles(1));
11292678Sktlim@umich.edu}
11302678Sktlim@umich.edu
11312678Sktlim@umich.edubool
11322678Sktlim@umich.eduDevice::rxFilter(const PacketPtr &packet)
11332678Sktlim@umich.edu{
11342678Sktlim@umich.edu    if (!Regs::get_Config_Filter(regs.Config))
11352678Sktlim@umich.edu        return false;
11362678Sktlim@umich.edu
11372678Sktlim@umich.edu    panic("receive filter not implemented\n");
11382678Sktlim@umich.edu    bool drop = true;
11392678Sktlim@umich.edu
11402678Sktlim@umich.edu#if 0
11412678Sktlim@umich.edu    string type;
11422678Sktlim@umich.edu
11437598Sminkyu.jeong@arm.com    EthHdr *eth = packet->eth();
11447598Sminkyu.jeong@arm.com    if (eth->unicast()) {
11457598Sminkyu.jeong@arm.com        // If we're accepting all unicast addresses
11462678Sktlim@umich.edu        if (acceptUnicast)
11472678Sktlim@umich.edu            drop = false;
11482678Sktlim@umich.edu
11492678Sktlim@umich.edu        // If we make a perfect match
11502292SN/A        if (acceptPerfect && params->eaddr == eth.dst())
11512292SN/A            drop = false;
11522292SN/A
11532292SN/A        if (acceptArp && eth->type() == ETH_TYPE_ARP)
11542292SN/A            drop = false;
11552292SN/A
11562292SN/A    } else if (eth->broadcast()) {
11572292SN/A        // if we're accepting broadcasts
11583126Sktlim@umich.edu        if (acceptBroadcast)
11592292SN/A            drop = false;
11602292SN/A
11612292SN/A    } else if (eth->multicast()) {
11622292SN/A        // if we're accepting all multicasts
11632292SN/A        if (acceptMulticast)
11642292SN/A            drop = false;
11652292SN/A
11662292SN/A    }
11672292SN/A
11682292SN/A    if (drop) {
11692292SN/A        DPRINTF(Ethernet, "rxFilter drop\n");
11702292SN/A        DDUMP(EthernetData, packet->data, packet->length);
11712292SN/A    }
11722329SN/A#endif
11732329SN/A    return drop;
11742329SN/A}
11752292SN/A
11769527SMatt.Horsnell@arm.combool
11779527SMatt.Horsnell@arm.comDevice::recvPacket(PacketPtr packet)
11789527SMatt.Horsnell@arm.com{
11799527SMatt.Horsnell@arm.com    rxBytes += packet->length;
11809527SMatt.Horsnell@arm.com    rxPackets++;
11819527SMatt.Horsnell@arm.com
11829527SMatt.Horsnell@arm.com    DPRINTF(Ethernet, "Receiving packet from wire, rxFifo Available is %d\n",
11832292SN/A            rxFifo.avail());
11842292SN/A
11852292SN/A    if (!rxEnable) {
11862292SN/A        DPRINTF(Ethernet, "receive disabled...packet dropped\n");
11872292SN/A        return true;
11882292SN/A    }
11892292SN/A
11902292SN/A    if (rxFilter(packet)) {
11912292SN/A        DPRINTF(Ethernet, "packet filtered...dropped\n");
11922316SN/A        return true;
11932316SN/A    }
11942329SN/A
11958727Snilay@cs.wisc.edu    if (rxFifo.size() >= regs.RxFifoMark)
11968727Snilay@cs.wisc.edu        devIntrPost(Regs::Intr_RxHigh);
11978727Snilay@cs.wisc.edu
11988727Snilay@cs.wisc.edu    if (!rxFifo.push(packet)) {
11992329SN/A        DPRINTF(Ethernet,
12002329SN/A                "packet will not fit in receive buffer...packet dropped\n");
12012329SN/A        return false;
12022316SN/A    }
12032732Sktlim@umich.edu
12042316SN/A    devIntrPost(Regs::Intr_RxPacket);
12052292SN/A    rxKick();
12062292SN/A    return true;
12072292SN/A}
12086974Stjones1@inf.ed.ac.uk
12096974Stjones1@inf.ed.ac.uk//=====================================================================
12106974Stjones1@inf.ed.ac.uk//
12118975Sandreas.hansson@arm.com//
12126974Stjones1@inf.ed.ac.ukvoid
12136974Stjones1@inf.ed.ac.ukBase::serialize(ostream &os)
12146974Stjones1@inf.ed.ac.uk{
12156974Stjones1@inf.ed.ac.uk    // Serialize the PciDev base class
12166974Stjones1@inf.ed.ac.uk    PciDev::serialize(os);
12176974Stjones1@inf.ed.ac.uk
12186974Stjones1@inf.ed.ac.uk    SERIALIZE_SCALAR(rxEnable);
12196974Stjones1@inf.ed.ac.uk    SERIALIZE_SCALAR(txEnable);
12206974Stjones1@inf.ed.ac.uk    SERIALIZE_SCALAR(cpuIntrEnable);
12216974Stjones1@inf.ed.ac.uk
12226974Stjones1@inf.ed.ac.uk    /*
12232693Sktlim@umich.edu     * Keep track of pending interrupt status.
12242693Sktlim@umich.edu     */
12252693Sktlim@umich.edu    SERIALIZE_SCALAR(intrTick);
12262698Sktlim@umich.edu    SERIALIZE_SCALAR(cpuPendingIntr);
12274985Sktlim@umich.edu    Tick intrEventTick = 0;
12282698Sktlim@umich.edu    if (intrEvent)
12292693Sktlim@umich.edu        intrEventTick = intrEvent->when();
12308587Snilay@cs.wisc.edu    SERIALIZE_SCALAR(intrEventTick);
12318587Snilay@cs.wisc.edu}
12328587Snilay@cs.wisc.edu
12338975Sandreas.hansson@arm.comvoid
12346974Stjones1@inf.ed.ac.ukBase::unserialize(Checkpoint *cp, const std::string &section)
12358133SAli.Saidi@ARM.com{
12368133SAli.Saidi@ARM.com    // Unserialize the PciDev base class
12378133SAli.Saidi@ARM.com    PciDev::unserialize(cp, section);
12386974Stjones1@inf.ed.ac.uk
12396974Stjones1@inf.ed.ac.uk    UNSERIALIZE_SCALAR(rxEnable);
12402699Sktlim@umich.edu    UNSERIALIZE_SCALAR(txEnable);
12412693Sktlim@umich.edu    UNSERIALIZE_SCALAR(cpuIntrEnable);
12426974Stjones1@inf.ed.ac.uk
12436974Stjones1@inf.ed.ac.uk    /*
12446974Stjones1@inf.ed.ac.uk     * Keep track of pending interrupt status.
12456974Stjones1@inf.ed.ac.uk     */
12466974Stjones1@inf.ed.ac.uk    UNSERIALIZE_SCALAR(intrTick);
12476974Stjones1@inf.ed.ac.uk    UNSERIALIZE_SCALAR(cpuPendingIntr);
12486974Stjones1@inf.ed.ac.uk    Tick intrEventTick;
12496974Stjones1@inf.ed.ac.uk    UNSERIALIZE_SCALAR(intrEventTick);
12502693Sktlim@umich.edu    if (intrEventTick) {
12512693Sktlim@umich.edu        intrEvent = new IntrEvent(this, true);
12522727Sktlim@umich.edu        intrEvent->schedule(intrEventTick);
12532693Sktlim@umich.edu    }
12542693Sktlim@umich.edu}
12552693Sktlim@umich.edu
12562693Sktlim@umich.eduvoid
12572693Sktlim@umich.eduDevice::serialize(ostream &os)
12582292SN/A{
12599440SAndreas.Sandberg@ARM.com    // Serialize the PciDev base class
12602292SN/A    Base::serialize(os);
12612292SN/A
12622292SN/A    if (rxState == rxCopy)
12632292SN/A        panic("can't serialize with an in flight dma request rxState=%s",
12642292SN/A              RxStateStrings[rxState]);
12652292SN/A
12662292SN/A    if (txState == txCopy)
12679440SAndreas.Sandberg@ARM.com        panic("can't serialize with an in flight dma request txState=%s",
12682292SN/A              TxStateStrings[txState]);
12692292SN/A
12702292SN/A    /*
12712292SN/A     * Serialize the device registers
12722292SN/A     */
12732292SN/A    SERIALIZE_SCALAR(regs.Config);
12742292SN/A    SERIALIZE_SCALAR(regs.IntrStatus);
12759440SAndreas.Sandberg@ARM.com    SERIALIZE_SCALAR(regs.IntrMask);
12762292SN/A    SERIALIZE_SCALAR(regs.RxMaxCopy);
12772292SN/A    SERIALIZE_SCALAR(regs.TxMaxCopy);
12782292SN/A    SERIALIZE_SCALAR(regs.RxMaxIntr);
12792292SN/A    SERIALIZE_SCALAR(regs.RxData);
12802292SN/A    SERIALIZE_SCALAR(regs.RxDone);
12812292SN/A    SERIALIZE_SCALAR(regs.TxData);
12822292SN/A    SERIALIZE_SCALAR(regs.TxDone);
12839440SAndreas.Sandberg@ARM.com
12842292SN/A    /*
12852292SN/A     * Serialize rx state machine
12862292SN/A     */
12872292SN/A    int rxState = this->rxState;
12882329SN/A    SERIALIZE_SCALAR(rxState);
12892329SN/A    SERIALIZE_SCALAR(rxEmpty);
12902329SN/A    rxFifo.serialize("rxFifo", os);
12919440SAndreas.Sandberg@ARM.com    bool rxPacketExists = rxPacket;
12922329SN/A    SERIALIZE_SCALAR(rxPacketExists);
12932329SN/A    if (rxPacketExists) {
12942329SN/A        rxPacket->serialize("rxPacket", os);
12952329SN/A        uint32_t rxPktBufPtr = (uint32_t) (rxPacketBufPtr - rxPacket->data);
12962329SN/A        SERIALIZE_SCALAR(rxPktBufPtr);
12972329SN/A        SERIALIZE_SCALAR(rxPktBytes);
12982329SN/A    }
12992329SN/A    SERIALIZE_SCALAR(rxDoneData);
13009440SAndreas.Sandberg@ARM.com
13019440SAndreas.Sandberg@ARM.com    /*
13022329SN/A     * Serialize tx state machine
13032329SN/A     */
13042329SN/A    int txState = this->txState;
13059440SAndreas.Sandberg@ARM.com    SERIALIZE_SCALAR(txState);
13062329SN/A    SERIALIZE_SCALAR(txFull);
13072329SN/A    txFifo.serialize("txFifo", os);
13082329SN/A    bool txPacketExists = txPacket;
13092329SN/A    SERIALIZE_SCALAR(txPacketExists);
13102329SN/A    if (txPacketExists) {
13112329SN/A        txPacket->serialize("txPacket", os);
13122329SN/A        uint32_t txPktBufPtr = (uint32_t) (txPacketBufPtr - txPacket->data);
13139440SAndreas.Sandberg@ARM.com        SERIALIZE_SCALAR(txPktBufPtr);
13149440SAndreas.Sandberg@ARM.com        SERIALIZE_SCALAR(txPktBytes);
13152329SN/A    }
13162329SN/A
13172329SN/A    /*
13182329SN/A     * If there's a pending transmit, store the time so we can
13192329SN/A     * reschedule it later
13202329SN/A     */
13219944Smatt.horsnell@ARM.com    Tick transmitTick = txEvent.scheduled() ? txEvent.when() - curTick : 0;
13229944Smatt.horsnell@ARM.com    SERIALIZE_SCALAR(transmitTick);
1323}
1324
1325void
1326Device::unserialize(Checkpoint *cp, const std::string &section)
1327{
1328    // Unserialize the PciDev base class
1329    Base::unserialize(cp, section);
1330
1331    /*
1332     * Unserialize the device registers
1333     */
1334    UNSERIALIZE_SCALAR(regs.Config);
1335    UNSERIALIZE_SCALAR(regs.IntrStatus);
1336    UNSERIALIZE_SCALAR(regs.IntrMask);
1337    UNSERIALIZE_SCALAR(regs.RxMaxCopy);
1338    UNSERIALIZE_SCALAR(regs.TxMaxCopy);
1339    UNSERIALIZE_SCALAR(regs.RxMaxIntr);
1340    UNSERIALIZE_SCALAR(regs.RxData);
1341    UNSERIALIZE_SCALAR(regs.RxDone);
1342    UNSERIALIZE_SCALAR(regs.TxData);
1343    UNSERIALIZE_SCALAR(regs.TxDone);
1344
1345    /*
1346     * Unserialize rx state machine
1347     */
1348    int rxState;
1349    UNSERIALIZE_SCALAR(rxState);
1350    UNSERIALIZE_SCALAR(rxEmpty);
1351    this->rxState = (RxState) rxState;
1352    rxFifo.unserialize("rxFifo", cp, section);
1353    bool rxPacketExists;
1354    UNSERIALIZE_SCALAR(rxPacketExists);
1355    rxPacket = 0;
1356    if (rxPacketExists) {
1357        rxPacket = new PacketData(16384);
1358        rxPacket->unserialize("rxPacket", cp, section);
1359        uint32_t rxPktBufPtr;
1360        UNSERIALIZE_SCALAR(rxPktBufPtr);
1361        this->rxPacketBufPtr = (uint8_t *) rxPacket->data + rxPktBufPtr;
1362        UNSERIALIZE_SCALAR(rxPktBytes);
1363    }
1364    UNSERIALIZE_SCALAR(rxDoneData);
1365
1366    /*
1367     * Unserialize tx state machine
1368     */
1369    int txState;
1370    UNSERIALIZE_SCALAR(txState);
1371    UNSERIALIZE_SCALAR(txFull);
1372    this->txState = (TxState) txState;
1373    txFifo.unserialize("txFifo", cp, section);
1374    bool txPacketExists;
1375    UNSERIALIZE_SCALAR(txPacketExists);
1376    txPacket = 0;
1377    if (txPacketExists) {
1378        txPacket = new PacketData(16384);
1379        txPacket->unserialize("txPacket", cp, section);
1380        uint32_t txPktBufPtr;
1381        UNSERIALIZE_SCALAR(txPktBufPtr);
1382        this->txPacketBufPtr = (uint8_t *) txPacket->data + txPktBufPtr;
1383        UNSERIALIZE_SCALAR(txPktBytes);
1384    }
1385
1386    /*
1387     * If there's a pending transmit, reschedule it now
1388     */
1389    Tick transmitTick;
1390    UNSERIALIZE_SCALAR(transmitTick);
1391    if (transmitTick)
1392        txEvent.schedule(curTick + transmitTick);
1393
1394    /*
1395     * re-add addrRanges to bus bridges
1396     */
1397    if (pioInterface) {
1398        pioInterface->addAddrRange(RangeSize(BARAddrs[0], BARSize[0]));
1399        pioInterface->addAddrRange(RangeSize(BARAddrs[1], BARSize[1]));
1400    }
1401}
1402
1403Tick
1404Device::cacheAccess(MemReqPtr &req)
1405{
1406    Addr daddr;
1407    int bar;
1408    if (!getBAR(req->paddr, daddr, bar))
1409        panic("address does not map to a BAR pa=%#x va=%#x size=%d",
1410              req->paddr, req->vaddr, req->size);
1411
1412    DPRINTF(EthernetPIO, "timing %s to paddr=%#x bar=%d daddr=%#x\n",
1413            req->cmd.toString(), req->paddr, bar, daddr);
1414
1415    if (!pioDelayWrite || !req->cmd.isWrite())
1416        return curTick + pioLatency;
1417
1418    if (bar == 0) {
1419        int cpu = (req->xc->regs.ipr[TheISA::IPR_PALtemp16] >> 8) & 0xff;
1420        std::list<RegWriteData> &wq = writeQueue[cpu];
1421        if (wq.empty())
1422            panic("WriteQueue for cpu %d empty timing daddr=%#x", cpu, daddr);
1423
1424        const RegWriteData &data = wq.front();
1425        if (data.daddr != daddr)
1426            panic("read mismatch on cpu %d, daddr functional=%#x timing=%#x",
1427                  cpu, data.daddr, daddr);
1428
1429        const Regs::Info &info = regInfo(data.daddr);
1430        if (info.delay_write)
1431            regWrite(daddr, cpu, (uint8_t *)&data.value);
1432
1433        wq.pop_front();
1434    }
1435
1436    return curTick + pioLatency;
1437}
1438
1439BEGIN_DECLARE_SIM_OBJECT_PARAMS(Interface)
1440
1441    SimObjectParam<EtherInt *> peer;
1442    SimObjectParam<Device *> device;
1443
1444END_DECLARE_SIM_OBJECT_PARAMS(Interface)
1445
1446BEGIN_INIT_SIM_OBJECT_PARAMS(Interface)
1447
1448    INIT_PARAM_DFLT(peer, "peer interface", NULL),
1449    INIT_PARAM(device, "Ethernet device of this interface")
1450
1451END_INIT_SIM_OBJECT_PARAMS(Interface)
1452
1453CREATE_SIM_OBJECT(Interface)
1454{
1455    Interface *dev_int = new Interface(getInstanceName(), device);
1456
1457    EtherInt *p = (EtherInt *)peer;
1458    if (p) {
1459        dev_int->setPeer(p);
1460        p->setPeer(dev_int);
1461    }
1462
1463    return dev_int;
1464}
1465
1466REGISTER_SIM_OBJECT("SinicInt", Interface)
1467
1468
1469BEGIN_DECLARE_SIM_OBJECT_PARAMS(Device)
1470
1471    Param<Tick> clock;
1472
1473    Param<Addr> addr;
1474    SimObjectParam<MemoryController *> mmu;
1475    SimObjectParam<PhysicalMemory *> physmem;
1476    SimObjectParam<PciConfigAll *> configspace;
1477    SimObjectParam<PciConfigData *> configdata;
1478    SimObjectParam<Platform *> platform;
1479    Param<uint32_t> pci_bus;
1480    Param<uint32_t> pci_dev;
1481    Param<uint32_t> pci_func;
1482
1483    SimObjectParam<HierParams *> hier;
1484    SimObjectParam<Bus*> pio_bus;
1485    SimObjectParam<Bus*> dma_bus;
1486    SimObjectParam<Bus*> payload_bus;
1487    Param<Tick> dma_read_delay;
1488    Param<Tick> dma_read_factor;
1489    Param<Tick> dma_write_delay;
1490    Param<Tick> dma_write_factor;
1491    Param<bool> dma_no_allocate;
1492    Param<Tick> pio_latency;
1493    Param<bool> pio_delay_write;
1494    Param<Tick> intr_delay;
1495
1496    Param<Tick> rx_delay;
1497    Param<Tick> tx_delay;
1498    Param<uint32_t> rx_max_copy;
1499    Param<uint32_t> tx_max_copy;
1500    Param<uint32_t> rx_max_intr;
1501    Param<uint32_t> rx_fifo_size;
1502    Param<uint32_t> tx_fifo_size;
1503    Param<uint32_t> rx_fifo_threshold;
1504    Param<uint32_t> tx_fifo_threshold;
1505
1506    Param<bool> rx_filter;
1507    Param<string> hardware_address;
1508    Param<bool> dedicated;
1509
1510END_DECLARE_SIM_OBJECT_PARAMS(Device)
1511
1512BEGIN_INIT_SIM_OBJECT_PARAMS(Device)
1513
1514    INIT_PARAM(clock, "State machine cycle time"),
1515
1516    INIT_PARAM(addr, "Device Address"),
1517    INIT_PARAM(mmu, "Memory Controller"),
1518    INIT_PARAM(physmem, "Physical Memory"),
1519    INIT_PARAM(configspace, "PCI Configspace"),
1520    INIT_PARAM(configdata, "PCI Config data"),
1521    INIT_PARAM(platform, "Platform"),
1522    INIT_PARAM(pci_bus, "PCI bus"),
1523    INIT_PARAM(pci_dev, "PCI device number"),
1524    INIT_PARAM(pci_func, "PCI function code"),
1525
1526    INIT_PARAM(hier, "Hierarchy global variables"),
1527    INIT_PARAM(pio_bus, ""),
1528    INIT_PARAM(dma_bus, ""),
1529    INIT_PARAM(payload_bus, "The IO Bus to attach to for payload"),
1530    INIT_PARAM(dma_read_delay, "fixed delay for dma reads"),
1531    INIT_PARAM(dma_read_factor, "multiplier for dma reads"),
1532    INIT_PARAM(dma_write_delay, "fixed delay for dma writes"),
1533    INIT_PARAM(dma_write_factor, "multiplier for dma writes"),
1534    INIT_PARAM(dma_no_allocate, "Should we allocat on read in cache"),
1535    INIT_PARAM(pio_latency, "Programmed IO latency in bus cycles"),
1536    INIT_PARAM(pio_delay_write, ""),
1537    INIT_PARAM(intr_delay, "Interrupt Delay"),
1538
1539    INIT_PARAM(rx_delay, "Receive Delay"),
1540    INIT_PARAM(tx_delay, "Transmit Delay"),
1541    INIT_PARAM(rx_max_copy, "rx max copy"),
1542    INIT_PARAM(tx_max_copy, "rx max copy"),
1543    INIT_PARAM(rx_max_intr, "rx max intr"),
1544    INIT_PARAM(rx_fifo_size, "max size in bytes of rxFifo"),
1545    INIT_PARAM(tx_fifo_size, "max size in bytes of txFifo"),
1546    INIT_PARAM(rx_fifo_threshold, "max size in bytes of rxFifo"),
1547    INIT_PARAM(tx_fifo_threshold, "max size in bytes of txFifo"),
1548
1549    INIT_PARAM(rx_filter, "Enable Receive Filter"),
1550    INIT_PARAM(hardware_address, "Ethernet Hardware Address"),
1551    INIT_PARAM(dedicated, "dedicate a kernel thread to the driver")
1552
1553END_INIT_SIM_OBJECT_PARAMS(Device)
1554
1555
1556CREATE_SIM_OBJECT(Device)
1557{
1558    Device::Params *params = new Device::Params;
1559
1560    params->name = getInstanceName();
1561
1562    params->clock = clock;
1563
1564    params->mmu = mmu;
1565    params->physmem = physmem;
1566    params->configSpace = configspace;
1567    params->configData = configdata;
1568    params->plat = platform;
1569    params->busNum = pci_bus;
1570    params->deviceNum = pci_dev;
1571    params->functionNum = pci_func;
1572
1573    params->hier = hier;
1574    params->pio_bus = pio_bus;
1575    params->header_bus = dma_bus;
1576    params->payload_bus = payload_bus;
1577    params->dma_read_delay = dma_read_delay;
1578    params->dma_read_factor = dma_read_factor;
1579    params->dma_write_delay = dma_write_delay;
1580    params->dma_write_factor = dma_write_factor;
1581    params->dma_no_allocate = dma_no_allocate;
1582    params->pio_latency = pio_latency;
1583    params->pio_delay_write = pio_delay_write;
1584    params->intr_delay = intr_delay;
1585
1586    params->tx_delay = tx_delay;
1587    params->rx_delay = rx_delay;
1588    params->rx_max_copy = rx_max_copy;
1589    params->tx_max_copy = tx_max_copy;
1590    params->rx_max_intr = rx_max_intr;
1591    params->rx_fifo_size = rx_fifo_size;
1592    params->tx_fifo_size = tx_fifo_size;
1593    params->rx_fifo_threshold = rx_fifo_threshold;
1594    params->tx_fifo_threshold = tx_fifo_threshold;
1595
1596    params->rx_filter = rx_filter;
1597    params->eaddr = hardware_address;
1598    params->dedicated = dedicated;
1599
1600    return new Device(params);
1601}
1602
1603REGISTER_SIM_OBJECT("Sinic", Device)
1604
1605/* namespace Sinic */ }
1606