ns_gige.cc revision 1057
17119Sgblack@eecs.umich.edu/* 27119Sgblack@eecs.umich.edu * Copyright (c) 2004 The Regents of The University of Michigan 310037SARM gem5 Developers * All rights reserved. 47120Sgblack@eecs.umich.edu * 57120Sgblack@eecs.umich.edu * Redistribution and use in source and binary forms, with or without 67120Sgblack@eecs.umich.edu * modification, are permitted provided that the following conditions are 77120Sgblack@eecs.umich.edu * met: redistributions of source code must retain the above copyright 87120Sgblack@eecs.umich.edu * notice, this list of conditions and the following disclaimer; 97120Sgblack@eecs.umich.edu * redistributions in binary form must reproduce the above copyright 107120Sgblack@eecs.umich.edu * notice, this list of conditions and the following disclaimer in the 117120Sgblack@eecs.umich.edu * documentation and/or other materials provided with the distribution; 127120Sgblack@eecs.umich.edu * neither the name of the copyright holders nor the names of its 137120Sgblack@eecs.umich.edu * contributors may be used to endorse or promote products derived from 147120Sgblack@eecs.umich.edu * this software without specific prior written permission. 157119Sgblack@eecs.umich.edu * 167119Sgblack@eecs.umich.edu * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 177119Sgblack@eecs.umich.edu * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 187119Sgblack@eecs.umich.edu * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR 197119Sgblack@eecs.umich.edu * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT 207119Sgblack@eecs.umich.edu * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 217119Sgblack@eecs.umich.edu * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT 227119Sgblack@eecs.umich.edu * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 237119Sgblack@eecs.umich.edu * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 247119Sgblack@eecs.umich.edu * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 257119Sgblack@eecs.umich.edu * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 267119Sgblack@eecs.umich.edu * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 277119Sgblack@eecs.umich.edu */ 287119Sgblack@eecs.umich.edu 297119Sgblack@eecs.umich.edu/* @file 307119Sgblack@eecs.umich.edu * Device module for modelling the National Semiconductor 317119Sgblack@eecs.umich.edu * DP83820 ethernet controller. Does not support priority queueing 327119Sgblack@eecs.umich.edu */ 337119Sgblack@eecs.umich.edu#include <cstdio> 347119Sgblack@eecs.umich.edu#include <deque> 357119Sgblack@eecs.umich.edu#include <string> 367119Sgblack@eecs.umich.edu 377119Sgblack@eecs.umich.edu#include "base/inet.hh" 387119Sgblack@eecs.umich.edu#include "cpu/exec_context.hh" 397119Sgblack@eecs.umich.edu#include "cpu/intr_control.hh" 407119Sgblack@eecs.umich.edu#include "dev/dma.hh" 417119Sgblack@eecs.umich.edu#include "dev/etherlink.hh" 427119Sgblack@eecs.umich.edu#include "dev/ns_gige.hh" 437119Sgblack@eecs.umich.edu#include "dev/pciconfigall.hh" 447646Sgene.wu@arm.com#include "dev/tsunami_cchip.hh" 4510196SCurtis.Dunham@arm.com#include "mem/bus/bus.hh" 467646Sgene.wu@arm.com#include "mem/bus/dma_interface.hh" 477646Sgene.wu@arm.com#include "mem/bus/pio_interface.hh" 487646Sgene.wu@arm.com#include "mem/bus/pio_interface_impl.hh" 497646Sgene.wu@arm.com#include "mem/functional_mem/memory_control.hh" 507646Sgene.wu@arm.com#include "mem/functional_mem/physical_memory.hh" 517646Sgene.wu@arm.com#include "sim/builder.hh" 527646Sgene.wu@arm.com#include "sim/debug.hh" 537646Sgene.wu@arm.com#include "sim/host.hh" 5410196SCurtis.Dunham@arm.com#include "sim/sim_stats.hh" 557646Sgene.wu@arm.com#include "targetarch/vtophys.hh" 567646Sgene.wu@arm.com 577646Sgene.wu@arm.comconst char *NsRxStateStrings[] = 587646Sgene.wu@arm.com{ 597646Sgene.wu@arm.com "rxIdle", 607646Sgene.wu@arm.com "rxDescRefr", 617646Sgene.wu@arm.com "rxDescRead", 627646Sgene.wu@arm.com "rxFifoBlock", 637646Sgene.wu@arm.com "rxFragWrite", 6410196SCurtis.Dunham@arm.com "rxDescWrite", 657646Sgene.wu@arm.com "rxAdvance" 667646Sgene.wu@arm.com}; 677646Sgene.wu@arm.com 687646Sgene.wu@arm.comconst char *NsTxStateStrings[] = 697646Sgene.wu@arm.com{ 707646Sgene.wu@arm.com "txIdle", 717646Sgene.wu@arm.com "txDescRefr", 727646Sgene.wu@arm.com "txDescRead", 737205Sgblack@eecs.umich.edu "txFifoBlock", 7410196SCurtis.Dunham@arm.com "txFragRead", 757205Sgblack@eecs.umich.edu "txDescWrite", 767205Sgblack@eecs.umich.edu "txAdvance" 777205Sgblack@eecs.umich.edu}; 787205Sgblack@eecs.umich.edu 797205Sgblack@eecs.umich.educonst char *NsDmaState[] = 807205Sgblack@eecs.umich.edu{ 817205Sgblack@eecs.umich.edu "dmaIdle", 827205Sgblack@eecs.umich.edu "dmaReading", 837205Sgblack@eecs.umich.edu "dmaWriting", 847205Sgblack@eecs.umich.edu "dmaReadWaiting", 857205Sgblack@eecs.umich.edu "dmaWriteWaiting" 867205Sgblack@eecs.umich.edu}; 877205Sgblack@eecs.umich.edu 887205Sgblack@eecs.umich.eduusing namespace std; 897205Sgblack@eecs.umich.edu 908442Sgblack@eecs.umich.edu// helper function declarations 918442Sgblack@eecs.umich.edu// These functions reverse Endianness so we can evaluate network data 927205Sgblack@eecs.umich.edu// correctly 937205Sgblack@eecs.umich.eduuint16_t reverseEnd16(uint16_t); 947205Sgblack@eecs.umich.eduuint32_t reverseEnd32(uint32_t); 957205Sgblack@eecs.umich.edu 967205Sgblack@eecs.umich.edu/////////////////////////////////////////////////////////////////////// 977205Sgblack@eecs.umich.edu// 987205Sgblack@eecs.umich.edu// NSGigE PCI Device 997205Sgblack@eecs.umich.edu// 1007205Sgblack@eecs.umich.eduNSGigE::NSGigE(const std::string &name, IntrControl *i, Tick intr_delay, 1017597Sminkyu.jeong@arm.com PhysicalMemory *pmem, Tick tx_delay, Tick rx_delay, 1027597Sminkyu.jeong@arm.com MemoryController *mmu, HierParams *hier, Bus *header_bus, 1037205Sgblack@eecs.umich.edu Bus *payload_bus, Tick pio_latency, bool dma_desc_free, 1047205Sgblack@eecs.umich.edu bool dma_data_free, Tick dma_read_delay, Tick dma_write_delay, 1057205Sgblack@eecs.umich.edu Tick dma_read_factor, Tick dma_write_factor, PciConfigAll *cf, 1067205Sgblack@eecs.umich.edu PciConfigData *cd, Tsunami *t, uint32_t bus, uint32_t dev, 1077205Sgblack@eecs.umich.edu uint32_t func, bool rx_filter, const int eaddr[6], 1087205Sgblack@eecs.umich.edu uint32_t tx_fifo_size, uint32_t rx_fifo_size) 1097205Sgblack@eecs.umich.edu : PciDev(name, mmu, cf, cd, bus, dev, func), tsunami(t), ioEnable(false), 11010196SCurtis.Dunham@arm.com maxTxFifoSize(tx_fifo_size), maxRxFifoSize(rx_fifo_size), 1117205Sgblack@eecs.umich.edu txPacket(0), rxPacket(0), txPacketBufPtr(NULL), rxPacketBufPtr(NULL), 1127205Sgblack@eecs.umich.edu txXferLen(0), rxXferLen(0), txState(txIdle), txEnable(false), 1137205Sgblack@eecs.umich.edu CTDD(false), txFifoAvail(tx_fifo_size), 1147205Sgblack@eecs.umich.edu txFragPtr(0), txDescCnt(0), txDmaState(dmaIdle), rxState(rxIdle), 1157205Sgblack@eecs.umich.edu rxEnable(false), CRDD(false), rxPktBytes(0), rxFifoCnt(0), 1167205Sgblack@eecs.umich.edu rxFragPtr(0), rxDescCnt(0), rxDmaState(dmaIdle), extstsEnable(false), 1177205Sgblack@eecs.umich.edu rxDmaReadEvent(this), rxDmaWriteEvent(this), 1187205Sgblack@eecs.umich.edu txDmaReadEvent(this), txDmaWriteEvent(this), 1197205Sgblack@eecs.umich.edu dmaDescFree(dma_desc_free), dmaDataFree(dma_data_free), 1207205Sgblack@eecs.umich.edu txDelay(tx_delay), rxDelay(rx_delay), rxKickTick(0), txKickTick(0), 1217205Sgblack@eecs.umich.edu txEvent(this), rxFilterEnable(rx_filter), acceptBroadcast(false), 1227205Sgblack@eecs.umich.edu acceptMulticast(false), acceptUnicast(false), 1237205Sgblack@eecs.umich.edu acceptPerfect(false), acceptArp(false), 1247205Sgblack@eecs.umich.edu physmem(pmem), intctrl(i), intrTick(0), cpuPendingIntr(false), 1257205Sgblack@eecs.umich.edu intrEvent(0), interface(0) 1268442Sgblack@eecs.umich.edu{ 1278442Sgblack@eecs.umich.edu tsunami->ethernet = this; 1287205Sgblack@eecs.umich.edu 1297597Sminkyu.jeong@arm.com if (header_bus) { 1307597Sminkyu.jeong@arm.com pioInterface = newPioInterface(name, hier, header_bus, this, 1317205Sgblack@eecs.umich.edu &NSGigE::cacheAccess); 1327205Sgblack@eecs.umich.edu 1337205Sgblack@eecs.umich.edu pioLatency = pio_latency * header_bus->clockRatio; 1347205Sgblack@eecs.umich.edu 1357205Sgblack@eecs.umich.edu if (payload_bus) 1367205Sgblack@eecs.umich.edu dmaInterface = new DMAInterface<Bus>(name + ".dma", 1377205Sgblack@eecs.umich.edu header_bus, payload_bus, 1); 1387205Sgblack@eecs.umich.edu else 13910196SCurtis.Dunham@arm.com dmaInterface = new DMAInterface<Bus>(name + ".dma", 1407205Sgblack@eecs.umich.edu header_bus, header_bus, 1); 1417205Sgblack@eecs.umich.edu } else if (payload_bus) { 1427205Sgblack@eecs.umich.edu pioInterface = newPioInterface(name, hier, payload_bus, this, 1437205Sgblack@eecs.umich.edu &NSGigE::cacheAccess); 1447205Sgblack@eecs.umich.edu 1457205Sgblack@eecs.umich.edu pioLatency = pio_latency * payload_bus->clockRatio; 1467205Sgblack@eecs.umich.edu 1477205Sgblack@eecs.umich.edu dmaInterface = new DMAInterface<Bus>(name + ".dma", payload_bus, 1487205Sgblack@eecs.umich.edu payload_bus, 1); 1497205Sgblack@eecs.umich.edu } 1508442Sgblack@eecs.umich.edu 1518442Sgblack@eecs.umich.edu 1527205Sgblack@eecs.umich.edu intrDelay = US2Ticks(intr_delay); 1537205Sgblack@eecs.umich.edu dmaReadDelay = dma_read_delay; 1547205Sgblack@eecs.umich.edu dmaWriteDelay = dma_write_delay; 1557205Sgblack@eecs.umich.edu dmaReadFactor = dma_read_factor; 1567205Sgblack@eecs.umich.edu dmaWriteFactor = dma_write_factor; 1577205Sgblack@eecs.umich.edu 1587205Sgblack@eecs.umich.edu regsReset(); 1597205Sgblack@eecs.umich.edu rom.perfectMatch[0] = eaddr[0]; 1607205Sgblack@eecs.umich.edu rom.perfectMatch[1] = eaddr[1]; 1617205Sgblack@eecs.umich.edu rom.perfectMatch[2] = eaddr[2]; 1627205Sgblack@eecs.umich.edu rom.perfectMatch[3] = eaddr[3]; 1637205Sgblack@eecs.umich.edu rom.perfectMatch[4] = eaddr[4]; 1647119Sgblack@eecs.umich.edu rom.perfectMatch[5] = eaddr[5]; 16510196SCurtis.Dunham@arm.com} 1667119Sgblack@eecs.umich.edu 1677119Sgblack@eecs.umich.eduNSGigE::~NSGigE() 1687119Sgblack@eecs.umich.edu{} 1697119Sgblack@eecs.umich.edu 1707119Sgblack@eecs.umich.eduvoid 1717119Sgblack@eecs.umich.eduNSGigE::regStats() 1727119Sgblack@eecs.umich.edu{ 1737119Sgblack@eecs.umich.edu txBytes 1747119Sgblack@eecs.umich.edu .name(name() + ".txBytes") 1757119Sgblack@eecs.umich.edu .desc("Bytes Transmitted") 1767119Sgblack@eecs.umich.edu .prereq(txBytes) 1777119Sgblack@eecs.umich.edu ; 1788442Sgblack@eecs.umich.edu 1797119Sgblack@eecs.umich.edu rxBytes 1807119Sgblack@eecs.umich.edu .name(name() + ".rxBytes") 1817119Sgblack@eecs.umich.edu .desc("Bytes Received") 1827119Sgblack@eecs.umich.edu .prereq(rxBytes) 1837119Sgblack@eecs.umich.edu ; 1847119Sgblack@eecs.umich.edu 1857597Sminkyu.jeong@arm.com txPackets 1867597Sminkyu.jeong@arm.com .name(name() + ".txPackets") 1877119Sgblack@eecs.umich.edu .desc("Number of Packets Transmitted") 1887119Sgblack@eecs.umich.edu .prereq(txBytes) 1897119Sgblack@eecs.umich.edu ; 1907119Sgblack@eecs.umich.edu 1917119Sgblack@eecs.umich.edu rxPackets 1927119Sgblack@eecs.umich.edu .name(name() + ".rxPackets") 1937639Sgblack@eecs.umich.edu .desc("Number of Packets Received") 1947639Sgblack@eecs.umich.edu .prereq(rxBytes) 1957639Sgblack@eecs.umich.edu ; 19610196SCurtis.Dunham@arm.com 1977639Sgblack@eecs.umich.edu txIPChecksums 1987639Sgblack@eecs.umich.edu .name(name() + ".txIPChecksums") 1997639Sgblack@eecs.umich.edu .desc("Number of tx IP Checksums done by device") 2007639Sgblack@eecs.umich.edu .precision(0) 2017639Sgblack@eecs.umich.edu .prereq(txBytes) 2027639Sgblack@eecs.umich.edu ; 2037639Sgblack@eecs.umich.edu 2047639Sgblack@eecs.umich.edu rxIPChecksums 2057639Sgblack@eecs.umich.edu .name(name() + ".rxIPChecksums") 2067639Sgblack@eecs.umich.edu .desc("Number of rx IP Checksums done by device") 2077639Sgblack@eecs.umich.edu .precision(0) 2087639Sgblack@eecs.umich.edu .prereq(rxBytes) 2097639Sgblack@eecs.umich.edu ; 2107639Sgblack@eecs.umich.edu 2117639Sgblack@eecs.umich.edu txTCPChecksums 2128444Sgblack@eecs.umich.edu .name(name() + ".txTCPChecksums") 2137639Sgblack@eecs.umich.edu .desc("Number of tx TCP Checksums done by device") 2147639Sgblack@eecs.umich.edu .precision(0) 2157639Sgblack@eecs.umich.edu .prereq(txBytes) 2167639Sgblack@eecs.umich.edu ; 2177639Sgblack@eecs.umich.edu 2187639Sgblack@eecs.umich.edu rxTCPChecksums 2198072SGiacomo.Gabrielli@arm.com .name(name() + ".rxTCPChecksums") 2208072SGiacomo.Gabrielli@arm.com .desc("Number of rx TCP Checksums done by device") 2217639Sgblack@eecs.umich.edu .precision(0) 2227639Sgblack@eecs.umich.edu .prereq(rxBytes) 2237639Sgblack@eecs.umich.edu ; 2247639Sgblack@eecs.umich.edu 2257639Sgblack@eecs.umich.edu descDmaReads 2267639Sgblack@eecs.umich.edu .name(name() + ".descDMAReads") 2277120Sgblack@eecs.umich.edu .desc("Number of descriptors the device read w/ DMA") 22810196SCurtis.Dunham@arm.com .precision(0) 2297120Sgblack@eecs.umich.edu ; 2307120Sgblack@eecs.umich.edu 2317120Sgblack@eecs.umich.edu descDmaWrites 2327120Sgblack@eecs.umich.edu .name(name() + ".descDMAWrites") 2337120Sgblack@eecs.umich.edu .desc("Number of descriptors the device wrote w/ DMA") 2347120Sgblack@eecs.umich.edu .precision(0) 2357120Sgblack@eecs.umich.edu ; 2367120Sgblack@eecs.umich.edu 2377120Sgblack@eecs.umich.edu descDmaRdBytes 2387120Sgblack@eecs.umich.edu .name(name() + ".descDmaReadBytes") 2397120Sgblack@eecs.umich.edu .desc("number of descriptor bytes read w/ DMA") 2407120Sgblack@eecs.umich.edu .precision(0) 2417120Sgblack@eecs.umich.edu ; 2427120Sgblack@eecs.umich.edu 2437120Sgblack@eecs.umich.edu descDmaWrBytes 2447120Sgblack@eecs.umich.edu .name(name() + ".descDmaWriteBytes") 2458442Sgblack@eecs.umich.edu .desc("number of descriptor bytes write w/ DMA") 2468442Sgblack@eecs.umich.edu .precision(0) 2477120Sgblack@eecs.umich.edu ; 2487120Sgblack@eecs.umich.edu 2497120Sgblack@eecs.umich.edu 2507120Sgblack@eecs.umich.edu txBandwidth 2517120Sgblack@eecs.umich.edu .name(name() + ".txBandwidth") 2527597Sminkyu.jeong@arm.com .desc("Transmit Bandwidth (bits/s)") 2537597Sminkyu.jeong@arm.com .precision(0) 2547120Sgblack@eecs.umich.edu .prereq(txBytes) 2557120Sgblack@eecs.umich.edu ; 2567120Sgblack@eecs.umich.edu 2577120Sgblack@eecs.umich.edu rxBandwidth 2587120Sgblack@eecs.umich.edu .name(name() + ".rxBandwidth") 2597120Sgblack@eecs.umich.edu .desc("Receive Bandwidth (bits/s)") 2607639Sgblack@eecs.umich.edu .precision(0) 2617639Sgblack@eecs.umich.edu .prereq(rxBytes) 2627639Sgblack@eecs.umich.edu ; 26310196SCurtis.Dunham@arm.com 2647639Sgblack@eecs.umich.edu txPacketRate 2657639Sgblack@eecs.umich.edu .name(name() + ".txPPS") 2667639Sgblack@eecs.umich.edu .desc("Packet Tranmission Rate (packets/s)") 2677639Sgblack@eecs.umich.edu .precision(0) 2687639Sgblack@eecs.umich.edu .prereq(txBytes) 2697639Sgblack@eecs.umich.edu ; 2707639Sgblack@eecs.umich.edu 2717639Sgblack@eecs.umich.edu rxPacketRate 2727639Sgblack@eecs.umich.edu .name(name() + ".rxPPS") 2737639Sgblack@eecs.umich.edu .desc("Packet Reception Rate (packets/s)") 2747639Sgblack@eecs.umich.edu .precision(0) 2757639Sgblack@eecs.umich.edu .prereq(rxBytes) 2767639Sgblack@eecs.umich.edu ; 2777639Sgblack@eecs.umich.edu 2787639Sgblack@eecs.umich.edu txBandwidth = txBytes * Stats::constant(8) / simSeconds; 2797639Sgblack@eecs.umich.edu rxBandwidth = rxBytes * Stats::constant(8) / simSeconds; 2807639Sgblack@eecs.umich.edu txPacketRate = txPackets / simSeconds; 2817639Sgblack@eecs.umich.edu rxPacketRate = rxPackets / simSeconds; 2827639Sgblack@eecs.umich.edu} 2838444Sgblack@eecs.umich.edu 2848444Sgblack@eecs.umich.edu/** 2857639Sgblack@eecs.umich.edu * This is to read the PCI general configuration registers 2867639Sgblack@eecs.umich.edu */ 2877639Sgblack@eecs.umich.eduvoid 2887639Sgblack@eecs.umich.eduNSGigE::ReadConfig(int offset, int size, uint8_t *data) 2897639Sgblack@eecs.umich.edu{ 2908072SGiacomo.Gabrielli@arm.com if (offset < PCI_DEVICE_SPECIFIC) 2918072SGiacomo.Gabrielli@arm.com PciDev::ReadConfig(offset, size, data); 2927639Sgblack@eecs.umich.edu else 2937639Sgblack@eecs.umich.edu panic("Device specific PCI config space not implemented!\n"); 2947639Sgblack@eecs.umich.edu} 2957639Sgblack@eecs.umich.edu 2967639Sgblack@eecs.umich.edu/** 2977639Sgblack@eecs.umich.edu * This is to write to the PCI general configuration registers 2987303Sgblack@eecs.umich.edu */ 29910196SCurtis.Dunham@arm.comvoid 3007303Sgblack@eecs.umich.eduNSGigE::WriteConfig(int offset, int size, uint32_t data) 3017303Sgblack@eecs.umich.edu{ 3027303Sgblack@eecs.umich.edu if (offset < PCI_DEVICE_SPECIFIC) 3037303Sgblack@eecs.umich.edu PciDev::WriteConfig(offset, size, data); 3047303Sgblack@eecs.umich.edu else 3057303Sgblack@eecs.umich.edu panic("Device specific PCI config space not implemented!\n"); 3067303Sgblack@eecs.umich.edu 3077303Sgblack@eecs.umich.edu // Need to catch writes to BARs to update the PIO interface 3087303Sgblack@eecs.umich.edu switch (offset) { 3097303Sgblack@eecs.umich.edu // seems to work fine without all these PCI settings, but i 3107303Sgblack@eecs.umich.edu // put in the IO to double check, an assertion will fail if we 3117303Sgblack@eecs.umich.edu // need to properly implement it 3127303Sgblack@eecs.umich.edu case PCI_COMMAND: 3137303Sgblack@eecs.umich.edu if (config.data[offset] & PCI_CMD_IOSE) 3147303Sgblack@eecs.umich.edu ioEnable = true; 3157303Sgblack@eecs.umich.edu else 3167303Sgblack@eecs.umich.edu ioEnable = false; 3177303Sgblack@eecs.umich.edu 3188442Sgblack@eecs.umich.edu#if 0 3198442Sgblack@eecs.umich.edu if (config.data[offset] & PCI_CMD_BME) { 3207303Sgblack@eecs.umich.edu bmEnabled = true; 3217303Sgblack@eecs.umich.edu } 3227303Sgblack@eecs.umich.edu else { 3237303Sgblack@eecs.umich.edu bmEnabled = false; 3247303Sgblack@eecs.umich.edu } 3257303Sgblack@eecs.umich.edu 3267303Sgblack@eecs.umich.edu if (config.data[offset] & PCI_CMD_MSE) { 3277303Sgblack@eecs.umich.edu memEnable = true; 3287303Sgblack@eecs.umich.edu } 3297597Sminkyu.jeong@arm.com else { 3307597Sminkyu.jeong@arm.com memEnable = false; 3317303Sgblack@eecs.umich.edu } 3327303Sgblack@eecs.umich.edu#endif 3337303Sgblack@eecs.umich.edu break; 3347303Sgblack@eecs.umich.edu 3357303Sgblack@eecs.umich.edu case PCI0_BASE_ADDR0: 3367303Sgblack@eecs.umich.edu if (BARAddrs[0] != 0) { 3377303Sgblack@eecs.umich.edu if (pioInterface) 33810196SCurtis.Dunham@arm.com pioInterface->addAddrRange(BARAddrs[0], 3397303Sgblack@eecs.umich.edu BARAddrs[0] + BARSize[0] - 1); 3407303Sgblack@eecs.umich.edu 3417303Sgblack@eecs.umich.edu BARAddrs[0] &= PA_UNCACHED_MASK; 3427303Sgblack@eecs.umich.edu } 3437303Sgblack@eecs.umich.edu break; 3447303Sgblack@eecs.umich.edu case PCI0_BASE_ADDR1: 3457303Sgblack@eecs.umich.edu if (BARAddrs[1] != 0) { 3467303Sgblack@eecs.umich.edu if (pioInterface) 3477303Sgblack@eecs.umich.edu pioInterface->addAddrRange(BARAddrs[1], 3487303Sgblack@eecs.umich.edu BARAddrs[1] + BARSize[1] - 1); 3497303Sgblack@eecs.umich.edu 3507303Sgblack@eecs.umich.edu BARAddrs[1] &= PA_UNCACHED_MASK; 3517303Sgblack@eecs.umich.edu } 3527303Sgblack@eecs.umich.edu break; 3537303Sgblack@eecs.umich.edu } 3547303Sgblack@eecs.umich.edu} 3558442Sgblack@eecs.umich.edu 3568442Sgblack@eecs.umich.edu/** 3577303Sgblack@eecs.umich.edu * This reads the device registers, which are detailed in the NS83820 3587597Sminkyu.jeong@arm.com * spec sheet 3597597Sminkyu.jeong@arm.com */ 3607303Sgblack@eecs.umich.eduFault 3617408Sgblack@eecs.umich.eduNSGigE::read(MemReqPtr &req, uint8_t *data) 3627303Sgblack@eecs.umich.edu{ 3637303Sgblack@eecs.umich.edu assert(ioEnable); 3647303Sgblack@eecs.umich.edu 3657303Sgblack@eecs.umich.edu //The mask is to give you only the offset into the device register file 3667120Sgblack@eecs.umich.edu Addr daddr = req->paddr & 0xfff; 36710196SCurtis.Dunham@arm.com DPRINTF(EthernetPIO, "read da=%#x pa=%#x va=%#x size=%d\n", 3687120Sgblack@eecs.umich.edu daddr, req->paddr, req->vaddr, req->size); 3697120Sgblack@eecs.umich.edu 3707120Sgblack@eecs.umich.edu 3717120Sgblack@eecs.umich.edu // there are some reserved registers, you can see ns_gige_reg.h and 3727120Sgblack@eecs.umich.edu // the spec sheet for details 3737120Sgblack@eecs.umich.edu if (daddr > LAST && daddr <= RESERVED) { 3747120Sgblack@eecs.umich.edu panic("Accessing reserved register"); 3757120Sgblack@eecs.umich.edu } else if (daddr > RESERVED && daddr <= 0x3FC) { 3767120Sgblack@eecs.umich.edu ReadConfig(daddr & 0xff, req->size, data); 3777120Sgblack@eecs.umich.edu return No_Fault; 3787120Sgblack@eecs.umich.edu } else if (daddr >= MIB_START && daddr <= MIB_END) { 3797120Sgblack@eecs.umich.edu // don't implement all the MIB's. hopefully the kernel 3807120Sgblack@eecs.umich.edu // doesn't actually DEPEND upon their values 3817120Sgblack@eecs.umich.edu // MIB are just hardware stats keepers 3827120Sgblack@eecs.umich.edu uint32_t ® = *(uint32_t *) data; 3837120Sgblack@eecs.umich.edu reg = 0; 3848442Sgblack@eecs.umich.edu return No_Fault; 3858442Sgblack@eecs.umich.edu } else if (daddr > 0x3FC) 3867120Sgblack@eecs.umich.edu panic("Something is messed up!\n"); 3877597Sminkyu.jeong@arm.com 3887597Sminkyu.jeong@arm.com switch (req->size) { 3897120Sgblack@eecs.umich.edu case sizeof(uint32_t): 3907120Sgblack@eecs.umich.edu { 3917120Sgblack@eecs.umich.edu uint32_t ® = *(uint32_t *)data; 3927120Sgblack@eecs.umich.edu 3937120Sgblack@eecs.umich.edu switch (daddr) { 3947120Sgblack@eecs.umich.edu case CR: 3957639Sgblack@eecs.umich.edu reg = regs.command; 3967639Sgblack@eecs.umich.edu //these are supposed to be cleared on a read 3977639Sgblack@eecs.umich.edu reg &= ~(CR_RXD | CR_TXD | CR_TXR | CR_RXR); 39810196SCurtis.Dunham@arm.com break; 3997639Sgblack@eecs.umich.edu 4007639Sgblack@eecs.umich.edu case CFG: 4017639Sgblack@eecs.umich.edu reg = regs.config; 4027639Sgblack@eecs.umich.edu break; 4037639Sgblack@eecs.umich.edu 4047639Sgblack@eecs.umich.edu case MEAR: 4057639Sgblack@eecs.umich.edu reg = regs.mear; 4067639Sgblack@eecs.umich.edu break; 4077639Sgblack@eecs.umich.edu 4087639Sgblack@eecs.umich.edu case PTSCR: 4097639Sgblack@eecs.umich.edu reg = regs.ptscr; 4107639Sgblack@eecs.umich.edu break; 4117639Sgblack@eecs.umich.edu 4127639Sgblack@eecs.umich.edu case ISR: 4137639Sgblack@eecs.umich.edu reg = regs.isr; 4147639Sgblack@eecs.umich.edu devIntrClear(ISR_ALL); 4157639Sgblack@eecs.umich.edu break; 4168444Sgblack@eecs.umich.edu 4178444Sgblack@eecs.umich.edu case IMR: 4187639Sgblack@eecs.umich.edu reg = regs.imr; 4198072SGiacomo.Gabrielli@arm.com break; 4208072SGiacomo.Gabrielli@arm.com 4217639Sgblack@eecs.umich.edu case IER: 4227639Sgblack@eecs.umich.edu reg = regs.ier; 4237639Sgblack@eecs.umich.edu break; 4247639Sgblack@eecs.umich.edu 4257639Sgblack@eecs.umich.edu case IHR: 4267639Sgblack@eecs.umich.edu reg = regs.ihr; 4277119Sgblack@eecs.umich.edu break; 42810196SCurtis.Dunham@arm.com 4297119Sgblack@eecs.umich.edu case TXDP: 4307119Sgblack@eecs.umich.edu reg = regs.txdp; 4317119Sgblack@eecs.umich.edu break; 4327119Sgblack@eecs.umich.edu 4337119Sgblack@eecs.umich.edu case TXDP_HI: 4347119Sgblack@eecs.umich.edu reg = regs.txdp_hi; 4357119Sgblack@eecs.umich.edu break; 4367119Sgblack@eecs.umich.edu 4377119Sgblack@eecs.umich.edu case TXCFG: 4387119Sgblack@eecs.umich.edu reg = regs.txcfg; 4397119Sgblack@eecs.umich.edu break; 4407119Sgblack@eecs.umich.edu 4418442Sgblack@eecs.umich.edu case GPIOR: 4427119Sgblack@eecs.umich.edu reg = regs.gpior; 4437597Sminkyu.jeong@arm.com break; 4447597Sminkyu.jeong@arm.com 4457119Sgblack@eecs.umich.edu case RXDP: 4467119Sgblack@eecs.umich.edu reg = regs.rxdp; 4477119Sgblack@eecs.umich.edu break; 4487119Sgblack@eecs.umich.edu 4497119Sgblack@eecs.umich.edu case RXDP_HI: 4507119Sgblack@eecs.umich.edu reg = regs.rxdp_hi; 4517639Sgblack@eecs.umich.edu break; 4527639Sgblack@eecs.umich.edu 4537639Sgblack@eecs.umich.edu case RXCFG: 45410196SCurtis.Dunham@arm.com reg = regs.rxcfg; 4557639Sgblack@eecs.umich.edu break; 4567639Sgblack@eecs.umich.edu 4577639Sgblack@eecs.umich.edu case PQCR: 4587639Sgblack@eecs.umich.edu reg = regs.pqcr; 4598207SAli.Saidi@ARM.com break; 4608207SAli.Saidi@ARM.com 4617639Sgblack@eecs.umich.edu case WCSR: 4627639Sgblack@eecs.umich.edu reg = regs.wcsr; 4637639Sgblack@eecs.umich.edu break; 4648207SAli.Saidi@ARM.com 4658207SAli.Saidi@ARM.com case PCR: 4668207SAli.Saidi@ARM.com reg = regs.pcr; 4677639Sgblack@eecs.umich.edu break; 4687639Sgblack@eecs.umich.edu 4697639Sgblack@eecs.umich.edu // see the spec sheet for how RFCR and RFDR work 4708444Sgblack@eecs.umich.edu // basically, you write to RFCR to tell the machine 4717639Sgblack@eecs.umich.edu // what you want to do next, then you act upon RFDR, 4728072SGiacomo.Gabrielli@arm.com // and the device will be prepared b/c of what you 4738072SGiacomo.Gabrielli@arm.com // wrote to RFCR 4747639Sgblack@eecs.umich.edu case RFCR: 4757639Sgblack@eecs.umich.edu reg = regs.rfcr; 4767639Sgblack@eecs.umich.edu break; 4777639Sgblack@eecs.umich.edu 4787639Sgblack@eecs.umich.edu case RFDR: 4797639Sgblack@eecs.umich.edu switch (regs.rfcr & RFCR_RFADDR) { 4807119Sgblack@eecs.umich.edu case 0x000: 4817119Sgblack@eecs.umich.edu reg = rom.perfectMatch[1]; 48210196SCurtis.Dunham@arm.com reg = reg << 8; 4837119Sgblack@eecs.umich.edu reg += rom.perfectMatch[0]; 4847119Sgblack@eecs.umich.edu break; 4857119Sgblack@eecs.umich.edu case 0x002: 4867119Sgblack@eecs.umich.edu reg = rom.perfectMatch[3] << 8; 4877119Sgblack@eecs.umich.edu reg += rom.perfectMatch[2]; 4887119Sgblack@eecs.umich.edu break; 4897119Sgblack@eecs.umich.edu case 0x004: 4907119Sgblack@eecs.umich.edu reg = rom.perfectMatch[5] << 8; 4917119Sgblack@eecs.umich.edu reg += rom.perfectMatch[4]; 4927119Sgblack@eecs.umich.edu break; 4938442Sgblack@eecs.umich.edu default: 4947119Sgblack@eecs.umich.edu panic("reading RFDR for something other than PMATCH!\n"); 4957119Sgblack@eecs.umich.edu // didn't implement other RFDR functionality b/c 4967119Sgblack@eecs.umich.edu // driver didn't use it 4977119Sgblack@eecs.umich.edu } 4987119Sgblack@eecs.umich.edu break; 4997119Sgblack@eecs.umich.edu 5007119Sgblack@eecs.umich.edu case SRR: 5017119Sgblack@eecs.umich.edu reg = regs.srr; 5027119Sgblack@eecs.umich.edu break; 5037119Sgblack@eecs.umich.edu 5047119Sgblack@eecs.umich.edu case MIBC: 5057119Sgblack@eecs.umich.edu reg = regs.mibc; 5067119Sgblack@eecs.umich.edu reg &= ~(MIBC_MIBS | MIBC_ACLR); 5077119Sgblack@eecs.umich.edu break; 5087639Sgblack@eecs.umich.edu 5097639Sgblack@eecs.umich.edu case VRCR: 5107639Sgblack@eecs.umich.edu reg = regs.vrcr; 51110196SCurtis.Dunham@arm.com break; 5127639Sgblack@eecs.umich.edu 5137639Sgblack@eecs.umich.edu case VTCR: 5147639Sgblack@eecs.umich.edu reg = regs.vtcr; 5157639Sgblack@eecs.umich.edu break; 5167639Sgblack@eecs.umich.edu 5177639Sgblack@eecs.umich.edu case VDR: 5187639Sgblack@eecs.umich.edu reg = regs.vdr; 5197639Sgblack@eecs.umich.edu break; 5207639Sgblack@eecs.umich.edu 5217639Sgblack@eecs.umich.edu case CCSR: 5227639Sgblack@eecs.umich.edu reg = regs.ccsr; 5237639Sgblack@eecs.umich.edu break; 5247639Sgblack@eecs.umich.edu 5257639Sgblack@eecs.umich.edu case TBICR: 5267639Sgblack@eecs.umich.edu reg = regs.tbicr; 5277639Sgblack@eecs.umich.edu break; 5287639Sgblack@eecs.umich.edu 5297639Sgblack@eecs.umich.edu case TBISR: 5307639Sgblack@eecs.umich.edu reg = regs.tbisr; 5317639Sgblack@eecs.umich.edu break; 5327639Sgblack@eecs.umich.edu 5337639Sgblack@eecs.umich.edu case TANAR: 5347639Sgblack@eecs.umich.edu reg = regs.tanar; 5357639Sgblack@eecs.umich.edu break; 5367639Sgblack@eecs.umich.edu 5377639Sgblack@eecs.umich.edu case TANLPAR: 5387120Sgblack@eecs.umich.edu reg = regs.tanlpar; 5397120Sgblack@eecs.umich.edu break; 54010196SCurtis.Dunham@arm.com 5417120Sgblack@eecs.umich.edu case TANER: 5427120Sgblack@eecs.umich.edu reg = regs.taner; 5437712Sgblack@eecs.umich.edu break; 5447120Sgblack@eecs.umich.edu 5457120Sgblack@eecs.umich.edu case TESR: 5467120Sgblack@eecs.umich.edu reg = regs.tesr; 5477639Sgblack@eecs.umich.edu break; 5487639Sgblack@eecs.umich.edu 5497639Sgblack@eecs.umich.edu default: 55010196SCurtis.Dunham@arm.com panic("reading unimplemented register: addr=%#x", daddr); 5517639Sgblack@eecs.umich.edu } 5527639Sgblack@eecs.umich.edu 5537712Sgblack@eecs.umich.edu DPRINTF(EthernetPIO, "read from %#x: data=%d data=%#x\n", 5547639Sgblack@eecs.umich.edu daddr, reg, reg); 5557639Sgblack@eecs.umich.edu } 5567639Sgblack@eecs.umich.edu break; 5577303Sgblack@eecs.umich.edu 5587303Sgblack@eecs.umich.edu default: 55910196SCurtis.Dunham@arm.com panic("accessing register with invalid size: addr=%#x, size=%d", 5607303Sgblack@eecs.umich.edu daddr, req->size); 5617303Sgblack@eecs.umich.edu } 5627303Sgblack@eecs.umich.edu 5637303Sgblack@eecs.umich.edu return No_Fault; 5647303Sgblack@eecs.umich.edu} 5657303Sgblack@eecs.umich.edu 5667303Sgblack@eecs.umich.eduFault 5677303Sgblack@eecs.umich.eduNSGigE::write(MemReqPtr &req, const uint8_t *data) 5687303Sgblack@eecs.umich.edu{ 5697303Sgblack@eecs.umich.edu assert(ioEnable); 5707303Sgblack@eecs.umich.edu 5717303Sgblack@eecs.umich.edu Addr daddr = req->paddr & 0xfff; 5727303Sgblack@eecs.umich.edu DPRINTF(EthernetPIO, "write da=%#x pa=%#x va=%#x size=%d\n", 5737303Sgblack@eecs.umich.edu daddr, req->paddr, req->vaddr, req->size); 5747303Sgblack@eecs.umich.edu 5757303Sgblack@eecs.umich.edu if (daddr > LAST && daddr <= RESERVED) { 5767303Sgblack@eecs.umich.edu panic("Accessing reserved register"); 5777303Sgblack@eecs.umich.edu } else if (daddr > RESERVED && daddr <= 0x3FC) { 5787303Sgblack@eecs.umich.edu WriteConfig(daddr & 0xff, req->size, *(uint32_t *)data); 5797303Sgblack@eecs.umich.edu return No_Fault; 5807303Sgblack@eecs.umich.edu } else if (daddr > 0x3FC) 5817291Sgblack@eecs.umich.edu panic("Something is messed up!\n"); 5827291Sgblack@eecs.umich.edu 5837291Sgblack@eecs.umich.edu if (req->size == sizeof(uint32_t)) { 5847291Sgblack@eecs.umich.edu uint32_t reg = *(uint32_t *)data; 5857291Sgblack@eecs.umich.edu DPRINTF(EthernetPIO, "write data=%d data=%#x\n", reg, reg); 5867291Sgblack@eecs.umich.edu 5877291Sgblack@eecs.umich.edu switch (daddr) { 5887291Sgblack@eecs.umich.edu case CR: 5897291Sgblack@eecs.umich.edu regs.command = reg; 5907291Sgblack@eecs.umich.edu if (reg & CR_TXD) { 5917291Sgblack@eecs.umich.edu txEnable = false; 5927291Sgblack@eecs.umich.edu } else if (reg & CR_TXE) { 5937291Sgblack@eecs.umich.edu txEnable = true; 5947291Sgblack@eecs.umich.edu 5957291Sgblack@eecs.umich.edu // the kernel is enabling the transmit machine 5967291Sgblack@eecs.umich.edu if (txState == txIdle) 5977291Sgblack@eecs.umich.edu txKick(); 5987291Sgblack@eecs.umich.edu } 5997291Sgblack@eecs.umich.edu 6007291Sgblack@eecs.umich.edu if (reg & CR_RXD) { 6017312Sgblack@eecs.umich.edu rxEnable = false; 6027312Sgblack@eecs.umich.edu } else if (reg & CR_RXE) { 6037312Sgblack@eecs.umich.edu rxEnable = true; 6047312Sgblack@eecs.umich.edu 6057312Sgblack@eecs.umich.edu if (rxState == rxIdle) 6067312Sgblack@eecs.umich.edu rxKick(); 6077312Sgblack@eecs.umich.edu } 6087312Sgblack@eecs.umich.edu 6097312Sgblack@eecs.umich.edu if (reg & CR_TXR) 6107312Sgblack@eecs.umich.edu txReset(); 6117312Sgblack@eecs.umich.edu 6127312Sgblack@eecs.umich.edu if (reg & CR_RXR) 6137312Sgblack@eecs.umich.edu rxReset(); 6147312Sgblack@eecs.umich.edu 6157312Sgblack@eecs.umich.edu if (reg & CR_SWI) 6167312Sgblack@eecs.umich.edu devIntrPost(ISR_SWI); 6177312Sgblack@eecs.umich.edu 6187312Sgblack@eecs.umich.edu if (reg & CR_RST) { 6197312Sgblack@eecs.umich.edu txReset(); 6207312Sgblack@eecs.umich.edu rxReset(); 6217205Sgblack@eecs.umich.edu 6227205Sgblack@eecs.umich.edu regsReset(); 6237205Sgblack@eecs.umich.edu } 6247205Sgblack@eecs.umich.edu break; 6257205Sgblack@eecs.umich.edu 6267205Sgblack@eecs.umich.edu case CFG: 6277205Sgblack@eecs.umich.edu if (reg & CFG_LNKSTS || 6287205Sgblack@eecs.umich.edu reg & CFG_SPDSTS || 6297205Sgblack@eecs.umich.edu reg & CFG_DUPSTS || 6307205Sgblack@eecs.umich.edu reg & CFG_RESERVED || 6317205Sgblack@eecs.umich.edu reg & CFG_T64ADDR || 6327205Sgblack@eecs.umich.edu reg & CFG_PCI64_DET) 6337205Sgblack@eecs.umich.edu panic("writing to read-only or reserved CFG bits!\n"); 6347205Sgblack@eecs.umich.edu 6357205Sgblack@eecs.umich.edu regs.config |= reg & ~(CFG_LNKSTS | CFG_SPDSTS | CFG_DUPSTS | 6367205Sgblack@eecs.umich.edu CFG_RESERVED | CFG_T64ADDR | CFG_PCI64_DET); 6377205Sgblack@eecs.umich.edu 6387205Sgblack@eecs.umich.edu// all these #if 0's are because i don't THINK the kernel needs to 6397205Sgblack@eecs.umich.edu// have these implemented. if there is a problem relating to one of 6407205Sgblack@eecs.umich.edu// these, you may need to add functionality in. 6417279Sgblack@eecs.umich.edu#if 0 6427279Sgblack@eecs.umich.edu if (reg & CFG_TBI_EN) ; 6437279Sgblack@eecs.umich.edu if (reg & CFG_MODE_1000) ; 6447279Sgblack@eecs.umich.edu#endif 6457279Sgblack@eecs.umich.edu 6467279Sgblack@eecs.umich.edu if (reg & CFG_AUTO_1000) 6477279Sgblack@eecs.umich.edu panic("CFG_AUTO_1000 not implemented!\n"); 6487279Sgblack@eecs.umich.edu 6497279Sgblack@eecs.umich.edu#if 0 6507279Sgblack@eecs.umich.edu if (reg & CFG_PINT_DUPSTS || 6517279Sgblack@eecs.umich.edu reg & CFG_PINT_LNKSTS || 6527279Sgblack@eecs.umich.edu reg & CFG_PINT_SPDSTS) 6537279Sgblack@eecs.umich.edu ; 6547279Sgblack@eecs.umich.edu 6557279Sgblack@eecs.umich.edu if (reg & CFG_TMRTEST) ; 6567279Sgblack@eecs.umich.edu if (reg & CFG_MRM_DIS) ; 6577279Sgblack@eecs.umich.edu if (reg & CFG_MWI_DIS) ; 6587279Sgblack@eecs.umich.edu 6597279Sgblack@eecs.umich.edu if (reg & CFG_T64ADDR) 6607279Sgblack@eecs.umich.edu panic("CFG_T64ADDR is read only register!\n"); 6617279Sgblack@eecs.umich.edu 6627303Sgblack@eecs.umich.edu if (reg & CFG_PCI64_DET) 6637303Sgblack@eecs.umich.edu panic("CFG_PCI64_DET is read only register!\n"); 6647303Sgblack@eecs.umich.edu 6657303Sgblack@eecs.umich.edu if (reg & CFG_DATA64_EN) ; 6667303Sgblack@eecs.umich.edu if (reg & CFG_M64ADDR) ; 6677303Sgblack@eecs.umich.edu if (reg & CFG_PHY_RST) ; 6687303Sgblack@eecs.umich.edu if (reg & CFG_PHY_DIS) ; 6697303Sgblack@eecs.umich.edu#endif 6707303Sgblack@eecs.umich.edu 6717303Sgblack@eecs.umich.edu if (reg & CFG_EXTSTS_EN) 6727303Sgblack@eecs.umich.edu extstsEnable = true; 6737303Sgblack@eecs.umich.edu else 6747303Sgblack@eecs.umich.edu extstsEnable = false; 6757303Sgblack@eecs.umich.edu 6767303Sgblack@eecs.umich.edu#if 0 6777303Sgblack@eecs.umich.edu if (reg & CFG_REQALG) ; 6787303Sgblack@eecs.umich.edu if (reg & CFG_SB) ; 6797303Sgblack@eecs.umich.edu if (reg & CFG_POW) ; 6807303Sgblack@eecs.umich.edu if (reg & CFG_EXD) ; 6817303Sgblack@eecs.umich.edu if (reg & CFG_PESEL) ; 6827303Sgblack@eecs.umich.edu if (reg & CFG_BROM_DIS) ; 6837119Sgblack@eecs.umich.edu if (reg & CFG_EXT_125) ; 6847119Sgblack@eecs.umich.edu if (reg & CFG_BEM) ; 6857119Sgblack@eecs.umich.edu#endif 6867119Sgblack@eecs.umich.edu break; 6877119Sgblack@eecs.umich.edu 6887119Sgblack@eecs.umich.edu case MEAR: 6897119Sgblack@eecs.umich.edu regs.mear = reg; 6907119Sgblack@eecs.umich.edu // since phy is completely faked, MEAR_MD* don't matter 6917119Sgblack@eecs.umich.edu // and since the driver never uses MEAR_EE*, they don't 6927119Sgblack@eecs.umich.edu // matter 6937119Sgblack@eecs.umich.edu#if 0 6947119Sgblack@eecs.umich.edu if (reg & MEAR_EEDI) ; 6957119Sgblack@eecs.umich.edu if (reg & MEAR_EEDO) ; // this one is read only 6967119Sgblack@eecs.umich.edu if (reg & MEAR_EECLK) ; 6977119Sgblack@eecs.umich.edu if (reg & MEAR_EESEL) ; 6987119Sgblack@eecs.umich.edu if (reg & MEAR_MDIO) ; 6997119Sgblack@eecs.umich.edu if (reg & MEAR_MDDIR) ; 70010037SARM gem5 Developers if (reg & MEAR_MDC) ; 70110037SARM gem5 Developers#endif 70210037SARM gem5 Developers break; 70310037SARM gem5 Developers 70410037SARM gem5 Developers case PTSCR: 7057119Sgblack@eecs.umich.edu regs.ptscr = reg & ~(PTSCR_RBIST_RDONLY); 7067119Sgblack@eecs.umich.edu // these control BISTs for various parts of chip - we 7077119Sgblack@eecs.umich.edu // don't care or do just fake that the BIST is done 7087303Sgblack@eecs.umich.edu if (reg & PTSCR_RBIST_EN) 7097303Sgblack@eecs.umich.edu regs.ptscr |= PTSCR_RBIST_DONE; 7107303Sgblack@eecs.umich.edu if (reg & PTSCR_EEBIST_EN) 7117303Sgblack@eecs.umich.edu regs.ptscr &= ~PTSCR_EEBIST_EN; 7127303Sgblack@eecs.umich.edu if (reg & PTSCR_EELOAD_EN) 7137303Sgblack@eecs.umich.edu regs.ptscr &= ~PTSCR_EELOAD_EN; 7147303Sgblack@eecs.umich.edu break; 7157303Sgblack@eecs.umich.edu 7167303Sgblack@eecs.umich.edu case ISR: /* writing to the ISR has no effect */ 7177303Sgblack@eecs.umich.edu panic("ISR is a read only register!\n"); 7187303Sgblack@eecs.umich.edu 7197303Sgblack@eecs.umich.edu case IMR: 7207303Sgblack@eecs.umich.edu regs.imr = reg; 7217303Sgblack@eecs.umich.edu devIntrChangeMask(); 7227303Sgblack@eecs.umich.edu break; 7237303Sgblack@eecs.umich.edu 7247303Sgblack@eecs.umich.edu case IER: 7257303Sgblack@eecs.umich.edu regs.ier = reg; 7267303Sgblack@eecs.umich.edu break; 7277303Sgblack@eecs.umich.edu 7287303Sgblack@eecs.umich.edu case IHR: 7297646Sgene.wu@arm.com regs.ihr = reg; 7307279Sgblack@eecs.umich.edu /* not going to implement real interrupt holdoff */ 7317279Sgblack@eecs.umich.edu break; 7327279Sgblack@eecs.umich.edu 7337279Sgblack@eecs.umich.edu case TXDP: 7347279Sgblack@eecs.umich.edu regs.txdp = (reg & 0xFFFFFFFC); 7357279Sgblack@eecs.umich.edu assert(txState == txIdle); 7367279Sgblack@eecs.umich.edu CTDD = false; 7377279Sgblack@eecs.umich.edu break; 7387279Sgblack@eecs.umich.edu 7397279Sgblack@eecs.umich.edu case TXDP_HI: 7407279Sgblack@eecs.umich.edu regs.txdp_hi = reg; 7417279Sgblack@eecs.umich.edu break; 7427279Sgblack@eecs.umich.edu 7437279Sgblack@eecs.umich.edu case TXCFG: 7447279Sgblack@eecs.umich.edu regs.txcfg = reg; 7457279Sgblack@eecs.umich.edu#if 0 7467279Sgblack@eecs.umich.edu if (reg & TXCFG_CSI) ; 7477279Sgblack@eecs.umich.edu if (reg & TXCFG_HBI) ; 7487279Sgblack@eecs.umich.edu if (reg & TXCFG_MLB) ; 7497279Sgblack@eecs.umich.edu if (reg & TXCFG_ATP) ; 7507279Sgblack@eecs.umich.edu if (reg & TXCFG_ECRETRY) { 7517279Sgblack@eecs.umich.edu /* 7527646Sgene.wu@arm.com * this could easily be implemented, but considering 7537119Sgblack@eecs.umich.edu * the network is just a fake pipe, wouldn't make 7547119Sgblack@eecs.umich.edu * sense to do this 7557119Sgblack@eecs.umich.edu */ 7567119Sgblack@eecs.umich.edu } 7577119Sgblack@eecs.umich.edu 7587119Sgblack@eecs.umich.edu if (reg & TXCFG_BRST_DIS) ; 7597119Sgblack@eecs.umich.edu#endif 7607119Sgblack@eecs.umich.edu 7617119Sgblack@eecs.umich.edu#if 0 7627119Sgblack@eecs.umich.edu /* we handle our own DMA, ignore the kernel's exhortations */ 7637119Sgblack@eecs.umich.edu if (reg & TXCFG_MXDMA) ; 7647119Sgblack@eecs.umich.edu#endif 7657119Sgblack@eecs.umich.edu 7667119Sgblack@eecs.umich.edu // also, we currently don't care about fill/drain 7677119Sgblack@eecs.umich.edu // thresholds though this may change in the future with 7687119Sgblack@eecs.umich.edu // more realistic networks or a driver which changes it 7697119Sgblack@eecs.umich.edu // according to feedback 7707119Sgblack@eecs.umich.edu 77110037SARM gem5 Developers break; 77210037SARM gem5 Developers 77310037SARM gem5 Developers case GPIOR: 77410037SARM gem5 Developers regs.gpior = reg; 77510037SARM gem5 Developers /* these just control general purpose i/o pins, don't matter */ 7767119Sgblack@eecs.umich.edu break; 7777119Sgblack@eecs.umich.edu 7787119Sgblack@eecs.umich.edu case RXDP: 7797646Sgene.wu@arm.com regs.rxdp = reg; 7807646Sgene.wu@arm.com CRDD = false; 7817646Sgene.wu@arm.com break; 7827646Sgene.wu@arm.com 7837646Sgene.wu@arm.com case RXDP_HI: 7847646Sgene.wu@arm.com regs.rxdp_hi = reg; 7857646Sgene.wu@arm.com break; 7867646Sgene.wu@arm.com 7877646Sgene.wu@arm.com case RXCFG: 7887646Sgene.wu@arm.com regs.rxcfg = reg; 7897646Sgene.wu@arm.com#if 0 7907646Sgene.wu@arm.com if (reg & RXCFG_AEP) ; 7917646Sgene.wu@arm.com if (reg & RXCFG_ARP) ; 7927646Sgene.wu@arm.com if (reg & RXCFG_STRIPCRC) ; 7937646Sgene.wu@arm.com if (reg & RXCFG_RX_RD) ; 7947646Sgene.wu@arm.com if (reg & RXCFG_ALP) ; 7957646Sgene.wu@arm.com if (reg & RXCFG_AIRL) ; 7967646Sgene.wu@arm.com 7977646Sgene.wu@arm.com /* we handle our own DMA, ignore what kernel says about it */ 7987646Sgene.wu@arm.com if (reg & RXCFG_MXDMA) ; 7997646Sgene.wu@arm.com 8007646Sgene.wu@arm.com //also, we currently don't care about fill/drain thresholds 8017646Sgene.wu@arm.com //though this may change in the future with more realistic 8027646Sgene.wu@arm.com //networks or a driver which changes it according to feedback 8037646Sgene.wu@arm.com if (reg & (RXCFG_DRTH | RXCFG_DRTH0)) ; 8047646Sgene.wu@arm.com#endif 8057646Sgene.wu@arm.com break; 8067646Sgene.wu@arm.com 8077646Sgene.wu@arm.com case PQCR: 8087646Sgene.wu@arm.com /* there is no priority queueing used in the linux 2.6 driver */ 8097646Sgene.wu@arm.com regs.pqcr = reg; 8107646Sgene.wu@arm.com break; 8117646Sgene.wu@arm.com 8127646Sgene.wu@arm.com case WCSR: 8137646Sgene.wu@arm.com /* not going to implement wake on LAN */ 8147646Sgene.wu@arm.com regs.wcsr = reg; 8157646Sgene.wu@arm.com break; 8167646Sgene.wu@arm.com 8177646Sgene.wu@arm.com case PCR: 8187646Sgene.wu@arm.com /* not going to implement pause control */ 8197646Sgene.wu@arm.com regs.pcr = reg; 8207646Sgene.wu@arm.com break; 82110037SARM gem5 Developers 82210037SARM gem5 Developers case RFCR: 82310037SARM gem5 Developers regs.rfcr = reg; 82410037SARM gem5 Developers 82510037SARM gem5 Developers rxFilterEnable = (reg & RFCR_RFEN) ? true : false; 8267646Sgene.wu@arm.com acceptBroadcast = (reg & RFCR_AAB) ? true : false; 8277646Sgene.wu@arm.com acceptMulticast = (reg & RFCR_AAM) ? true : false; 8287646Sgene.wu@arm.com acceptUnicast = (reg & RFCR_AAU) ? true : false; 8297646Sgene.wu@arm.com acceptPerfect = (reg & RFCR_APM) ? true : false; 8307646Sgene.wu@arm.com acceptArp = (reg & RFCR_AARP) ? true : false; 8317646Sgene.wu@arm.com 8327646Sgene.wu@arm.com#if 0 8337646Sgene.wu@arm.com if (reg & RFCR_APAT) 8347646Sgene.wu@arm.com panic("RFCR_APAT not implemented!\n"); 8357646Sgene.wu@arm.com#endif 8367646Sgene.wu@arm.com 8377646Sgene.wu@arm.com if (reg & RFCR_MHEN || reg & RFCR_UHEN) 8387646Sgene.wu@arm.com panic("hash filtering not implemented!\n"); 8397646Sgene.wu@arm.com 8407646Sgene.wu@arm.com if (reg & RFCR_ULM) 8417646Sgene.wu@arm.com panic("RFCR_ULM not implemented!\n"); 8427646Sgene.wu@arm.com 8437646Sgene.wu@arm.com break; 8447646Sgene.wu@arm.com 8457646Sgene.wu@arm.com case RFDR: 84610037SARM gem5 Developers panic("the driver never writes to RFDR, something is wrong!\n"); 84710037SARM gem5 Developers 84810037SARM gem5 Developers case BRAR: 84910037SARM gem5 Developers panic("the driver never uses BRAR, something is wrong!\n"); 85010037SARM gem5 Developers 8517646Sgene.wu@arm.com case BRDR: 8527646Sgene.wu@arm.com panic("the driver never uses BRDR, something is wrong!\n"); 8537646Sgene.wu@arm.com 8547119Sgblack@eecs.umich.edu case SRR: 8557119Sgblack@eecs.umich.edu panic("SRR is read only register!\n"); 8567119Sgblack@eecs.umich.edu 8577119Sgblack@eecs.umich.edu case MIBC: 8587119Sgblack@eecs.umich.edu panic("the driver never uses MIBC, something is wrong!\n"); 8597119Sgblack@eecs.umich.edu 8607119Sgblack@eecs.umich.edu case VRCR: 8617119Sgblack@eecs.umich.edu regs.vrcr = reg; 8627291Sgblack@eecs.umich.edu break; 86310184SCurtis.Dunham@arm.com 8648140SMatt.Horsnell@arm.com case VTCR: 8658140SMatt.Horsnell@arm.com regs.vtcr = reg; 8668140SMatt.Horsnell@arm.com break; 8677291Sgblack@eecs.umich.edu 8687291Sgblack@eecs.umich.edu case VDR: 8697848SAli.Saidi@ARM.com panic("the driver never uses VDR, something is wrong!\n"); 8707848SAli.Saidi@ARM.com break; 8717848SAli.Saidi@ARM.com 8727848SAli.Saidi@ARM.com case CCSR: 8737848SAli.Saidi@ARM.com /* not going to implement clockrun stuff */ 8747646Sgene.wu@arm.com regs.ccsr = reg; 8758140SMatt.Horsnell@arm.com break; 8768140SMatt.Horsnell@arm.com 8778140SMatt.Horsnell@arm.com case TBICR: 8788140SMatt.Horsnell@arm.com regs.tbicr = reg; 8798140SMatt.Horsnell@arm.com if (reg & TBICR_MR_LOOPBACK) 8808140SMatt.Horsnell@arm.com panic("TBICR_MR_LOOPBACK never used, something wrong!\n"); 8818140SMatt.Horsnell@arm.com 8828140SMatt.Horsnell@arm.com if (reg & TBICR_MR_AN_ENABLE) { 8838140SMatt.Horsnell@arm.com regs.tanlpar = regs.tanar; 8848140SMatt.Horsnell@arm.com regs.tbisr |= (TBISR_MR_AN_COMPLETE | TBISR_MR_LINK_STATUS); 8858140SMatt.Horsnell@arm.com } 8868140SMatt.Horsnell@arm.com 8877646Sgene.wu@arm.com#if 0 8887291Sgblack@eecs.umich.edu if (reg & TBICR_MR_RESTART_AN) ; 8897291Sgblack@eecs.umich.edu#endif 8907291Sgblack@eecs.umich.edu 8917312Sgblack@eecs.umich.edu break; 89210184SCurtis.Dunham@arm.com 8937312Sgblack@eecs.umich.edu case TBISR: 8947312Sgblack@eecs.umich.edu panic("TBISR is read only register!\n"); 8957312Sgblack@eecs.umich.edu 8967312Sgblack@eecs.umich.edu case TANAR: 8977312Sgblack@eecs.umich.edu regs.tanar = reg; 8987848SAli.Saidi@ARM.com if (reg & TANAR_PS2) 8997848SAli.Saidi@ARM.com panic("this isn't used in driver, something wrong!\n"); 9007848SAli.Saidi@ARM.com 9017848SAli.Saidi@ARM.com if (reg & TANAR_PS1) 9027848SAli.Saidi@ARM.com panic("this isn't used in driver, something wrong!\n"); 9037646Sgene.wu@arm.com break; 9047646Sgene.wu@arm.com 9057646Sgene.wu@arm.com case TANLPAR: 9067646Sgene.wu@arm.com panic("this should only be written to by the fake phy!\n"); 9077724SAli.Saidi@ARM.com 9087646Sgene.wu@arm.com case TANER: 9097646Sgene.wu@arm.com panic("TANER is read only register!\n"); 9107646Sgene.wu@arm.com 9117312Sgblack@eecs.umich.edu case TESR: 9127312Sgblack@eecs.umich.edu regs.tesr = reg; 9137312Sgblack@eecs.umich.edu break; 9147205Sgblack@eecs.umich.edu 91510184SCurtis.Dunham@arm.com default: 9167205Sgblack@eecs.umich.edu panic("invalid register access daddr=%#x", daddr); 9177205Sgblack@eecs.umich.edu } 9187205Sgblack@eecs.umich.edu } else { 9197205Sgblack@eecs.umich.edu panic("Invalid Request Size"); 9207205Sgblack@eecs.umich.edu } 9217848SAli.Saidi@ARM.com 9227848SAli.Saidi@ARM.com return No_Fault; 9237848SAli.Saidi@ARM.com} 9247848SAli.Saidi@ARM.com 9257848SAli.Saidi@ARM.comvoid 9267205Sgblack@eecs.umich.eduNSGigE::devIntrPost(uint32_t interrupts) 9277205Sgblack@eecs.umich.edu{ 9287205Sgblack@eecs.umich.edu if (interrupts & ISR_RESERVE) 9297279Sgblack@eecs.umich.edu panic("Cannot set a reserved interrupt"); 93010184SCurtis.Dunham@arm.com 9317279Sgblack@eecs.umich.edu if (interrupts & ISR_NOIMPL) 9327279Sgblack@eecs.umich.edu warn("interrupt not implemented %#x\n", interrupts); 9337279Sgblack@eecs.umich.edu 9347279Sgblack@eecs.umich.edu interrupts &= ~ISR_NOIMPL; 9357279Sgblack@eecs.umich.edu regs.isr |= interrupts; 9367279Sgblack@eecs.umich.edu 9377279Sgblack@eecs.umich.edu DPRINTF(EthernetIntr, 9387848SAli.Saidi@ARM.com "interrupt written to ISR: intr=%#x isr=%#x imr=%#x\n", 9397848SAli.Saidi@ARM.com interrupts, regs.isr, regs.imr); 9407848SAli.Saidi@ARM.com 9417848SAli.Saidi@ARM.com if ((regs.isr & regs.imr)) { 9427848SAli.Saidi@ARM.com Tick when = curTick; 9437646Sgene.wu@arm.com if (!(regs.isr & regs.imr & ISR_NODELAY)) 9447646Sgene.wu@arm.com when += intrDelay; 9457646Sgene.wu@arm.com cpuIntrPost(when); 9467646Sgene.wu@arm.com } 9477724SAli.Saidi@ARM.com} 9487646Sgene.wu@arm.com 9497646Sgene.wu@arm.comvoid 9507646Sgene.wu@arm.comNSGigE::devIntrClear(uint32_t interrupts) 9517279Sgblack@eecs.umich.edu{ 9527279Sgblack@eecs.umich.edu if (interrupts & ISR_RESERVE) 9537279Sgblack@eecs.umich.edu panic("Cannot clear a reserved interrupt"); 9547303Sgblack@eecs.umich.edu 95510184SCurtis.Dunham@arm.com interrupts &= ~ISR_NOIMPL; 9567303Sgblack@eecs.umich.edu regs.isr &= ~interrupts; 9577303Sgblack@eecs.umich.edu 9587303Sgblack@eecs.umich.edu DPRINTF(EthernetIntr, 9597303Sgblack@eecs.umich.edu "interrupt cleared from ISR: intr=%x isr=%x imr=%x\n", 9607303Sgblack@eecs.umich.edu interrupts, regs.isr, regs.imr); 9617303Sgblack@eecs.umich.edu 9627303Sgblack@eecs.umich.edu if (!(regs.isr & regs.imr)) 9637303Sgblack@eecs.umich.edu cpuIntrClear(); 9647848SAli.Saidi@ARM.com} 9657848SAli.Saidi@ARM.com 9667848SAli.Saidi@ARM.comvoid 9677848SAli.Saidi@ARM.comNSGigE::devIntrChangeMask() 9687848SAli.Saidi@ARM.com{ 9697646Sgene.wu@arm.com DPRINTF(EthernetIntr, "interrupt mask changed: isr=%x imr=%x masked=%x\n", 9707646Sgene.wu@arm.com regs.isr, regs.imr, regs.isr & regs.imr); 9717646Sgene.wu@arm.com 9727646Sgene.wu@arm.com if (regs.isr & regs.imr) 9737646Sgene.wu@arm.com cpuIntrPost(curTick); 9747724SAli.Saidi@ARM.com else 9757646Sgene.wu@arm.com cpuIntrClear(); 9767646Sgene.wu@arm.com} 9777646Sgene.wu@arm.com 9787303Sgblack@eecs.umich.eduvoid 9797303Sgblack@eecs.umich.eduNSGigE::cpuIntrPost(Tick when) 9807303Sgblack@eecs.umich.edu{ 9817119Sgblack@eecs.umich.edu // If the interrupt you want to post is later than an interrupt 98210184SCurtis.Dunham@arm.com // already scheduled, just let it post in the coming one and don't 9837119Sgblack@eecs.umich.edu // schedule another. 9847119Sgblack@eecs.umich.edu // HOWEVER, must be sure that the scheduled intrTick is in the 9857119Sgblack@eecs.umich.edu // future (this was formerly the source of a bug) 9867119Sgblack@eecs.umich.edu /** 9877119Sgblack@eecs.umich.edu * @todo this warning should be removed and the intrTick code should 9887848SAli.Saidi@ARM.com * be fixed. 9897848SAli.Saidi@ARM.com */ 9907848SAli.Saidi@ARM.com if (intrTick < curTick && intrTick != 0) { 9917848SAli.Saidi@ARM.com warn("intrTick < curTick !!! intrTick=%d curTick=%d\n", 9927848SAli.Saidi@ARM.com intrTick, curTick); 9937646Sgene.wu@arm.com intrTick = 0; 9947646Sgene.wu@arm.com } 9957646Sgene.wu@arm.com assert((intrTick >= curTick) || (intrTick == 0)); 9967646Sgene.wu@arm.com if (when > intrTick && intrTick != 0) 9977724SAli.Saidi@ARM.com return; 9987646Sgene.wu@arm.com 9997646Sgene.wu@arm.com intrTick = when; 10007646Sgene.wu@arm.com 10017119Sgblack@eecs.umich.edu if (intrEvent) { 10027119Sgblack@eecs.umich.edu intrEvent->squash(); 10037119Sgblack@eecs.umich.edu intrEvent = 0; 10047303Sgblack@eecs.umich.edu } 100510184SCurtis.Dunham@arm.com 10067303Sgblack@eecs.umich.edu if (when < curTick) { 10077303Sgblack@eecs.umich.edu cpuInterrupt(); 10087303Sgblack@eecs.umich.edu } else { 10097303Sgblack@eecs.umich.edu DPRINTF(EthernetIntr, 10107303Sgblack@eecs.umich.edu "going to schedule an interrupt for intrTick=%d\n", 10117303Sgblack@eecs.umich.edu intrTick); 10127303Sgblack@eecs.umich.edu intrEvent = new IntrEvent(this, true); 10137848SAli.Saidi@ARM.com intrEvent->schedule(intrTick); 10147848SAli.Saidi@ARM.com } 10157848SAli.Saidi@ARM.com} 10167848SAli.Saidi@ARM.com 10177848SAli.Saidi@ARM.comvoid 10187646Sgene.wu@arm.comNSGigE::cpuInterrupt() 10197646Sgene.wu@arm.com{ 10207646Sgene.wu@arm.com // Don't send an interrupt if there's already one 10217646Sgene.wu@arm.com if (cpuPendingIntr) { 10227646Sgene.wu@arm.com DPRINTF(EthernetIntr, 10237724SAli.Saidi@ARM.com "would send an interrupt now, but there's already pending\n"); 10247646Sgene.wu@arm.com intrTick = 0; 10257646Sgene.wu@arm.com return; 10267646Sgene.wu@arm.com } 10277303Sgblack@eecs.umich.edu // Don't send an interrupt if it's supposed to be delayed 10287303Sgblack@eecs.umich.edu if (intrTick > curTick) { 10297303Sgblack@eecs.umich.edu DPRINTF(EthernetIntr, 10307646Sgene.wu@arm.com "an interrupt is scheduled for %d, wait til then\n", 103110184SCurtis.Dunham@arm.com intrTick); 10327279Sgblack@eecs.umich.edu return; 10337279Sgblack@eecs.umich.edu } 10347279Sgblack@eecs.umich.edu 10357279Sgblack@eecs.umich.edu // Whether or not there's a pending interrupt, we don't care about 10367279Sgblack@eecs.umich.edu // it anymore 10377279Sgblack@eecs.umich.edu intrEvent = 0; 10387279Sgblack@eecs.umich.edu intrTick = 0; 10397279Sgblack@eecs.umich.edu 10407279Sgblack@eecs.umich.edu // Send interrupt 10417848SAli.Saidi@ARM.com cpuPendingIntr = true; 10427848SAli.Saidi@ARM.com 10437848SAli.Saidi@ARM.com DPRINTF(EthernetIntr, "posting cchip interrupt\n"); 10447848SAli.Saidi@ARM.com tsunami->cchip->postDRIR(configData->config.hdr.pci0.interruptLine); 10457848SAli.Saidi@ARM.com} 10467646Sgene.wu@arm.com 10477646Sgene.wu@arm.comvoid 10487646Sgene.wu@arm.comNSGigE::cpuIntrClear() 10497646Sgene.wu@arm.com{ 10507646Sgene.wu@arm.com if (!cpuPendingIntr) 10517724SAli.Saidi@ARM.com return; 10527646Sgene.wu@arm.com 10537646Sgene.wu@arm.com cpuPendingIntr = false; 10547646Sgene.wu@arm.com 10557279Sgblack@eecs.umich.edu DPRINTF(EthernetIntr, "clearing cchip interrupt\n"); 10567279Sgblack@eecs.umich.edu tsunami->cchip->clearDRIR(configData->config.hdr.pci0.interruptLine); 10577279Sgblack@eecs.umich.edu} 10587646Sgene.wu@arm.com 105910184SCurtis.Dunham@arm.combool 10607119Sgblack@eecs.umich.eduNSGigE::cpuIntrPending() const 10617119Sgblack@eecs.umich.edu{ return cpuPendingIntr; } 10627119Sgblack@eecs.umich.edu 10637119Sgblack@eecs.umich.eduvoid 10647119Sgblack@eecs.umich.eduNSGigE::txReset() 10657119Sgblack@eecs.umich.edu{ 10667119Sgblack@eecs.umich.edu 10677119Sgblack@eecs.umich.edu DPRINTF(Ethernet, "transmit reset\n"); 10687848SAli.Saidi@ARM.com 10697848SAli.Saidi@ARM.com CTDD = false; 10707848SAli.Saidi@ARM.com txFifoAvail = maxTxFifoSize; 10717848SAli.Saidi@ARM.com txEnable = false;; 10727848SAli.Saidi@ARM.com txFragPtr = 0; 10737646Sgene.wu@arm.com assert(txDescCnt == 0); 10747646Sgene.wu@arm.com txFifo.clear(); 10757646Sgene.wu@arm.com txState = txIdle; 10767646Sgene.wu@arm.com assert(txDmaState == dmaIdle); 10777646Sgene.wu@arm.com} 10787724SAli.Saidi@ARM.com 10797646Sgene.wu@arm.comvoid 10807646Sgene.wu@arm.comNSGigE::rxReset() 10817646Sgene.wu@arm.com{ 10827119Sgblack@eecs.umich.edu DPRINTF(Ethernet, "receive reset\n"); 10837119Sgblack@eecs.umich.edu 10847646Sgene.wu@arm.com CRDD = false; 10857646Sgene.wu@arm.com assert(rxPktBytes == 0); 108610184SCurtis.Dunham@arm.com rxFifoCnt = 0; 10877646Sgene.wu@arm.com rxEnable = false; 10887646Sgene.wu@arm.com rxFragPtr = 0; 10897646Sgene.wu@arm.com assert(rxDescCnt == 0); 10907646Sgene.wu@arm.com assert(rxDmaState == dmaIdle); 10917646Sgene.wu@arm.com rxFifo.clear(); 10927646Sgene.wu@arm.com rxState = rxIdle; 10937646Sgene.wu@arm.com} 10947646Sgene.wu@arm.com 10957646Sgene.wu@arm.comvoid 10967848SAli.Saidi@ARM.comNSGigE::regsReset() 10977848SAli.Saidi@ARM.com{ 10987848SAli.Saidi@ARM.com memset(®s, 0, sizeof(regs)); 10997848SAli.Saidi@ARM.com regs.config = CFG_LNKSTS; 11007848SAli.Saidi@ARM.com regs.mear = MEAR_MDDIR | MEAR_EEDO; 11017646Sgene.wu@arm.com regs.txcfg = 0x120; // set drain threshold to 1024 bytes and 11027646Sgene.wu@arm.com // fill threshold to 32 bytes 11037646Sgene.wu@arm.com regs.rxcfg = 0x4; // set drain threshold to 16 bytes 11047646Sgene.wu@arm.com regs.srr = 0x0103; // set the silicon revision to rev B or 0x103 11057646Sgene.wu@arm.com regs.mibc = MIBC_FRZ; 11067646Sgene.wu@arm.com regs.vdr = 0x81; // set the vlan tag type to 802.1q 11077724SAli.Saidi@ARM.com regs.tesr = 0xc000; // TBI capable of both full and half duplex 11087646Sgene.wu@arm.com 11097646Sgene.wu@arm.com extstsEnable = false; 11107724SAli.Saidi@ARM.com acceptBroadcast = false; 11117646Sgene.wu@arm.com acceptMulticast = false; 11127646Sgene.wu@arm.com acceptUnicast = false; 11137646Sgene.wu@arm.com acceptPerfect = false; 11147646Sgene.wu@arm.com acceptArp = false; 11157646Sgene.wu@arm.com} 11167646Sgene.wu@arm.com 11177724SAli.Saidi@ARM.comvoid 11187646Sgene.wu@arm.comNSGigE::rxDmaReadCopy() 11197646Sgene.wu@arm.com{ 11207646Sgene.wu@arm.com assert(rxDmaState == dmaReading); 11217646Sgene.wu@arm.com 11227646Sgene.wu@arm.com physmem->dma_read((uint8_t *)rxDmaData, rxDmaAddr, rxDmaLen); 11237646Sgene.wu@arm.com rxDmaState = dmaIdle; 11247646Sgene.wu@arm.com 11257646Sgene.wu@arm.com DPRINTF(EthernetDMA, "rx dma read paddr=%#x len=%d\n", 112610184SCurtis.Dunham@arm.com rxDmaAddr, rxDmaLen); 11277646Sgene.wu@arm.com DDUMP(EthernetDMA, rxDmaData, rxDmaLen); 11287646Sgene.wu@arm.com} 11297646Sgene.wu@arm.com 11307646Sgene.wu@arm.combool 11317646Sgene.wu@arm.comNSGigE::doRxDmaRead() 11327646Sgene.wu@arm.com{ 11337646Sgene.wu@arm.com assert(rxDmaState == dmaIdle || rxDmaState == dmaReadWaiting); 11347646Sgene.wu@arm.com rxDmaState = dmaReading; 11358607Sgblack@eecs.umich.edu 11367848SAli.Saidi@ARM.com if (dmaInterface && !rxDmaFree) { 11378203SAli.Saidi@ARM.com if (dmaInterface->busy()) 11387848SAli.Saidi@ARM.com rxDmaState = dmaReadWaiting; 11397848SAli.Saidi@ARM.com else 11407848SAli.Saidi@ARM.com dmaInterface->doDMA(Read, rxDmaAddr, rxDmaLen, curTick, 11417848SAli.Saidi@ARM.com &rxDmaReadEvent, true); 11427646Sgene.wu@arm.com return true; 11437646Sgene.wu@arm.com } 11447646Sgene.wu@arm.com 11459573Ssaidi@eecs.umich.edu if (dmaReadDelay == 0 && dmaReadFactor == 0) { 11467646Sgene.wu@arm.com rxDmaReadCopy(); 11477646Sgene.wu@arm.com return false; 11487646Sgene.wu@arm.com } 11497724SAli.Saidi@ARM.com 11507646Sgene.wu@arm.com Tick factor = ((rxDmaLen + ULL(63)) >> ULL(6)) * dmaReadFactor; 11517724SAli.Saidi@ARM.com Tick start = curTick + dmaReadDelay + factor; 11527646Sgene.wu@arm.com rxDmaReadEvent.schedule(start); 11538203SAli.Saidi@ARM.com return true; 11548203SAli.Saidi@ARM.com} 11558203SAli.Saidi@ARM.com 11568203SAli.Saidi@ARM.comvoid 11578203SAli.Saidi@ARM.comNSGigE::rxDmaReadDone() 11588203SAli.Saidi@ARM.com{ 11597646Sgene.wu@arm.com assert(rxDmaState == dmaReading); 11607646Sgene.wu@arm.com rxDmaReadCopy(); 11617646Sgene.wu@arm.com 11627646Sgene.wu@arm.com // If the transmit state machine has a pending DMA, let it go first 11637724SAli.Saidi@ARM.com if (txDmaState == dmaReadWaiting || txDmaState == dmaWriteWaiting) 11647646Sgene.wu@arm.com txKick(); 11657646Sgene.wu@arm.com 11667724SAli.Saidi@ARM.com rxKick(); 11677646Sgene.wu@arm.com} 11687646Sgene.wu@arm.com 11697646Sgene.wu@arm.comvoid 11707646Sgene.wu@arm.comNSGigE::rxDmaWriteCopy() 11717646Sgene.wu@arm.com{ 11727646Sgene.wu@arm.com assert(rxDmaState == dmaWriting); 11737724SAli.Saidi@ARM.com 11747646Sgene.wu@arm.com physmem->dma_write(rxDmaAddr, (uint8_t *)rxDmaData, rxDmaLen); 11757646Sgene.wu@arm.com rxDmaState = dmaIdle; 11767646Sgene.wu@arm.com 11777646Sgene.wu@arm.com DPRINTF(EthernetDMA, "rx dma write paddr=%#x len=%d\n", 11789250SAli.Saidi@ARM.com rxDmaAddr, rxDmaLen); 11799573Ssaidi@eecs.umich.edu DDUMP(EthernetDMA, rxDmaData, rxDmaLen); 11809250SAli.Saidi@ARM.com} 11819250SAli.Saidi@ARM.com 11829250SAli.Saidi@ARM.combool 11839250SAli.Saidi@ARM.comNSGigE::doRxDmaWrite() 11849250SAli.Saidi@ARM.com{ 11859250SAli.Saidi@ARM.com assert(rxDmaState == dmaIdle || rxDmaState == dmaWriteWaiting); 11869250SAli.Saidi@ARM.com rxDmaState = dmaWriting; 11877646Sgene.wu@arm.com 11887646Sgene.wu@arm.com if (dmaInterface && !rxDmaFree) { 11897646Sgene.wu@arm.com if (dmaInterface->busy()) 11907646Sgene.wu@arm.com rxDmaState = dmaWriteWaiting; 11917646Sgene.wu@arm.com else 119210184SCurtis.Dunham@arm.com dmaInterface->doDMA(WriteInvalidate, rxDmaAddr, rxDmaLen, curTick, 11937646Sgene.wu@arm.com &rxDmaWriteEvent, true); 11947646Sgene.wu@arm.com return true; 11957646Sgene.wu@arm.com } 11967646Sgene.wu@arm.com 11977646Sgene.wu@arm.com if (dmaWriteDelay == 0 && dmaWriteFactor == 0) { 11988607Sgblack@eecs.umich.edu rxDmaWriteCopy(); 11997848SAli.Saidi@ARM.com return false; 12008203SAli.Saidi@ARM.com } 12017848SAli.Saidi@ARM.com 12027848SAli.Saidi@ARM.com Tick factor = ((rxDmaLen + ULL(63)) >> ULL(6)) * dmaWriteFactor; 12037848SAli.Saidi@ARM.com Tick start = curTick + dmaWriteDelay + factor; 12047848SAli.Saidi@ARM.com rxDmaWriteEvent.schedule(start); 12057646Sgene.wu@arm.com return true; 12067646Sgene.wu@arm.com} 12077646Sgene.wu@arm.com 12089573Ssaidi@eecs.umich.eduvoid 12097646Sgene.wu@arm.comNSGigE::rxDmaWriteDone() 12107646Sgene.wu@arm.com{ 12117724SAli.Saidi@ARM.com assert(rxDmaState == dmaWriting); 12127646Sgene.wu@arm.com rxDmaWriteCopy(); 12137724SAli.Saidi@ARM.com 12147646Sgene.wu@arm.com // If the transmit state machine has a pending DMA, let it go first 12158203SAli.Saidi@ARM.com if (txDmaState == dmaReadWaiting || txDmaState == dmaWriteWaiting) 12168203SAli.Saidi@ARM.com txKick(); 121710199SAndrew.Bardsley@arm.com 121810199SAndrew.Bardsley@arm.com rxKick(); 121910199SAndrew.Bardsley@arm.com} 122010199SAndrew.Bardsley@arm.com 122110199SAndrew.Bardsley@arm.comvoid 12228203SAli.Saidi@ARM.comNSGigE::rxKick() 122310199SAndrew.Bardsley@arm.com{ 122410199SAndrew.Bardsley@arm.com DPRINTF(EthernetSM, "receive kick rxState=%s (rxBuf.size=%d)\n", 12258203SAli.Saidi@ARM.com NsRxStateStrings[rxState], rxFifo.size()); 122610199SAndrew.Bardsley@arm.com 122710199SAndrew.Bardsley@arm.com if (rxKickTick > curTick) { 122810199SAndrew.Bardsley@arm.com DPRINTF(EthernetSM, "receive kick exiting, can't run till %d\n", 12298203SAli.Saidi@ARM.com rxKickTick); 123010199SAndrew.Bardsley@arm.com return; 123110199SAndrew.Bardsley@arm.com } 12327646Sgene.wu@arm.com 12337646Sgene.wu@arm.com next: 12347646Sgene.wu@arm.com switch(rxDmaState) { 12357724SAli.Saidi@ARM.com case dmaReadWaiting: 12367646Sgene.wu@arm.com if (doRxDmaRead()) 12377646Sgene.wu@arm.com goto exit; 12387646Sgene.wu@arm.com break; 12399250SAli.Saidi@ARM.com case dmaWriteWaiting: 12409573Ssaidi@eecs.umich.edu if (doRxDmaWrite()) 12419250SAli.Saidi@ARM.com goto exit; 12429250SAli.Saidi@ARM.com break; 12439250SAli.Saidi@ARM.com default: 12449250SAli.Saidi@ARM.com break; 12459250SAli.Saidi@ARM.com } 12469250SAli.Saidi@ARM.com 12479250SAli.Saidi@ARM.com // see state machine from spec for details 12487646Sgene.wu@arm.com // the way this works is, if you finish work on one state and can 12497646Sgene.wu@arm.com // go directly to another, you do that through jumping to the 12507646Sgene.wu@arm.com // label "next". however, if you have intermediate work, like DMA 12517646Sgene.wu@arm.com // so that you can't go to the next state yet, you go to exit and 1252 // exit the loop. however, when the DMA is done it will trigger 1253 // an event and come back to this loop. 1254 switch (rxState) { 1255 case rxIdle: 1256 if (!rxEnable) { 1257 DPRINTF(EthernetSM, "Receive Disabled! Nothing to do.\n"); 1258 goto exit; 1259 } 1260 1261 if (CRDD) { 1262 rxState = rxDescRefr; 1263 1264 rxDmaAddr = regs.rxdp & 0x3fffffff; 1265 rxDmaData = &rxDescCache + offsetof(ns_desc, link); 1266 rxDmaLen = sizeof(rxDescCache.link); 1267 rxDmaFree = dmaDescFree; 1268 1269 descDmaReads++; 1270 descDmaRdBytes += rxDmaLen; 1271 1272 if (doRxDmaRead()) 1273 goto exit; 1274 } else { 1275 rxState = rxDescRead; 1276 1277 rxDmaAddr = regs.rxdp & 0x3fffffff; 1278 rxDmaData = &rxDescCache; 1279 rxDmaLen = sizeof(ns_desc); 1280 rxDmaFree = dmaDescFree; 1281 1282 descDmaReads++; 1283 descDmaRdBytes += rxDmaLen; 1284 1285 if (doRxDmaRead()) 1286 goto exit; 1287 } 1288 break; 1289 1290 case rxDescRefr: 1291 if (rxDmaState != dmaIdle) 1292 goto exit; 1293 1294 rxState = rxAdvance; 1295 break; 1296 1297 case rxDescRead: 1298 if (rxDmaState != dmaIdle) 1299 goto exit; 1300 1301 DPRINTF(EthernetDesc, 1302 "rxDescCache: addr=%08x read descriptor\n", 1303 regs.rxdp & 0x3fffffff); 1304 DPRINTF(EthernetDesc, 1305 "rxDescCache: link=%08x bufptr=%08x cmdsts=%08x extsts=%08x\n", 1306 rxDescCache.link, rxDescCache.bufptr, rxDescCache.cmdsts, 1307 rxDescCache.extsts); 1308 1309 if (rxDescCache.cmdsts & CMDSTS_OWN) { 1310 devIntrPost(ISR_RXIDLE); 1311 rxState = rxIdle; 1312 goto exit; 1313 } else { 1314 rxState = rxFifoBlock; 1315 rxFragPtr = rxDescCache.bufptr; 1316 rxDescCnt = rxDescCache.cmdsts & CMDSTS_LEN_MASK; 1317 } 1318 break; 1319 1320 case rxFifoBlock: 1321 if (!rxPacket) { 1322 /** 1323 * @todo in reality, we should be able to start processing 1324 * the packet as it arrives, and not have to wait for the 1325 * full packet ot be in the receive fifo. 1326 */ 1327 if (rxFifo.empty()) 1328 goto exit; 1329 1330 DPRINTF(EthernetSM, "****processing receive of new packet****\n"); 1331 1332 // If we don't have a packet, grab a new one from the fifo. 1333 rxPacket = rxFifo.front(); 1334 rxPktBytes = rxPacket->length; 1335 rxPacketBufPtr = rxPacket->data; 1336 1337#if TRACING_ON 1338 if (DTRACE(Ethernet)) { 1339 if (rxPacket->isIpPkt()) { 1340 ip_header *ip = rxPacket->getIpHdr(); 1341 DPRINTF(Ethernet, "ID is %d\n", reverseEnd16(ip->ID)); 1342 if (rxPacket->isTcpPkt()) { 1343 tcp_header *tcp = rxPacket->getTcpHdr(ip); 1344 DPRINTF(Ethernet, "Src Port=%d, Dest Port=%d\n", 1345 reverseEnd16(tcp->src_port_num), 1346 reverseEnd16(tcp->dest_port_num)); 1347 } 1348 } 1349 } 1350#endif 1351 1352 // sanity check - i think the driver behaves like this 1353 assert(rxDescCnt >= rxPktBytes); 1354 1355 // Must clear the value before popping to decrement the 1356 // reference count 1357 rxFifo.front() = NULL; 1358 rxFifo.pop_front(); 1359 rxFifoCnt -= rxPacket->length; 1360 } 1361 1362 1363 // dont' need the && rxDescCnt > 0 if driver sanity check 1364 // above holds 1365 if (rxPktBytes > 0) { 1366 rxState = rxFragWrite; 1367 // don't need min<>(rxPktBytes,rxDescCnt) if above sanity 1368 // check holds 1369 rxXferLen = rxPktBytes; 1370 1371 rxDmaAddr = rxFragPtr & 0x3fffffff; 1372 rxDmaData = rxPacketBufPtr; 1373 rxDmaLen = rxXferLen; 1374 rxDmaFree = dmaDataFree; 1375 1376 if (doRxDmaWrite()) 1377 goto exit; 1378 1379 } else { 1380 rxState = rxDescWrite; 1381 1382 //if (rxPktBytes == 0) { /* packet is done */ 1383 assert(rxPktBytes == 0); 1384 DPRINTF(EthernetSM, "done with receiving packet\n"); 1385 1386 rxDescCache.cmdsts |= CMDSTS_OWN; 1387 rxDescCache.cmdsts &= ~CMDSTS_MORE; 1388 rxDescCache.cmdsts |= CMDSTS_OK; 1389 rxDescCache.cmdsts &= 0xffff0000; 1390 rxDescCache.cmdsts += rxPacket->length; //i.e. set CMDSTS_SIZE 1391 1392#if 0 1393 /* 1394 * all the driver uses these are for its own stats keeping 1395 * which we don't care about, aren't necessary for 1396 * functionality and doing this would just slow us down. 1397 * if they end up using this in a later version for 1398 * functional purposes, just undef 1399 */ 1400 if (rxFilterEnable) { 1401 rxDescCache.cmdsts &= ~CMDSTS_DEST_MASK; 1402 if (rxFifo.front()->IsUnicast()) 1403 rxDescCache.cmdsts |= CMDSTS_DEST_SELF; 1404 if (rxFifo.front()->IsMulticast()) 1405 rxDescCache.cmdsts |= CMDSTS_DEST_MULTI; 1406 if (rxFifo.front()->IsBroadcast()) 1407 rxDescCache.cmdsts |= CMDSTS_DEST_MASK; 1408 } 1409#endif 1410 1411 if (rxPacket->isIpPkt() && extstsEnable) { 1412 rxDescCache.extsts |= EXTSTS_IPPKT; 1413 rxIPChecksums++; 1414 if (!ipChecksum(rxPacket, false)) { 1415 DPRINTF(EthernetCksum, "Rx IP Checksum Error\n"); 1416 rxDescCache.extsts |= EXTSTS_IPERR; 1417 } 1418 if (rxPacket->isTcpPkt()) { 1419 rxDescCache.extsts |= EXTSTS_TCPPKT; 1420 rxTCPChecksums++; 1421 if (!tcpChecksum(rxPacket, false)) { 1422 DPRINTF(EthernetCksum, "Rx TCP Checksum Error\n"); 1423 rxDescCache.extsts |= EXTSTS_TCPERR; 1424 1425 } 1426 } else if (rxPacket->isUdpPkt()) { 1427 rxDescCache.extsts |= EXTSTS_UDPPKT; 1428 if (!udpChecksum(rxPacket, false)) { 1429 DPRINTF(EthernetCksum, "Rx UDP Checksum Error\n"); 1430 rxDescCache.extsts |= EXTSTS_UDPERR; 1431 } 1432 } 1433 } 1434 rxPacket = 0; 1435 1436 /* 1437 * the driver seems to always receive into desc buffers 1438 * of size 1514, so you never have a pkt that is split 1439 * into multiple descriptors on the receive side, so 1440 * i don't implement that case, hence the assert above. 1441 */ 1442 1443 DPRINTF(EthernetDesc, 1444 "rxDescCache: addr=%08x writeback cmdsts extsts\n", 1445 regs.rxdp & 0x3fffffff); 1446 DPRINTF(EthernetDesc, 1447 "rxDescCache: link=%08x bufptr=%08x cmdsts=%08x extsts=%08x\n", 1448 rxDescCache.link, rxDescCache.bufptr, rxDescCache.cmdsts, 1449 rxDescCache.extsts); 1450 1451 rxDmaAddr = (regs.rxdp + offsetof(ns_desc, cmdsts)) & 0x3fffffff; 1452 rxDmaData = &(rxDescCache.cmdsts); 1453 rxDmaLen = sizeof(rxDescCache.cmdsts) + sizeof(rxDescCache.extsts); 1454 rxDmaFree = dmaDescFree; 1455 1456 descDmaWrites++; 1457 descDmaWrBytes += rxDmaLen; 1458 1459 if (doRxDmaWrite()) 1460 goto exit; 1461 } 1462 break; 1463 1464 case rxFragWrite: 1465 if (rxDmaState != dmaIdle) 1466 goto exit; 1467 1468 rxPacketBufPtr += rxXferLen; 1469 rxFragPtr += rxXferLen; 1470 rxPktBytes -= rxXferLen; 1471 1472 rxState = rxFifoBlock; 1473 break; 1474 1475 case rxDescWrite: 1476 if (rxDmaState != dmaIdle) 1477 goto exit; 1478 1479 assert(rxDescCache.cmdsts & CMDSTS_OWN); 1480 1481 assert(rxPacket == 0); 1482 devIntrPost(ISR_RXOK); 1483 1484 if (rxDescCache.cmdsts & CMDSTS_INTR) 1485 devIntrPost(ISR_RXDESC); 1486 1487 if (!rxEnable) { 1488 DPRINTF(EthernetSM, "Halting the RX state machine\n"); 1489 rxState = rxIdle; 1490 goto exit; 1491 } else 1492 rxState = rxAdvance; 1493 break; 1494 1495 case rxAdvance: 1496 if (rxDescCache.link == 0) { 1497 devIntrPost(ISR_RXIDLE); 1498 rxState = rxIdle; 1499 CRDD = true; 1500 goto exit; 1501 } else { 1502 rxState = rxDescRead; 1503 regs.rxdp = rxDescCache.link; 1504 CRDD = false; 1505 1506 rxDmaAddr = regs.rxdp & 0x3fffffff; 1507 rxDmaData = &rxDescCache; 1508 rxDmaLen = sizeof(ns_desc); 1509 rxDmaFree = dmaDescFree; 1510 1511 if (doRxDmaRead()) 1512 goto exit; 1513 } 1514 break; 1515 1516 default: 1517 panic("Invalid rxState!"); 1518 } 1519 1520 DPRINTF(EthernetSM, "entering next rxState=%s\n", 1521 NsRxStateStrings[rxState]); 1522 1523 goto next; 1524 1525 exit: 1526 /** 1527 * @todo do we want to schedule a future kick? 1528 */ 1529 DPRINTF(EthernetSM, "rx state machine exited rxState=%s\n", 1530 NsRxStateStrings[rxState]); 1531} 1532 1533void 1534NSGigE::transmit() 1535{ 1536 if (txFifo.empty()) { 1537 DPRINTF(Ethernet, "nothing to transmit\n"); 1538 return; 1539 } 1540 1541 DPRINTF(Ethernet, "Attempt Pkt Transmit: txFifo length=%d\n", 1542 maxTxFifoSize - txFifoAvail); 1543 if (interface->sendPacket(txFifo.front())) { 1544#if TRACING_ON 1545 if (DTRACE(Ethernet)) { 1546 if (txFifo.front()->isIpPkt()) { 1547 ip_header *ip = txFifo.front()->getIpHdr(); 1548 DPRINTF(Ethernet, "ID is %d\n", reverseEnd16(ip->ID)); 1549 if (txFifo.front()->isTcpPkt()) { 1550 tcp_header *tcp = txFifo.front()->getTcpHdr(ip); 1551 DPRINTF(Ethernet, "Src Port=%d, Dest Port=%d\n", 1552 reverseEnd16(tcp->src_port_num), 1553 reverseEnd16(tcp->dest_port_num)); 1554 } 1555 } 1556 } 1557#endif 1558 1559 DDUMP(Ethernet, txFifo.front()->data, txFifo.front()->length); 1560 txBytes += txFifo.front()->length; 1561 txPackets++; 1562 1563 txFifoAvail += txFifo.front()->length; 1564 1565 DPRINTF(Ethernet, "Successful Xmit! now txFifoAvail is %d\n", 1566 txFifoAvail); 1567 txFifo.front() = NULL; 1568 txFifo.pop_front(); 1569 1570 /* 1571 * normally do a writeback of the descriptor here, and ONLY 1572 * after that is done, send this interrupt. but since our 1573 * stuff never actually fails, just do this interrupt here, 1574 * otherwise the code has to stray from this nice format. 1575 * besides, it's functionally the same. 1576 */ 1577 devIntrPost(ISR_TXOK); 1578 } else { 1579 DPRINTF(Ethernet, 1580 "May need to rethink always sending the descriptors back?\n"); 1581 } 1582 1583 if (!txFifo.empty() && !txEvent.scheduled()) { 1584 DPRINTF(Ethernet, "reschedule transmit\n"); 1585 txEvent.schedule(curTick + 1000); 1586 } 1587} 1588 1589void 1590NSGigE::txDmaReadCopy() 1591{ 1592 assert(txDmaState == dmaReading); 1593 1594 physmem->dma_read((uint8_t *)txDmaData, txDmaAddr, txDmaLen); 1595 txDmaState = dmaIdle; 1596 1597 DPRINTF(EthernetDMA, "tx dma read paddr=%#x len=%d\n", 1598 txDmaAddr, txDmaLen); 1599 DDUMP(EthernetDMA, txDmaData, txDmaLen); 1600} 1601 1602bool 1603NSGigE::doTxDmaRead() 1604{ 1605 assert(txDmaState == dmaIdle || txDmaState == dmaReadWaiting); 1606 txDmaState = dmaReading; 1607 1608 if (dmaInterface && !txDmaFree) { 1609 if (dmaInterface->busy()) 1610 txDmaState = dmaReadWaiting; 1611 else 1612 dmaInterface->doDMA(Read, txDmaAddr, txDmaLen, curTick, 1613 &txDmaReadEvent, true); 1614 return true; 1615 } 1616 1617 if (dmaReadDelay == 0 && dmaReadFactor == 0.0) { 1618 txDmaReadCopy(); 1619 return false; 1620 } 1621 1622 Tick factor = ((txDmaLen + ULL(63)) >> ULL(6)) * dmaReadFactor; 1623 Tick start = curTick + dmaReadDelay + factor; 1624 txDmaReadEvent.schedule(start); 1625 return true; 1626} 1627 1628void 1629NSGigE::txDmaReadDone() 1630{ 1631 assert(txDmaState == dmaReading); 1632 txDmaReadCopy(); 1633 1634 // If the receive state machine has a pending DMA, let it go first 1635 if (rxDmaState == dmaReadWaiting || rxDmaState == dmaWriteWaiting) 1636 rxKick(); 1637 1638 txKick(); 1639} 1640 1641void 1642NSGigE::txDmaWriteCopy() 1643{ 1644 assert(txDmaState == dmaWriting); 1645 1646 physmem->dma_write(txDmaAddr, (uint8_t *)txDmaData, txDmaLen); 1647 txDmaState = dmaIdle; 1648 1649 DPRINTF(EthernetDMA, "tx dma write paddr=%#x len=%d\n", 1650 txDmaAddr, txDmaLen); 1651 DDUMP(EthernetDMA, txDmaData, txDmaLen); 1652} 1653 1654bool 1655NSGigE::doTxDmaWrite() 1656{ 1657 assert(txDmaState == dmaIdle || txDmaState == dmaWriteWaiting); 1658 txDmaState = dmaWriting; 1659 1660 if (dmaInterface && !txDmaFree) { 1661 if (dmaInterface->busy()) 1662 txDmaState = dmaWriteWaiting; 1663 else 1664 dmaInterface->doDMA(WriteInvalidate, txDmaAddr, txDmaLen, curTick, 1665 &txDmaWriteEvent, true); 1666 return true; 1667 } 1668 1669 if (dmaWriteDelay == 0 && dmaWriteFactor == 0.0) { 1670 txDmaWriteCopy(); 1671 return false; 1672 } 1673 1674 Tick factor = ((txDmaLen + ULL(63)) >> ULL(6)) * dmaWriteFactor; 1675 Tick start = curTick + dmaWriteDelay + factor; 1676 txDmaWriteEvent.schedule(start); 1677 return true; 1678} 1679 1680void 1681NSGigE::txDmaWriteDone() 1682{ 1683 assert(txDmaState == dmaWriting); 1684 txDmaWriteCopy(); 1685 1686 // If the receive state machine has a pending DMA, let it go first 1687 if (rxDmaState == dmaReadWaiting || rxDmaState == dmaWriteWaiting) 1688 rxKick(); 1689 1690 txKick(); 1691} 1692 1693void 1694NSGigE::txKick() 1695{ 1696 DPRINTF(EthernetSM, "transmit kick txState=%s\n", 1697 NsTxStateStrings[txState]); 1698 1699 if (txKickTick > curTick) { 1700 DPRINTF(EthernetSM, "transmit kick exiting, can't run till %d\n", 1701 txKickTick); 1702 1703 return; 1704 } 1705 1706 next: 1707 switch(txDmaState) { 1708 case dmaReadWaiting: 1709 if (doTxDmaRead()) 1710 goto exit; 1711 break; 1712 case dmaWriteWaiting: 1713 if (doTxDmaWrite()) 1714 goto exit; 1715 break; 1716 default: 1717 break; 1718 } 1719 1720 switch (txState) { 1721 case txIdle: 1722 if (!txEnable) { 1723 DPRINTF(EthernetSM, "Transmit disabled. Nothing to do.\n"); 1724 goto exit; 1725 } 1726 1727 if (CTDD) { 1728 txState = txDescRefr; 1729 1730 txDmaAddr = regs.txdp & 0x3fffffff; 1731 txDmaData = &txDescCache + offsetof(ns_desc, link); 1732 txDmaLen = sizeof(txDescCache.link); 1733 txDmaFree = dmaDescFree; 1734 1735 descDmaReads++; 1736 descDmaRdBytes += txDmaLen; 1737 1738 if (doTxDmaRead()) 1739 goto exit; 1740 1741 } else { 1742 txState = txDescRead; 1743 1744 txDmaAddr = regs.txdp & 0x3fffffff; 1745 txDmaData = &txDescCache; 1746 txDmaLen = sizeof(ns_desc); 1747 txDmaFree = dmaDescFree; 1748 1749 descDmaReads++; 1750 descDmaRdBytes += txDmaLen; 1751 1752 if (doTxDmaRead()) 1753 goto exit; 1754 } 1755 break; 1756 1757 case txDescRefr: 1758 if (txDmaState != dmaIdle) 1759 goto exit; 1760 1761 txState = txAdvance; 1762 break; 1763 1764 case txDescRead: 1765 if (txDmaState != dmaIdle) 1766 goto exit; 1767 1768 DPRINTF(EthernetDesc, 1769 "txDescCache: link=%08x bufptr=%08x cmdsts=%08x extsts=%08x\n", 1770 txDescCache.link, txDescCache.bufptr, txDescCache.cmdsts, 1771 txDescCache.extsts); 1772 1773 if (txDescCache.cmdsts & CMDSTS_OWN) { 1774 txState = txFifoBlock; 1775 txFragPtr = txDescCache.bufptr; 1776 txDescCnt = txDescCache.cmdsts & CMDSTS_LEN_MASK; 1777 } else { 1778 devIntrPost(ISR_TXIDLE); 1779 txState = txIdle; 1780 goto exit; 1781 } 1782 break; 1783 1784 case txFifoBlock: 1785 if (!txPacket) { 1786 DPRINTF(EthernetSM, "****starting the tx of a new packet****\n"); 1787 txPacket = new EtherPacket; 1788 txPacket->data = new uint8_t[16384]; 1789 txPacketBufPtr = txPacket->data; 1790 } 1791 1792 if (txDescCnt == 0) { 1793 DPRINTF(EthernetSM, "the txDescCnt == 0, done with descriptor\n"); 1794 if (txDescCache.cmdsts & CMDSTS_MORE) { 1795 DPRINTF(EthernetSM, "there are more descriptors to come\n"); 1796 txState = txDescWrite; 1797 1798 txDescCache.cmdsts &= ~CMDSTS_OWN; 1799 1800 txDmaAddr = regs.txdp + offsetof(ns_desc, cmdsts); 1801 txDmaAddr &= 0x3fffffff; 1802 txDmaData = &(txDescCache.cmdsts); 1803 txDmaLen = sizeof(txDescCache.cmdsts); 1804 txDmaFree = dmaDescFree; 1805 1806 if (doTxDmaWrite()) 1807 goto exit; 1808 1809 } else { /* this packet is totally done */ 1810 DPRINTF(EthernetSM, "This packet is done, let's wrap it up\n"); 1811 /* deal with the the packet that just finished */ 1812 if ((regs.vtcr & VTCR_PPCHK) && extstsEnable) { 1813 if (txDescCache.extsts & EXTSTS_UDPPKT) { 1814 udpChecksum(txPacket, true); 1815 } else if (txDescCache.extsts & EXTSTS_TCPPKT) { 1816 tcpChecksum(txPacket, true); 1817 txTCPChecksums++; 1818 } 1819 if (txDescCache.extsts & EXTSTS_IPPKT) { 1820 ipChecksum(txPacket, true); 1821 txIPChecksums++; 1822 } 1823 } 1824 1825 txPacket->length = txPacketBufPtr - txPacket->data; 1826 // this is just because the receive can't handle a 1827 // packet bigger want to make sure 1828 assert(txPacket->length <= 1514); 1829 txFifo.push_back(txPacket); 1830 1831 /* 1832 * this following section is not tqo spec, but 1833 * functionally shouldn't be any different. normally, 1834 * the chip will wait til the transmit has occurred 1835 * before writing back the descriptor because it has 1836 * to wait to see that it was successfully transmitted 1837 * to decide whether to set CMDSTS_OK or not. 1838 * however, in the simulator since it is always 1839 * successfully transmitted, and writing it exactly to 1840 * spec would complicate the code, we just do it here 1841 */ 1842 1843 txDescCache.cmdsts &= ~CMDSTS_OWN; 1844 txDescCache.cmdsts |= CMDSTS_OK; 1845 1846 DPRINTF(EthernetDesc, 1847 "txDesc writeback: cmdsts=%08x extsts=%08x\n", 1848 txDescCache.cmdsts, txDescCache.extsts); 1849 1850 txDmaAddr = regs.txdp + offsetof(ns_desc, cmdsts); 1851 txDmaAddr &= 0x3fffffff; 1852 txDmaData = &(txDescCache.cmdsts); 1853 txDmaLen = sizeof(txDescCache.cmdsts) + 1854 sizeof(txDescCache.extsts); 1855 txDmaFree = dmaDescFree; 1856 1857 descDmaWrites++; 1858 descDmaWrBytes += txDmaLen; 1859 1860 transmit(); 1861 txPacket = 0; 1862 1863 if (!txEnable) { 1864 DPRINTF(EthernetSM, "halting TX state machine\n"); 1865 txState = txIdle; 1866 goto exit; 1867 } else 1868 txState = txAdvance; 1869 1870 if (doTxDmaWrite()) 1871 goto exit; 1872 } 1873 } else { 1874 DPRINTF(EthernetSM, "this descriptor isn't done yet\n"); 1875 if (txFifoAvail) { 1876 txState = txFragRead; 1877 1878 /* 1879 * The number of bytes transferred is either whatever 1880 * is left in the descriptor (txDescCnt), or if there 1881 * is not enough room in the fifo, just whatever room 1882 * is left in the fifo 1883 */ 1884 txXferLen = min<uint32_t>(txDescCnt, txFifoAvail); 1885 1886 txDmaAddr = txFragPtr & 0x3fffffff; 1887 txDmaData = txPacketBufPtr; 1888 txDmaLen = txXferLen; 1889 txDmaFree = dmaDataFree; 1890 1891 if (doTxDmaRead()) 1892 goto exit; 1893 } else { 1894 txState = txFifoBlock; 1895 transmit(); 1896 1897 goto exit; 1898 } 1899 1900 } 1901 break; 1902 1903 case txFragRead: 1904 if (txDmaState != dmaIdle) 1905 goto exit; 1906 1907 txPacketBufPtr += txXferLen; 1908 txFragPtr += txXferLen; 1909 txDescCnt -= txXferLen; 1910 txFifoAvail -= txXferLen; 1911 1912 txState = txFifoBlock; 1913 break; 1914 1915 case txDescWrite: 1916 if (txDmaState != dmaIdle) 1917 goto exit; 1918 1919 if (txDescCache.cmdsts & CMDSTS_INTR) 1920 devIntrPost(ISR_TXDESC); 1921 1922 txState = txAdvance; 1923 break; 1924 1925 case txAdvance: 1926 if (txDescCache.link == 0) { 1927 devIntrPost(ISR_TXIDLE); 1928 txState = txIdle; 1929 goto exit; 1930 } else { 1931 txState = txDescRead; 1932 regs.txdp = txDescCache.link; 1933 CTDD = false; 1934 1935 txDmaAddr = txDescCache.link & 0x3fffffff; 1936 txDmaData = &txDescCache; 1937 txDmaLen = sizeof(ns_desc); 1938 txDmaFree = dmaDescFree; 1939 1940 if (doTxDmaRead()) 1941 goto exit; 1942 } 1943 break; 1944 1945 default: 1946 panic("invalid state"); 1947 } 1948 1949 DPRINTF(EthernetSM, "entering next txState=%s\n", 1950 NsTxStateStrings[txState]); 1951 1952 goto next; 1953 1954 exit: 1955 /** 1956 * @todo do we want to schedule a future kick? 1957 */ 1958 DPRINTF(EthernetSM, "tx state machine exited txState=%s\n", 1959 NsTxStateStrings[txState]); 1960} 1961 1962void 1963NSGigE::transferDone() 1964{ 1965 if (txFifo.empty()) { 1966 DPRINTF(Ethernet, "transfer complete: txFifo empty...nothing to do\n"); 1967 return; 1968 } 1969 1970 DPRINTF(Ethernet, "transfer complete: data in txFifo...schedule xmit\n"); 1971 1972 if (txEvent.scheduled()) 1973 txEvent.reschedule(curTick + 1); 1974 else 1975 txEvent.schedule(curTick + 1); 1976} 1977 1978bool 1979NSGigE::rxFilter(PacketPtr packet) 1980{ 1981 bool drop = true; 1982 string type; 1983 1984 if (packet->IsUnicast()) { 1985 type = "unicast"; 1986 1987 // If we're accepting all unicast addresses 1988 if (acceptUnicast) 1989 drop = false; 1990 1991 // If we make a perfect match 1992 if (acceptPerfect && 1993 memcmp(rom.perfectMatch, packet->data, EADDR_LEN) == 0) 1994 drop = false; 1995 1996 eth_header *eth = (eth_header *) packet->data; 1997 if ((acceptArp) && (eth->type == 0x608)) 1998 drop = false; 1999 2000 } else if (packet->IsBroadcast()) { 2001 type = "broadcast"; 2002 2003 // if we're accepting broadcasts 2004 if (acceptBroadcast) 2005 drop = false; 2006 2007 } else if (packet->IsMulticast()) { 2008 type = "multicast"; 2009 2010 // if we're accepting all multicasts 2011 if (acceptMulticast) 2012 drop = false; 2013 2014 } else { 2015 type = "unknown"; 2016 2017 // oh well, punt on this one 2018 } 2019 2020 if (drop) { 2021 DPRINTF(Ethernet, "rxFilter drop\n"); 2022 DDUMP(EthernetData, packet->data, packet->length); 2023 } 2024 2025 return drop; 2026} 2027 2028bool 2029NSGigE::recvPacket(PacketPtr packet) 2030{ 2031 rxBytes += packet->length; 2032 rxPackets++; 2033 2034 DPRINTF(Ethernet, "Receiving packet from wire, rxFifoAvail=%d\n", 2035 maxRxFifoSize - rxFifoCnt); 2036 2037 if (!rxEnable) { 2038 DPRINTF(Ethernet, "receive disabled...packet dropped\n"); 2039 debug_break(); 2040 interface->recvDone(); 2041 return true; 2042 } 2043 2044 if (rxFilterEnable && rxFilter(packet)) { 2045 DPRINTF(Ethernet, "packet filtered...dropped\n"); 2046 interface->recvDone(); 2047 return true; 2048 } 2049 2050 if ((rxFifoCnt + packet->length) >= maxRxFifoSize) { 2051 DPRINTF(Ethernet, 2052 "packet will not fit in receive buffer...packet dropped\n"); 2053 devIntrPost(ISR_RXORN); 2054 return false; 2055 } 2056 2057 rxFifo.push_back(packet); 2058 rxFifoCnt += packet->length; 2059 interface->recvDone(); 2060 2061 rxKick(); 2062 return true; 2063} 2064 2065/** 2066 * does a udp checksum. if gen is true, then it generates it and puts 2067 * it in the right place else, it just checks what it calculates 2068 * against the value in the header in packet 2069 */ 2070bool 2071NSGigE::udpChecksum(PacketPtr packet, bool gen) 2072{ 2073 ip_header *ip = packet->getIpHdr(); 2074 udp_header *hdr = packet->getUdpHdr(ip); 2075 2076 pseudo_header *pseudo = new pseudo_header; 2077 2078 pseudo->src_ip_addr = ip->src_ip_addr; 2079 pseudo->dest_ip_addr = ip->dest_ip_addr; 2080 pseudo->protocol = ip->protocol; 2081 pseudo->len = hdr->len; 2082 2083 uint16_t cksum = checksumCalc((uint16_t *) pseudo, (uint16_t *) hdr, 2084 (uint32_t) hdr->len); 2085 2086 delete pseudo; 2087 if (gen) 2088 hdr->chksum = cksum; 2089 else 2090 if (cksum != 0) 2091 return false; 2092 2093 return true; 2094} 2095 2096bool 2097NSGigE::tcpChecksum(PacketPtr packet, bool gen) 2098{ 2099 ip_header *ip = packet->getIpHdr(); 2100 tcp_header *hdr = packet->getTcpHdr(ip); 2101 2102 uint16_t cksum; 2103 pseudo_header *pseudo = new pseudo_header; 2104 if (!gen) { 2105 pseudo->src_ip_addr = ip->src_ip_addr; 2106 pseudo->dest_ip_addr = ip->dest_ip_addr; 2107 pseudo->protocol = reverseEnd16(ip->protocol); 2108 pseudo->len = reverseEnd16(reverseEnd16(ip->dgram_len) - 2109 (ip->vers_len & 0xf)*4); 2110 2111 cksum = checksumCalc((uint16_t *) pseudo, (uint16_t *) hdr, 2112 (uint32_t) reverseEnd16(pseudo->len)); 2113 } else { 2114 pseudo->src_ip_addr = 0; 2115 pseudo->dest_ip_addr = 0; 2116 pseudo->protocol = hdr->chksum; 2117 pseudo->len = 0; 2118 hdr->chksum = 0; 2119 cksum = checksumCalc((uint16_t *) pseudo, (uint16_t *) hdr, 2120 (uint32_t) (reverseEnd16(ip->dgram_len) - 2121 (ip->vers_len & 0xf)*4)); 2122 } 2123 2124 delete pseudo; 2125 if (gen) 2126 hdr->chksum = cksum; 2127 else 2128 if (cksum != 0) 2129 return false; 2130 2131 return true; 2132} 2133 2134bool 2135NSGigE::ipChecksum(PacketPtr packet, bool gen) 2136{ 2137 ip_header *hdr = packet->getIpHdr(); 2138 2139 uint16_t cksum = checksumCalc(NULL, (uint16_t *) hdr, 2140 (hdr->vers_len & 0xf)*4); 2141 2142 if (gen) { 2143 DPRINTF(EthernetCksum, "generated checksum: %#x\n", cksum); 2144 hdr->hdr_chksum = cksum; 2145 } 2146 else 2147 if (cksum != 0) 2148 return false; 2149 2150 return true; 2151} 2152 2153uint16_t 2154NSGigE::checksumCalc(uint16_t *pseudo, uint16_t *buf, uint32_t len) 2155{ 2156 uint32_t sum = 0; 2157 2158 uint16_t last_pad = 0; 2159 if (len & 1) { 2160 last_pad = buf[len/2] & 0xff; 2161 len--; 2162 sum += last_pad; 2163 } 2164 2165 if (pseudo) { 2166 sum = pseudo[0] + pseudo[1] + pseudo[2] + 2167 pseudo[3] + pseudo[4] + pseudo[5]; 2168 } 2169 2170 for (int i=0; i < (len/2); ++i) { 2171 sum += buf[i]; 2172 } 2173 2174 while (sum >> 16) 2175 sum = (sum >> 16) + (sum & 0xffff); 2176 2177 return ~sum; 2178} 2179 2180//===================================================================== 2181// 2182// 2183void 2184NSGigE::serialize(ostream &os) 2185{ 2186 // Serialize the PciDev base class 2187 PciDev::serialize(os); 2188 2189 /* 2190 * Finalize any DMA events now. 2191 */ 2192 if (rxDmaReadEvent.scheduled()) 2193 rxDmaReadCopy(); 2194 if (rxDmaWriteEvent.scheduled()) 2195 rxDmaWriteCopy(); 2196 if (txDmaReadEvent.scheduled()) 2197 txDmaReadCopy(); 2198 if (txDmaWriteEvent.scheduled()) 2199 txDmaWriteCopy(); 2200 2201 /* 2202 * Serialize the device registers 2203 */ 2204 SERIALIZE_SCALAR(regs.command); 2205 SERIALIZE_SCALAR(regs.config); 2206 SERIALIZE_SCALAR(regs.mear); 2207 SERIALIZE_SCALAR(regs.ptscr); 2208 SERIALIZE_SCALAR(regs.isr); 2209 SERIALIZE_SCALAR(regs.imr); 2210 SERIALIZE_SCALAR(regs.ier); 2211 SERIALIZE_SCALAR(regs.ihr); 2212 SERIALIZE_SCALAR(regs.txdp); 2213 SERIALIZE_SCALAR(regs.txdp_hi); 2214 SERIALIZE_SCALAR(regs.txcfg); 2215 SERIALIZE_SCALAR(regs.gpior); 2216 SERIALIZE_SCALAR(regs.rxdp); 2217 SERIALIZE_SCALAR(regs.rxdp_hi); 2218 SERIALIZE_SCALAR(regs.rxcfg); 2219 SERIALIZE_SCALAR(regs.pqcr); 2220 SERIALIZE_SCALAR(regs.wcsr); 2221 SERIALIZE_SCALAR(regs.pcr); 2222 SERIALIZE_SCALAR(regs.rfcr); 2223 SERIALIZE_SCALAR(regs.rfdr); 2224 SERIALIZE_SCALAR(regs.srr); 2225 SERIALIZE_SCALAR(regs.mibc); 2226 SERIALIZE_SCALAR(regs.vrcr); 2227 SERIALIZE_SCALAR(regs.vtcr); 2228 SERIALIZE_SCALAR(regs.vdr); 2229 SERIALIZE_SCALAR(regs.ccsr); 2230 SERIALIZE_SCALAR(regs.tbicr); 2231 SERIALIZE_SCALAR(regs.tbisr); 2232 SERIALIZE_SCALAR(regs.tanar); 2233 SERIALIZE_SCALAR(regs.tanlpar); 2234 SERIALIZE_SCALAR(regs.taner); 2235 SERIALIZE_SCALAR(regs.tesr); 2236 2237 SERIALIZE_ARRAY(rom.perfectMatch, EADDR_LEN); 2238 2239 SERIALIZE_SCALAR(ioEnable); 2240 2241 /* 2242 * Serialize the data Fifos 2243 */ 2244 int txNumPkts = txFifo.size(); 2245 SERIALIZE_SCALAR(txNumPkts); 2246 int i = 0; 2247 pktiter_t end = txFifo.end(); 2248 for (pktiter_t p = txFifo.begin(); p != end; ++p) { 2249 nameOut(os, csprintf("%s.txFifo%d", name(), i++)); 2250 (*p)->serialize(os); 2251 } 2252 2253 int rxNumPkts = rxFifo.size(); 2254 SERIALIZE_SCALAR(rxNumPkts); 2255 i = 0; 2256 end = rxFifo.end(); 2257 for (pktiter_t p = rxFifo.begin(); p != end; ++p) { 2258 nameOut(os, csprintf("%s.rxFifo%d", name(), i++)); 2259 (*p)->serialize(os); 2260 } 2261 2262 /* 2263 * Serialize the various helper variables 2264 */ 2265 bool txPacketExists = txPacket; 2266 SERIALIZE_SCALAR(txPacketExists); 2267 if (txPacketExists) { 2268 nameOut(os, csprintf("%s.txPacket", name())); 2269 txPacket->serialize(os); 2270 uint32_t txPktBufPtr = (uint32_t) (txPacketBufPtr - txPacket->data); 2271 SERIALIZE_SCALAR(txPktBufPtr); 2272 } 2273 2274 bool rxPacketExists = rxPacket; 2275 SERIALIZE_SCALAR(rxPacketExists); 2276 if (rxPacketExists) { 2277 nameOut(os, csprintf("%s.rxPacket", name())); 2278 rxPacket->serialize(os); 2279 uint32_t rxPktBufPtr = (uint32_t) (rxPacketBufPtr - rxPacket->data); 2280 SERIALIZE_SCALAR(rxPktBufPtr); 2281 } 2282 2283 SERIALIZE_SCALAR(txXferLen); 2284 SERIALIZE_SCALAR(rxXferLen); 2285 2286 /* 2287 * Serialize DescCaches 2288 */ 2289 SERIALIZE_SCALAR(txDescCache.link); 2290 SERIALIZE_SCALAR(txDescCache.bufptr); 2291 SERIALIZE_SCALAR(txDescCache.cmdsts); 2292 SERIALIZE_SCALAR(txDescCache.extsts); 2293 SERIALIZE_SCALAR(rxDescCache.link); 2294 SERIALIZE_SCALAR(rxDescCache.bufptr); 2295 SERIALIZE_SCALAR(rxDescCache.cmdsts); 2296 SERIALIZE_SCALAR(rxDescCache.extsts); 2297 2298 /* 2299 * Serialize tx state machine 2300 */ 2301 int txState = this->txState; 2302 SERIALIZE_SCALAR(txState); 2303 SERIALIZE_SCALAR(txEnable); 2304 SERIALIZE_SCALAR(CTDD); 2305 SERIALIZE_SCALAR(txFifoAvail); 2306 SERIALIZE_SCALAR(txFragPtr); 2307 SERIALIZE_SCALAR(txDescCnt); 2308 int txDmaState = this->txDmaState; 2309 SERIALIZE_SCALAR(txDmaState); 2310 2311 /* 2312 * Serialize rx state machine 2313 */ 2314 int rxState = this->rxState; 2315 SERIALIZE_SCALAR(rxState); 2316 SERIALIZE_SCALAR(rxEnable); 2317 SERIALIZE_SCALAR(CRDD); 2318 SERIALIZE_SCALAR(rxPktBytes); 2319 SERIALIZE_SCALAR(rxFifoCnt); 2320 SERIALIZE_SCALAR(rxDescCnt); 2321 int rxDmaState = this->rxDmaState; 2322 SERIALIZE_SCALAR(rxDmaState); 2323 2324 SERIALIZE_SCALAR(extstsEnable); 2325 2326 /* 2327 * If there's a pending transmit, store the time so we can 2328 * reschedule it later 2329 */ 2330 Tick transmitTick = txEvent.scheduled() ? txEvent.when() - curTick : 0; 2331 SERIALIZE_SCALAR(transmitTick); 2332 2333 /* 2334 * receive address filter settings 2335 */ 2336 SERIALIZE_SCALAR(rxFilterEnable); 2337 SERIALIZE_SCALAR(acceptBroadcast); 2338 SERIALIZE_SCALAR(acceptMulticast); 2339 SERIALIZE_SCALAR(acceptUnicast); 2340 SERIALIZE_SCALAR(acceptPerfect); 2341 SERIALIZE_SCALAR(acceptArp); 2342 2343 /* 2344 * Keep track of pending interrupt status. 2345 */ 2346 SERIALIZE_SCALAR(intrTick); 2347 SERIALIZE_SCALAR(cpuPendingIntr); 2348 Tick intrEventTick = 0; 2349 if (intrEvent) 2350 intrEventTick = intrEvent->when(); 2351 SERIALIZE_SCALAR(intrEventTick); 2352 2353} 2354 2355void 2356NSGigE::unserialize(Checkpoint *cp, const std::string §ion) 2357{ 2358 // Unserialize the PciDev base class 2359 PciDev::unserialize(cp, section); 2360 2361 UNSERIALIZE_SCALAR(regs.command); 2362 UNSERIALIZE_SCALAR(regs.config); 2363 UNSERIALIZE_SCALAR(regs.mear); 2364 UNSERIALIZE_SCALAR(regs.ptscr); 2365 UNSERIALIZE_SCALAR(regs.isr); 2366 UNSERIALIZE_SCALAR(regs.imr); 2367 UNSERIALIZE_SCALAR(regs.ier); 2368 UNSERIALIZE_SCALAR(regs.ihr); 2369 UNSERIALIZE_SCALAR(regs.txdp); 2370 UNSERIALIZE_SCALAR(regs.txdp_hi); 2371 UNSERIALIZE_SCALAR(regs.txcfg); 2372 UNSERIALIZE_SCALAR(regs.gpior); 2373 UNSERIALIZE_SCALAR(regs.rxdp); 2374 UNSERIALIZE_SCALAR(regs.rxdp_hi); 2375 UNSERIALIZE_SCALAR(regs.rxcfg); 2376 UNSERIALIZE_SCALAR(regs.pqcr); 2377 UNSERIALIZE_SCALAR(regs.wcsr); 2378 UNSERIALIZE_SCALAR(regs.pcr); 2379 UNSERIALIZE_SCALAR(regs.rfcr); 2380 UNSERIALIZE_SCALAR(regs.rfdr); 2381 UNSERIALIZE_SCALAR(regs.srr); 2382 UNSERIALIZE_SCALAR(regs.mibc); 2383 UNSERIALIZE_SCALAR(regs.vrcr); 2384 UNSERIALIZE_SCALAR(regs.vtcr); 2385 UNSERIALIZE_SCALAR(regs.vdr); 2386 UNSERIALIZE_SCALAR(regs.ccsr); 2387 UNSERIALIZE_SCALAR(regs.tbicr); 2388 UNSERIALIZE_SCALAR(regs.tbisr); 2389 UNSERIALIZE_SCALAR(regs.tanar); 2390 UNSERIALIZE_SCALAR(regs.tanlpar); 2391 UNSERIALIZE_SCALAR(regs.taner); 2392 UNSERIALIZE_SCALAR(regs.tesr); 2393 2394 UNSERIALIZE_ARRAY(rom.perfectMatch, EADDR_LEN); 2395 2396 UNSERIALIZE_SCALAR(ioEnable); 2397 2398 /* 2399 * unserialize the data fifos 2400 */ 2401 int txNumPkts; 2402 UNSERIALIZE_SCALAR(txNumPkts); 2403 int i; 2404 for (i = 0; i < txNumPkts; ++i) { 2405 PacketPtr p = new EtherPacket; 2406 p->unserialize(cp, csprintf("%s.rxFifo%d", section, i)); 2407 txFifo.push_back(p); 2408 } 2409 2410 int rxNumPkts; 2411 UNSERIALIZE_SCALAR(rxNumPkts); 2412 for (i = 0; i < rxNumPkts; ++i) { 2413 PacketPtr p = new EtherPacket; 2414 p->unserialize(cp, csprintf("%s.rxFifo%d", section, i)); 2415 rxFifo.push_back(p); 2416 } 2417 2418 /* 2419 * unserialize the various helper variables 2420 */ 2421 bool txPacketExists; 2422 UNSERIALIZE_SCALAR(txPacketExists); 2423 if (txPacketExists) { 2424 txPacket = new EtherPacket; 2425 txPacket->unserialize(cp, csprintf("%s.txPacket", section)); 2426 uint32_t txPktBufPtr; 2427 UNSERIALIZE_SCALAR(txPktBufPtr); 2428 txPacketBufPtr = (uint8_t *) txPacket->data + txPktBufPtr; 2429 } else 2430 txPacket = 0; 2431 2432 bool rxPacketExists; 2433 UNSERIALIZE_SCALAR(rxPacketExists); 2434 rxPacket = 0; 2435 if (rxPacketExists) { 2436 rxPacket = new EtherPacket; 2437 rxPacket->unserialize(cp, csprintf("%s.rxPacket", section)); 2438 uint32_t rxPktBufPtr; 2439 UNSERIALIZE_SCALAR(rxPktBufPtr); 2440 rxPacketBufPtr = (uint8_t *) rxPacket->data + rxPktBufPtr; 2441 } else 2442 rxPacket = 0; 2443 2444 UNSERIALIZE_SCALAR(txXferLen); 2445 UNSERIALIZE_SCALAR(rxXferLen); 2446 2447 /* 2448 * Unserialize DescCaches 2449 */ 2450 UNSERIALIZE_SCALAR(txDescCache.link); 2451 UNSERIALIZE_SCALAR(txDescCache.bufptr); 2452 UNSERIALIZE_SCALAR(txDescCache.cmdsts); 2453 UNSERIALIZE_SCALAR(txDescCache.extsts); 2454 UNSERIALIZE_SCALAR(rxDescCache.link); 2455 UNSERIALIZE_SCALAR(rxDescCache.bufptr); 2456 UNSERIALIZE_SCALAR(rxDescCache.cmdsts); 2457 UNSERIALIZE_SCALAR(rxDescCache.extsts); 2458 2459 /* 2460 * unserialize tx state machine 2461 */ 2462 int txState; 2463 UNSERIALIZE_SCALAR(txState); 2464 this->txState = (TxState) txState; 2465 UNSERIALIZE_SCALAR(txEnable); 2466 UNSERIALIZE_SCALAR(CTDD); 2467 UNSERIALIZE_SCALAR(txFifoAvail); 2468 UNSERIALIZE_SCALAR(txFragPtr); 2469 UNSERIALIZE_SCALAR(txDescCnt); 2470 int txDmaState; 2471 UNSERIALIZE_SCALAR(txDmaState); 2472 this->txDmaState = (DmaState) txDmaState; 2473 2474 /* 2475 * unserialize rx state machine 2476 */ 2477 int rxState; 2478 UNSERIALIZE_SCALAR(rxState); 2479 this->rxState = (RxState) rxState; 2480 UNSERIALIZE_SCALAR(rxEnable); 2481 UNSERIALIZE_SCALAR(CRDD); 2482 UNSERIALIZE_SCALAR(rxPktBytes); 2483 UNSERIALIZE_SCALAR(rxFifoCnt); 2484 UNSERIALIZE_SCALAR(rxDescCnt); 2485 int rxDmaState; 2486 UNSERIALIZE_SCALAR(rxDmaState); 2487 this->rxDmaState = (DmaState) rxDmaState; 2488 2489 UNSERIALIZE_SCALAR(extstsEnable); 2490 2491 /* 2492 * If there's a pending transmit, reschedule it now 2493 */ 2494 Tick transmitTick; 2495 UNSERIALIZE_SCALAR(transmitTick); 2496 if (transmitTick) 2497 txEvent.schedule(curTick + transmitTick); 2498 2499 /* 2500 * unserialize receive address filter settings 2501 */ 2502 UNSERIALIZE_SCALAR(rxFilterEnable); 2503 UNSERIALIZE_SCALAR(acceptBroadcast); 2504 UNSERIALIZE_SCALAR(acceptMulticast); 2505 UNSERIALIZE_SCALAR(acceptUnicast); 2506 UNSERIALIZE_SCALAR(acceptPerfect); 2507 UNSERIALIZE_SCALAR(acceptArp); 2508 2509 /* 2510 * Keep track of pending interrupt status. 2511 */ 2512 UNSERIALIZE_SCALAR(intrTick); 2513 UNSERIALIZE_SCALAR(cpuPendingIntr); 2514 Tick intrEventTick; 2515 UNSERIALIZE_SCALAR(intrEventTick); 2516 if (intrEventTick) { 2517 intrEvent = new IntrEvent(this, true); 2518 intrEvent->schedule(intrEventTick); 2519 } 2520 2521 /* 2522 * re-add addrRanges to bus bridges 2523 */ 2524 if (pioInterface) { 2525 pioInterface->addAddrRange(BARAddrs[0], BARAddrs[0] + BARSize[0] - 1); 2526 pioInterface->addAddrRange(BARAddrs[1], BARAddrs[1] + BARSize[1] - 1); 2527 } 2528} 2529 2530Tick 2531NSGigE::cacheAccess(MemReqPtr &req) 2532{ 2533 DPRINTF(EthernetPIO, "timing access to paddr=%#x (daddr=%#x)\n", 2534 req->paddr, req->paddr - addr); 2535 return curTick + pioLatency; 2536} 2537//===================================================================== 2538 2539 2540//********** helper functions****************************************** 2541 2542uint16_t reverseEnd16(uint16_t num) 2543{ 2544 uint16_t reverse = (num & 0xff)<<8; 2545 reverse += ((num & 0xff00) >> 8); 2546 return reverse; 2547} 2548 2549uint32_t reverseEnd32(uint32_t num) 2550{ 2551 uint32_t reverse = (reverseEnd16(num & 0xffff)) << 16; 2552 reverse += reverseEnd16((uint16_t) ((num & 0xffff0000) >> 8)); 2553 return reverse; 2554} 2555 2556 2557 2558//===================================================================== 2559 2560BEGIN_DECLARE_SIM_OBJECT_PARAMS(NSGigEInt) 2561 2562 SimObjectParam<EtherInt *> peer; 2563 SimObjectParam<NSGigE *> device; 2564 2565END_DECLARE_SIM_OBJECT_PARAMS(NSGigEInt) 2566 2567BEGIN_INIT_SIM_OBJECT_PARAMS(NSGigEInt) 2568 2569 INIT_PARAM_DFLT(peer, "peer interface", NULL), 2570 INIT_PARAM(device, "Ethernet device of this interface") 2571 2572END_INIT_SIM_OBJECT_PARAMS(NSGigEInt) 2573 2574CREATE_SIM_OBJECT(NSGigEInt) 2575{ 2576 NSGigEInt *dev_int = new NSGigEInt(getInstanceName(), device); 2577 2578 EtherInt *p = (EtherInt *)peer; 2579 if (p) { 2580 dev_int->setPeer(p); 2581 p->setPeer(dev_int); 2582 } 2583 2584 return dev_int; 2585} 2586 2587REGISTER_SIM_OBJECT("NSGigEInt", NSGigEInt) 2588 2589 2590BEGIN_DECLARE_SIM_OBJECT_PARAMS(NSGigE) 2591 2592 Param<Tick> tx_delay; 2593 Param<Tick> rx_delay; 2594 SimObjectParam<IntrControl *> intr_ctrl; 2595 Param<Tick> intr_delay; 2596 SimObjectParam<MemoryController *> mmu; 2597 SimObjectParam<PhysicalMemory *> physmem; 2598 Param<bool> rx_filter; 2599 Param<string> hardware_address; 2600 SimObjectParam<Bus*> header_bus; 2601 SimObjectParam<Bus*> payload_bus; 2602 SimObjectParam<HierParams *> hier; 2603 Param<Tick> pio_latency; 2604 Param<bool> dma_desc_free; 2605 Param<bool> dma_data_free; 2606 Param<Tick> dma_read_delay; 2607 Param<Tick> dma_write_delay; 2608 Param<Tick> dma_read_factor; 2609 Param<Tick> dma_write_factor; 2610 SimObjectParam<PciConfigAll *> configspace; 2611 SimObjectParam<PciConfigData *> configdata; 2612 SimObjectParam<Tsunami *> tsunami; 2613 Param<uint32_t> pci_bus; 2614 Param<uint32_t> pci_dev; 2615 Param<uint32_t> pci_func; 2616 Param<uint32_t> tx_fifo_size; 2617 Param<uint32_t> rx_fifo_size; 2618 2619END_DECLARE_SIM_OBJECT_PARAMS(NSGigE) 2620 2621BEGIN_INIT_SIM_OBJECT_PARAMS(NSGigE) 2622 2623 INIT_PARAM_DFLT(tx_delay, "Transmit Delay", 1000), 2624 INIT_PARAM_DFLT(rx_delay, "Receive Delay", 1000), 2625 INIT_PARAM(intr_ctrl, "Interrupt Controller"), 2626 INIT_PARAM_DFLT(intr_delay, "Interrupt Delay in microseconds", 0), 2627 INIT_PARAM(mmu, "Memory Controller"), 2628 INIT_PARAM(physmem, "Physical Memory"), 2629 INIT_PARAM_DFLT(rx_filter, "Enable Receive Filter", true), 2630 INIT_PARAM_DFLT(hardware_address, "Ethernet Hardware Address", 2631 "00:99:00:00:00:01"), 2632 INIT_PARAM_DFLT(header_bus, "The IO Bus to attach to for headers", NULL), 2633 INIT_PARAM_DFLT(payload_bus, "The IO Bus to attach to for payload", NULL), 2634 INIT_PARAM_DFLT(hier, "Hierarchy global variables", &defaultHierParams), 2635 INIT_PARAM_DFLT(pio_latency, "Programmed IO latency in bus cycles", 1), 2636 INIT_PARAM_DFLT(dma_desc_free, "DMA of Descriptors is free", false), 2637 INIT_PARAM_DFLT(dma_data_free, "DMA of Data is free", false), 2638 INIT_PARAM_DFLT(dma_read_delay, "fixed delay for dma reads", 0), 2639 INIT_PARAM_DFLT(dma_write_delay, "fixed delay for dma writes", 0), 2640 INIT_PARAM_DFLT(dma_read_factor, "multiplier for dma reads", 0), 2641 INIT_PARAM_DFLT(dma_write_factor, "multiplier for dma writes", 0), 2642 INIT_PARAM(configspace, "PCI Configspace"), 2643 INIT_PARAM(configdata, "PCI Config data"), 2644 INIT_PARAM(tsunami, "Tsunami"), 2645 INIT_PARAM(pci_bus, "PCI bus"), 2646 INIT_PARAM(pci_dev, "PCI device number"), 2647 INIT_PARAM(pci_func, "PCI function code"), 2648 INIT_PARAM_DFLT(tx_fifo_size, "max size in bytes of txFifo", 131072), 2649 INIT_PARAM_DFLT(rx_fifo_size, "max size in bytes of rxFifo", 131072) 2650 2651END_INIT_SIM_OBJECT_PARAMS(NSGigE) 2652 2653 2654CREATE_SIM_OBJECT(NSGigE) 2655{ 2656 int eaddr[6]; 2657 sscanf(((string)hardware_address).c_str(), "%x:%x:%x:%x:%x:%x", 2658 &eaddr[0], &eaddr[1], &eaddr[2], &eaddr[3], &eaddr[4], &eaddr[5]); 2659 2660 return new NSGigE(getInstanceName(), intr_ctrl, intr_delay, 2661 physmem, tx_delay, rx_delay, mmu, hier, header_bus, 2662 payload_bus, pio_latency, dma_desc_free, dma_data_free, 2663 dma_read_delay, dma_write_delay, dma_read_factor, 2664 dma_write_factor, configspace, configdata, 2665 tsunami, pci_bus, pci_dev, pci_func, rx_filter, eaddr, 2666 tx_fifo_size, rx_fifo_size); 2667} 2668 2669REGISTER_SIM_OBJECT("NSGigE", NSGigE) 2670