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