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 ® = *(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 ® = *(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(®s, 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 §ion) 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 §ion) 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