ns_gige.cc revision 854
15331Sgblack@eecs.umich.edu/* 25331Sgblack@eecs.umich.edu * Copyright (c) 2003 The Regents of The University of Michigan 35331Sgblack@eecs.umich.edu * All rights reserved. 45331Sgblack@eecs.umich.edu * 55331Sgblack@eecs.umich.edu * Redistribution and use in source and binary forms, with or without 65331Sgblack@eecs.umich.edu * modification, are permitted provided that the following conditions are 75331Sgblack@eecs.umich.edu * met: redistributions of source code must retain the above copyright 85331Sgblack@eecs.umich.edu * notice, this list of conditions and the following disclaimer; 95331Sgblack@eecs.umich.edu * redistributions in binary form must reproduce the above copyright 105331Sgblack@eecs.umich.edu * notice, this list of conditions and the following disclaimer in the 115331Sgblack@eecs.umich.edu * documentation and/or other materials provided with the distribution; 125331Sgblack@eecs.umich.edu * neither the name of the copyright holders nor the names of its 135331Sgblack@eecs.umich.edu * contributors may be used to endorse or promote products derived from 145331Sgblack@eecs.umich.edu * this software without specific prior written permission. 155331Sgblack@eecs.umich.edu * 165331Sgblack@eecs.umich.edu * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 175331Sgblack@eecs.umich.edu * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 185331Sgblack@eecs.umich.edu * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR 195331Sgblack@eecs.umich.edu * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT 205331Sgblack@eecs.umich.edu * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 215331Sgblack@eecs.umich.edu * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT 225331Sgblack@eecs.umich.edu * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 235331Sgblack@eecs.umich.edu * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 245331Sgblack@eecs.umich.edu * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 255331Sgblack@eecs.umich.edu * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 265331Sgblack@eecs.umich.edu * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 275331Sgblack@eecs.umich.edu */ 285331Sgblack@eecs.umich.edu 295331Sgblack@eecs.umich.edu/* @file 304276Sgblack@eecs.umich.edu * Device module for modelling the National Semiconductor 314276Sgblack@eecs.umich.edu * DP83820 ethernet controller. Does not support priority queueing 324276Sgblack@eecs.umich.edu */ 334276Sgblack@eecs.umich.edu#include <cstdio> 344276Sgblack@eecs.umich.edu#include <deque> 354276Sgblack@eecs.umich.edu#include <string> 364276Sgblack@eecs.umich.edu 374276Sgblack@eecs.umich.edu#include "base/inet.hh" 384276Sgblack@eecs.umich.edu#include "cpu/exec_context.hh" 394276Sgblack@eecs.umich.edu#include "cpu/intr_control.hh" 404276Sgblack@eecs.umich.edu#include "dev/dma.hh" 414276Sgblack@eecs.umich.edu#include "dev/ns_gige.hh" 424276Sgblack@eecs.umich.edu#include "dev/etherlink.hh" 434276Sgblack@eecs.umich.edu#include "mem/bus/bus.hh" 444276Sgblack@eecs.umich.edu#include "mem/bus/dma_interface.hh" 454276Sgblack@eecs.umich.edu#include "mem/bus/pio_interface.hh" 464276Sgblack@eecs.umich.edu#include "mem/bus/pio_interface_impl.hh" 474276Sgblack@eecs.umich.edu#include "mem/functional_mem/memory_control.hh" 484276Sgblack@eecs.umich.edu#include "mem/functional_mem/physical_memory.hh" 494276Sgblack@eecs.umich.edu#include "sim/builder.hh" 504276Sgblack@eecs.umich.edu#include "sim/host.hh" 514276Sgblack@eecs.umich.edu#include "sim/sim_stats.hh" 524276Sgblack@eecs.umich.edu#include "targetarch/vtophys.hh" 534276Sgblack@eecs.umich.edu#include "dev/pciconfigall.hh" 544276Sgblack@eecs.umich.edu#include "dev/tsunami_cchip.hh" 554276Sgblack@eecs.umich.edu 564276Sgblack@eecs.umich.educonst char *NsRxStateStrings[] = 574276Sgblack@eecs.umich.edu{ 584276Sgblack@eecs.umich.edu "rxIdle", 594276Sgblack@eecs.umich.edu "rxDescRefr", 604276Sgblack@eecs.umich.edu "rxDescRead", 614276Sgblack@eecs.umich.edu "rxFifoBlock", 624276Sgblack@eecs.umich.edu "rxFragWrite", 634276Sgblack@eecs.umich.edu "rxDescWrite", 644276Sgblack@eecs.umich.edu "rxAdvance" 654276Sgblack@eecs.umich.edu}; 664276Sgblack@eecs.umich.edu 674276Sgblack@eecs.umich.educonst char *NsTxStateStrings[] = 684276Sgblack@eecs.umich.edu{ 694276Sgblack@eecs.umich.edu "txIdle", 704276Sgblack@eecs.umich.edu "txDescRefr", 714276Sgblack@eecs.umich.edu "txDescRead", 724276Sgblack@eecs.umich.edu "txFifoBlock", 734276Sgblack@eecs.umich.edu "txFragRead", 744276Sgblack@eecs.umich.edu "txDescWrite", 754276Sgblack@eecs.umich.edu "txAdvance" 764276Sgblack@eecs.umich.edu}; 774276Sgblack@eecs.umich.edu 784276Sgblack@eecs.umich.educonst char *NsDmaState[] = 794276Sgblack@eecs.umich.edu{ 804276Sgblack@eecs.umich.edu "dmaIdle", 814276Sgblack@eecs.umich.edu "dmaReading", 824276Sgblack@eecs.umich.edu "dmaWriting", 834276Sgblack@eecs.umich.edu "dmaReadWaiting", 844276Sgblack@eecs.umich.edu "dmaWriteWaiting" 854276Sgblack@eecs.umich.edu}; 864276Sgblack@eecs.umich.edu 874276Sgblack@eecs.umich.eduusing namespace std; 884276Sgblack@eecs.umich.edu 894711Sgblack@eecs.umich.edu/////////////////////////////////////////////////////////////////////// 904276Sgblack@eecs.umich.edu// 914276Sgblack@eecs.umich.edu// EtherDev PCI Device 925238Sgblack@eecs.umich.edu// 935238Sgblack@eecs.umich.eduEtherDev::EtherDev(const std::string &name, IntrControl *i, Tick intr_delay, 945238Sgblack@eecs.umich.edu PhysicalMemory *pmem, Tick tx_delay, Tick rx_delay, 955238Sgblack@eecs.umich.edu MemoryController *mmu, HierParams *hier, Bus *header_bus, 965937Sgblack@eecs.umich.edu Bus *payload_bus, Tick pio_latency, bool dma_desc_free, 975902Sgblack@eecs.umich.edu bool dma_data_free, Tick dma_read_delay, Tick dma_write_delay, 985238Sgblack@eecs.umich.edu Tick dma_read_factor, Tick dma_write_factor, PciConfigAll *cf, 995238Sgblack@eecs.umich.edu PciConfigData *cd, Tsunami *t, uint32_t bus, uint32_t dev, 1005238Sgblack@eecs.umich.edu uint32_t func, bool rx_filter, const int eaddr[6], Addr addr) 1015238Sgblack@eecs.umich.edu : PciDev(name, mmu, cf, cd, bus, dev, func), tsunami(t), 1025238Sgblack@eecs.umich.edu addr(addr), txPacketBufPtr(NULL), rxPacketBufPtr(NULL), 1035238Sgblack@eecs.umich.edu txXferLen(0), rxXferLen(0), txPktXmitted(0), txState(txIdle), CTDD(false), 1046611Sgblack@eecs.umich.edu txFifoCnt(0), txFifoAvail(MAX_TX_FIFO_SIZE), txHalt(false), 1056611Sgblack@eecs.umich.edu txFragPtr(0), txDescCnt(0), txDmaState(dmaIdle), rxState(rxIdle), 1066611Sgblack@eecs.umich.edu CRDD(false), rxPktBytes(0), rxFifoCnt(0), rxHalt(false), 1075238Sgblack@eecs.umich.edu rxFragPtr(0), rxDescCnt(0), rxDmaState(dmaIdle), extstsEnable(false), 1085238Sgblack@eecs.umich.edu rxDmaReadEvent(this), rxDmaWriteEvent(this), 1095238Sgblack@eecs.umich.edu txDmaReadEvent(this), txDmaWriteEvent(this), 1105238Sgblack@eecs.umich.edu dmaDescFree(dma_desc_free), dmaDataFree(dma_data_free), 1115238Sgblack@eecs.umich.edu txDelay(tx_delay), rxDelay(rx_delay), rxKickTick(0), txKickTick(0), 1125238Sgblack@eecs.umich.edu txEvent(this), rxFilterEnable(rx_filter), acceptBroadcast(false), 1136611Sgblack@eecs.umich.edu acceptMulticast(false), acceptUnicast(false), 1146611Sgblack@eecs.umich.edu acceptPerfect(false), acceptArp(false), 1156611Sgblack@eecs.umich.edu physmem(pmem), intctrl(i), intrTick(0), 1166611Sgblack@eecs.umich.edu cpuPendingIntr(false), intrEvent(0), interface(0), pioLatency(pio_latency) 1175238Sgblack@eecs.umich.edu{ 1185238Sgblack@eecs.umich.edu mmu->add_child(this, Range<Addr>(addr, addr + size)); 1195238Sgblack@eecs.umich.edu tsunami->ethernet = this; 1205238Sgblack@eecs.umich.edu 1216611Sgblack@eecs.umich.edu if (header_bus) { 1226611Sgblack@eecs.umich.edu pioInterface = newPioInterface(name, hier, header_bus, this, 1236611Sgblack@eecs.umich.edu &EtherDev::cacheAccess); 1246611Sgblack@eecs.umich.edu pioInterface->addAddrRange(addr, addr + size - 1); 1256611Sgblack@eecs.umich.edu if (payload_bus) 1266611Sgblack@eecs.umich.edu dmaInterface = new DMAInterface<Bus>(name + ".dma", 1276611Sgblack@eecs.umich.edu header_bus, payload_bus, 1); 1286611Sgblack@eecs.umich.edu else 1296611Sgblack@eecs.umich.edu dmaInterface = new DMAInterface<Bus>(name + ".dma", 1306611Sgblack@eecs.umich.edu header_bus, header_bus, 1); 1316611Sgblack@eecs.umich.edu } else if (payload_bus) { 1326611Sgblack@eecs.umich.edu pioInterface = newPioInterface(name, hier, payload_bus, this, 1336611Sgblack@eecs.umich.edu &EtherDev::cacheAccess); 1346611Sgblack@eecs.umich.edu pioInterface->addAddrRange(addr, addr + size - 1); 1356611Sgblack@eecs.umich.edu dmaInterface = new DMAInterface<Bus>(name + ".dma", 1366611Sgblack@eecs.umich.edu payload_bus, payload_bus, 1); 1376611Sgblack@eecs.umich.edu 1386611Sgblack@eecs.umich.edu } 1395238Sgblack@eecs.umich.edu 1405238Sgblack@eecs.umich.edu 1415238Sgblack@eecs.umich.edu intrDelay = US2Ticks(intr_delay); 1425238Sgblack@eecs.umich.edu dmaReadDelay = dma_read_delay; 1435238Sgblack@eecs.umich.edu dmaWriteDelay = dma_write_delay; 1445238Sgblack@eecs.umich.edu dmaReadFactor = dma_read_factor; 1455238Sgblack@eecs.umich.edu dmaWriteFactor = dma_write_factor; 1465238Sgblack@eecs.umich.edu 1475238Sgblack@eecs.umich.edu memset(®s, 0, sizeof(regs)); 1485238Sgblack@eecs.umich.edu regsReset(); 1496611Sgblack@eecs.umich.edu rom.perfectMatch[0] = eaddr[0]; 1505292Sgblack@eecs.umich.edu rom.perfectMatch[1] = eaddr[1]; 1515292Sgblack@eecs.umich.edu rom.perfectMatch[2] = eaddr[2]; 1525292Sgblack@eecs.umich.edu rom.perfectMatch[3] = eaddr[3]; 1535292Sgblack@eecs.umich.edu rom.perfectMatch[4] = eaddr[4]; 1545292Sgblack@eecs.umich.edu rom.perfectMatch[5] = eaddr[5]; 1555292Sgblack@eecs.umich.edu} 1565292Sgblack@eecs.umich.edu 1575292Sgblack@eecs.umich.eduEtherDev::~EtherDev() 1586611Sgblack@eecs.umich.edu{} 1596611Sgblack@eecs.umich.edu 1606611Sgblack@eecs.umich.eduvoid 1616611Sgblack@eecs.umich.eduEtherDev::regStats() 1626611Sgblack@eecs.umich.edu{ 1636611Sgblack@eecs.umich.edu txBytes 1646611Sgblack@eecs.umich.edu .name(name() + ".txBytes") 1656611Sgblack@eecs.umich.edu .desc("Bytes Transmitted") 1666611Sgblack@eecs.umich.edu .prereq(txBytes) 1676611Sgblack@eecs.umich.edu ; 1686611Sgblack@eecs.umich.edu 1696611Sgblack@eecs.umich.edu rxBytes 1706611Sgblack@eecs.umich.edu .name(name() + ".rxBytes") 1715238Sgblack@eecs.umich.edu .desc("Bytes Received") 1725238Sgblack@eecs.umich.edu .prereq(rxBytes) 1734276Sgblack@eecs.umich.edu ; 1744276Sgblack@eecs.umich.edu 1755789Sgblack@eecs.umich.edu txPackets 1765789Sgblack@eecs.umich.edu .name(name() + ".txPackets") 1775789Sgblack@eecs.umich.edu .desc("Number of Packets Transmitted") 1785789Sgblack@eecs.umich.edu .prereq(txBytes) 1795789Sgblack@eecs.umich.edu ; 1805789Sgblack@eecs.umich.edu 1815789Sgblack@eecs.umich.edu rxPackets 1825789Sgblack@eecs.umich.edu .name(name() + ".rxPackets") 1835789Sgblack@eecs.umich.edu .desc("Number of Packets Received") 1845789Sgblack@eecs.umich.edu .prereq(rxBytes) 1855789Sgblack@eecs.umich.edu ; 1865789Sgblack@eecs.umich.edu 1875789Sgblack@eecs.umich.edu txBandwidth 1885789Sgblack@eecs.umich.edu .name(name() + ".txBandwidth") 1895789Sgblack@eecs.umich.edu .desc("Transmit Bandwidth (bits/s)") 1905789Sgblack@eecs.umich.edu .precision(0) 1915789Sgblack@eecs.umich.edu .prereq(txBytes) 1925789Sgblack@eecs.umich.edu ; 1935789Sgblack@eecs.umich.edu 1945789Sgblack@eecs.umich.edu rxBandwidth 1955789Sgblack@eecs.umich.edu .name(name() + ".rxBandwidth") 1965789Sgblack@eecs.umich.edu .desc("Receive Bandwidth (bits/s)") 1975789Sgblack@eecs.umich.edu .precision(0) 1985789Sgblack@eecs.umich.edu .prereq(rxBytes) 1995789Sgblack@eecs.umich.edu ; 2005789Sgblack@eecs.umich.edu 2015789Sgblack@eecs.umich.edu txPacketRate 2025789Sgblack@eecs.umich.edu .name(name() + ".txPPS") 2035789Sgblack@eecs.umich.edu .desc("Packet Tranmission Rate (packets/s)") 2045789Sgblack@eecs.umich.edu .precision(0) 2055789Sgblack@eecs.umich.edu .prereq(txBytes) 2065789Sgblack@eecs.umich.edu ; 2075789Sgblack@eecs.umich.edu 2085789Sgblack@eecs.umich.edu rxPacketRate 2095789Sgblack@eecs.umich.edu .name(name() + ".rxPPS") 2105789Sgblack@eecs.umich.edu .desc("Packet Reception Rate (packets/s)") 2115789Sgblack@eecs.umich.edu .precision(0) 2125789Sgblack@eecs.umich.edu .prereq(rxBytes) 2135789Sgblack@eecs.umich.edu ; 2145789Sgblack@eecs.umich.edu 2155789Sgblack@eecs.umich.edu txBandwidth = txBytes * Statistics::constant(8) / simSeconds; 2165789Sgblack@eecs.umich.edu rxBandwidth = rxBytes * Statistics::constant(8) / simSeconds; 2175789Sgblack@eecs.umich.edu txPacketRate = txPackets / simSeconds; 2185789Sgblack@eecs.umich.edu rxPacketRate = rxPackets / simSeconds; 2195789Sgblack@eecs.umich.edu} 2205789Sgblack@eecs.umich.edu 2215789Sgblack@eecs.umich.eduvoid 2225789Sgblack@eecs.umich.eduEtherDev::ReadConfig(int offset, int size, uint8_t *data) 2235789Sgblack@eecs.umich.edu{ 2245789Sgblack@eecs.umich.edu if (offset < PCI_DEVICE_SPECIFIC) 2255789Sgblack@eecs.umich.edu PciDev::ReadConfig(offset, size, data); 2265789Sgblack@eecs.umich.edu else { 2275789Sgblack@eecs.umich.edu panic("need to do this\n"); 2285789Sgblack@eecs.umich.edu } 2295789Sgblack@eecs.umich.edu} 2305789Sgblack@eecs.umich.edu 2315789Sgblack@eecs.umich.eduvoid 2325789Sgblack@eecs.umich.eduEtherDev::WriteConfig(int offset, int size, uint32_t data) 2335789Sgblack@eecs.umich.edu{ 2345789Sgblack@eecs.umich.edu if (offset < PCI_DEVICE_SPECIFIC) 2355789Sgblack@eecs.umich.edu PciDev::WriteConfig(offset, size, data); 2365789Sgblack@eecs.umich.edu else 2375789Sgblack@eecs.umich.edu panic("Need to do that\n"); 2385789Sgblack@eecs.umich.edu} 2395789Sgblack@eecs.umich.edu 2405789Sgblack@eecs.umich.eduFault 2415789Sgblack@eecs.umich.eduEtherDev::read(MemReqPtr &req, uint8_t *data) 2425789Sgblack@eecs.umich.edu{ 2435789Sgblack@eecs.umich.edu Addr daddr = req->paddr & 0xfff; 2445789Sgblack@eecs.umich.edu DPRINTF(EthernetPIO, "read da=%#x pa=%#x va=%#x size=%d\n", 2455789Sgblack@eecs.umich.edu daddr, req->paddr, req->vaddr, req->size); 2465789Sgblack@eecs.umich.edu 2475789Sgblack@eecs.umich.edu if (daddr > LAST && daddr <= RESERVED) { 2485789Sgblack@eecs.umich.edu panic("Accessing reserved register"); 2495789Sgblack@eecs.umich.edu } else if (daddr > RESERVED && daddr <= 0x3FC) { 2505789Sgblack@eecs.umich.edu ReadConfig(daddr & 0xff, req->size, data); 2515789Sgblack@eecs.umich.edu return No_Fault; 2525789Sgblack@eecs.umich.edu } else if (daddr >= MIB_START && daddr <= MIB_END) { 2535789Sgblack@eecs.umich.edu // don't implement all the MIB's. hopefully the kernel 2545789Sgblack@eecs.umich.edu // doesn't actually DEPEND upon their values 2555789Sgblack@eecs.umich.edu uint32_t ® = *(uint32_t *) data; 2565789Sgblack@eecs.umich.edu reg = 0; 2575789Sgblack@eecs.umich.edu return No_Fault; 2585789Sgblack@eecs.umich.edu } else if (daddr > 0x3FC) 2595789Sgblack@eecs.umich.edu panic("Something is messed up!\n"); 2605789Sgblack@eecs.umich.edu 2615789Sgblack@eecs.umich.edu switch (req->size) { 2625789Sgblack@eecs.umich.edu case sizeof(uint32_t): 2635789Sgblack@eecs.umich.edu { 2645789Sgblack@eecs.umich.edu uint32_t ® = *(uint32_t *)data; 2654712Sgblack@eecs.umich.edu 2665907Sgblack@eecs.umich.edu switch (daddr) { 2675907Sgblack@eecs.umich.edu case CR: 2685907Sgblack@eecs.umich.edu reg = regs.command; 2695907Sgblack@eecs.umich.edu reg &= ~(CR_RXD | CR_TXD | CR_TXR | CR_RXR); 2705907Sgblack@eecs.umich.edu break; 2715907Sgblack@eecs.umich.edu 2725907Sgblack@eecs.umich.edu case CFG: 2734712Sgblack@eecs.umich.edu reg = regs.config; 2745659Sgblack@eecs.umich.edu break; 2754712Sgblack@eecs.umich.edu 2765933Sgblack@eecs.umich.edu case MEAR: 2775908Sgblack@eecs.umich.edu reg = regs.mear; 2785908Sgblack@eecs.umich.edu break; 2795908Sgblack@eecs.umich.edu 2805908Sgblack@eecs.umich.edu case PTSCR: 2815908Sgblack@eecs.umich.edu reg = regs.ptscr; 2825908Sgblack@eecs.umich.edu break; 2835908Sgblack@eecs.umich.edu 2845908Sgblack@eecs.umich.edu case ISR: 2855908Sgblack@eecs.umich.edu reg = regs.isr; 2864276Sgblack@eecs.umich.edu regs.isr = 0; 2874276Sgblack@eecs.umich.edu break; 2884712Sgblack@eecs.umich.edu 2894712Sgblack@eecs.umich.edu case IMR: 2904730Sgblack@eecs.umich.edu reg = regs.imr; 2914760Sgblack@eecs.umich.edu break; 2924730Sgblack@eecs.umich.edu 2935920Sgblack@eecs.umich.edu case IER: 2945422Sgblack@eecs.umich.edu reg = regs.ier; 2956616Sgblack@eecs.umich.edu break; 2966616Sgblack@eecs.umich.edu 2976616Sgblack@eecs.umich.edu case IHR: 2986616Sgblack@eecs.umich.edu reg = regs.ihr; 2996616Sgblack@eecs.umich.edu break; 3006616Sgblack@eecs.umich.edu 3016616Sgblack@eecs.umich.edu case TXDP: 3026616Sgblack@eecs.umich.edu reg = regs.txdp; 3036616Sgblack@eecs.umich.edu break; 3046616Sgblack@eecs.umich.edu 3056616Sgblack@eecs.umich.edu case TXDP_HI: 3066616Sgblack@eecs.umich.edu reg = regs.txdp_hi; 3076616Sgblack@eecs.umich.edu break; 3086616Sgblack@eecs.umich.edu 3096616Sgblack@eecs.umich.edu case TXCFG: 3106616Sgblack@eecs.umich.edu reg = regs.txcfg; 3116616Sgblack@eecs.umich.edu break; 3126616Sgblack@eecs.umich.edu 3136616Sgblack@eecs.umich.edu case GPIOR: 3146616Sgblack@eecs.umich.edu reg = regs.gpior; 3156616Sgblack@eecs.umich.edu break; 3166616Sgblack@eecs.umich.edu 3176616Sgblack@eecs.umich.edu case RXDP: 3186616Sgblack@eecs.umich.edu reg = regs.rxdp; 3196616Sgblack@eecs.umich.edu break; 3206616Sgblack@eecs.umich.edu 3216616Sgblack@eecs.umich.edu case RXDP_HI: 3224276Sgblack@eecs.umich.edu reg = regs.rxdp_hi; 3236576Sgblack@eecs.umich.edu break; 3246576Sgblack@eecs.umich.edu 3256576Sgblack@eecs.umich.edu case RXCFG: 3266576Sgblack@eecs.umich.edu reg = regs.rxcfg; 3276576Sgblack@eecs.umich.edu break; 3286576Sgblack@eecs.umich.edu 3296576Sgblack@eecs.umich.edu case PQCR: 3306611Sgblack@eecs.umich.edu reg = regs.pqcr; 3316611Sgblack@eecs.umich.edu break; 3326576Sgblack@eecs.umich.edu 3336611Sgblack@eecs.umich.edu case WCSR: 3346576Sgblack@eecs.umich.edu reg = regs.wcsr; 3356611Sgblack@eecs.umich.edu break; 3366576Sgblack@eecs.umich.edu 3376611Sgblack@eecs.umich.edu case PCR: 3386611Sgblack@eecs.umich.edu reg = regs.pcr; 3396576Sgblack@eecs.umich.edu break; 3406576Sgblack@eecs.umich.edu 3415020Sgblack@eecs.umich.edu case RFCR: 3426576Sgblack@eecs.umich.edu reg = regs.rfcr; 3436576Sgblack@eecs.umich.edu break; 3446600Sgblack@eecs.umich.edu 3456600Sgblack@eecs.umich.edu case RFDR: 3466576Sgblack@eecs.umich.edu DPRINTF(Ethernet, "reading from RFDR\n"); 3476576Sgblack@eecs.umich.edu switch (regs.rfcr & RFCR_RFADDR) { 3486576Sgblack@eecs.umich.edu case 0x000: 3495020Sgblack@eecs.umich.edu reg = rom.perfectMatch[1]; 3506576Sgblack@eecs.umich.edu reg = reg << 8; 3516576Sgblack@eecs.umich.edu reg += rom.perfectMatch[0]; 3526576Sgblack@eecs.umich.edu break; 3536576Sgblack@eecs.umich.edu case 0x002: 3546576Sgblack@eecs.umich.edu reg = rom.perfectMatch[3] << 8; 3556576Sgblack@eecs.umich.edu reg += rom.perfectMatch[2]; 3566576Sgblack@eecs.umich.edu break; 3576576Sgblack@eecs.umich.edu case 0x004: 3586576Sgblack@eecs.umich.edu reg = rom.perfectMatch[5] << 8; 3596576Sgblack@eecs.umich.edu reg += rom.perfectMatch[4]; 3606576Sgblack@eecs.umich.edu break; 3616576Sgblack@eecs.umich.edu default: 3626576Sgblack@eecs.umich.edu panic("reading from RFDR for something for other than PMATCH!\n"); 3636576Sgblack@eecs.umich.edu //didn't implement other RFDR functionality b/c driver didn't use 3646576Sgblack@eecs.umich.edu } 3656576Sgblack@eecs.umich.edu break; 3666576Sgblack@eecs.umich.edu 3676576Sgblack@eecs.umich.edu case SRR: 3686576Sgblack@eecs.umich.edu reg = regs.srr; 3694760Sgblack@eecs.umich.edu break; 3706576Sgblack@eecs.umich.edu 3716611Sgblack@eecs.umich.edu case MIBC: 3726576Sgblack@eecs.umich.edu reg = regs.mibc; 3736576Sgblack@eecs.umich.edu reg &= ~(MIBC_MIBS | MIBC_ACLR); 3746576Sgblack@eecs.umich.edu break; 3756576Sgblack@eecs.umich.edu 3766576Sgblack@eecs.umich.edu case VRCR: 3776576Sgblack@eecs.umich.edu reg = regs.vrcr; 3786576Sgblack@eecs.umich.edu break; 3796576Sgblack@eecs.umich.edu 3806576Sgblack@eecs.umich.edu case VTCR: 3816576Sgblack@eecs.umich.edu reg = regs.vtcr; 3826576Sgblack@eecs.umich.edu break; 3836576Sgblack@eecs.umich.edu 3846576Sgblack@eecs.umich.edu case VDR: 3856576Sgblack@eecs.umich.edu reg = regs.vdr; 3864760Sgblack@eecs.umich.edu break; 3876576Sgblack@eecs.umich.edu 3886576Sgblack@eecs.umich.edu case CCSR: 3896576Sgblack@eecs.umich.edu reg = regs.ccsr; 3906576Sgblack@eecs.umich.edu break; 3916576Sgblack@eecs.umich.edu 3926576Sgblack@eecs.umich.edu case TBICR: 3936576Sgblack@eecs.umich.edu reg = regs.tbicr; 3946576Sgblack@eecs.umich.edu break; 3956576Sgblack@eecs.umich.edu 3966576Sgblack@eecs.umich.edu case TBISR: 3974760Sgblack@eecs.umich.edu reg = regs.tbisr; 3986611Sgblack@eecs.umich.edu break; 3996611Sgblack@eecs.umich.edu 4006611Sgblack@eecs.umich.edu case TANAR: 4016611Sgblack@eecs.umich.edu reg = regs.tanar; 4026611Sgblack@eecs.umich.edu break; 4036611Sgblack@eecs.umich.edu 4046611Sgblack@eecs.umich.edu case TANLPAR: 4056611Sgblack@eecs.umich.edu reg = regs.tanlpar; 4066611Sgblack@eecs.umich.edu break; 4076611Sgblack@eecs.umich.edu 4086611Sgblack@eecs.umich.edu case TANER: 4096611Sgblack@eecs.umich.edu reg = regs.taner; 4106611Sgblack@eecs.umich.edu break; 4116611Sgblack@eecs.umich.edu 4126611Sgblack@eecs.umich.edu case TESR: 4136611Sgblack@eecs.umich.edu reg = regs.tesr; 4146611Sgblack@eecs.umich.edu break; 4156611Sgblack@eecs.umich.edu 4166611Sgblack@eecs.umich.edu default: 4176611Sgblack@eecs.umich.edu panic("reading unimplemented register: addr = %#x", daddr); 4186611Sgblack@eecs.umich.edu } 4196611Sgblack@eecs.umich.edu 4206611Sgblack@eecs.umich.edu DPRINTF(EthernetPIO, "read from %#x: data=%d data=%#x\n", daddr, reg, reg); 4216611Sgblack@eecs.umich.edu } 4226611Sgblack@eecs.umich.edu break; 4236611Sgblack@eecs.umich.edu 4246611Sgblack@eecs.umich.edu default: 4256611Sgblack@eecs.umich.edu panic("accessing register with invalid size: addr=%#x, size=%d", 4266611Sgblack@eecs.umich.edu daddr, req->size); 4276611Sgblack@eecs.umich.edu } 4286611Sgblack@eecs.umich.edu 4296611Sgblack@eecs.umich.edu return No_Fault; 4306611Sgblack@eecs.umich.edu} 4316611Sgblack@eecs.umich.edu 4326611Sgblack@eecs.umich.eduFault 4336611Sgblack@eecs.umich.eduEtherDev::write(MemReqPtr &req, const uint8_t *data) 4346611Sgblack@eecs.umich.edu{ 4356611Sgblack@eecs.umich.edu Addr daddr = req->paddr & 0xfff; 4366611Sgblack@eecs.umich.edu DPRINTF(EthernetPIO, "write da=%#x pa=%#x va=%#x size=%d\n", 4376611Sgblack@eecs.umich.edu daddr, req->paddr, req->vaddr, req->size); 4386611Sgblack@eecs.umich.edu 4396611Sgblack@eecs.umich.edu if (daddr > LAST && daddr <= RESERVED) { 4405020Sgblack@eecs.umich.edu panic("Accessing reserved register"); 4414276Sgblack@eecs.umich.edu } else if (daddr > RESERVED && daddr <= 0x3FC) { 4424276Sgblack@eecs.umich.edu WriteConfig(daddr & 0xff, req->size, *(uint32_t *)data); 4435149Sgblack@eecs.umich.edu return No_Fault; 4445409Sgblack@eecs.umich.edu } else if (daddr > 0x3FC) 4455149Sgblack@eecs.umich.edu panic("Something is messed up!\n"); 4464712Sgblack@eecs.umich.edu 4475972Sgblack@eecs.umich.edu if (req->size == sizeof(uint32_t)) { 4484712Sgblack@eecs.umich.edu uint32_t reg = *(uint32_t *)data; 4495972Sgblack@eecs.umich.edu DPRINTF(EthernetPIO, "write data=%d data=%#x\n", reg, reg); 4505972Sgblack@eecs.umich.edu 4515972Sgblack@eecs.umich.edu switch (daddr) { 4524712Sgblack@eecs.umich.edu case CR: 4534730Sgblack@eecs.umich.edu regs.command = reg; 4544712Sgblack@eecs.umich.edu if ((reg & (CR_TXE | CR_TXD)) == (CR_TXE | CR_TXD)) { 4554276Sgblack@eecs.umich.edu txHalt = true; 4564276Sgblack@eecs.umich.edu } else if (reg & CR_TXE) { 4576615Sgblack@eecs.umich.edu if (txState == txIdle) 4586615Sgblack@eecs.umich.edu txKick(); 4596615Sgblack@eecs.umich.edu } else if (reg & CR_TXD) { 4606615Sgblack@eecs.umich.edu txHalt = true; 4616615Sgblack@eecs.umich.edu } 4626615Sgblack@eecs.umich.edu 4636611Sgblack@eecs.umich.edu if ((reg & (CR_RXE | CR_RXD)) == (CR_RXE | CR_RXD)) { 4644276Sgblack@eecs.umich.edu rxHalt = true; 4654760Sgblack@eecs.umich.edu } else if (reg & CR_RXE) { 4664760Sgblack@eecs.umich.edu if (rxState == rxIdle) { 4674760Sgblack@eecs.umich.edu rxKick(); 4684760Sgblack@eecs.umich.edu } 4694760Sgblack@eecs.umich.edu } else if (reg & CR_RXD) { 4704760Sgblack@eecs.umich.edu rxHalt = true; 4714760Sgblack@eecs.umich.edu } 4724760Sgblack@eecs.umich.edu 4734760Sgblack@eecs.umich.edu if (reg & CR_TXR) 4744760Sgblack@eecs.umich.edu txReset(); 4754760Sgblack@eecs.umich.edu 4764760Sgblack@eecs.umich.edu if (reg & CR_RXR) 4774760Sgblack@eecs.umich.edu rxReset(); 4784760Sgblack@eecs.umich.edu 4794760Sgblack@eecs.umich.edu if (reg & CR_SWI) 4804760Sgblack@eecs.umich.edu devIntrPost(ISR_SWI); 4814760Sgblack@eecs.umich.edu 4824760Sgblack@eecs.umich.edu if (reg & CR_RST) { 4834760Sgblack@eecs.umich.edu txReset(); 4844760Sgblack@eecs.umich.edu rxReset(); 4854760Sgblack@eecs.umich.edu 4866576Sgblack@eecs.umich.edu regsReset(); 4876576Sgblack@eecs.umich.edu } 4886576Sgblack@eecs.umich.edu break; 4896593Sgblack@eecs.umich.edu 4906576Sgblack@eecs.umich.edu case CFG: 4916576Sgblack@eecs.umich.edu if (reg & CFG_LNKSTS || reg & CFG_SPDSTS || reg & CFG_DUPSTS 4926576Sgblack@eecs.umich.edu || reg & CFG_RESERVED || reg & CFG_T64ADDR 4936576Sgblack@eecs.umich.edu || reg & CFG_PCI64_DET) 4946576Sgblack@eecs.umich.edu panic("writing to read-only or reserved CFG bits!\n"); 4956576Sgblack@eecs.umich.edu 4966576Sgblack@eecs.umich.edu regs.config |= reg & ~(CFG_LNKSTS | CFG_SPDSTS | CFG_DUPSTS | CFG_RESERVED | 4976576Sgblack@eecs.umich.edu CFG_T64ADDR | CFG_PCI64_DET); 4986576Sgblack@eecs.umich.edu 4996576Sgblack@eecs.umich.edu#if 0 5006576Sgblack@eecs.umich.edu if (reg & CFG_TBI_EN) ; 5016576Sgblack@eecs.umich.edu if (reg & CFG_MODE_1000) ; 5026576Sgblack@eecs.umich.edu#endif 5036576Sgblack@eecs.umich.edu 5046576Sgblack@eecs.umich.edu if (reg & CFG_AUTO_1000) 5056576Sgblack@eecs.umich.edu panic("CFG_AUTO_1000 not implemented!\n"); 5066576Sgblack@eecs.umich.edu 5076593Sgblack@eecs.umich.edu#if 0 5086576Sgblack@eecs.umich.edu if (reg & CFG_PINT_DUPSTS || reg & CFG_PINT_LNKSTS || reg & CFG_PINT_SPDSTS) ; 5096576Sgblack@eecs.umich.edu if (reg & CFG_TMRTEST) ; 5106576Sgblack@eecs.umich.edu if (reg & CFG_MRM_DIS) ; 5116576Sgblack@eecs.umich.edu if (reg & CFG_MWI_DIS) ; 5126611Sgblack@eecs.umich.edu 5136576Sgblack@eecs.umich.edu if (reg & CFG_T64ADDR) 5146576Sgblack@eecs.umich.edu panic("CFG_T64ADDR is read only register!\n"); 5155059Sgblack@eecs.umich.edu 5165059Sgblack@eecs.umich.edu if (reg & CFG_PCI64_DET) 5176576Sgblack@eecs.umich.edu panic("CFG_PCI64_DET is read only register!\n"); 5185059Sgblack@eecs.umich.edu 5195059Sgblack@eecs.umich.edu if (reg & CFG_DATA64_EN) ; 5205059Sgblack@eecs.umich.edu if (reg & CFG_M64ADDR) ; 5215020Sgblack@eecs.umich.edu if (reg & CFG_PHY_RST) ; 5226576Sgblack@eecs.umich.edu if (reg & CFG_PHY_DIS) ; 5236576Sgblack@eecs.umich.edu#endif 5246576Sgblack@eecs.umich.edu 5256576Sgblack@eecs.umich.edu if (reg & CFG_EXTSTS_EN) 5266576Sgblack@eecs.umich.edu extstsEnable = true; 5276576Sgblack@eecs.umich.edu else 5286576Sgblack@eecs.umich.edu extstsEnable = false; 5296576Sgblack@eecs.umich.edu 5306576Sgblack@eecs.umich.edu#if 0 5316576Sgblack@eecs.umich.edu if (reg & CFG_REQALG) ; 5326576Sgblack@eecs.umich.edu if (reg & CFG_SB) ; 5336576Sgblack@eecs.umich.edu if (reg & CFG_POW) ; 5346576Sgblack@eecs.umich.edu if (reg & CFG_EXD) ; 5356576Sgblack@eecs.umich.edu if (reg & CFG_PESEL) ; 5366576Sgblack@eecs.umich.edu if (reg & CFG_BROM_DIS) ; 5376576Sgblack@eecs.umich.edu if (reg & CFG_EXT_125) ; 5386576Sgblack@eecs.umich.edu if (reg & CFG_BEM) ; 5396606Sgblack@eecs.umich.edu#endif 5406576Sgblack@eecs.umich.edu break; 5416576Sgblack@eecs.umich.edu 5426576Sgblack@eecs.umich.edu case MEAR: 5436576Sgblack@eecs.umich.edu regs.mear = reg; 5446576Sgblack@eecs.umich.edu /* since phy is completely faked, MEAR_MD* don't matter 5456576Sgblack@eecs.umich.edu and since the driver never uses MEAR_EE*, they don't matter */ 5466576Sgblack@eecs.umich.edu#if 0 5476576Sgblack@eecs.umich.edu if (reg & MEAR_EEDI) ; 5486576Sgblack@eecs.umich.edu if (reg & MEAR_EEDO) ; //this one is read only 5496576Sgblack@eecs.umich.edu if (reg & MEAR_EECLK) ; 5506606Sgblack@eecs.umich.edu if (reg & MEAR_EESEL) ; 5516576Sgblack@eecs.umich.edu if (reg & MEAR_MDIO) ; 5526576Sgblack@eecs.umich.edu if (reg & MEAR_MDDIR) ; 5536576Sgblack@eecs.umich.edu if (reg & MEAR_MDC) ; 5546576Sgblack@eecs.umich.edu#endif 5556576Sgblack@eecs.umich.edu break; 5566576Sgblack@eecs.umich.edu 5576576Sgblack@eecs.umich.edu case PTSCR: 5586576Sgblack@eecs.umich.edu regs.ptscr = reg & ~(PTSCR_RBIST_RDONLY); 5596576Sgblack@eecs.umich.edu /* these control BISTs for various parts of chip - we don't care or do 5606576Sgblack@eecs.umich.edu just fake that the BIST is done */ 5616576Sgblack@eecs.umich.edu if (reg & PTSCR_RBIST_EN) 5626576Sgblack@eecs.umich.edu regs.ptscr |= PTSCR_RBIST_DONE; 5636576Sgblack@eecs.umich.edu if (reg & PTSCR_EEBIST_EN) 5646576Sgblack@eecs.umich.edu regs.ptscr &= ~PTSCR_EEBIST_EN; 5656576Sgblack@eecs.umich.edu if (reg & PTSCR_EELOAD_EN) 5666576Sgblack@eecs.umich.edu regs.ptscr &= ~PTSCR_EELOAD_EN; 5676576Sgblack@eecs.umich.edu break; 5685020Sgblack@eecs.umich.edu 5696576Sgblack@eecs.umich.edu case ISR: /* writing to the ISR has no effect */ 5706576Sgblack@eecs.umich.edu panic("ISR is a read only register!\n"); 5716576Sgblack@eecs.umich.edu 5726576Sgblack@eecs.umich.edu case IMR: 5736576Sgblack@eecs.umich.edu regs.imr = reg; 5746576Sgblack@eecs.umich.edu devIntrChangeMask(); 5756576Sgblack@eecs.umich.edu break; 5766576Sgblack@eecs.umich.edu 5776576Sgblack@eecs.umich.edu case IER: 5786576Sgblack@eecs.umich.edu regs.ier = reg; 5796576Sgblack@eecs.umich.edu break; 5806576Sgblack@eecs.umich.edu 5816576Sgblack@eecs.umich.edu case IHR: 5826576Sgblack@eecs.umich.edu regs.ihr = reg; 5836576Sgblack@eecs.umich.edu /* not going to implement real interrupt holdoff */ 5846576Sgblack@eecs.umich.edu break; 5856576Sgblack@eecs.umich.edu 5866576Sgblack@eecs.umich.edu case TXDP: 5876576Sgblack@eecs.umich.edu regs.txdp = (reg & 0xFFFFFFFC); 5886576Sgblack@eecs.umich.edu assert(txState == txIdle); 5896576Sgblack@eecs.umich.edu CTDD = false; 5906576Sgblack@eecs.umich.edu break; 5916576Sgblack@eecs.umich.edu 5926576Sgblack@eecs.umich.edu case TXDP_HI: 5935020Sgblack@eecs.umich.edu regs.txdp_hi = reg; 5946576Sgblack@eecs.umich.edu break; 5956576Sgblack@eecs.umich.edu 5966576Sgblack@eecs.umich.edu case TXCFG: 5976576Sgblack@eecs.umich.edu regs.txcfg = reg; 5986576Sgblack@eecs.umich.edu#if 0 5996576Sgblack@eecs.umich.edu if (reg & TXCFG_CSI) ; 6006576Sgblack@eecs.umich.edu if (reg & TXCFG_HBI) ; 6016576Sgblack@eecs.umich.edu if (reg & TXCFG_MLB) ; 6026576Sgblack@eecs.umich.edu if (reg & TXCFG_ATP) ; 6036576Sgblack@eecs.umich.edu if (reg & TXCFG_ECRETRY) ; /* this could easily be implemented, but 6046576Sgblack@eecs.umich.edu considering the network is just a fake 6056576Sgblack@eecs.umich.edu pipe, wouldn't make sense to do this */ 6066576Sgblack@eecs.umich.edu 6076696Svince@csl.cornell.edu if (reg & TXCFG_BRST_DIS) ; 6086576Sgblack@eecs.umich.edu#endif 6096576Sgblack@eecs.umich.edu 6106576Sgblack@eecs.umich.edu 6116576Sgblack@eecs.umich.edu /* we handle our own DMA, ignore the kernel's exhortations */ 6126576Sgblack@eecs.umich.edu if (reg & TXCFG_MXDMA) ; 6136576Sgblack@eecs.umich.edu 6146576Sgblack@eecs.umich.edu break; 6156576Sgblack@eecs.umich.edu 6166576Sgblack@eecs.umich.edu case GPIOR: 6176576Sgblack@eecs.umich.edu regs.gpior = reg; 6186706Svince@csl.cornell.edu /* these just control general purpose i/o pins, don't matter */ 6196696Svince@csl.cornell.edu break; 6206576Sgblack@eecs.umich.edu 6216576Sgblack@eecs.umich.edu case RXDP: 6225020Sgblack@eecs.umich.edu regs.rxdp = reg; 6236584Sgblack@eecs.umich.edu break; 6246584Sgblack@eecs.umich.edu 6256584Sgblack@eecs.umich.edu case RXDP_HI: 6266597Sgblack@eecs.umich.edu regs.rxdp_hi = reg; 6276611Sgblack@eecs.umich.edu break; 6286584Sgblack@eecs.umich.edu 6296611Sgblack@eecs.umich.edu case RXCFG: 6306611Sgblack@eecs.umich.edu regs.rxcfg = reg; 6316611Sgblack@eecs.umich.edu#if 0 6326584Sgblack@eecs.umich.edu if (reg & RXCFG_AEP) ; 6335238Sgblack@eecs.umich.edu if (reg & RXCFG_ARP) ; 6346611Sgblack@eecs.umich.edu if (reg & RXCFG_STRIPCRC) ; 6356584Sgblack@eecs.umich.edu if (reg & RXCFG_RX_RD) ; 6366611Sgblack@eecs.umich.edu if (reg & RXCFG_ALP) ; 6376611Sgblack@eecs.umich.edu if (reg & RXCFG_AIRL) ; 6386611Sgblack@eecs.umich.edu#endif 6396584Sgblack@eecs.umich.edu 6405238Sgblack@eecs.umich.edu /* we handle our own DMA, ignore what kernel says about it */ 6416611Sgblack@eecs.umich.edu if (reg & RXCFG_MXDMA) ; 6426584Sgblack@eecs.umich.edu 6436611Sgblack@eecs.umich.edu#if 0 6446611Sgblack@eecs.umich.edu if (reg & (RXCFG_DRTH | RXCFG_DRTH0)) ; 6456584Sgblack@eecs.umich.edu#endif 6465238Sgblack@eecs.umich.edu break; 6476584Sgblack@eecs.umich.edu 6486584Sgblack@eecs.umich.edu case PQCR: 6496584Sgblack@eecs.umich.edu /* there is no priority queueing used in the linux 2.6 driver */ 6506584Sgblack@eecs.umich.edu regs.pqcr = reg; 6515238Sgblack@eecs.umich.edu break; 6526584Sgblack@eecs.umich.edu 6536584Sgblack@eecs.umich.edu case WCSR: 6546597Sgblack@eecs.umich.edu /* not going to implement wake on LAN */ 6556584Sgblack@eecs.umich.edu regs.wcsr = reg; 6566584Sgblack@eecs.umich.edu break; 6576584Sgblack@eecs.umich.edu 6586584Sgblack@eecs.umich.edu case PCR: 6596597Sgblack@eecs.umich.edu /* not going to implement pause control */ 6606611Sgblack@eecs.umich.edu regs.pcr = reg; 6616584Sgblack@eecs.umich.edu break; 6626611Sgblack@eecs.umich.edu 6636611Sgblack@eecs.umich.edu case RFCR: 6646611Sgblack@eecs.umich.edu regs.rfcr = reg; 6655238Sgblack@eecs.umich.edu DPRINTF(Ethernet, "Writing to RFCR, RFADDR is %#x\n", reg & RFCR_RFADDR); 6666611Sgblack@eecs.umich.edu 6676584Sgblack@eecs.umich.edu rxFilterEnable = (reg & RFCR_RFEN) ? true : false; 6686611Sgblack@eecs.umich.edu 6696611Sgblack@eecs.umich.edu acceptBroadcast = (reg & RFCR_AAB) ? true : false; 6706611Sgblack@eecs.umich.edu 6716584Sgblack@eecs.umich.edu acceptMulticast = (reg & RFCR_AAM) ? true : false; 6725238Sgblack@eecs.umich.edu 6736611Sgblack@eecs.umich.edu acceptUnicast = (reg & RFCR_AAU) ? true : false; 6746584Sgblack@eecs.umich.edu 6756611Sgblack@eecs.umich.edu acceptPerfect = (reg & RFCR_APM) ? true : false; 6766707Svince@csl.cornell.edu 6776611Sgblack@eecs.umich.edu acceptArp = (reg & RFCR_AARP) ? true : false; 6786707Svince@csl.cornell.edu 6796584Sgblack@eecs.umich.edu if (reg & RFCR_APAT) ; 6805238Sgblack@eecs.umich.edu// panic("RFCR_APAT not implemented!\n"); 6816584Sgblack@eecs.umich.edu 6826584Sgblack@eecs.umich.edu if (reg & RFCR_MHEN || reg & RFCR_UHEN) 6836584Sgblack@eecs.umich.edu panic("hash filtering not implemented!\n"); 6846584Sgblack@eecs.umich.edu 6855238Sgblack@eecs.umich.edu if (reg & RFCR_ULM) 6866584Sgblack@eecs.umich.edu panic("RFCR_ULM not implemented!\n"); 6876584Sgblack@eecs.umich.edu 6886597Sgblack@eecs.umich.edu break; 6896584Sgblack@eecs.umich.edu 6905238Sgblack@eecs.umich.edu case RFDR: 6916584Sgblack@eecs.umich.edu panic("the driver never writes to RFDR, something is wrong!\n"); 6925020Sgblack@eecs.umich.edu 6936584Sgblack@eecs.umich.edu case BRAR: 6946584Sgblack@eecs.umich.edu panic("the driver never uses BRAR, something is wrong!\n"); 6956584Sgblack@eecs.umich.edu 6966611Sgblack@eecs.umich.edu case BRDR: 6976611Sgblack@eecs.umich.edu panic("the driver never uses BRDR, something is wrong!\n"); 6986584Sgblack@eecs.umich.edu 6996584Sgblack@eecs.umich.edu case SRR: 7006584Sgblack@eecs.umich.edu panic("SRR is read only register!\n"); 7016584Sgblack@eecs.umich.edu 7026584Sgblack@eecs.umich.edu case MIBC: 7036584Sgblack@eecs.umich.edu panic("the driver never uses MIBC, something is wrong!\n"); 7046584Sgblack@eecs.umich.edu 7056696Svince@csl.cornell.edu case VRCR: 7066584Sgblack@eecs.umich.edu regs.vrcr = reg; 7076584Sgblack@eecs.umich.edu break; 7086584Sgblack@eecs.umich.edu 7096584Sgblack@eecs.umich.edu case VTCR: 7106705Svince@csl.cornell.edu regs.vtcr = reg; 7116584Sgblack@eecs.umich.edu break; 7126706Svince@csl.cornell.edu 7136696Svince@csl.cornell.edu case VDR: 7146584Sgblack@eecs.umich.edu panic("the driver never uses VDR, something is wrong!\n"); 7156584Sgblack@eecs.umich.edu break; 7166584Sgblack@eecs.umich.edu 7176584Sgblack@eecs.umich.edu case CCSR: 7186584Sgblack@eecs.umich.edu /* not going to implement clockrun stuff */ 7196584Sgblack@eecs.umich.edu regs.ccsr = reg; 7206584Sgblack@eecs.umich.edu break; 7216584Sgblack@eecs.umich.edu 7226584Sgblack@eecs.umich.edu case TBICR: 7235020Sgblack@eecs.umich.edu regs.tbicr = reg; 7244727Sgblack@eecs.umich.edu if (reg & TBICR_MR_LOOPBACK) 7254727Sgblack@eecs.umich.edu panic("TBICR_MR_LOOPBACK never used, something wrong!\n"); 7264727Sgblack@eecs.umich.edu 7274727Sgblack@eecs.umich.edu if (reg & TBICR_MR_AN_ENABLE) { 7284727Sgblack@eecs.umich.edu regs.tanlpar = regs.tanar; 7294727Sgblack@eecs.umich.edu regs.tbisr |= (TBISR_MR_AN_COMPLETE | TBISR_MR_LINK_STATUS); 7304727Sgblack@eecs.umich.edu } 7314727Sgblack@eecs.umich.edu 7324727Sgblack@eecs.umich.edu#if 0 7334727Sgblack@eecs.umich.edu if (reg & TBICR_MR_RESTART_AN) ; 7344727Sgblack@eecs.umich.edu#endif 7354727Sgblack@eecs.umich.edu 7364727Sgblack@eecs.umich.edu break; 7374727Sgblack@eecs.umich.edu 7384727Sgblack@eecs.umich.edu case TBISR: 7394727Sgblack@eecs.umich.edu panic("TBISR is read only register!\n"); 7404727Sgblack@eecs.umich.edu 7414727Sgblack@eecs.umich.edu case TANAR: 7424727Sgblack@eecs.umich.edu regs.tanar = reg; 7434727Sgblack@eecs.umich.edu if (reg & TANAR_PS2) 7444760Sgblack@eecs.umich.edu panic("this isn't used in driver, something wrong!\n"); 7454760Sgblack@eecs.umich.edu 7464760Sgblack@eecs.umich.edu if (reg & TANAR_PS1) 7474760Sgblack@eecs.umich.edu panic("this isn't used in driver, something wrong!\n"); 7484760Sgblack@eecs.umich.edu break; 7494760Sgblack@eecs.umich.edu 7504760Sgblack@eecs.umich.edu case TANLPAR: 7514760Sgblack@eecs.umich.edu panic("this should only be written to by the fake phy!\n"); 7524760Sgblack@eecs.umich.edu 7534760Sgblack@eecs.umich.edu case TANER: 7544760Sgblack@eecs.umich.edu panic("TANER is read only register!\n"); 7554760Sgblack@eecs.umich.edu 7564760Sgblack@eecs.umich.edu case TESR: 7574760Sgblack@eecs.umich.edu regs.tesr = reg; 7584760Sgblack@eecs.umich.edu break; 7594760Sgblack@eecs.umich.edu 7604760Sgblack@eecs.umich.edu default: 7614760Sgblack@eecs.umich.edu panic("thought i covered all the register, what is this? addr=%#x", 7624760Sgblack@eecs.umich.edu daddr); 7634760Sgblack@eecs.umich.edu } 7644276Sgblack@eecs.umich.edu } else 7654276Sgblack@eecs.umich.edu panic("Invalid Request Size"); 7664712Sgblack@eecs.umich.edu 7674712Sgblack@eecs.umich.edu return No_Fault; 7685659Sgblack@eecs.umich.edu} 7695659Sgblack@eecs.umich.edu 7707072Sgblack@eecs.umich.eduvoid 7717072Sgblack@eecs.umich.eduEtherDev::devIntrPost(uint32_t interrupts) 7725659Sgblack@eecs.umich.edu{ 7735659Sgblack@eecs.umich.edu DPRINTF(Ethernet, "interrupt posted intr=%#x isr=%#x imr=%#x\n", 7745659Sgblack@eecs.umich.edu interrupts, regs.isr, regs.imr); 7755659Sgblack@eecs.umich.edu 7765659Sgblack@eecs.umich.edu bool delay = false; 7775240Sgblack@eecs.umich.edu 7786480Sgblack@eecs.umich.edu if (interrupts & ISR_RESERVE) 7796480Sgblack@eecs.umich.edu panic("Cannot set a reserved interrupt"); 7806611Sgblack@eecs.umich.edu 7814276Sgblack@eecs.umich.edu if (interrupts & ISR_TXRCMP) 7824276Sgblack@eecs.umich.edu regs.isr |= ISR_TXRCMP; 7834712Sgblack@eecs.umich.edu 7844712Sgblack@eecs.umich.edu if (interrupts & ISR_RXRCMP) 7854712Sgblack@eecs.umich.edu regs.isr |= ISR_RXRCMP; 7865240Sgblack@eecs.umich.edu 7875977Sgblack@eecs.umich.edu//ISR_DPERR not implemented 7886481Sgblack@eecs.umich.edu//ISR_SSERR not implemented 7896611Sgblack@eecs.umich.edu//ISR_RMABT not implemented 7906611Sgblack@eecs.umich.edu//ISR_RXSOVR not implemented 7916611Sgblack@eecs.umich.edu//ISR_HIBINT not implemented 7926611Sgblack@eecs.umich.edu//ISR_PHY not implemented 7935923Sgblack@eecs.umich.edu//ISR_PME not implemented 7946611Sgblack@eecs.umich.edu 7956611Sgblack@eecs.umich.edu if (interrupts & ISR_SWI) 7966611Sgblack@eecs.umich.edu regs.isr |= ISR_SWI; 7976611Sgblack@eecs.umich.edu 7985238Sgblack@eecs.umich.edu//ISR_MIB not implemented 7995238Sgblack@eecs.umich.edu//ISR_TXURN not implemented 8006611Sgblack@eecs.umich.edu 8016611Sgblack@eecs.umich.edu if (interrupts & ISR_TXIDLE) 8026611Sgblack@eecs.umich.edu regs.isr |= ISR_TXIDLE; 8036611Sgblack@eecs.umich.edu 8046611Sgblack@eecs.umich.edu if (interrupts & ISR_TXERR) 8056611Sgblack@eecs.umich.edu regs.isr |= ISR_TXERR; 8066611Sgblack@eecs.umich.edu 8076611Sgblack@eecs.umich.edu if (interrupts & ISR_TXDESC) 8086611Sgblack@eecs.umich.edu regs.isr |= ISR_TXDESC; 8095238Sgblack@eecs.umich.edu 8105238Sgblack@eecs.umich.edu if (interrupts & ISR_TXOK) { 8114724Sgblack@eecs.umich.edu regs.isr |= ISR_TXOK; 8124276Sgblack@eecs.umich.edu delay = true; 8136593Sgblack@eecs.umich.edu } 8146593Sgblack@eecs.umich.edu 8156593Sgblack@eecs.umich.edu if (interrupts & ISR_RXORN) 8166593Sgblack@eecs.umich.edu regs.isr |= ISR_RXORN; 8176593Sgblack@eecs.umich.edu 8186593Sgblack@eecs.umich.edu if (interrupts & ISR_RXIDLE) 8196593Sgblack@eecs.umich.edu regs.isr |= ISR_RXIDLE; 8206593Sgblack@eecs.umich.edu 8216593Sgblack@eecs.umich.edu//ISR_RXEARLY not implemented 8226593Sgblack@eecs.umich.edu 8236593Sgblack@eecs.umich.edu if (interrupts & ISR_RXERR) 8246593Sgblack@eecs.umich.edu regs.isr |= ISR_RXERR; 8256593Sgblack@eecs.umich.edu 8266593Sgblack@eecs.umich.edu if (interrupts & ISR_RXOK) { 8276593Sgblack@eecs.umich.edu delay = true; 8286593Sgblack@eecs.umich.edu regs.isr |= ISR_RXOK; 8296611Sgblack@eecs.umich.edu } 8306611Sgblack@eecs.umich.edu 8316611Sgblack@eecs.umich.edu if ((regs.isr & regs.imr)) { 8326611Sgblack@eecs.umich.edu Tick when = curTick; 8336611Sgblack@eecs.umich.edu if (delay) 8345240Sgblack@eecs.umich.edu when += intrDelay; 8355240Sgblack@eecs.umich.edu cpuIntrPost(when); 8365240Sgblack@eecs.umich.edu } 8375240Sgblack@eecs.umich.edu} 8385240Sgblack@eecs.umich.edu 8395240Sgblack@eecs.umich.eduvoid 8405240Sgblack@eecs.umich.eduEtherDev::devIntrClear(uint32_t interrupts) 8415240Sgblack@eecs.umich.edu{ 8425240Sgblack@eecs.umich.edu DPRINTF(Ethernet, "interrupt cleared intr=%x isr=%x imr=%x\n", 8435240Sgblack@eecs.umich.edu interrupts, regs.isr, regs.imr); 8446593Sgblack@eecs.umich.edu 8456593Sgblack@eecs.umich.edu if (interrupts & ISR_RESERVE) 8466593Sgblack@eecs.umich.edu panic("Cannot clear a reserved interrupt"); 8476593Sgblack@eecs.umich.edu 8486593Sgblack@eecs.umich.edu if (interrupts & ISR_TXRCMP) 8496593Sgblack@eecs.umich.edu regs.isr &= ~ISR_TXRCMP; 8506593Sgblack@eecs.umich.edu 8516593Sgblack@eecs.umich.edu if (interrupts & ISR_RXRCMP) 8525238Sgblack@eecs.umich.edu regs.isr &= ~ISR_RXRCMP; 8536576Sgblack@eecs.umich.edu 8546576Sgblack@eecs.umich.edu//ISR_DPERR not implemented 8556576Sgblack@eecs.umich.edu//ISR_SSERR not implemented 8566576Sgblack@eecs.umich.edu//ISR_RMABT not implemented 8576576Sgblack@eecs.umich.edu//ISR_RXSOVR not implemented 8586576Sgblack@eecs.umich.edu//ISR_HIBINT not implemented 8596576Sgblack@eecs.umich.edu//ISR_PHY not implemented 8606576Sgblack@eecs.umich.edu//ISR_PME not implemented 8616576Sgblack@eecs.umich.edu 8626576Sgblack@eecs.umich.edu if (interrupts & ISR_SWI) 8636576Sgblack@eecs.umich.edu regs.isr &= ~ISR_SWI; 8646576Sgblack@eecs.umich.edu 8656576Sgblack@eecs.umich.edu//ISR_MIB not implemented 8665238Sgblack@eecs.umich.edu//ISR_TXURN not implemented 8676576Sgblack@eecs.umich.edu 8686576Sgblack@eecs.umich.edu if (interrupts & ISR_TXIDLE) 8695238Sgblack@eecs.umich.edu regs.isr &= ~ISR_TXIDLE; 8706576Sgblack@eecs.umich.edu 8716576Sgblack@eecs.umich.edu if (interrupts & ISR_TXERR) 8726576Sgblack@eecs.umich.edu regs.isr &= ~ISR_TXERR; 8736604Sgblack@eecs.umich.edu 8746610Sgblack@eecs.umich.edu if (interrupts & ISR_TXDESC) 8756591Sgblack@eecs.umich.edu regs.isr &= ~ISR_TXDESC; 8766591Sgblack@eecs.umich.edu 8776597Sgblack@eecs.umich.edu if (interrupts & ISR_TXOK) 8786576Sgblack@eecs.umich.edu regs.isr &= ~ISR_TXOK; 8796576Sgblack@eecs.umich.edu 8806576Sgblack@eecs.umich.edu if (interrupts & ISR_RXORN) 8816604Sgblack@eecs.umich.edu regs.isr &= ~ISR_RXORN; 8826576Sgblack@eecs.umich.edu 8836576Sgblack@eecs.umich.edu if (interrupts & ISR_RXIDLE) 8846576Sgblack@eecs.umich.edu regs.isr &= ~ISR_RXIDLE; 8856576Sgblack@eecs.umich.edu 8866604Sgblack@eecs.umich.edu//ISR_RXEARLY not implemented 8876591Sgblack@eecs.umich.edu 8886591Sgblack@eecs.umich.edu if (interrupts & ISR_RXERR) 8896597Sgblack@eecs.umich.edu regs.isr &= ~ISR_RXERR; 8906576Sgblack@eecs.umich.edu 8916576Sgblack@eecs.umich.edu if (interrupts & ISR_RXOK) 8926576Sgblack@eecs.umich.edu regs.isr &= ~ISR_RXOK; 8936576Sgblack@eecs.umich.edu 8946604Sgblack@eecs.umich.edu if (!(regs.isr & regs.imr)) 8956576Sgblack@eecs.umich.edu cpuIntrClear(); 8966576Sgblack@eecs.umich.edu} 8976576Sgblack@eecs.umich.edu 8986576Sgblack@eecs.umich.eduvoid 8995238Sgblack@eecs.umich.eduEtherDev::devIntrChangeMask() 9006576Sgblack@eecs.umich.edu{ 9016576Sgblack@eecs.umich.edu DPRINTF(Ethernet, "interrupt mask changed\n"); 9026576Sgblack@eecs.umich.edu 9036576Sgblack@eecs.umich.edu if (regs.isr & regs.imr) 9045020Sgblack@eecs.umich.edu cpuIntrPost(curTick); 9056593Sgblack@eecs.umich.edu else 9066593Sgblack@eecs.umich.edu cpuIntrClear(); 9076593Sgblack@eecs.umich.edu} 9086593Sgblack@eecs.umich.edu 9096593Sgblack@eecs.umich.eduvoid 9106593Sgblack@eecs.umich.eduEtherDev::cpuIntrPost(Tick when) 9116593Sgblack@eecs.umich.edu{ 9126593Sgblack@eecs.umich.edu if (when > intrTick && intrTick != 0) 9136593Sgblack@eecs.umich.edu return; 9146593Sgblack@eecs.umich.edu 9156593Sgblack@eecs.umich.edu intrTick = when; 9166593Sgblack@eecs.umich.edu 9176593Sgblack@eecs.umich.edu if (intrEvent) { 9186608Sgblack@eecs.umich.edu intrEvent->squash(); 9196593Sgblack@eecs.umich.edu intrEvent = 0; 9206593Sgblack@eecs.umich.edu } 9216593Sgblack@eecs.umich.edu 9226593Sgblack@eecs.umich.edu if (when < curTick) { 9236593Sgblack@eecs.umich.edu cpuInterrupt(); 9246593Sgblack@eecs.umich.edu } else { 9256593Sgblack@eecs.umich.edu intrEvent = new IntrEvent(this, true); 9266593Sgblack@eecs.umich.edu intrEvent->schedule(intrTick); 9276593Sgblack@eecs.umich.edu } 9286593Sgblack@eecs.umich.edu} 9296593Sgblack@eecs.umich.edu 9306593Sgblack@eecs.umich.eduvoid 9316593Sgblack@eecs.umich.eduEtherDev::cpuInterrupt() 9326593Sgblack@eecs.umich.edu{ 9336593Sgblack@eecs.umich.edu // Don't send an interrupt if there's already one 9346593Sgblack@eecs.umich.edu if (cpuPendingIntr) 9356607Sgblack@eecs.umich.edu return; 9366593Sgblack@eecs.umich.edu 9376593Sgblack@eecs.umich.edu // Don't send an interrupt if it's supposed to be delayed 9386593Sgblack@eecs.umich.edu if (intrTick > curTick) 9395020Sgblack@eecs.umich.edu return; 9406576Sgblack@eecs.umich.edu 9416576Sgblack@eecs.umich.edu // Whether or not there's a pending interrupt, we don't care about 9426576Sgblack@eecs.umich.edu // it anymore 9436580Sgblack@eecs.umich.edu intrEvent = 0; 9446580Sgblack@eecs.umich.edu intrTick = 0; 9456576Sgblack@eecs.umich.edu 9466576Sgblack@eecs.umich.edu // Send interrupt 9476576Sgblack@eecs.umich.edu cpuPendingIntr = true; 9486576Sgblack@eecs.umich.edu /** @todo rework the intctrl to be tsunami ok */ 9496576Sgblack@eecs.umich.edu //intctrl->post(TheISA::INTLEVEL_IRQ1, TheISA::INTINDEX_ETHERNET); 9506576Sgblack@eecs.umich.edu tsunami->cchip->postDRIR(configData->config.hdr.pci0.interruptLine); 9516576Sgblack@eecs.umich.edu} 9526576Sgblack@eecs.umich.edu 9536576Sgblack@eecs.umich.eduvoid 9546580Sgblack@eecs.umich.eduEtherDev::cpuIntrClear() 9556580Sgblack@eecs.umich.edu{ 9566576Sgblack@eecs.umich.edu if (cpuPendingIntr) { 9576576Sgblack@eecs.umich.edu cpuPendingIntr = false; 9586576Sgblack@eecs.umich.edu /** @todo rework the intctrl to be tsunami ok */ 9596576Sgblack@eecs.umich.edu //intctrl->clear(TheISA::INTLEVEL_IRQ1, TheISA::INTINDEX_ETHERNET); 9606576Sgblack@eecs.umich.edu tsunami->cchip->clearDRIR(configData->config.hdr.pci0.interruptLine); 9616576Sgblack@eecs.umich.edu } 9626576Sgblack@eecs.umich.edu} 9636576Sgblack@eecs.umich.edu 9645020Sgblack@eecs.umich.edubool 9656588Sgblack@eecs.umich.eduEtherDev::cpuIntrPending() const 9666588Sgblack@eecs.umich.edu{ return cpuPendingIntr; } 9676588Sgblack@eecs.umich.edu 9686588Sgblack@eecs.umich.eduvoid 9696588Sgblack@eecs.umich.eduEtherDev::txReset() 9706588Sgblack@eecs.umich.edu{ 9716588Sgblack@eecs.umich.edu 9726588Sgblack@eecs.umich.edu DPRINTF(Ethernet, "transmit reset\n"); 9736588Sgblack@eecs.umich.edu 9746588Sgblack@eecs.umich.edu CTDD = false; 9756588Sgblack@eecs.umich.edu txFifoCnt = 0; 9766588Sgblack@eecs.umich.edu txFifoAvail = MAX_TX_FIFO_SIZE; 9776588Sgblack@eecs.umich.edu txHalt = false; 9786588Sgblack@eecs.umich.edu txFragPtr = 0; 9796588Sgblack@eecs.umich.edu assert(txDescCnt == 0); 9806588Sgblack@eecs.umich.edu txFifo.clear(); 9816588Sgblack@eecs.umich.edu regs.command &= ~CR_TXE; 9826588Sgblack@eecs.umich.edu txState = txIdle; 9836588Sgblack@eecs.umich.edu assert(txDmaState == dmaIdle); 9846588Sgblack@eecs.umich.edu} 9856588Sgblack@eecs.umich.edu 9866588Sgblack@eecs.umich.eduvoid 9876588Sgblack@eecs.umich.eduEtherDev::rxReset() 9886588Sgblack@eecs.umich.edu{ 9896588Sgblack@eecs.umich.edu DPRINTF(Ethernet, "receive reset\n"); 9906606Sgblack@eecs.umich.edu 9916588Sgblack@eecs.umich.edu CRDD = false; 9926588Sgblack@eecs.umich.edu assert(rxPktBytes == 0); 9936588Sgblack@eecs.umich.edu rxFifoCnt = 0; 9946588Sgblack@eecs.umich.edu rxHalt = false; 9956606Sgblack@eecs.umich.edu rxFragPtr = 0; 9966588Sgblack@eecs.umich.edu assert(rxDescCnt == 0); 9976588Sgblack@eecs.umich.edu assert(rxDmaState == dmaIdle); 9986588Sgblack@eecs.umich.edu rxFifo.clear(); 9995022Sgblack@eecs.umich.edu regs.command &= ~CR_RXE; 10006576Sgblack@eecs.umich.edu rxState = rxIdle; 10016576Sgblack@eecs.umich.edu} 10026576Sgblack@eecs.umich.edu 10036580Sgblack@eecs.umich.eduvoid 10046580Sgblack@eecs.umich.eduEtherDev::rxDmaReadCopy() 10056576Sgblack@eecs.umich.edu{ 10066576Sgblack@eecs.umich.edu assert(rxDmaState == dmaReading); 10076576Sgblack@eecs.umich.edu 10086576Sgblack@eecs.umich.edu memcpy(rxDmaData, physmem->dma_addr(rxDmaAddr, rxDmaLen), rxDmaLen); 10096576Sgblack@eecs.umich.edu rxDmaState = dmaIdle; 10106576Sgblack@eecs.umich.edu 10116576Sgblack@eecs.umich.edu DPRINTF(EthernetDMA, "rx dma read paddr=%#x len=%d\n", 10126576Sgblack@eecs.umich.edu rxDmaAddr, rxDmaLen); 10136576Sgblack@eecs.umich.edu DDUMP(EthernetDMA, rxDmaData, rxDmaLen); 10146580Sgblack@eecs.umich.edu} 10156580Sgblack@eecs.umich.edu 10166576Sgblack@eecs.umich.edubool 10176576Sgblack@eecs.umich.eduEtherDev::doRxDmaRead() 10186576Sgblack@eecs.umich.edu{ 10196576Sgblack@eecs.umich.edu assert(rxDmaState == dmaIdle || rxDmaState == dmaReadWaiting); 10206576Sgblack@eecs.umich.edu rxDmaState = dmaReading; 10216576Sgblack@eecs.umich.edu 10226576Sgblack@eecs.umich.edu if (dmaInterface && !rxDmaFree) { 10236576Sgblack@eecs.umich.edu if (dmaInterface->busy()) 10245020Sgblack@eecs.umich.edu rxDmaState = dmaReadWaiting; 10256586Sgblack@eecs.umich.edu else 10266586Sgblack@eecs.umich.edu dmaInterface->doDMA(Read, rxDmaAddr, rxDmaLen, curTick, 10276586Sgblack@eecs.umich.edu &rxDmaReadEvent); 10286586Sgblack@eecs.umich.edu return true; 10296586Sgblack@eecs.umich.edu } 10306586Sgblack@eecs.umich.edu 10316586Sgblack@eecs.umich.edu if (dmaReadDelay == 0 && dmaReadFactor == 0) { 10326586Sgblack@eecs.umich.edu rxDmaReadCopy(); 10336586Sgblack@eecs.umich.edu return false; 10346595Sgblack@eecs.umich.edu } 10356586Sgblack@eecs.umich.edu 10366586Sgblack@eecs.umich.edu Tick factor = ((rxDmaLen + ULL(63)) >> ULL(6)) * dmaReadFactor; 10376586Sgblack@eecs.umich.edu Tick start = curTick + dmaReadDelay + factor; 10386586Sgblack@eecs.umich.edu rxDmaReadEvent.schedule(start); 10396586Sgblack@eecs.umich.edu return true; 10406586Sgblack@eecs.umich.edu} 10416586Sgblack@eecs.umich.edu 10426586Sgblack@eecs.umich.eduvoid 10436586Sgblack@eecs.umich.eduEtherDev::rxDmaReadDone() 10446586Sgblack@eecs.umich.edu{ 10456595Sgblack@eecs.umich.edu assert(rxDmaState == dmaReading); 10466586Sgblack@eecs.umich.edu rxDmaReadCopy(); 10476586Sgblack@eecs.umich.edu 10486586Sgblack@eecs.umich.edu // If the transmit state machine has a pending DMA, let it go first 10496586Sgblack@eecs.umich.edu if (txDmaState == dmaReadWaiting || txDmaState == dmaWriteWaiting) 10506586Sgblack@eecs.umich.edu txKick(); 10516586Sgblack@eecs.umich.edu 10526586Sgblack@eecs.umich.edu rxKick(); 10536586Sgblack@eecs.umich.edu} 10545022Sgblack@eecs.umich.edu 10556576Sgblack@eecs.umich.eduvoid 10566576Sgblack@eecs.umich.eduEtherDev::rxDmaWriteCopy() 10576576Sgblack@eecs.umich.edu{ 10586580Sgblack@eecs.umich.edu assert(rxDmaState == dmaWriting); 10596580Sgblack@eecs.umich.edu 10606580Sgblack@eecs.umich.edu memcpy(physmem->dma_addr(rxDmaAddr, rxDmaLen), rxDmaData, rxDmaLen); 10616580Sgblack@eecs.umich.edu rxDmaState = dmaIdle; 10626576Sgblack@eecs.umich.edu 10636576Sgblack@eecs.umich.edu DPRINTF(EthernetDMA, "rx dma write paddr=%#x len=%d\n", 10646576Sgblack@eecs.umich.edu rxDmaAddr, rxDmaLen); 10656576Sgblack@eecs.umich.edu DDUMP(EthernetDMA, rxDmaData, rxDmaLen); 10666576Sgblack@eecs.umich.edu} 10676576Sgblack@eecs.umich.edu 10686576Sgblack@eecs.umich.edubool 10696580Sgblack@eecs.umich.eduEtherDev::doRxDmaWrite() 10706580Sgblack@eecs.umich.edu{ 10716580Sgblack@eecs.umich.edu assert(rxDmaState == dmaIdle || rxDmaState == dmaWriteWaiting); 10726580Sgblack@eecs.umich.edu rxDmaState = dmaWriting; 10736576Sgblack@eecs.umich.edu 10746576Sgblack@eecs.umich.edu if (dmaInterface && !rxDmaFree) { 10756576Sgblack@eecs.umich.edu if (dmaInterface->busy()) 10766576Sgblack@eecs.umich.edu rxDmaState = dmaWriteWaiting; 10776576Sgblack@eecs.umich.edu else 10786576Sgblack@eecs.umich.edu dmaInterface->doDMA(WriteInvalidate, rxDmaAddr, rxDmaLen, curTick, 10795020Sgblack@eecs.umich.edu &rxDmaWriteEvent); 10804276Sgblack@eecs.umich.edu return true; 10814276Sgblack@eecs.umich.edu } 10824276Sgblack@eecs.umich.edu 10834276Sgblack@eecs.umich.edu if (dmaWriteDelay == 0 && dmaWriteFactor == 0) { 10844276Sgblack@eecs.umich.edu rxDmaWriteCopy(); 10854276Sgblack@eecs.umich.edu return false; 10864276Sgblack@eecs.umich.edu } 1087 1088 Tick factor = ((rxDmaLen + ULL(63)) >> ULL(6)) * dmaWriteFactor; 1089 Tick start = curTick + dmaWriteDelay + factor; 1090 rxDmaWriteEvent.schedule(start); 1091 return true; 1092} 1093 1094void 1095EtherDev::rxDmaWriteDone() 1096{ 1097 assert(rxDmaState == dmaWriting); 1098 rxDmaWriteCopy(); 1099 1100 // If the transmit state machine has a pending DMA, let it go first 1101 if (txDmaState == dmaReadWaiting || txDmaState == dmaWriteWaiting) 1102 txKick(); 1103 1104 rxKick(); 1105} 1106 1107void 1108EtherDev::rxKick() 1109{ 1110 DPRINTF(Ethernet, "receive kick state=%s (rxBuf.size=%d)\n", 1111 NsRxStateStrings[rxState], rxFifo.size()); 1112 1113 if (rxKickTick > curTick) { 1114 DPRINTF(Ethernet, "receive kick exiting, can't run till %d\n", 1115 rxKickTick); 1116 return; 1117 } 1118 1119 next: 1120 switch(rxDmaState) { 1121 case dmaReadWaiting: 1122 if (doRxDmaRead()) 1123 goto exit; 1124 break; 1125 case dmaWriteWaiting: 1126 if (doRxDmaWrite()) 1127 goto exit; 1128 break; 1129 default: 1130 break; 1131 } 1132 1133 switch (rxState) { 1134 case rxIdle: 1135 if (!regs.command & CR_RXE) { 1136 DPRINTF(Ethernet, "Receive Disabled! Nothing to do.\n"); 1137 goto exit; 1138 } 1139 1140 if (CRDD) { 1141 rxState = rxDescRefr; 1142 1143 rxDmaAddr = regs.rxdp & 0x3fffffff; 1144 rxDmaData = &rxDescCache + offsetof(ns_desc, link); 1145 rxDmaLen = sizeof(rxDescCache.link); 1146 rxDmaFree = dmaDescFree; 1147 1148 if (doRxDmaRead()) 1149 goto exit; 1150 } else { 1151 rxState = rxDescRead; 1152 1153 rxDmaAddr = regs.rxdp & 0x3fffffff; 1154 rxDmaData = &rxDescCache; 1155 rxDmaLen = sizeof(ns_desc); 1156 rxDmaFree = dmaDescFree; 1157 1158 if (doRxDmaRead()) 1159 goto exit; 1160 } 1161 break; 1162 1163 case rxDescRefr: 1164 if (rxDmaState != dmaIdle) 1165 goto exit; 1166 1167 rxState = rxAdvance; 1168 break; 1169 1170 case rxDescRead: 1171 if (rxDmaState != dmaIdle) 1172 goto exit; 1173 1174 if (rxDescCache.cmdsts & CMDSTS_OWN) { 1175 rxState = rxIdle; 1176 } else { 1177 rxState = rxFifoBlock; 1178 rxFragPtr = rxDescCache.bufptr; 1179 rxDescCnt = rxDescCache.cmdsts & CMDSTS_LEN_MASK; 1180 } 1181 break; 1182 1183 case rxFifoBlock: 1184 if (!rxPacket) { 1185 /** 1186 * @todo in reality, we should be able to start processing 1187 * the packet as it arrives, and not have to wait for the 1188 * full packet ot be in the receive fifo. 1189 */ 1190 if (rxFifo.empty()) 1191 goto exit; 1192 1193 // If we don't have a packet, grab a new one from the fifo. 1194 rxPacket = rxFifo.front(); 1195 rxPktBytes = rxPacket->length; 1196 rxPacketBufPtr = rxPacket->data; 1197 1198 // sanity check - i think the driver behaves like this 1199 assert(rxDescCnt >= rxPktBytes); 1200 1201 // Must clear the value before popping to decrement the 1202 // reference count 1203 rxFifo.front() = NULL; 1204 rxFifo.pop_front(); 1205 } 1206 1207 1208 // dont' need the && rxDescCnt > 0 if driver sanity check above holds 1209 if (rxPktBytes > 0) { 1210 rxState = rxFragWrite; 1211 // don't need min<>(rxPktBytes,rxDescCnt) if above sanity check holds 1212 rxXferLen = rxPktBytes; 1213 1214 rxDmaAddr = rxFragPtr & 0x3fffffff; 1215 rxDmaData = rxPacketBufPtr; 1216 rxDmaLen = rxXferLen; 1217 rxDmaFree = dmaDataFree; 1218 1219 if (doRxDmaWrite()) 1220 goto exit; 1221 1222 } else { 1223 rxState = rxDescWrite; 1224 1225 //if (rxPktBytes == 0) { /* packet is done */ 1226 assert(rxPktBytes == 0); 1227 1228 rxFifoCnt -= rxPacket->length; 1229 rxPacket = 0; 1230 1231 rxDescCache.cmdsts |= CMDSTS_OWN; 1232 rxDescCache.cmdsts &= ~CMDSTS_MORE; 1233 rxDescCache.cmdsts |= CMDSTS_OK; 1234 rxDescCache.cmdsts += rxPacket->length; //i.e. set CMDSTS_SIZE 1235 1236#if 0 1237 /* all the driver uses these are for its own stats keeping 1238 which we don't care about, aren't necessary for functionality 1239 and doing this would just slow us down. if they end up using 1240 this in a later version for functional purposes, just undef 1241 */ 1242 if (rxFilterEnable) { 1243 rxDescCache.cmdsts &= ~CMDSTS_DEST_MASK; 1244 if (rxFifo.front()->IsUnicast()) 1245 rxDescCache.cmdsts |= CMDSTS_DEST_SELF; 1246 if (rxFifo.front()->IsMulticast()) 1247 rxDescCache.cmdsts |= CMDSTS_DEST_MULTI; 1248 if (rxFifo.front()->IsBroadcast()) 1249 rxDescCache.cmdsts |= CMDSTS_DEST_MASK; 1250 } 1251#endif 1252 1253 eth_header *eth = (eth_header *) rxPacket->data; 1254 if (eth->type == 0x800 && extstsEnable) { 1255 rxDescCache.extsts |= EXTSTS_IPPKT; 1256 if (!ipChecksum(rxPacket, false)) 1257 rxDescCache.extsts |= EXTSTS_IPERR; 1258 ip_header *ip = rxFifo.front()->getIpHdr(); 1259 1260 if (ip->protocol == 6) { 1261 rxDescCache.extsts |= EXTSTS_TCPPKT; 1262 if (!tcpChecksum(rxPacket, false)) 1263 rxDescCache.extsts |= EXTSTS_TCPERR; 1264 } else if (ip->protocol == 17) { 1265 rxDescCache.extsts |= EXTSTS_UDPPKT; 1266 if (!udpChecksum(rxPacket, false)) 1267 rxDescCache.extsts |= EXTSTS_UDPERR; 1268 } 1269 } 1270 1271 /* the driver seems to always receive into desc buffers 1272 of size 1514, so you never have a pkt that is split 1273 into multiple descriptors on the receive side, so 1274 i don't implement that case, hence the assert above. 1275 */ 1276 1277 rxDmaAddr = (regs.rxdp + offsetof(ns_desc, cmdsts)) & 0x3fffffff; 1278 rxDmaData = &(rxDescCache.cmdsts); 1279 rxDmaLen = sizeof(rxDescCache.cmdsts) + sizeof(rxDescCache.extsts); 1280 rxDmaFree = dmaDescFree; 1281 1282 if (doRxDmaWrite()) 1283 goto exit; 1284 } 1285 break; 1286 1287 case rxFragWrite: 1288 if (rxDmaState != dmaIdle) 1289 goto exit; 1290 1291 rxPacketBufPtr += rxXferLen; 1292 rxFragPtr += rxXferLen; 1293 rxPktBytes -= rxXferLen; 1294 1295 rxState = rxFifoBlock; 1296 break; 1297 1298 case rxDescWrite: 1299 if (rxDmaState != dmaIdle) 1300 goto exit; 1301 1302 assert(rxDescCache.cmdsts & CMDSTS_OWN); 1303 1304 assert(rxPacket == 0); 1305 devIntrPost(ISR_RXOK); 1306 1307 if (rxDescCache.cmdsts & CMDSTS_INTR) 1308 devIntrPost(ISR_RXDESC); 1309 1310 if (rxHalt) { 1311 rxState = rxIdle; 1312 rxHalt = false; 1313 } else 1314 rxState = rxAdvance; 1315 break; 1316 1317 case rxAdvance: 1318 if (rxDescCache.link == 0) { 1319 rxState = rxIdle; 1320 return; 1321 } else { 1322 rxState = rxDescRead; 1323 regs.rxdp = rxDescCache.link; 1324 CRDD = false; 1325 1326 rxDmaAddr = regs.rxdp & 0x3fffffff; 1327 rxDmaData = &rxDescCache; 1328 rxDmaLen = sizeof(ns_desc); 1329 rxDmaFree = dmaDescFree; 1330 1331 if (doRxDmaRead()) 1332 goto exit; 1333 } 1334 break; 1335 1336 default: 1337 panic("Invalid rxState!"); 1338 } 1339 1340 1341 DPRINTF(Ethernet, "entering next rx state = %s\n", 1342 NsRxStateStrings[rxState]); 1343 1344 if (rxState == rxIdle) { 1345 regs.command &= ~CR_RXE; 1346 devIntrPost(ISR_RXIDLE); 1347 return; 1348 } 1349 1350 goto next; 1351 1352 exit: 1353 /** 1354 * @todo do we want to schedule a future kick? 1355 */ 1356 DPRINTF(Ethernet, "rx state machine exited state=%s\n", 1357 NsRxStateStrings[rxState]); 1358} 1359 1360void 1361EtherDev::transmit() 1362{ 1363 if (txFifo.empty()) { 1364 DPRINTF(Ethernet, "nothing to transmit\n"); 1365 return; 1366 } 1367 1368 if (interface->sendPacket(txFifo.front())) { 1369 DPRINTF(Ethernet, "transmit packet\n"); 1370 DDUMP(Ethernet, txFifo.front()->data, txFifo.front()->length); 1371 txBytes += txFifo.front()->length; 1372 txPackets++; 1373 1374 txFifoCnt -= (txFifo.front()->length - txPktXmitted); 1375 txPktXmitted = 0; 1376 txFifo.front() = NULL; 1377 txFifo.pop_front(); 1378 1379 /* normally do a writeback of the descriptor here, and ONLY after that is 1380 done, send this interrupt. but since our stuff never actually fails, 1381 just do this interrupt here, otherwise the code has to stray from this 1382 nice format. besides, it's functionally the same. 1383 */ 1384 devIntrPost(ISR_TXOK); 1385 } 1386 1387 if (!txFifo.empty() && !txEvent.scheduled()) { 1388 DPRINTF(Ethernet, "reschedule transmit\n"); 1389 txEvent.schedule(curTick + 1000); 1390 } 1391} 1392 1393void 1394EtherDev::txDmaReadCopy() 1395{ 1396 assert(txDmaState == dmaReading); 1397 1398 memcpy(txDmaData, physmem->dma_addr(txDmaAddr, txDmaLen), txDmaLen); 1399 txDmaState = dmaIdle; 1400 1401 DPRINTF(EthernetDMA, "tx dma read paddr=%#x len=%d\n", 1402 txDmaAddr, txDmaLen); 1403 DDUMP(EthernetDMA, txDmaData, txDmaLen); 1404} 1405 1406bool 1407EtherDev::doTxDmaRead() 1408{ 1409 assert(txDmaState == dmaIdle || txDmaState == dmaReadWaiting); 1410 txDmaState = dmaReading; 1411 1412 if (dmaInterface && !txDmaFree) { 1413 if (dmaInterface->busy()) 1414 txDmaState = dmaReadWaiting; 1415 else 1416 dmaInterface->doDMA(Read, txDmaAddr, txDmaLen, curTick, 1417 &txDmaReadEvent); 1418 return true; 1419 } 1420 1421 if (dmaReadDelay == 0 && dmaReadFactor == 0.0) { 1422 txDmaReadCopy(); 1423 return false; 1424 } 1425 1426 Tick factor = ((txDmaLen + ULL(63)) >> ULL(6)) * dmaReadFactor; 1427 Tick start = curTick + dmaReadDelay + factor; 1428 txDmaReadEvent.schedule(start); 1429 return true; 1430} 1431 1432void 1433EtherDev::txDmaReadDone() 1434{ 1435 assert(txDmaState == dmaReading); 1436 txDmaReadCopy(); 1437 1438 // If the receive state machine has a pending DMA, let it go first 1439 if (rxDmaState == dmaReadWaiting || rxDmaState == dmaWriteWaiting) 1440 rxKick(); 1441 1442 txKick(); 1443} 1444 1445void 1446EtherDev::txDmaWriteCopy() 1447{ 1448 assert(txDmaState == dmaWriting); 1449 1450 memcpy(physmem->dma_addr(txDmaAddr, txDmaLen), txDmaData, txDmaLen); 1451 txDmaState = dmaIdle; 1452 1453 DPRINTF(EthernetDMA, "tx dma write paddr=%#x len=%d\n", 1454 txDmaAddr, txDmaLen); 1455 DDUMP(EthernetDMA, txDmaData, txDmaLen); 1456} 1457 1458bool 1459EtherDev::doTxDmaWrite() 1460{ 1461 assert(txDmaState == dmaIdle || txDmaState == dmaWriteWaiting); 1462 txDmaState = dmaWriting; 1463 1464 if (dmaInterface && !txDmaFree) { 1465 if (dmaInterface->busy()) 1466 txDmaState = dmaWriteWaiting; 1467 else 1468 dmaInterface->doDMA(WriteInvalidate, txDmaAddr, txDmaLen, curTick, 1469 &txDmaWriteEvent); 1470 return true; 1471 } 1472 1473 if (dmaWriteDelay == 0 && dmaWriteFactor == 0.0) { 1474 txDmaWriteCopy(); 1475 return false; 1476 } 1477 1478 Tick factor = ((txDmaLen + ULL(63)) >> ULL(6)) * dmaWriteFactor; 1479 Tick start = curTick + dmaWriteDelay + factor; 1480 txDmaWriteEvent.schedule(start); 1481 return true; 1482} 1483 1484void 1485EtherDev::txDmaWriteDone() 1486{ 1487 assert(txDmaState == dmaWriting); 1488 txDmaWriteCopy(); 1489 1490 // If the receive state machine has a pending DMA, let it go first 1491 if (rxDmaState == dmaReadWaiting || rxDmaState == dmaWriteWaiting) 1492 rxKick(); 1493 1494 txKick(); 1495} 1496 1497void 1498EtherDev::txKick() 1499{ 1500 DPRINTF(Ethernet, "transmit kick state=%s\n", NsTxStateStrings[txState]); 1501 1502 if (rxKickTick > curTick) { 1503 DPRINTF(Ethernet, "receive kick exiting, can't run till %d\n", 1504 rxKickTick); 1505 1506 return; 1507 } 1508 1509 next: 1510 switch(txDmaState) { 1511 case dmaReadWaiting: 1512 if (doTxDmaRead()) 1513 goto exit; 1514 break; 1515 case dmaWriteWaiting: 1516 if (doTxDmaWrite()) 1517 goto exit; 1518 break; 1519 default: 1520 break; 1521 } 1522 1523 switch (txState) { 1524 case txIdle: 1525 if (!regs.command & CR_TXE) { 1526 DPRINTF(Ethernet, "Transmit disabled. Nothing to do.\n"); 1527 goto exit; 1528 } 1529 1530 if (CTDD) { 1531 txState = txDescRefr; 1532 1533 txDmaAddr = txDescCache.link & 0x3fffffff; 1534 txDmaData = &txDescCache; 1535 txDmaLen = sizeof(txDescCache.link); 1536 txDmaFree = dmaDescFree; 1537 1538 if (doTxDmaRead()) 1539 goto exit; 1540 1541 } else { 1542 txState = txDescRead; 1543 1544 txDmaAddr = regs.txdp & 0x3fffffff; 1545 txDmaData = &txDescCache + offsetof(ns_desc, link); 1546 txDmaLen = sizeof(ns_desc); 1547 txDmaFree = dmaDescFree; 1548 1549 if (doTxDmaRead()) 1550 goto exit; 1551 } 1552 break; 1553 1554 case txDescRefr: 1555 if (txDmaState != dmaIdle) 1556 goto exit; 1557 1558 txState = txAdvance; 1559 break; 1560 1561 case txDescRead: 1562 if (txDmaState != dmaIdle) 1563 goto exit; 1564 1565 if (txDescCache.cmdsts & CMDSTS_OWN) { 1566 txState = txFifoBlock; 1567 txFragPtr = txDescCache.bufptr; 1568 txDescCnt = txDescCache.cmdsts & CMDSTS_LEN_MASK; 1569 } else { 1570 txState = txIdle; 1571 } 1572 break; 1573 1574 case txFifoBlock: 1575 if (!txPacket) { 1576 DPRINTF(Ethernet, "starting the tx of a new packet\n"); 1577 txPacket = new EtherPacket; 1578 txPacket->data = new uint8_t[16384]; 1579 txPacketBufPtr = txPacket->data; 1580 } 1581 1582 if (txDescCnt == 0) { 1583 DPRINTF(Ethernet, "the txDescCnt == 0, done with descriptor\n"); 1584 if (txDescCache.cmdsts & CMDSTS_MORE) { 1585 DPRINTF(Ethernet, "there are more descriptors to come\n"); 1586 txState = txDescWrite; 1587 1588 txDescCache.cmdsts &= ~CMDSTS_OWN; 1589 1590 txDmaAddr = (regs.txdp + offsetof(ns_desc, cmdsts)) & 0x3fffffff; 1591 txDmaData = &(txDescCache.cmdsts); 1592 txDmaLen = sizeof(txDescCache.cmdsts); 1593 txDmaFree = dmaDescFree; 1594 1595 if (doTxDmaWrite()) 1596 goto exit; 1597 1598 } else { /* this packet is totally done */ 1599 DPRINTF(Ethernet, "This packet is done, let's wrap it up\n"); 1600 /* deal with the the packet that just finished */ 1601 if ((regs.vtcr & VTCR_PPCHK) && extstsEnable) { 1602 if (txDescCache.extsts & EXTSTS_UDPPKT) { 1603 udpChecksum(txPacket, true); 1604 } else if (txDescCache.extsts & EXTSTS_TCPPKT) { 1605 tcpChecksum(txPacket, true); 1606 } else if (txDescCache.extsts & EXTSTS_IPPKT) { 1607 ipChecksum(txPacket, true); 1608 } 1609 } 1610 1611 txPacket->length = txPacketBufPtr - txPacket->data; 1612 /* this is just because the receive can't handle a packet bigger 1613 want to make sure */ 1614 assert(txPacket->length <= 1514); 1615 txFifo.push_back(txPacket); 1616 1617 1618 /* this following section is not to spec, but functionally shouldn't 1619 be any different. normally, the chip will wait til the transmit has 1620 occurred before writing back the descriptor because it has to wait 1621 to see that it was successfully transmitted to decide whether to set 1622 CMDSTS_OK or not. however, in the simulator since it is always 1623 successfully transmitted, and writing it exactly to spec would 1624 complicate the code, we just do it here 1625 */ 1626 txDescCache.cmdsts &= ~CMDSTS_OWN; 1627 txDescCache.cmdsts |= CMDSTS_OK; 1628 1629 txDmaAddr = regs.txdp & 0x3fffffff; 1630 txDmaData = &txDescCache + offsetof(ns_desc, cmdsts); 1631 txDmaLen = sizeof(txDescCache.cmdsts) + sizeof(txDescCache.extsts); 1632 txDmaFree = dmaDescFree; 1633 1634 1635 if (doTxDmaWrite()) 1636 goto exit; 1637 1638 txPacket = 0; 1639 transmit(); 1640 1641 if (txHalt) { 1642 txState = txIdle; 1643 txHalt = false; 1644 } else 1645 txState = txAdvance; 1646 } 1647 } else { 1648 DPRINTF(Ethernet, "this descriptor isn't done yet\n"); 1649 /* the fill thresh is in units of 32 bytes, shift right by 8 to get the 1650 value, shift left by 5 to get the real number of bytes */ 1651 if (txFifoAvail < ((regs.txcfg & TXCFG_FLTH_MASK) >> 3)) { 1652 DPRINTF(Ethernet, "txFifoAvail=%d, regs.txcfg & TXCFG_FLTH_MASK = %#x\n", 1653 txFifoAvail, regs.txcfg & TXCFG_FLTH_MASK); 1654 goto exit; 1655 } 1656 1657 txState = txFragRead; 1658 1659 /* The number of bytes transferred is either whatever is left 1660 in the descriptor (txDescCnt), or if there is not enough 1661 room in the fifo, just whatever room is left in the fifo 1662 */ 1663 txXferLen = min<uint32_t>(txDescCnt, txFifoAvail); 1664 1665 txDmaAddr = txFragPtr & 0x3fffffff; 1666 txDmaData = txPacketBufPtr; 1667 txDmaLen = txXferLen; 1668 txDmaFree = dmaDataFree; 1669 1670 if (doTxDmaRead()) 1671 goto exit; 1672 } 1673 break; 1674 1675 case txFragRead: 1676 if (txDmaState != dmaIdle) 1677 goto exit; 1678 1679 txPacketBufPtr += txXferLen; 1680 txFragPtr += txXferLen; 1681 txFifoCnt += txXferLen; 1682 txDescCnt -= txXferLen; 1683 1684 txState = txFifoBlock; 1685 break; 1686 1687 case txDescWrite: 1688 if (txDmaState != dmaIdle) 1689 goto exit; 1690 1691 if (txFifoCnt >= ((regs.txcfg & TXCFG_DRTH_MASK) << 5)) { 1692 if (txFifo.empty()) { 1693 uint32_t xmitted = (uint32_t) (txPacketBufPtr - txPacket->data - txPktXmitted); 1694 txFifoCnt -= xmitted; 1695 txPktXmitted += xmitted; 1696 } else { 1697 transmit(); 1698 } 1699 } 1700 1701 if (txDescCache.cmdsts & CMDSTS_INTR) { 1702 devIntrPost(ISR_TXDESC); 1703 } 1704 1705 txState = txAdvance; 1706 break; 1707 1708 case txAdvance: 1709 if (txDescCache.link == 0) { 1710 txState = txIdle; 1711 } else { 1712 txState = txDescRead; 1713 regs.txdp = txDescCache.link; 1714 CTDD = false; 1715 1716 txDmaAddr = txDescCache.link & 0x3fffffff; 1717 txDmaData = &txDescCache; 1718 txDmaLen = sizeof(ns_desc); 1719 txDmaFree = dmaDescFree; 1720 1721 if (doTxDmaRead()) 1722 goto exit; 1723 } 1724 break; 1725 1726 default: 1727 panic("invalid state"); 1728 } 1729 1730 DPRINTF(Ethernet, "entering next tx state=%s\n", 1731 NsTxStateStrings[txState]); 1732 1733 if (txState == txIdle) { 1734 regs.command &= ~CR_TXE; 1735 devIntrPost(ISR_TXIDLE); 1736 return; 1737 } 1738 1739 goto next; 1740 1741 exit: 1742 /** 1743 * @todo do we want to schedule a future kick? 1744 */ 1745 DPRINTF(Ethernet, "tx state machine exited state=%s\n", 1746 NsTxStateStrings[txState]); 1747} 1748 1749void 1750EtherDev::transferDone() 1751{ 1752 if (txFifo.empty()) 1753 return; 1754 1755 DPRINTF(Ethernet, "schedule transmit\n"); 1756 1757 if (txEvent.scheduled()) 1758 txEvent.reschedule(curTick + 1); 1759 else 1760 txEvent.schedule(curTick + 1); 1761} 1762 1763bool 1764EtherDev::rxFilter(PacketPtr packet) 1765{ 1766 bool drop = true; 1767 string type; 1768 1769 if (packet->IsUnicast()) { 1770 type = "unicast"; 1771 1772 // If we're accepting all unicast addresses 1773 if (acceptUnicast) 1774 drop = false; 1775 1776 // If we make a perfect match 1777 if ((acceptPerfect) 1778 && (memcmp(rom.perfectMatch, packet->data, sizeof(rom.perfectMatch)) == 0)) 1779 drop = false; 1780 1781 eth_header *eth = (eth_header *) packet->data; 1782 if ((acceptArp) && (eth->type == 0x806)) 1783 drop = false; 1784 1785 } else if (packet->IsBroadcast()) { 1786 type = "broadcast"; 1787 1788 // if we're accepting broadcasts 1789 if (acceptBroadcast) 1790 drop = false; 1791 1792 } else if (packet->IsMulticast()) { 1793 type = "multicast"; 1794 1795 // if we're accepting all multicasts 1796 if (acceptMulticast) 1797 drop = false; 1798 1799 } else { 1800 type = "unknown"; 1801 1802 // oh well, punt on this one 1803 } 1804 1805 if (drop) { 1806 DPRINTF(Ethernet, "rxFilter drop\n"); 1807 DDUMP(EthernetData, packet->data, packet->length); 1808 } 1809 1810 return drop; 1811} 1812 1813bool 1814EtherDev::recvPacket(PacketPtr packet) 1815{ 1816 rxBytes += packet->length; 1817 rxPackets++; 1818 1819 if (rxState == rxIdle) { 1820 DPRINTF(Ethernet, "receive disabled...packet dropped\n"); 1821 interface->recvDone(); 1822 return true; 1823 } 1824 1825 if (rxFilterEnable && rxFilter(packet)) { 1826 DPRINTF(Ethernet, "packet filtered...dropped\n"); 1827 interface->recvDone(); 1828 return true; 1829 } 1830 1831 if (rxFifoCnt + packet->length >= MAX_RX_FIFO_SIZE) { 1832 DPRINTF(Ethernet, 1833 "packet will not fit in receive buffer...packet dropped\n"); 1834 devIntrPost(ISR_RXORN); 1835 return false; 1836 } 1837 1838 rxFifo.push_back(packet); 1839 rxFifoCnt += packet->length; 1840 interface->recvDone(); 1841 1842 rxKick(); 1843 return true; 1844} 1845 1846bool 1847EtherDev::udpChecksum(PacketPtr packet, bool gen) 1848{ 1849 udp_header *hdr = (udp_header *) packet->getTransportHdr(); 1850 1851 ip_header *ip = packet->getIpHdr(); 1852 1853 pseudo_header *pseudo = new pseudo_header; 1854 1855 pseudo->src_ip_addr = ip->src_ip_addr; 1856 pseudo->dest_ip_addr = ip->dest_ip_addr; 1857 pseudo->protocol = ip->protocol; 1858 pseudo->len = hdr->len; 1859 1860 uint16_t cksum = checksumCalc((uint16_t *) pseudo, (uint16_t *) hdr, 1861 (uint32_t) hdr->len); 1862 1863 delete pseudo; 1864 if (gen) 1865 hdr->chksum = cksum; 1866 else 1867 if (cksum != 0) 1868 return false; 1869 1870 return true; 1871} 1872 1873bool 1874EtherDev::tcpChecksum(PacketPtr packet, bool gen) 1875{ 1876 tcp_header *hdr = (tcp_header *) packet->getTransportHdr(); 1877 1878 ip_header *ip = packet->getIpHdr(); 1879 1880 pseudo_header *pseudo = new pseudo_header; 1881 1882 pseudo->src_ip_addr = ip->src_ip_addr; 1883 pseudo->dest_ip_addr = ip->dest_ip_addr; 1884 pseudo->protocol = ip->protocol; 1885 pseudo->len = ip->dgram_len - (ip->vers_len & 0xf); 1886 1887 uint16_t cksum = checksumCalc((uint16_t *) pseudo, (uint16_t *) hdr, 1888 (uint32_t) pseudo->len); 1889 1890 delete pseudo; 1891 if (gen) 1892 hdr->chksum = cksum; 1893 else 1894 if (cksum != 0) 1895 return false; 1896 1897 return true; 1898} 1899 1900bool 1901EtherDev::ipChecksum(PacketPtr packet, bool gen) 1902{ 1903 ip_header *hdr = packet->getIpHdr(); 1904 1905 uint16_t cksum = checksumCalc(NULL, (uint16_t *) hdr, (hdr->vers_len & 0xf)); 1906 1907 if (gen) 1908 hdr->hdr_chksum = cksum; 1909 else 1910 if (cksum != 0) 1911 return false; 1912 1913 return true; 1914} 1915 1916uint16_t 1917EtherDev::checksumCalc(uint16_t *pseudo, uint16_t *buf, uint32_t len) 1918{ 1919 uint32_t sum = 0; 1920 1921 uint16_t last_pad = 0; 1922 if (len & 1) { 1923 last_pad = buf[len/2] & 0xff; 1924 len--; 1925 sum += last_pad; 1926 } 1927 1928 if (pseudo) { 1929 sum = pseudo[0] + pseudo[1] + pseudo[2] + 1930 pseudo[3] + pseudo[4] + pseudo[5]; 1931 } 1932 1933 for (int i=0; i < (len/2); ++i) { 1934 sum += buf[i]; 1935 } 1936 1937 while (sum >> 16) 1938 sum = (sum >> 16) + (sum & 0xffff); 1939 1940 return ~sum; 1941} 1942 1943//===================================================================== 1944// 1945// 1946void 1947EtherDev::serialize(ostream &os) 1948{ 1949 /* 1950 * Finalize any DMA events now. 1951 */ 1952 if (rxDmaReadEvent.scheduled()) 1953 rxDmaReadCopy(); 1954 if (rxDmaWriteEvent.scheduled()) 1955 rxDmaWriteCopy(); 1956 if (txDmaReadEvent.scheduled()) 1957 txDmaReadCopy(); 1958 if (txDmaWriteEvent.scheduled()) 1959 txDmaWriteCopy(); 1960 1961 /* 1962 * Serialize the device registers 1963 */ 1964 SERIALIZE_SCALAR(regs.command); 1965 SERIALIZE_SCALAR(regs.config); 1966 SERIALIZE_SCALAR(regs.mear); 1967 SERIALIZE_SCALAR(regs.ptscr); 1968 SERIALIZE_SCALAR(regs.isr); 1969 SERIALIZE_SCALAR(regs.imr); 1970 SERIALIZE_SCALAR(regs.ier); 1971 SERIALIZE_SCALAR(regs.ihr); 1972 SERIALIZE_SCALAR(regs.txdp); 1973 SERIALIZE_SCALAR(regs.txdp_hi); 1974 SERIALIZE_SCALAR(regs.txcfg); 1975 SERIALIZE_SCALAR(regs.gpior); 1976 SERIALIZE_SCALAR(regs.rxdp); 1977 SERIALIZE_SCALAR(regs.rxdp_hi); 1978 SERIALIZE_SCALAR(regs.rxcfg); 1979 SERIALIZE_SCALAR(regs.pqcr); 1980 SERIALIZE_SCALAR(regs.wcsr); 1981 SERIALIZE_SCALAR(regs.pcr); 1982 SERIALIZE_SCALAR(regs.rfcr); 1983 SERIALIZE_SCALAR(regs.rfdr); 1984 SERIALIZE_SCALAR(regs.srr); 1985 SERIALIZE_SCALAR(regs.mibc); 1986 SERIALIZE_SCALAR(regs.vrcr); 1987 SERIALIZE_SCALAR(regs.vtcr); 1988 SERIALIZE_SCALAR(regs.vdr); 1989 SERIALIZE_SCALAR(regs.ccsr); 1990 SERIALIZE_SCALAR(regs.tbicr); 1991 SERIALIZE_SCALAR(regs.tbisr); 1992 SERIALIZE_SCALAR(regs.tanar); 1993 SERIALIZE_SCALAR(regs.tanlpar); 1994 SERIALIZE_SCALAR(regs.taner); 1995 SERIALIZE_SCALAR(regs.tesr); 1996 1997 SERIALIZE_ARRAY(rom.perfectMatch, EADDR_LEN); 1998 1999 /* 2000 * Serialize the various helper variables 2001 */ 2002 uint32_t txPktBufPtr = (uint32_t) txPacketBufPtr; 2003 SERIALIZE_SCALAR(txPktBufPtr); 2004 uint32_t rxPktBufPtr = (uint32_t) rxPktBufPtr; 2005 SERIALIZE_SCALAR(rxPktBufPtr); 2006 SERIALIZE_SCALAR(txXferLen); 2007 SERIALIZE_SCALAR(rxXferLen); 2008 SERIALIZE_SCALAR(txPktXmitted); 2009 2010 bool txPacketExists = txPacket; 2011 SERIALIZE_SCALAR(txPacketExists); 2012 bool rxPacketExists = rxPacket; 2013 SERIALIZE_SCALAR(rxPacketExists); 2014 2015 /* 2016 * Serialize DescCaches 2017 */ 2018 SERIALIZE_SCALAR(txDescCache.link); 2019 SERIALIZE_SCALAR(txDescCache.bufptr); 2020 SERIALIZE_SCALAR(txDescCache.cmdsts); 2021 SERIALIZE_SCALAR(txDescCache.extsts); 2022 SERIALIZE_SCALAR(rxDescCache.link); 2023 SERIALIZE_SCALAR(rxDescCache.bufptr); 2024 SERIALIZE_SCALAR(rxDescCache.cmdsts); 2025 SERIALIZE_SCALAR(rxDescCache.extsts); 2026 2027 /* 2028 * Serialize tx state machine 2029 */ 2030 int txNumPkts = txFifo.size(); 2031 SERIALIZE_SCALAR(txNumPkts); 2032 int txState = this->txState; 2033 SERIALIZE_SCALAR(txState); 2034 SERIALIZE_SCALAR(CTDD); 2035 SERIALIZE_SCALAR(txFifoCnt); 2036 SERIALIZE_SCALAR(txFifoAvail); 2037 SERIALIZE_SCALAR(txHalt); 2038 SERIALIZE_SCALAR(txFragPtr); 2039 SERIALIZE_SCALAR(txDescCnt); 2040 int txDmaState = this->txDmaState; 2041 SERIALIZE_SCALAR(txDmaState); 2042 2043 /* 2044 * Serialize rx state machine 2045 */ 2046 int rxNumPkts = rxFifo.size(); 2047 SERIALIZE_SCALAR(rxNumPkts); 2048 int rxState = this->rxState; 2049 SERIALIZE_SCALAR(rxState); 2050 SERIALIZE_SCALAR(CRDD); 2051 SERIALIZE_SCALAR(rxPktBytes); 2052 SERIALIZE_SCALAR(rxFifoCnt); 2053 SERIALIZE_SCALAR(rxHalt); 2054 SERIALIZE_SCALAR(rxDescCnt); 2055 int rxDmaState = this->rxDmaState; 2056 SERIALIZE_SCALAR(rxDmaState); 2057 2058 SERIALIZE_SCALAR(extstsEnable); 2059 2060 /* 2061 * If there's a pending transmit, store the time so we can 2062 * reschedule it later 2063 */ 2064 Tick transmitTick = txEvent.scheduled() ? txEvent.when() - curTick : 0; 2065 SERIALIZE_SCALAR(transmitTick); 2066 2067 /* 2068 * Keep track of pending interrupt status. 2069 */ 2070 SERIALIZE_SCALAR(intrTick); 2071 SERIALIZE_SCALAR(cpuPendingIntr); 2072 Tick intrEventTick = 0; 2073 if (intrEvent) 2074 intrEventTick = intrEvent->when(); 2075 SERIALIZE_SCALAR(intrEventTick); 2076 2077 int i = 0; 2078 for (pktiter_t p = rxFifo.begin(); p != rxFifo.end(); ++p) { 2079 nameOut(os, csprintf("%s.rxFifo%d", name(), i++)); 2080 (*p)->serialize(os); 2081 } 2082 if (rxPacketExists) { 2083 nameOut(os, csprintf("%s.rxPacket", name())); 2084 rxPacket->serialize(os); 2085 } 2086 i = 0; 2087 for (pktiter_t p = txFifo.begin(); p != txFifo.end(); ++p) { 2088 nameOut(os, csprintf("%s.txFifo%d", name(), i++)); 2089 (*p)->serialize(os); 2090 } 2091 if (txPacketExists) { 2092 nameOut(os, csprintf("%s.txPacket", name())); 2093 txPacket->serialize(os); 2094 } 2095} 2096 2097void 2098EtherDev::unserialize(Checkpoint *cp, const std::string §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